mirror of
https://github.com/lucko/LuckPerms.git
synced 2025-09-03 11:22:33 +02:00
Implement standalone/cli app
This commit is contained in:
41
standalone/app/build.gradle
Normal file
41
standalone/app/build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
plugins {
|
||||
id 'net.kyori.blossom' version '1.3.0'
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':api')
|
||||
|
||||
api 'org.apache.logging.log4j:log4j-core:2.17.2'
|
||||
api 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.2'
|
||||
api 'net.minecrell:terminalconsoleappender:1.3.0'
|
||||
api 'org.jline:jline-terminal-jansi:3.20.0'
|
||||
|
||||
api 'com.google.code.gson:gson:2.9.0'
|
||||
api 'com.google.guava:guava:31.1-jre'
|
||||
|
||||
api('net.kyori:adventure-api:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'annotations')
|
||||
}
|
||||
api('net.kyori:adventure-text-serializer-gson:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'gson')
|
||||
}
|
||||
api('net.kyori:adventure-text-serializer-legacy:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
api('net.kyori:adventure-text-serializer-plain:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
api('net.kyori:ansi:1.0.0-SNAPSHOT')
|
||||
}
|
||||
|
||||
blossom {
|
||||
replaceTokenIn('src/main/java/me/lucko/luckperms/standalone/app/LuckPermsApplication.java')
|
||||
replaceToken '@version@', project.ext.fullVersion
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.standalone.app;
|
||||
|
||||
import me.lucko.luckperms.standalone.app.integration.CommandExecutor;
|
||||
import me.lucko.luckperms.standalone.app.integration.DockerCommandSocket;
|
||||
import me.lucko.luckperms.standalone.app.integration.ShutdownCallback;
|
||||
import me.lucko.luckperms.standalone.app.integration.TerminalInterface;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* The LuckPerms standalone application.
|
||||
*/
|
||||
public class LuckPermsApplication implements AutoCloseable {
|
||||
|
||||
/** A logger instance */
|
||||
public static final Logger LOGGER = LogManager.getLogger(LuckPermsApplication.class);
|
||||
|
||||
/** A callback to shutdown the application via the loader bootstrap. */
|
||||
private final ShutdownCallback shutdownCallback;
|
||||
|
||||
/** The instance of the LuckPerms API available within the app */
|
||||
private LuckPerms luckPermsApi;
|
||||
/** A command executor interface to run LuckPerms commands */
|
||||
private CommandExecutor commandExecutor;
|
||||
|
||||
/** If the application is running */
|
||||
private final AtomicBoolean running = new AtomicBoolean(true);
|
||||
|
||||
/** The docker command socket */
|
||||
private DockerCommandSocket dockerCommandSocket;
|
||||
|
||||
public LuckPermsApplication(ShutdownCallback shutdownCallback) {
|
||||
this.shutdownCallback = shutdownCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the app
|
||||
*/
|
||||
public void start(String[] args) {
|
||||
TerminalInterface terminal = new TerminalInterface(this, this.commandExecutor);
|
||||
|
||||
List<String> arguments = Arrays.asList(args);
|
||||
if (arguments.contains("--docker")) {
|
||||
this.dockerCommandSocket = DockerCommandSocket.createAndStart(3000, terminal);
|
||||
}
|
||||
|
||||
terminal.start(); // blocking
|
||||
}
|
||||
|
||||
public void requestShutdown() {
|
||||
this.shutdownCallback.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.running.set(false);
|
||||
|
||||
if (this.dockerCommandSocket != null) {
|
||||
try {
|
||||
this.dockerCommandSocket.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AtomicBoolean runningState() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
// called before start()
|
||||
public void setApi(LuckPerms luckPermsApi) {
|
||||
this.luckPermsApi = luckPermsApi;
|
||||
}
|
||||
|
||||
// called before start()
|
||||
public void setCommandExecutor(CommandExecutor commandExecutor) {
|
||||
this.commandExecutor = commandExecutor;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return "@version@";
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.standalone.app.integration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Minimal command executor interface.
|
||||
*/
|
||||
public interface CommandExecutor {
|
||||
|
||||
CompletableFuture<Void> execute(String command);
|
||||
|
||||
List<String> tabComplete(String command);
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.standalone.app.integration;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Simple/dumb socket that listens for connections on a given port,
|
||||
* reads the input to a string, then executes it as a command.
|
||||
*
|
||||
* Combined with a small sh/nc program, this makes it easy to execute
|
||||
* commands against a standalone instance of LP in a Docker container.
|
||||
*/
|
||||
public class DockerCommandSocket extends ServerSocket implements Runnable {
|
||||
private static final Logger LOGGER = LogManager.getLogger(DockerCommandSocket.class);
|
||||
|
||||
public static DockerCommandSocket createAndStart(int port, TerminalInterface terminal) {
|
||||
DockerCommandSocket socket = null;
|
||||
|
||||
try {
|
||||
socket = new DockerCommandSocket(port, terminal::runCommand);
|
||||
|
||||
Thread thread = new Thread(socket, "docker-command-socket");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
|
||||
LOGGER.info("Created Docker command socket on port 3000");
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error starting docker command socket", e);
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
private final Consumer<String> callback;
|
||||
|
||||
public DockerCommandSocket(int port, Consumer<String> callback) throws IOException {
|
||||
super(port);
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!isClosed()) {
|
||||
try (Socket socket = accept()) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
|
||||
String cmd;
|
||||
while ((cmd = reader.readLine()) != null) {
|
||||
LOGGER.info("Executing command from Docker: " + cmd);
|
||||
this.callback.accept(cmd);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (e instanceof SocketException && e.getMessage().equals("Socket closed")) {
|
||||
return;
|
||||
}
|
||||
LOGGER.error("Error processing input from the Docker socket", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.standalone.app.integration;
|
||||
|
||||
/**
|
||||
* Shutdown callback for the whole standalone app.
|
||||
*
|
||||
* (in practice this is always implemented by the StandaloneLoader class)
|
||||
*/
|
||||
public interface ShutdownCallback {
|
||||
|
||||
void shutdown();
|
||||
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.standalone.app.integration;
|
||||
|
||||
import me.lucko.luckperms.standalone.app.LuckPermsApplication;
|
||||
import me.lucko.luckperms.standalone.app.utils.AnsiUtils;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Dummy/singleton player class used by the standalone plugin.
|
||||
*
|
||||
* In various places (ContextManager, SenderFactory, ..) the platform "player" type is used
|
||||
* as a generic parameter. This class acts as this type for the standalone plugin.
|
||||
*/
|
||||
public class SingletonPlayer {
|
||||
public static final SingletonPlayer INSTANCE = new SingletonPlayer();
|
||||
|
||||
private static final UUID UUID = new UUID(0, 0);
|
||||
|
||||
public String getName() {
|
||||
return "StandaloneUser";
|
||||
}
|
||||
|
||||
public UUID getUniqueId() {
|
||||
return UUID;
|
||||
}
|
||||
|
||||
public void printStdout(Component component) {
|
||||
LuckPermsApplication.LOGGER.info(AnsiUtils.format(component));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.standalone.app.integration;
|
||||
|
||||
import me.lucko.luckperms.standalone.app.LuckPermsApplication;
|
||||
|
||||
import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||
|
||||
import org.jline.reader.Candidate;
|
||||
import org.jline.reader.LineReader;
|
||||
import org.jline.reader.LineReaderBuilder;
|
||||
import org.jline.reader.ParsedLine;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The terminal/console-style interface presented to the user.
|
||||
*/
|
||||
public class TerminalInterface extends SimpleTerminalConsole {
|
||||
private final LuckPermsApplication application;
|
||||
private final CommandExecutor commandExecutor;
|
||||
|
||||
public TerminalInterface(LuckPermsApplication application, CommandExecutor commandExecutor) {
|
||||
this.application = application;
|
||||
this.commandExecutor = commandExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LineReader buildReader(LineReaderBuilder builder) {
|
||||
return super.buildReader(builder
|
||||
.appName("LuckPerms")
|
||||
.completer(this::completeCommand)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRunning() {
|
||||
return this.application.runningState().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdown() {
|
||||
this.application.requestShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runCommand(String command) {
|
||||
command = stripSlashLp(command);
|
||||
|
||||
if (command.equals("stop") || command.equals("exit")) {
|
||||
this.application.requestShutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
this.commandExecutor.execute(command);
|
||||
}
|
||||
|
||||
private void completeCommand(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||
String cmdLine = stripSlashLp(line.line());
|
||||
|
||||
for (String suggestion : this.commandExecutor.tabComplete(cmdLine)) {
|
||||
candidates.add(new Candidate(suggestion));
|
||||
}
|
||||
}
|
||||
|
||||
private static String stripSlashLp(String command) {
|
||||
if (command.startsWith("/")) {
|
||||
command = command.substring(1);
|
||||
}
|
||||
if (command.startsWith("lp ")) {
|
||||
command = command.substring(3);
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.standalone.app.utils;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.flattener.ComponentFlattener;
|
||||
import net.kyori.adventure.text.flattener.FlattenerListener;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.ansi.ANSIComponentRenderer;
|
||||
import net.kyori.ansi.StyleOps;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
/**
|
||||
* Utility to format a {@link Component} as an ANSI string.
|
||||
*/
|
||||
public final class AnsiUtils {
|
||||
private AnsiUtils() {}
|
||||
|
||||
public static String format(Component component) {
|
||||
ANSIComponentRenderer.ToString<Style> formatter = ANSIComponentRenderer.toString(AdventureStyleOps.INSTANCE);
|
||||
ComponentFlattener.basic().flatten(component, new AnsiFlattenerListener(formatter));
|
||||
return formatter.asString();
|
||||
}
|
||||
|
||||
private static final class AnsiFlattenerListener implements FlattenerListener {
|
||||
private final ANSIComponentRenderer.ToString<Style> formatter;
|
||||
|
||||
AnsiFlattenerListener(ANSIComponentRenderer.ToString<Style> formatter) {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushStyle(@NotNull Style style) {
|
||||
this.formatter.pushStyle(style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void component(@NotNull String text) {
|
||||
this.formatter.text(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popStyle(@NotNull Style style) {
|
||||
this.formatter.popStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class AdventureStyleOps implements StyleOps<Style> {
|
||||
private static final AdventureStyleOps INSTANCE = new AdventureStyleOps();
|
||||
|
||||
@Override
|
||||
public State bold(@NotNull Style style) {
|
||||
return state(style.decoration(TextDecoration.BOLD));
|
||||
}
|
||||
|
||||
@Override
|
||||
public State italics(@NotNull Style style) {
|
||||
return state(style.decoration(TextDecoration.ITALIC));
|
||||
}
|
||||
|
||||
@Override
|
||||
public State underlined(@NotNull Style style) {
|
||||
return state(style.decoration(TextDecoration.UNDERLINED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public State strikethrough(@NotNull Style style) {
|
||||
return state(style.decoration(TextDecoration.STRIKETHROUGH));
|
||||
}
|
||||
|
||||
@Override
|
||||
public State obfuscated(@NotNull Style style) {
|
||||
return state(style.decoration(TextDecoration.OBFUSCATED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Range(from = -1L, to = 16777215L) int color(@NotNull Style style) {
|
||||
TextColor color = style.color();
|
||||
return color == null ? StyleOps.COLOR_UNSET : color.value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String font(@NotNull Style style) {
|
||||
Key font = style.font();
|
||||
return font == null ? null : font.asString();
|
||||
}
|
||||
|
||||
private static State state(TextDecoration.State state) {
|
||||
switch (state) {
|
||||
case TRUE:
|
||||
return State.TRUE;
|
||||
case FALSE:
|
||||
return State.FALSE;
|
||||
case NOT_SET:
|
||||
return State.UNSET;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user