Implement standalone/cli app

This commit is contained in:
Luck 2022-07-20 22:46:22 +01:00
parent 8b0d6fd5d2
commit d36341c139
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
29 changed files with 2404 additions and 3 deletions

108
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,108 @@
name: Build Gradle and Publish Docker image
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
branches:
- 'master'
env:
REGISTRY: ghcr.io
IMAGE_NAME: luckperms-standalone
jobs:
build-gradle:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Run build with Gradle wrapper
run: ./gradlew build
- name: Upload all artifacts
uses: actions/upload-artifact@v3
with:
name: jars
path: |
bukkit/loader/build/libs/LuckPerms-Bukkit-*.jar
bukkit-legacy/loader/build/libs/LuckPerms-Bukkit-Legacy-*.jar
bungee/loader/build/libs/LuckPerms-Bungee-*.jar
sponge/loader/build/libs/LuckPerms-Sponge-*.jar
nukkit/loader/build/libs/LuckPerms-Nukkit-*.jar
velocity/build/libs/LuckPerms-Velocity-*.jar
fabric/build/libs/LuckPerms-Fabric-*.jar
forge/loader/build/libs/LuckPerms-Forge-*.jar
standalone/loader/build/libs/LuckPerms-Standalone-*.jar
- name: Upload standalone artifact
uses: actions/upload-artifact@v3
with:
name: standalone-binary
path: standalone/loader/build/libs/LuckPerms-Standalone-*.jar
build-docker:
needs: build-gradle
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Retrieve saved standalone jar artifact
uses: actions/download-artifact@v3
with:
name: standalone-binary
path: standalone/docker/
- name: Display structure of downloaded files
run: ls -R
working-directory: standalone/docker/
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Log in to the Container registry
uses: docker/login-action@v1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
latest=${{ github.ref == 'refs/heads/master' }}
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: standalone/docker/
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -76,7 +76,8 @@ public interface Platform {
NUKKIT("Nukkit"),
VELOCITY("Velocity"),
FABRIC("Fabric"),
FORGE("Forge");
FORGE("Forge"),
STANDALONE("Standalone");
private final String friendlyName;

View File

@ -52,7 +52,8 @@ subprojects {
repositories {
mavenCentral()
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://repo.lucko.me/' }
maven { url 'https://libraries.minecraft.net/' }
}

View File

@ -30,5 +30,8 @@ include (
'sponge:loader',
'sponge:sponge-service',
'sponge:sponge-service-api8',
'velocity'
'velocity',
'standalone',
'standalone:loader',
'standalone:app'
)

View 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
}

View File

@ -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@";
}
}

View File

@ -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);
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}
}

40
standalone/build.gradle Normal file
View File

@ -0,0 +1,40 @@
plugins {
id 'com.github.johnrengelman.shadow' version '7.0.0'
}
dependencies {
implementation project(':common')
compileOnly project(':common:loader-utils')
compileOnly project(':standalone:app')
compileOnly 'org.spongepowered:configurate-yaml:3.7.2'
}
shadowJar {
archiveFileName = 'luckperms-standalone.jarinjar'
dependencies {
include(dependency('me.lucko.luckperms:.*'))
}
relocate 'net.kyori.event', 'me.lucko.luckperms.lib.eventbus'
relocate 'com.github.benmanes.caffeine', 'me.lucko.luckperms.lib.caffeine'
relocate 'okio', 'me.lucko.luckperms.lib.okio'
relocate 'okhttp3', 'me.lucko.luckperms.lib.okhttp3'
relocate 'net.bytebuddy', 'me.lucko.luckperms.lib.bytebuddy'
relocate 'me.lucko.commodore', 'me.lucko.luckperms.lib.commodore'
relocate 'org.mariadb.jdbc', 'me.lucko.luckperms.lib.mariadb'
relocate 'com.mysql', 'me.lucko.luckperms.lib.mysql'
relocate 'org.postgresql', 'me.lucko.luckperms.lib.postgresql'
relocate 'com.zaxxer.hikari', 'me.lucko.luckperms.lib.hikari'
relocate 'com.mongodb', 'me.lucko.luckperms.lib.mongodb'
relocate 'org.bson', 'me.lucko.luckperms.lib.bson'
relocate 'redis.clients.jedis', 'me.lucko.luckperms.lib.jedis'
relocate 'com.rabbitmq', 'me.lucko.luckperms.lib.rabbitmq'
relocate 'org.apache.commons.pool2', 'me.lucko.luckperms.lib.commonspool2'
relocate 'ninja.leaping.configurate', 'me.lucko.luckperms.lib.configurate'
}
artifacts {
archives shadowJar
}

View File

@ -0,0 +1,22 @@
FROM alpine
RUN apk add --no-cache openjdk17 netcat-openbsd
# create a simple 'send' command that will allow users
# to run, for example: docker exec <container> send lp info
RUN printf '#!/bin/sh\n\
echo "$@" | nc -N localhost 3000\n' >> /usr/bin/send && chmod 777 /usr/bin/send
# setup user
RUN addgroup -S app && adduser -S -G app app
USER app
# copy jar file into image
WORKDIR /opt/luckperms
COPY LuckPerms-Standalone-*.jar .
RUN mv * luckperms-standalone.jar
# create volume for data directory
RUN mkdir data
VOLUME ["/opt/luckperms/data"]
CMD ["java", "-jar", "luckperms-standalone.jar", "--docker"]

View File

@ -0,0 +1,37 @@
import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
plugins {
id 'com.github.johnrengelman.shadow'
}
dependencies {
implementation project(':api')
implementation project(':common:loader-utils')
implementation project(':standalone:app')
}
jar {
manifest {
attributes(
'Main-Class': 'me.lucko.luckperms.standalone.loader.StandaloneLoader'
)
}
}
processResources {
include '*.xml'
}
shadowJar {
archiveFileName = "LuckPerms-Standalone-${project.ext.fullVersion}.jar"
from {
project(':standalone').tasks.shadowJar.archiveFile
}
transform(Log4j2PluginsCacheFileTransformer)
}
artifacts {
archives shadowJar
}

View File

@ -0,0 +1,97 @@
/*
* 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.loader;
import me.lucko.luckperms.common.loader.JarInJarClassLoader;
import me.lucko.luckperms.common.loader.LoaderBootstrap;
import me.lucko.luckperms.standalone.app.LuckPermsApplication;
import me.lucko.luckperms.standalone.app.integration.ShutdownCallback;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
/**
* Loader bootstrap for LuckPerms running as a "standalone" app.
*
* There are three main modules:
* 1. the loader (this)
* - performs jar-in-jar loading for the plugin
* - starts the application
* 2. the plugin (LPStandaloneBootstrap, LPStandalonePlugin, etc)
* - implements the standard classes required to create an abstract LuckPerms "plugin")
* 3. the application
* - allows the user to interact with the plugin through a basic terminal layer
*/
public class StandaloneLoader implements ShutdownCallback {
public static final Logger LOGGER = LogManager.getLogger(StandaloneLoader.class);
private static final String JAR_NAME = "luckperms-standalone.jarinjar";
private static final String BOOTSTRAP_CLASS = "me.lucko.luckperms.standalone.LPStandaloneBootstrap";
private LuckPermsApplication app;
private JarInJarClassLoader loader;
private LoaderBootstrap plugin;
// Entrypoint
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOGGER.error("Exception in thread " + t.getName(), e));
StandaloneLoader loader = new StandaloneLoader();
loader.start(args);
}
public void start(String[] args) {
// construct an application, but don't "start" it yet
this.app = new LuckPermsApplication(this);
// create a jar-in-jar classloader for the standalone plugin, then enable it
// the application is passes to the plugin constructor, to allow it to pass hooks back
this.loader = new JarInJarClassLoader(getClass().getClassLoader(), JAR_NAME);
this.plugin = this.loader.instantiatePlugin(BOOTSTRAP_CLASS, LuckPermsApplication.class, this.app);
this.plugin.onLoad();
this.plugin.onEnable();
// start the application
this.app.start(args);
}
@Override
public void shutdown() {
// shutdown in reverse order
this.app.close();
this.plugin.onDisable();
try {
this.loader.close();
} catch (IOException e) {
LOGGER.error(e);
}
LogManager.shutdown(true);
}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" shutdownHook="disable">
<Appenders>
<TerminalConsole name="Console">
<PatternLayout pattern="%highlight{[%d{HH:mm:ss} %level]: %msg%n%xEx}"/>
</TerminalConsole>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>

View File

@ -0,0 +1,199 @@
/*
* 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;
import me.lucko.luckperms.common.loader.LoaderBootstrap;
import me.lucko.luckperms.common.plugin.bootstrap.BootstrappedWithLoader;
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
import me.lucko.luckperms.common.plugin.classpath.ClassPathAppender;
import me.lucko.luckperms.common.plugin.classpath.JarInJarClassPathAppender;
import me.lucko.luckperms.common.plugin.logging.Log4jPluginLogger;
import me.lucko.luckperms.common.plugin.logging.PluginLogger;
import me.lucko.luckperms.standalone.app.LuckPermsApplication;
import net.luckperms.api.platform.Platform;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
/**
* Bootstrap plugin for LuckPerms running as a standalone app.
*/
public class LPStandaloneBootstrap implements LuckPermsBootstrap, LoaderBootstrap, BootstrappedWithLoader {
private final LuckPermsApplication loader;
private final PluginLogger logger;
private final StandaloneSchedulerAdapter schedulerAdapter;
private final ClassPathAppender classPathAppender;
private final LPStandalonePlugin plugin;
private Instant startTime;
private final CountDownLatch loadLatch = new CountDownLatch(1);
private final CountDownLatch enableLatch = new CountDownLatch(1);
public LPStandaloneBootstrap(LuckPermsApplication loader) {
this.loader = loader;
this.logger = new Log4jPluginLogger(LuckPermsApplication.LOGGER);
this.schedulerAdapter = new StandaloneSchedulerAdapter(this);
this.classPathAppender = new JarInJarClassPathAppender(getClass().getClassLoader());
this.plugin = new LPStandalonePlugin(this);
}
// provide adapters
@Override
public LuckPermsApplication getLoader() {
return this.loader;
}
@Override
public PluginLogger getPluginLogger() {
return this.logger;
}
@Override
public StandaloneSchedulerAdapter getScheduler() {
return this.schedulerAdapter;
}
@Override
public ClassPathAppender getClassPathAppender() {
return this.classPathAppender;
}
// lifecycle
@Override
public void onLoad() {
try {
this.plugin.load();
} finally {
this.loadLatch.countDown();
}
}
@Override
public void onEnable() {
this.startTime = Instant.now();
try {
this.plugin.enable();
} finally {
this.enableLatch.countDown();
}
}
@Override
public void onDisable() {
this.plugin.disable();
}
@Override
public CountDownLatch getEnableLatch() {
return this.enableLatch;
}
@Override
public CountDownLatch getLoadLatch() {
return this.loadLatch;
}
// provide information about the plugin
@Override
public String getVersion() {
return this.loader.getVersion();
}
@Override
public Instant getStartupTime() {
return this.startTime;
}
// provide information about the platform
@Override
public Platform.Type getType() {
return Platform.Type.STANDALONE;
}
@Override
public String getServerBrand() {
return "standalone";
}
@Override
public String getServerVersion() {
return "n/a";
}
@Override
public Path getDataDirectory() {
return Paths.get("data").toAbsolutePath();
}
@Override
public Optional<?> getPlayer(UUID uniqueId) {
return Optional.empty();
}
@Override
public Optional<UUID> lookupUniqueId(String username) {
return Optional.empty();
}
@Override
public Optional<String> lookupUsername(UUID uniqueId) {
return Optional.empty();
}
@Override
public int getPlayerCount() {
return 0;
}
@Override
public Collection<String> getPlayerList() {
return Collections.emptyList();
}
@Override
public Collection<UUID> getOnlinePlayers() {
return Collections.emptyList();
}
@Override
public boolean isPlayerOnline(UUID uniqueId) {
return false;
}
}

View File

@ -0,0 +1,208 @@
/*
* 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;
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.calculator.CalculatorFactory;
import me.lucko.luckperms.common.config.generic.adapter.ConfigurationAdapter;
import me.lucko.luckperms.common.dependencies.Dependency;
import me.lucko.luckperms.common.event.AbstractEventBus;
import me.lucko.luckperms.common.messaging.MessagingFactory;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.model.manager.group.StandardGroupManager;
import me.lucko.luckperms.common.model.manager.track.StandardTrackManager;
import me.lucko.luckperms.common.model.manager.user.StandardUserManager;
import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
import me.lucko.luckperms.standalone.app.LuckPermsApplication;
import me.lucko.luckperms.standalone.dummy.StandaloneContextManager;
import me.lucko.luckperms.standalone.dummy.StandaloneDummyConnectionListener;
import me.lucko.luckperms.standalone.dummy.StandaloneEventBus;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.query.QueryOptions;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
/**
* LuckPerms implementation for the standalone app.
*/
public class LPStandalonePlugin extends AbstractLuckPermsPlugin {
private final LPStandaloneBootstrap bootstrap;
private StandaloneSenderFactory senderFactory;
private StandaloneDummyConnectionListener connectionListener;
private StandaloneCommandManager commandManager;
private StandardUserManager userManager;
private StandardGroupManager groupManager;
private StandardTrackManager trackManager;
private StandaloneContextManager contextManager;
public LPStandalonePlugin(LPStandaloneBootstrap bootstrap) {
this.bootstrap = bootstrap;
}
@Override
public LPStandaloneBootstrap getBootstrap() {
return this.bootstrap;
}
public LuckPermsApplication getLoader() {
return this.bootstrap.getLoader();
}
@Override
protected void setupSenderFactory() {
this.senderFactory = new StandaloneSenderFactory(this);
}
@Override
protected Set<Dependency> getGlobalDependencies() {
Set<Dependency> dependencies = super.getGlobalDependencies();
dependencies.remove(Dependency.ADVENTURE);
dependencies.add(Dependency.CONFIGURATE_CORE);
dependencies.add(Dependency.CONFIGURATE_YAML);
dependencies.add(Dependency.SNAKEYAML);
return dependencies;
}
@Override
protected ConfigurationAdapter provideConfigurationAdapter() {
return new StandaloneConfigAdapter(this, resolveConfig("config.yml"));
}
@Override
protected void registerPlatformListeners() {
this.connectionListener = new StandaloneDummyConnectionListener(this);
}
@Override
protected MessagingFactory<?> provideMessagingFactory() {
return new StandaloneMessagingFactory(this);
}
@Override
protected void registerCommands() {
this.commandManager = new StandaloneCommandManager(this);
this.bootstrap.getLoader().setCommandExecutor(this.commandManager);
}
@Override
protected void setupManagers() {
this.userManager = new StandardUserManager(this);
this.groupManager = new StandardGroupManager(this);
this.trackManager = new StandardTrackManager(this);
}
@Override
protected CalculatorFactory provideCalculatorFactory() {
return new StandaloneCalculatorFactory(this);
}
@Override
protected void setupContextManager() {
this.contextManager = new StandaloneContextManager(this);
}
@Override
protected void setupPlatformHooks() {
}
@Override
protected AbstractEventBus<?> provideEventBus(LuckPermsApiProvider apiProvider) {
return new StandaloneEventBus(this, apiProvider);
}
@Override
protected void registerApiOnPlatform(LuckPerms api) {
this.bootstrap.getLoader().setApi(api);
}
@Override
protected void performFinalSetup() {
}
@Override
protected void removePlatformHooks() {
}
@Override
public Optional<QueryOptions> getQueryOptionsForUser(User user) {
return Optional.empty();
}
@Override
public Stream<Sender> getOnlineSenders() {
return Stream.of(getConsoleSender());
}
@Override
public Sender getConsoleSender() {
return getSenderFactory().wrap(SingletonPlayer.INSTANCE);
}
public StandaloneSenderFactory getSenderFactory() {
return this.senderFactory;
}
@Override
public AbstractConnectionListener getConnectionListener() {
return this.connectionListener;
}
@Override
public StandaloneCommandManager getCommandManager() {
return this.commandManager;
}
@Override
public StandardUserManager getUserManager() {
return this.userManager;
}
@Override
public StandardGroupManager getGroupManager() {
return this.groupManager;
}
@Override
public StandardTrackManager getTrackManager() {
return this.trackManager;
}
@Override
public StandaloneContextManager getContextManager() {
return this.contextManager;
}
}

View File

@ -0,0 +1,70 @@
/*
* 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;
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
import me.lucko.luckperms.common.calculator.CalculatorFactory;
import me.lucko.luckperms.common.calculator.PermissionCalculator;
import me.lucko.luckperms.common.calculator.processor.DirectProcessor;
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
import me.lucko.luckperms.common.calculator.processor.RegexProcessor;
import me.lucko.luckperms.common.calculator.processor.SpongeWildcardProcessor;
import me.lucko.luckperms.common.calculator.processor.WildcardProcessor;
import me.lucko.luckperms.common.config.ConfigKeys;
import net.luckperms.api.query.QueryOptions;
import java.util.ArrayList;
import java.util.List;
public class StandaloneCalculatorFactory implements CalculatorFactory {
private final LPStandalonePlugin plugin;
public StandaloneCalculatorFactory(LPStandalonePlugin plugin) {
this.plugin = plugin;
}
@Override
public PermissionCalculator build(QueryOptions queryOptions, CacheMetadata metadata) {
List<PermissionProcessor> processors = new ArrayList<>(8);
processors.add(new DirectProcessor());
if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) {
processors.add(new RegexProcessor());
}
if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS)) {
processors.add(new WildcardProcessor());
}
if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS_SPONGE)) {
processors.add(new SpongeWildcardProcessor());
}
return new PermissionCalculator(this.plugin, metadata, processors);
}
}

View File

@ -0,0 +1,59 @@
/*
* 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;
import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.command.utils.ArgumentTokenizer;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.standalone.app.integration.CommandExecutor;
import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class StandaloneCommandManager extends CommandManager implements CommandExecutor {
private final LPStandalonePlugin plugin;
public StandaloneCommandManager(LPStandalonePlugin plugin) {
super(plugin);
this.plugin = plugin;
}
@Override
public CompletableFuture<Void> execute(String command) {
Sender wrapped = this.plugin.getSenderFactory().wrap(SingletonPlayer.INSTANCE);
List<String> arguments = ArgumentTokenizer.EXECUTE.tokenizeInput(command);
return executeCommand(wrapped, "lp", arguments);
}
@Override
public List<String> tabComplete(String command) {
Sender wrapped = this.plugin.getSenderFactory().wrap(SingletonPlayer.INSTANCE);
List<String> arguments = ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(command);
return tabCompleteCommand(wrapped, arguments);
}
}

View File

@ -0,0 +1,47 @@
/*
* 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;
import me.lucko.luckperms.common.config.generic.adapter.ConfigurateConfigAdapter;
import me.lucko.luckperms.common.config.generic.adapter.ConfigurationAdapter;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import java.nio.file.Path;
public class StandaloneConfigAdapter extends ConfigurateConfigAdapter implements ConfigurationAdapter {
public StandaloneConfigAdapter(LuckPermsPlugin plugin, Path path) {
super(plugin, path);
}
@Override
protected ConfigurationLoader<? extends ConfigurationNode> createLoader(Path path) {
return YAMLConfigurationLoader.builder().setPath(path).build();
}
}

View File

@ -0,0 +1,41 @@
/*
* 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;
import me.lucko.luckperms.standalone.LPStandalonePlugin;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.messaging.MessagingFactory;
public class StandaloneMessagingFactory extends MessagingFactory<LPStandalonePlugin> {
public StandaloneMessagingFactory(LPStandalonePlugin plugin) {
super(plugin);
}
@Override
protected InternalMessagingService getServiceFor(String messagingType) {
return super.getServiceFor(messagingType);
}
}

View File

@ -0,0 +1,44 @@
/*
* 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;
import me.lucko.luckperms.common.plugin.scheduler.AbstractJavaScheduler;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
import java.util.concurrent.Executor;
public class StandaloneSchedulerAdapter extends AbstractJavaScheduler implements SchedulerAdapter {
public StandaloneSchedulerAdapter(LPStandaloneBootstrap bootstrap) {
super(bootstrap);
}
@Override
public Executor sync() {
return this.async();
}
}

View File

@ -0,0 +1,80 @@
/*
* 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;
import me.lucko.luckperms.common.locale.TranslationManager;
import me.lucko.luckperms.common.sender.SenderFactory;
import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
import net.kyori.adventure.text.Component;
import net.luckperms.api.util.Tristate;
import java.util.Locale;
import java.util.UUID;
public class StandaloneSenderFactory extends SenderFactory<LPStandalonePlugin, SingletonPlayer> {
public StandaloneSenderFactory(LPStandalonePlugin plugin) {
super(plugin);
}
@Override
protected String getName(SingletonPlayer sender) {
return sender.getName();
}
@Override
protected UUID getUniqueId(SingletonPlayer sender) {
return sender.getUniqueId();
}
@Override
protected void sendMessage(SingletonPlayer sender, Component message) {
Component rendered = TranslationManager.render(message, Locale.getDefault());
sender.printStdout(rendered);
}
@Override
protected Tristate getPermissionValue(SingletonPlayer sender, String node) {
return Tristate.TRUE;
}
@Override
protected boolean hasPermission(SingletonPlayer sender, String node) {
return true;
}
@Override
protected void performCommand(SingletonPlayer sender, String command) {
}
@Override
protected boolean isConsole(SingletonPlayer sender) {
return true;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.dummy;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.context.manager.ContextManager;
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
import me.lucko.luckperms.standalone.LPStandalonePlugin;
import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.query.QueryOptions;
import java.util.UUID;
public class StandaloneContextManager extends ContextManager<SingletonPlayer, SingletonPlayer> {
private final QueryOptionsCache<SingletonPlayer> singletonCache = new QueryOptionsCache<>(SingletonPlayer.INSTANCE, this);
public StandaloneContextManager(LPStandalonePlugin plugin) {
super(plugin, SingletonPlayer.class, SingletonPlayer.class);
}
@Override
public UUID getUniqueId(SingletonPlayer player) {
return player.getUniqueId();
}
@Override
public QueryOptionsCache<SingletonPlayer> getCacheFor(SingletonPlayer subject) {
if (subject == null) {
throw new NullPointerException("subject");
}
return this.singletonCache;
}
@Override
protected void invalidateCache(SingletonPlayer subject) {
this.singletonCache.invalidate();
}
@Override
public QueryOptions formQueryOptions(SingletonPlayer subject, ImmutableContextSet contextSet) {
QueryOptions.Builder queryOptions = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder();
return queryOptions.context(contextSet).build();
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.dummy;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener;
public class StandaloneDummyConnectionListener extends AbstractConnectionListener {
public StandaloneDummyConnectionListener(LuckPermsPlugin plugin) {
super(plugin);
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.dummy;
import me.lucko.luckperms.common.api.LuckPermsApiProvider;
import me.lucko.luckperms.common.event.AbstractEventBus;
import me.lucko.luckperms.standalone.LPStandalonePlugin;
public class StandaloneEventBus extends AbstractEventBus<Object> {
public StandaloneEventBus(LPStandalonePlugin plugin, LuckPermsApiProvider apiProvider) {
super(plugin, apiProvider);
}
@Override
protected Object checkPlugin(Object plugin) throws IllegalArgumentException {
return plugin;
}
}

View File

@ -0,0 +1,567 @@
####################################################################################################
# +----------------------------------------------------------------------------------------------+ #
# | __ __ ___ __ __ | #
# | | | | / ` |__/ |__) |__ |__) |\/| /__` | #
# | |___ \__/ \__, | \ | |___ | \ | | .__/ | #
# | | #
# | https://luckperms.net | #
# | | #
# | WIKI: https://luckperms.net/wiki | #
# | DISCORD: https://discord.gg/luckperms | #
# | BUG REPORTS: https://github.com/lucko/LuckPerms/issues | #
# | | #
# | Each option in this file is documented and explained here: | #
# | ==> https://luckperms.net/wiki/Configuration | #
# | | #
# | New options are not added to this file automatically. Default values are used if an | #
# | option cannot be found. The latest config versions can be obtained at the link above. | #
# +----------------------------------------------------------------------------------------------+ #
####################################################################################################
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | ESSENTIAL SETTINGS | #
# | | #
# | Important settings that control how LuckPerms functions. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# The name of the server, used for server specific permissions.
#
# - When set to "global" this setting is effectively ignored.
# - In all other cases, the value here is added to all players in a "server" context.
# - See: https://luckperms.net/wiki/Context
server: global
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | STORAGE SETTINGS | #
# | | #
# | Controls which storage method LuckPerms will use to store data. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# How the plugin should store data
#
# - The various options are explained in more detail on the wiki:
# https://luckperms.net/wiki/Storage-types
#
# - Possible options:
#
# | Remote databases - require connection information to be configured below
# |=> MySQL
# |=> MariaDB (preferred over MySQL)
# |=> PostgreSQL
# |=> MongoDB
#
# | Flatfile/local database - don't require any extra configuration
# |=> H2 (preferred over SQLite)
# |=> SQLite
#
# | Readable & editable text files - don't require any extra configuration
# |=> YAML (.yml files)
# |=> JSON (.json files)
# |=> HOCON (.conf files)
# |=> TOML (.toml files)
# |
# | By default, user, group and track data is separated into different files. Data can be combined
# | and all stored in the same file by switching to a combined storage variant.
# | Just add '-combined' to the end of the storage-method, e.g. 'yaml-combined'
#
# - A H2 database is the default option.
# - If you want to edit data manually in "traditional" storage files, we suggest using YAML.
storage-method: h2
# The following block defines the settings for remote database storage methods.
#
# - You don't need to touch any of the settings here if you're using a local storage method!
# - The connection detail options are shared between all remote storage types.
data:
# Define the address and port for the database.
# - The standard DB engine port is used by default
# (MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017)
# - Specify as "host:port" if differs
address: localhost
# The name of the database to store LuckPerms data in.
# - This must be created already. Don't worry about this setting if you're using MongoDB.
database: minecraft
# Credentials for the database.
username: root
password: ''
# These settings apply to the MySQL connection pool.
# - The default values will be suitable for the majority of users.
# - Do not change these settings unless you know what you're doing!
pool-settings:
# Sets the maximum size of the MySQL connection pool.
# - Basically this value will determine the maximum number of actual
# connections to the database backend.
# - More information about determining the size of connection pools can be found here:
# https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
maximum-pool-size: 10
# Sets the minimum number of idle connections that the pool will try to maintain.
# - For maximum performance and responsiveness to spike demands, it is recommended to not set
# this value and instead allow the pool to act as a fixed size connection pool.
# (set this value to the same as 'maximum-pool-size')
minimum-idle: 10
# This setting controls the maximum lifetime of a connection in the pool in milliseconds.
# - The value should be at least 30 seconds less than any database or infrastructure imposed
# connection time limit.
maximum-lifetime: 1800000 # 30 minutes
# This setting controls how frequently the pool will 'ping' a connection in order to prevent it
# from being timed out by the database or network infrastructure, measured in milliseconds.
# - The value should be less than maximum-lifetime and greater than 30000 (30 seconds).
# - Setting the value to zero will disable the keepalive functionality.
keepalive-time: 0
# This setting controls the maximum number of milliseconds that the plugin will wait for a
# connection from the pool, before timing out.
connection-timeout: 5000 # 5 seconds
# This setting allows you to define extra properties for connections.
#
# By default, the following options are set to enable utf8 encoding. (you may need to remove
# these if you are using PostgreSQL)
# useUnicode: true
# characterEncoding: utf8
#
# You can also use this section to disable SSL connections, by uncommenting the 'useSSL' and
# 'verifyServerCertificate' options below.
properties:
useUnicode: true
characterEncoding: utf8
#useSSL: false
#verifyServerCertificate: false
# The prefix for all LuckPerms SQL tables.
#
# - This only applies for remote SQL storage types (MySQL, MariaDB, etc).
# - Change this if you want to use different tables for different servers.
table-prefix: 'luckperms_'
# The prefix to use for all LuckPerms MongoDB collections.
#
# - This only applies for the MongoDB storage type.
# - Change this if you want to use different collections for different servers. The default is no
# prefix.
mongodb-collection-prefix: ''
# The connection string URI to use to connect to the MongoDB instance.
#
# - When configured, this setting will override anything defined in the address, database,
# username or password fields above.
# - If you have a connection string that starts with 'mongodb://' or 'mongodb+srv://', enter it
# below.
# - For more information, please see https://docs.mongodb.com/manual/reference/connection-string/
mongodb-connection-uri: ''
# Define settings for a "split" storage setup.
#
# - This allows you to define a storage method for each type of data.
# - The connection options above still have to be correct for each type here.
split-storage:
# Don't touch this if you don't want to use split storage!
enabled: false
methods:
# These options don't need to be modified if split storage isn't enabled.
user: h2
group: h2
track: h2
uuid: h2
log: h2
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | UPDATE PROPAGATION & MESSAGING SERVICE | #
# | | #
# | Controls the ways in which LuckPerms will sync data & notify other servers of changes. | #
# | These options are documented on greater detail on the wiki under "Instant Updates". | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# This option controls how frequently LuckPerms will perform a sync task.
#
# - A sync task will refresh all data from the storage, and ensure that the most up-to-date data is
# being used by the plugin.
# - This is disabled by default, as most users will not need it. However, if you're using a remote
# storage type without a messaging service setup, you may wish to set this to something like 3.
# - Set to -1 to disable the task completely.
sync-minutes: -1
# If the file watcher should be enabled.
#
# - When using a file-based storage type, LuckPerms can monitor the data files for changes, and
# automatically update when changes are detected.
# - If you don't want this feature to be active, set this option to false.
watch-files: true
# Define which messaging service should be used by the plugin.
#
# - If enabled and configured, LuckPerms will use the messaging service to inform other connected
# servers of changes.
# - Use the command "/lp networksync" to manually push changes.
# - Data is NOT stored using this service. It is only used as a messaging platform.
#
# - If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need
# for LuckPerms to poll the database for changes.
#
# - Possible options:
# => sql Uses the SQL database to form a queue system for communication. Will only work when
# 'storage-method' is set to MySQL or MariaDB. This is chosen by default if the
# option is set to 'auto' and SQL storage is in use. Set to 'notsql' to disable this.
# => redis Uses Redis pub-sub to push changes. Your server connection info must be configured
# below.
# => rabbitmq Uses RabbitMQ pub-sub to push changes. Your server connection info must be
# configured below.
# => custom Uses a messaging service provided using the LuckPerms API.
# => auto Attempts to automatically setup a messaging service using redis or sql.
messaging-service: auto
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# - If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you
# should set this option to false on either your backends or your proxies, to avoid players being
# messaged twice about log entries.
broadcast-received-log-entries: true
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
redis:
enabled: false
address: localhost
username: ''
password: ''
# Settings for RabbitMQ.
# Port 5672 is used by default; set address to "host:port" if differs
rabbitmq:
enabled: false
address: localhost
vhost: '/'
username: 'guest'
password: 'guest'
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | CUSTOMIZATION SETTINGS | #
# | | #
# | Settings that allow admins to customize the way LuckPerms operates. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# Controls how temporary permissions/parents/meta should be accumulated.
#
# - The default behaviour is "deny".
# - This behaviour can also be specified when the command is executed. See the command usage
# documentation for more info.
#
# - Possible options:
# => accumulate durations will be added to the existing expiry time
# => replace durations will be replaced if the new duration is later than the current
# expiration
# => deny the command will just fail if you try to add another node with the same expiry
temporary-add-behaviour: deny
# Controls how LuckPerms will determine a users "primary" group.
#
# - The meaning and influence of "primary groups" are explained in detail on the wiki.
# - The preferred approach is to let LuckPerms automatically determine a users primary group
# based on the relative weight of their parent groups.
#
# - Possible options:
# => stored use the value stored against the users record in the file/database
# => parents-by-weight just use the users most highly weighted parent
# => all-parents-by-weight same as above, but calculates based upon all parents inherited from
# both directly and indirectly
primary-group-calculation: parents-by-weight
# If the plugin should check for "extra" permissions with users run LP commands.
#
# - These extra permissions allow finer control over what users can do with each command, and who
# they have access to edit.
# - The nature of the checks are documented on the wiki under "Argument based command permissions".
# - Argument based permissions are *not* static, unlike the 'base' permissions, and will depend upon
# the arguments given within the command.
argument-based-command-permissions: false
# If the plugin should check whether senders are a member of a given group before they're able to
# edit the groups data or add/remove other users to/from it.
# Note: these limitations do not apply to the web editor!
require-sender-group-membership-to-modify: false
# If the plugin should send log notifications to users whenever permissions are modified.
#
# - Notifications are only sent to those with the appropriate permission to receive them
# - They can also be temporarily enabled/disabled on a per-user basis using
# '/lp log notify <on|off>'
log-notify: true
# Defines a list of log entries which should not be sent as notifications to users.
#
# - Each entry in the list is a RegEx expression which is matched against the log entry description.
log-notify-filtered-descriptions:
# - "parent add example"
# If LuckPerms should automatically install translation bundles and periodically update them.
auto-install-translations: true
# Defines the options for prefix and suffix stacking.
#
# - The feature allows you to display multiple prefixes or suffixes alongside a players username in
# chat.
# - It is explained and documented in more detail on the wiki under "Prefix & Suffix Stacking".
#
# - The options are divided into separate sections for prefixes and suffixes.
# - The 'duplicates' setting refers to how duplicate elements are handled. Can be 'retain-all',
# 'first-only' or 'last-only'.
# - The value of 'start-spacer' is included at the start of the resultant prefix/suffix.
# - The value of 'end-spacer' is included at the end of the resultant prefix/suffix.
# - The value of 'middle-spacer' is included between each element in the resultant prefix/suffix.
#
# - Possible format options:
# => highest Selects the value with the highest weight, from all values
# held by or inherited by the player.
#
# => lowest Same as above, except takes the one with the lowest weight.
#
# => highest_own Selects the value with the highest weight, but will not
# accept any inherited values.
#
# => lowest_own Same as above, except takes the value with the lowest weight.
#
# => highest_inherited Selects the value with the highest weight, but will only
# accept inherited values.
#
# => lowest_inherited Same as above, except takes the value with the lowest weight.
#
# => highest_on_track_<track> Selects the value with the highest weight, but only if the
# value was inherited from a group on the given track.
#
# => lowest_on_track_<track> Same as above, except takes the value with the lowest weight.
#
# => highest_not_on_track_<track> Selects the value with the highest weight, but only if the
# value was inherited from a group not on the given track.
#
# => lowest_not_on_track_<track> Same as above, except takes the value with the lowest weight.
#
# => highest_from_group_<group> Selects the value with the highest weight, but only if the
# value was inherited from the given group.
#
# => lowest_from_group_<group> Same as above, except takes the value with the lowest weight.
#
# => highest_not_from_group_<group> Selects the value with the highest weight, but only if the
# value was not inherited from the given group.
#
# => lowest_not_from_group_<group> Same as above, except takes the value with the lowest weight.
meta-formatting:
prefix:
format:
- "highest"
duplicates: first-only
start-spacer: ""
middle-spacer: " "
end-spacer: ""
suffix:
format:
- "highest"
duplicates: first-only
start-spacer: ""
middle-spacer: " "
end-spacer: ""
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | PERMISSION CALCULATION AND INHERITANCE | #
# | | #
# | Modify the way permission checks, meta lookups and inheritance resolutions are handled. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# The algorithm LuckPerms should use when traversing the "inheritance tree".
#
# - Possible options:
# => breadth-first See: https://en.wikipedia.org/wiki/Breadth-first_search
# => depth-first-pre-order See: https://en.wikipedia.org/wiki/Depth-first_search
# => depth-first-post-order See: https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# If a final sort according to "inheritance rules" should be performed after the traversal algorithm
# has resolved the inheritance tree.
#
# "Inheritance rules" refers to things such as group weightings, primary group status, and the
# natural contextual ordering of the group nodes.
#
# Setting this to 'true' will allow for the inheritance rules to take priority over the structure of
# the inheritance tree.
#
# Effectively when this setting is 'true': the tree is flattened, and rules applied afterwards,
# and when this setting is 'false':, the rules are just applied during each step of the traversal.
post-traversal-inheritance-sort: false
# Defines the mode used to determine whether a set of contexts are satisfied.
#
# - Possible options:
# => at-least-one-value-per-key Set A will be satisfied by another set B, if at least one of the
# key-value entries per key in A are also in B.
# => all-values-per-key Set A will be satisfied by another set B, if all key-value
# entries in A are also in B.
context-satisfy-mode: at-least-one-value-per-key
# +----------------------------------------------------------------------------------------------+ #
# | Permission resolution settings | #
# +----------------------------------------------------------------------------------------------+ #
# If users on this server should have their global permissions applied.
# When set to false, only server specific permissions will apply for users on this server
include-global: true
# If users on this server should have their global world permissions applied.
# When set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# +----------------------------------------------------------------------------------------------+ #
# | Meta lookup settings | #
# +----------------------------------------------------------------------------------------------+ #
# Defines how meta values should be selected.
#
# - Possible options:
# => inheritance Selects the meta value that was inherited first
# => highest-number Selects the highest numerical meta value
# => lowest-number Selects the lowest numerical meta value
meta-value-selection-default: inheritance
# Defines how meta values should be selected per key.
meta-value-selection:
# max-homes: highest-number
# +----------------------------------------------------------------------------------------------+ #
# | Inheritance settings | #
# +----------------------------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
#
# - If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered
# permissions matching the wildcard.
apply-wildcards: true
# If LuckPerms should resolve and apply permissions according to the Sponge style implicit wildcard
# inheritance system.
#
# - That being: If a user has been granted "example", then the player should have also be
# automatically granted "example.function", "example.another", "example.deeper.nesting",
# and so on.
apply-sponge-implicit-wildcards: false
# If the plugin should apply negated Bukkit default permissions before it considers wildcard
# assignments.
#
# - Plugin authors can define permissions which explicitly should not be given automatically to OPs.
# This is usually used for so called "anti-permissions" - permissions which, when granted, apply
# something negative.
# - If this option is set to true, LuckPerms will consider any negated declarations made by
# plugins before it considers wildcards. (similar to the way the OP system works)
# - If this option is set to false, LuckPerms will consider any wildcard assignments first.
apply-default-negated-permissions-before-wildcards: false
# If the plugin should parse regex permissions.
#
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
# node, and resolve & apply all registered permissions matching the regex.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
#
# - If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# +----------------------------------------------------------------------------------------------+ #
# | Extra settings | #
# +----------------------------------------------------------------------------------------------+ #
# A list of context calculators which will be skipped when calculating contexts.
#
# - You can disable context calculators by either:
# => specifying the Java class name used by the calculator (e.g. com.example.ExampleCalculator)
# => specifying a sub-section of the Java package used by the calculator (e.g. com.example)
disabled-context-calculators: []
# Define special group weights for this server.
#
# - Group weights can also be applied directly to group data, using the setweight command.
# - This section allows weights to be set on a per-server basis.
group-weight:
# admin: 10
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | FINE TUNING OPTIONS | #
# | | #
# | A number of more niche settings for tweaking and changing behaviour. The section also | #
# | contains toggles for some more specialised features. It is only necessary to make changes to | #
# | these options if you want to fine-tune LuckPerms behaviour. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# +----------------------------------------------------------------------------------------------+ #
# | Miscellaneous (and rarely used) settings | #
# +----------------------------------------------------------------------------------------------+ #
# If LuckPerms should allow usernames with non alphanumeric characters.
#
# - Note that due to the design of the storage implementation, usernames must still be 16 characters
# or less.
allow-invalid-usernames: false
# If LuckPerms should not require users to confirm bulkupdate operations.
#
# - When set to true, operations will be executed immediately.
# - This is not recommended, as bulkupdate has the potential to irreversibly delete large amounts of
# data, and is not designed to be executed automatically.
# - If automation is needed, users should prefer using the LuckPerms API.
skip-bulkupdate-confirmation: false
# If LuckPerms should prevent bulkupdate operations.
#
# - When set to true, bulkupdate operations (the /lp bulkupdate command) will not work.
# - When set to false, bulkupdate operations will be allowed via the console.
disable-bulkupdate: false
# If LuckPerms should allow a users primary group to be removed with the 'parent remove' command.
#
# - When this happens, the plugin will set their primary group back to default.
prevent-primary-group-removal: false