From 3c8dc9ecd40821491833330115af18a3b628d8b3 Mon Sep 17 00:00:00 2001 From: "Reichenbach, Michael" Date: Fri, 21 Jan 2022 08:28:24 +0100 Subject: [PATCH] feat: add platform module with config and commands --- platform/build.gradle | 40 +++++ .../template/platform/command/Command.java | 29 ++++ .../template/platform/command/Commands.java | 54 ++++++ .../command/commands/ExampleCommand.java | 30 ++++ .../template/platform/config/Config.java | 35 ++++ .../template/platform/config/ConfigKeys.java | 50 ++++++ .../platform/config/TemplateConfig.java | 32 ++++ .../config/adapter/ConfigurateAdapter.java | 72 ++++++++ .../adapter/ConfigurateConfigSection.java | 125 ++++++++++++++ .../config/adapter/ConfigurationAdapter.java | 47 ++++++ .../config/adapter/ConfigurationAdapters.java | 49 ++++++ .../config/adapter/ConfigurationSection.java | 48 ++++++ .../platform/config/key/ConfigKey.java | 52 ++++++ .../platform/config/key/ConfigKeyFactory.java | 90 ++++++++++ .../config/key/KeyedConfiguration.java | 159 ++++++++++++++++++ .../config/key/ModifiableConfigKey.java | 33 ++++ .../platform/config/key/SimpleConfigKey.java | 64 +++++++ .../config/key/SimpleModifiableConfigKey.java | 38 +++++ .../MiniMessageComponentSerializer.java | 45 +++++ .../serializers/SettingsSerializer.java | 54 ++++++ .../template/platform/locale/Messages.java | 147 ++++++++++++++++ .../plugin/AbstractTemplatePlugin.java | 105 ++++++++++++ .../platform/plugin/TemplatePlugin.java | 41 +++++ .../platform/plugin/bootstrap/Bootstrap.java | 68 ++++++++ .../plugin/bootstrap/LoaderBootstrap.java | 33 ++++ .../plugin/logging/JavaPluginLogger.java | 57 +++++++ .../platform/plugin/logging/PluginLogger.java | 40 +++++ .../scheduler/AbstractJavaScheduler.java | 124 ++++++++++++++ .../plugin/scheduler/SchedulerAdapter.java | 96 +++++++++++ .../plugin/scheduler/SchedulerTask.java | 31 ++++ .../platform/sender/DummyConsoleSender.java | 47 ++++++ .../platform/sender/FactorySender.java | 118 +++++++++++++ .../platform/sender/PlayerOnlineChecker.java | 28 +++ .../template/platform/sender/Sender.java | 90 ++++++++++ .../platform/sender/SenderFactory.java | 65 +++++++ .../platform/command/CommandTest.java | 67 ++++++++ .../command/commands/ExampleCommandTest.java | 39 +++++ .../template/platform/config/ConfigTests.java | 53 ++++++ .../template/platform/plugin/PluginTests.java | 97 +++++++++++ .../test/resources/junit-platform.properties | 19 +++ platform/src/test/resources/test-config.yaml | 1 + .../platform/command/CommandTestUtils.java | 78 +++++++++ .../template/platform/command/ParserTest.java | 78 +++++++++ .../config/TestConfigurationAdapter.java | 62 +++++++ .../template/platform/sender/SenderMock.java | 53 ++++++ 45 files changed, 2783 insertions(+) create mode 100644 platform/build.gradle create mode 100644 platform/src/main/java/net/silthus/template/platform/command/Command.java create mode 100644 platform/src/main/java/net/silthus/template/platform/command/Commands.java create mode 100644 platform/src/main/java/net/silthus/template/platform/command/commands/ExampleCommand.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/Config.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/ConfigKeys.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/TemplateConfig.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateAdapter.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateConfigSection.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapter.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapters.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationSection.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/key/ConfigKey.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/key/ConfigKeyFactory.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/key/KeyedConfiguration.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/key/ModifiableConfigKey.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/key/SimpleConfigKey.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/key/SimpleModifiableConfigKey.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/serializers/MiniMessageComponentSerializer.java create mode 100644 platform/src/main/java/net/silthus/template/platform/config/serializers/SettingsSerializer.java create mode 100644 platform/src/main/java/net/silthus/template/platform/locale/Messages.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/AbstractTemplatePlugin.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/TemplatePlugin.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/Bootstrap.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/LoaderBootstrap.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/logging/JavaPluginLogger.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/logging/PluginLogger.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/scheduler/AbstractJavaScheduler.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerAdapter.java create mode 100644 platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerTask.java create mode 100644 platform/src/main/java/net/silthus/template/platform/sender/DummyConsoleSender.java create mode 100644 platform/src/main/java/net/silthus/template/platform/sender/FactorySender.java create mode 100644 platform/src/main/java/net/silthus/template/platform/sender/PlayerOnlineChecker.java create mode 100644 platform/src/main/java/net/silthus/template/platform/sender/Sender.java create mode 100644 platform/src/main/java/net/silthus/template/platform/sender/SenderFactory.java create mode 100644 platform/src/test/java/net/silthus/template/platform/command/CommandTest.java create mode 100644 platform/src/test/java/net/silthus/template/platform/command/commands/ExampleCommandTest.java create mode 100644 platform/src/test/java/net/silthus/template/platform/config/ConfigTests.java create mode 100644 platform/src/test/java/net/silthus/template/platform/plugin/PluginTests.java create mode 100644 platform/src/test/resources/junit-platform.properties create mode 100644 platform/src/test/resources/test-config.yaml create mode 100644 platform/src/testFixtures/java/net/silthus/template/platform/command/CommandTestUtils.java create mode 100644 platform/src/testFixtures/java/net/silthus/template/platform/command/ParserTest.java create mode 100644 platform/src/testFixtures/java/net/silthus/template/platform/config/TestConfigurationAdapter.java create mode 100644 platform/src/testFixtures/java/net/silthus/template/platform/sender/SenderMock.java diff --git a/platform/build.gradle b/platform/build.gradle new file mode 100644 index 0000000..1987baa --- /dev/null +++ b/platform/build.gradle @@ -0,0 +1,40 @@ +allprojects { + dependencies { + api project(':core') + + testImplementation(testFixtures(project(":core"))) + + testFixturesImplementation(testFixtures(project(':api'))) + testFixturesImplementation(testFixtures(project(':core'))) + + testFixturesImplementation 'org.spongepowered:configurate-core:4.1.2' + } +} + +subprojects { + dependencies { + implementation project(':platform') + + testImplementation(testFixtures(project(":platform"))) + + testFixturesImplementation(testFixtures(project(':platform'))) + } +} + +dependencies { + implementation 'cloud.commandframework:cloud-core:1.6.1' + implementation 'cloud.commandframework:cloud-annotations:1.6.1' + + implementation 'net.kyori:adventure-platform-api:4.0.1' + implementation 'net.kyori:adventure-text-minimessage:4.2.0-SNAPSHOT' + + implementation 'org.spongepowered:configurate-core:4.1.2' + implementation 'org.spongepowered:configurate-yaml:4.1.2' + implementation 'org.spongepowered:configurate-xml:4.1.2' + implementation 'org.spongepowered:configurate-hocon:4.1.2' + implementation 'org.spongepowered:configurate-gson:4.1.2' + + implementation 'com.google.guava:guava:21.0' + + testFixturesImplementation 'cloud.commandframework:cloud-core:1.6.1' +} diff --git a/platform/src/main/java/net/silthus/template/platform/command/Command.java b/platform/src/main/java/net/silthus/template/platform/command/Command.java new file mode 100644 index 0000000..5ccfdac --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/command/Command.java @@ -0,0 +1,29 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.command; + +import cloud.commandframework.CommandManager; +import cloud.commandframework.annotations.AnnotationParser; +import net.silthus.template.platform.sender.Sender; + +public interface Command { + + void register(CommandManager commandManager, AnnotationParser parser); +} diff --git a/platform/src/main/java/net/silthus/template/platform/command/Commands.java b/platform/src/main/java/net/silthus/template/platform/command/Commands.java new file mode 100644 index 0000000..4029aa4 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/command/Commands.java @@ -0,0 +1,54 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.command; + +import cloud.commandframework.CommandManager; +import cloud.commandframework.annotations.AnnotationParser; +import cloud.commandframework.arguments.parser.StandardParameters; +import cloud.commandframework.meta.CommandMeta; +import net.silthus.template.platform.sender.Sender; +import org.jetbrains.annotations.NotNull; + +public final class Commands { + private final CommandManager commandManager; + private final AnnotationParser annotationParser; + + public Commands(CommandManager commandManager) { + this.commandManager = commandManager; + this.annotationParser = createAnnotationParser(); + } + + public void register(Command... commands) { + for (final Command command : commands) { + command.register(commandManager, annotationParser); + } + } + + @NotNull + private AnnotationParser createAnnotationParser() { + return new AnnotationParser<>( + this.commandManager, + Sender.class, + p -> CommandMeta.simple() + .with(CommandMeta.DESCRIPTION, p.get(StandardParameters.DESCRIPTION, "No description")) + .build() + ); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/command/commands/ExampleCommand.java b/platform/src/main/java/net/silthus/template/platform/command/commands/ExampleCommand.java new file mode 100644 index 0000000..69ffb7c --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/command/commands/ExampleCommand.java @@ -0,0 +1,30 @@ +package net.silthus.template.platform.command.commands; + +import cloud.commandframework.CommandManager; +import cloud.commandframework.annotations.AnnotationParser; +import cloud.commandframework.annotations.Argument; +import cloud.commandframework.annotations.CommandMethod; +import net.silthus.template.platform.command.Command; +import net.silthus.template.platform.config.Config; +import net.silthus.template.platform.sender.Sender; + +import static net.silthus.template.platform.config.ConfigKeys.TEST; +import static net.silthus.template.platform.locale.Messages.TEST_MESSAGE; + +public class ExampleCommand implements Command { + private final Config config; + + public ExampleCommand(Config config) {this.config = config;} + + @Override + public void register(CommandManager commandManager, AnnotationParser parser) { + parser.parse(this); + } + + @CommandMethod("template test [text]") + public void example(Sender sender, @Argument("text") String text) { + if (text == null) + text = config.get(TEST); + TEST_MESSAGE.send(sender, text); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/Config.java b/platform/src/main/java/net/silthus/template/platform/config/Config.java new file mode 100644 index 0000000..0e18249 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/Config.java @@ -0,0 +1,35 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config; + +import net.silthus.template.platform.config.key.ConfigKey; + +public interface Config { + + void load(); + + void save(); + + void reload(); + + T get(ConfigKey key); + + void set(ConfigKey key, T value); +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/ConfigKeys.java b/platform/src/main/java/net/silthus/template/platform/config/ConfigKeys.java new file mode 100644 index 0000000..2d62af6 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/ConfigKeys.java @@ -0,0 +1,50 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config; + +import java.util.List; +import net.silthus.template.platform.config.key.ConfigKey; +import net.silthus.template.platform.config.key.KeyedConfiguration; + +import static net.silthus.template.platform.config.key.ConfigKeyFactory.key; +import static net.silthus.template.platform.config.key.ConfigKeyFactory.modifiable; + +public final class ConfigKeys { + + private ConfigKeys() { + } + + public static final ConfigKey TEST = modifiable(key( + config -> config.getString("test", "Hi from template :)")), + (config, value) -> config.set("test", value) + ); + + /** + * A list of the keys defined in this class. + */ + private static final List> KEYS = KeyedConfiguration.initialise(ConfigKeys.class); + + public static List> getKeys() { + return KEYS; + } + + public static final class InvalidConfig extends RuntimeException { + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/TemplateConfig.java b/platform/src/main/java/net/silthus/template/platform/config/TemplateConfig.java new file mode 100644 index 0000000..1948ea0 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/TemplateConfig.java @@ -0,0 +1,32 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config; + +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; +import net.silthus.template.platform.config.key.KeyedConfiguration; + +public final class TemplateConfig extends KeyedConfiguration { + + public TemplateConfig(ConfigurationAdapter adapter) { + super(adapter, ConfigKeys.getKeys()); + + init(); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateAdapter.java b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateAdapter.java new file mode 100644 index 0000000..9803751 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateAdapter.java @@ -0,0 +1,72 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.adapter; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.function.Function; +import net.kyori.adventure.text.Component; +import net.silthus.template.platform.config.serializers.MiniMessageComponentSerializer; +import net.silthus.template.platform.config.serializers.SettingsSerializer; +import net.silthus.template.pointer.Settings; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.loader.AbstractConfigurationLoader; +import org.spongepowered.configurate.loader.ConfigurationLoader; +import org.spongepowered.configurate.serialize.TypeSerializerCollection; + +public abstract class ConfigurateAdapter, L extends AbstractConfigurationLoader> extends ConfigurateConfigSection implements ConfigurationAdapter { + + private static final TypeSerializerCollection SERIALIZERS = TypeSerializerCollection.builder() + .register(Component.class, new MiniMessageComponentSerializer()) + .register(Settings.class, new SettingsSerializer()) + .build(); + + private static final Function DEFAULT_OPTIONS = options -> + options.serializers(serializers -> serializers.registerAll(SERIALIZERS)); + + private final ConfigurationLoader loader; + + protected ConfigurateAdapter(Path path) { + final AbstractConfigurationLoader.Builder loader = createLoader(path); + this.loader = loader.defaultOptions(DEFAULT_OPTIONS.apply(loader.defaultOptions())).build(); + } + + protected abstract AbstractConfigurationLoader.Builder createLoader(Path path); + + @Override + public void save() { + try { + loader.save(getRoot()); + } catch (ConfigurateException e) { + throw new SaveFailed(e); + } + } + + @Override + public void load() { + try { + setRoot(loader.load()); + } catch (IOException e) { + throw new LoadFailed(e); + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateConfigSection.java b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateConfigSection.java new file mode 100644 index 0000000..b48d61a --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurateConfigSection.java @@ -0,0 +1,125 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.adapter; + +import com.google.common.base.Splitter; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import lombok.Getter; +import lombok.Setter; +import lombok.SneakyThrows; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.silthus.template.pointer.Settings; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; + +class ConfigurateConfigSection implements ConfigurationSection { + + private final MiniMessage parser = MiniMessage.miniMessage(); + @Getter + @Setter + private ConfigurationNode root; + + ConfigurateConfigSection() { + } + + private ConfigurateConfigSection(ConfigurationNode root) { + this.root = root; + } + + @Override + public ConfigurateConfigSection scoped(String path) { + return new ConfigurateConfigSection(resolvePath(path)); + } + + public @Nullable V get(String path, Class type) { + try { + return resolvePath(path).get(type); + } catch (SerializationException e) { + return null; + } + } + + @Override + public void set(String path, Object value) { + try { + resolvePath(path).set(value); + } catch (SerializationException e) { + throw new ConfigurationAdapter.SaveFailed(e); + } + } + + public String getString(String path, String def) { + return resolvePath(path).getString(def); + } + + public int getInteger(String path, int def) { + return resolvePath(path).getInt(def); + } + + public boolean getBoolean(String path, boolean def) { + return resolvePath(path).getBoolean(def); + } + + public Component getParsedString(String path, Component def) { + final String string = resolvePath(path).getString(); + if (string == null) return def; + return parser.parse(string); + } + + @Override + public Settings getSettings(String path) { + final Settings.Builder builder = Settings.settings(); + final ConfigurateConfigSection scoped = scoped(path); + for (final String key : getKeys(path, new ArrayList<>())) { + builder.withUnknown(key, setting -> scoped.get(key, setting.getType())); + } + return builder.create(); + } + + @SneakyThrows + public List getStringList(String path, List def) { + ConfigurationNode node = resolvePath(path); + if (node.virtual() || !node.isList()) { + return def; + } + + return node.getList(String.class); + } + + public List getKeys(String path, List def) { + ConfigurationNode node = resolvePath(path); + if (node.virtual() || !node.isMap()) { + return def; + } + + return node.childrenMap().keySet().stream().map(Object::toString).collect(Collectors.toList()); + } + + @SuppressWarnings("UnstableApiUsage") + private ConfigurationNode resolvePath(String path) { + if (path == null || path.isBlank()) return getRoot(); + + return getRoot().node(Splitter.on('.').splitToList(path).toArray()); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapter.java b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapter.java new file mode 100644 index 0000000..f50894b --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapter.java @@ -0,0 +1,47 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.adapter; + +import java.io.File; + +public interface ConfigurationAdapter extends ConfigurationSection { + + void save() throws SaveFailed; + + void load() throws LoadFailed; + + interface Factory { + ConfigurationAdapter create(File config); + } + + class LoadFailed extends RuntimeException { + + public LoadFailed(Throwable cause) { + super(cause); + } + } + + class SaveFailed extends RuntimeException { + + public SaveFailed(Throwable cause) { + super(cause); + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapters.java b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapters.java new file mode 100644 index 0000000..b7ce99f --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationAdapters.java @@ -0,0 +1,49 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.adapter; + +import java.nio.file.Path; +import org.spongepowered.configurate.loader.AbstractConfigurationLoader; +import org.spongepowered.configurate.loader.HeaderMode; +import org.spongepowered.configurate.yaml.NodeStyle; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; + +public final class ConfigurationAdapters { + + public static final ConfigurationAdapter.Factory YAML = file -> new YamlConfigurateAdapter(file.toPath()); + + private ConfigurationAdapters() { + } + + private static final class YamlConfigurateAdapter extends ConfigurateAdapter { + private YamlConfigurateAdapter(Path path) { + super(path); + } + + @Override + protected AbstractConfigurationLoader.Builder createLoader(Path path) { + return YamlConfigurationLoader.builder() + .path(path) + .indent(4) + .nodeStyle(NodeStyle.BLOCK) + .headerMode(HeaderMode.PRESERVE); + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationSection.java b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationSection.java new file mode 100644 index 0000000..5c7d613 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/adapter/ConfigurationSection.java @@ -0,0 +1,48 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.adapter; + +import java.util.List; +import net.kyori.adventure.text.Component; +import net.silthus.template.pointer.Settings; +import org.jetbrains.annotations.Nullable; + +public interface ConfigurationSection { + + ConfigurationSection scoped(String path); + + @Nullable V get(String path, Class type); + + void set(String path, Object value); + + String getString(String path, String def); + + int getInteger(String path, int def); + + boolean getBoolean(String path, boolean def); + + List getStringList(String path, List def); + + List getKeys(String path, List def); + + Component getParsedString(String path, Component def); + + Settings getSettings(String path); +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/key/ConfigKey.java b/platform/src/main/java/net/silthus/template/platform/config/key/ConfigKey.java new file mode 100644 index 0000000..6c2a0f5 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/key/ConfigKey.java @@ -0,0 +1,52 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.key; + +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; + +/** + * Represents a key in the configuration. + * + * @param the value type + */ +public interface ConfigKey { + + /** + * Gets the position of this key within the keys enum. + * + * @return the position + */ + int ordinal(); + + /** + * Gets if the config key can be reloaded. + * + * @return the if the key can be reloaded + */ + boolean reloadable(); + + /** + * Resolves and returns the value mapped to this key using the given config instance. + * + * @param adapter the config adapter instance + * @return the value mapped to this key + */ + T get(ConfigurationAdapter adapter); +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/key/ConfigKeyFactory.java b/platform/src/main/java/net/silthus/template/platform/config/key/ConfigKeyFactory.java new file mode 100644 index 0000000..52a98de --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/key/ConfigKeyFactory.java @@ -0,0 +1,90 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.key; + +import java.util.Locale; +import java.util.function.BiConsumer; +import java.util.function.Function; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; + +public interface ConfigKeyFactory { + + ConfigKeyFactory BOOLEAN = ConfigurationAdapter::getBoolean; + ConfigKeyFactory STRING = ConfigurationAdapter::getString; + ConfigKeyFactory LOWERCASE_STRING = (adapter, path, def) -> adapter.getString(path, def).toLowerCase(Locale.ROOT); + + static SimpleConfigKey key(Function function) { + return new SimpleConfigKey<>(function); + } + + static SimpleModifiableConfigKey modifiable(SimpleConfigKey key, BiConsumer setter) { + return new SimpleModifiableConfigKey<>(key, setter); + } + + static SimpleConfigKey notReloadable(SimpleConfigKey key) { + key.setReloadable(false); + return key; + } + + static SimpleConfigKey booleanKey(String path, boolean def) { + return key(new Bound<>(BOOLEAN, path, def)); + } + + static SimpleConfigKey stringKey(String path, String def) { + return key(new Bound<>(STRING, path, def)); + } + + static SimpleConfigKey lowercaseStringKey(String path, String def) { + return key(new Bound<>(LOWERCASE_STRING, path, def)); + } + + /** + * Extracts the value from the config. + * + * @param config the config + * @param path the path where the value is + * @param def the default value + * @return the value + */ + T getValue(ConfigurationAdapter config, String path, T def); + + /** + * A {@link ConfigKeyFactory} bound to a given {@code path}. + * + * @param the value type + */ + class Bound implements Function { + private final ConfigKeyFactory factory; + private final String path; + private final T def; + + Bound(ConfigKeyFactory factory, String path, T def) { + this.factory = factory; + this.path = path; + this.def = def; + } + + @Override + public T apply(ConfigurationAdapter adapter) { + return this.factory.getValue(adapter, this.path, this.def); + } + } + +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/key/KeyedConfiguration.java b/platform/src/main/java/net/silthus/template/platform/config/key/KeyedConfiguration.java new file mode 100644 index 0000000..54d84ad --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/key/KeyedConfiguration.java @@ -0,0 +1,159 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.key; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import lombok.SneakyThrows; +import net.silthus.template.platform.config.Config; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; + +public class KeyedConfiguration implements Config { + + /** + * Initialises the given pseudo-enum keys class. + * + * @param keysClass the keys class + * @return the list of keys defined by the class with their ordinal values set + */ + public static List> initialise(Class keysClass) { + List> keys = getAllConfigKeysFromClass(keysClass); + setOrdinalValues(keys); + return keys; + } + + @SuppressWarnings("SimplifyStreamApiCallChains") + private static List> getAllConfigKeysFromClass(Class keysClass) { + return Arrays.stream(keysClass.getFields()) + .filter(KeyedConfiguration::isStatic) + .filter(KeyedConfiguration::isConfigKey) + .map(KeyedConfiguration::getConfigKey) + .collect(Collectors.toUnmodifiableList()); + } + + private static boolean isStatic(Field f) { + return Modifier.isStatic(f.getModifiers()); + } + + private static boolean isConfigKey(Field f) { + return ConfigKey.class.equals(f.getType()); + } + + @SneakyThrows + private static SimpleConfigKey getConfigKey(Field f) { + return (SimpleConfigKey) f.get(null); + } + + private static void setOrdinalValues(List> keys) { + for (int i = 0; i < keys.size(); i++) { + keys.get(i).setOrdinal(i); + } + } + + private final ConfigurationAdapter adapter; + private final List> keys; + private final ValuesMap values; + + public KeyedConfiguration(ConfigurationAdapter adapter, List> keys) { + this.adapter = adapter; + this.keys = keys; + this.values = new ValuesMap(keys.size()); + } + + protected void init() { + load(configKey -> true); + } + + @Override + public void save() { + for (final ConfigKey key : this.keys) { + if (key instanceof ModifiableConfigKey modifiable) + saveConfigKey(modifiable); + + } + this.adapter.save(); + } + + @Override + public void load() { + load(ConfigKey::reloadable); + } + + /** + * Reloads the configuration. + */ + @Override + public void reload() { + save(); + load(); + } + + protected void load(Predicate> filter) { + this.adapter.load(); + for (ConfigKey key : this.keys) { + if (filter.test(key)) { + this.values.put(key, key.get(this.adapter)); + } + } + } + + /** + * Gets the value of a given context key. + * + * @param key the key + * @param the key return type + * @return the value mapped to the given key. May be null. + */ + @Override + public T get(ConfigKey key) { + return this.values.get(key); + } + + @Override + public void set(ConfigKey key, T value) { + if (key instanceof ModifiableConfigKey modifiable) + modifiable.set(this.adapter, value); + } + + private void saveConfigKey(ModifiableConfigKey key) { + key.set(this.adapter, key.get(this.adapter)); + } + + private static final class ValuesMap { + private final Object[] values; + + ValuesMap(int size) { + this.values = new Object[size]; + } + + @SuppressWarnings("unchecked") + public T get(ConfigKey key) { + return (T) this.values[key.ordinal()]; + } + + public void put(ConfigKey key, Object value) { + this.values[key.ordinal()] = value; + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/key/ModifiableConfigKey.java b/platform/src/main/java/net/silthus/template/platform/config/key/ModifiableConfigKey.java new file mode 100644 index 0000000..2398a58 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/key/ModifiableConfigKey.java @@ -0,0 +1,33 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.key; + +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; + +public interface ModifiableConfigKey extends ConfigKey { + + /** + * Sets a new value of the key using the given config instance. + * + * @param adapter the config adapter instance + * @param value the value to set + */ + void set(ConfigurationAdapter adapter, T value); +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/key/SimpleConfigKey.java b/platform/src/main/java/net/silthus/template/platform/config/key/SimpleConfigKey.java new file mode 100644 index 0000000..d656287 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/key/SimpleConfigKey.java @@ -0,0 +1,64 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.key; + +import java.util.function.Function; +import lombok.Getter; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; + +/** + * Basic {@link ConfigKey} implementation. + * + * @param the value type + */ +class SimpleConfigKey implements ConfigKey { + @Getter + private final Function function; + + private int ordinal = -1; + private boolean reloadable = true; + + SimpleConfigKey(Function function) { + this.function = function; + } + + @Override + public T get(ConfigurationAdapter adapter) { + return this.function.apply(adapter); + } + + @Override + public int ordinal() { + return this.ordinal; + } + + @Override + public boolean reloadable() { + return this.reloadable; + } + + public void setOrdinal(int ordinal) { + this.ordinal = ordinal; + } + + public void setReloadable(boolean reloadable) { + this.reloadable = reloadable; + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/key/SimpleModifiableConfigKey.java b/platform/src/main/java/net/silthus/template/platform/config/key/SimpleModifiableConfigKey.java new file mode 100644 index 0000000..98d59b4 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/key/SimpleModifiableConfigKey.java @@ -0,0 +1,38 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.key; + +import java.util.function.BiConsumer; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; + +final class SimpleModifiableConfigKey extends SimpleConfigKey implements ModifiableConfigKey { + + private final BiConsumer setter; + + SimpleModifiableConfigKey(SimpleConfigKey key, BiConsumer setter) { + super(key.getFunction()); + this.setter = setter; + } + + @Override + public void set(ConfigurationAdapter adapter, T value) { + this.setter.accept(adapter, value); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/serializers/MiniMessageComponentSerializer.java b/platform/src/main/java/net/silthus/template/platform/config/serializers/MiniMessageComponentSerializer.java new file mode 100644 index 0000000..6ffc3e8 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/serializers/MiniMessageComponentSerializer.java @@ -0,0 +1,45 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.serializers; + +import java.lang.reflect.Type; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializer; + +public final class MiniMessageComponentSerializer implements TypeSerializer { + + private final MiniMessage serializer = MiniMessage.miniMessage(); + + @Override + public Component deserialize(Type type, ConfigurationNode node) { + final String string = node.getString(); + if (node.virtual() || node.empty() || string == null) return Component.empty(); + return serializer.parse(string); + } + + @Override + public void serialize(Type type, @Nullable Component obj, ConfigurationNode node) throws SerializationException { + node.set(String.class, obj == null ? "" : serializer.serialize(obj)); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/config/serializers/SettingsSerializer.java b/platform/src/main/java/net/silthus/template/platform/config/serializers/SettingsSerializer.java new file mode 100644 index 0000000..406bbdb --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/config/serializers/SettingsSerializer.java @@ -0,0 +1,54 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config.serializers; + +import java.lang.reflect.Type; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; +import net.silthus.template.pointer.Setting; +import net.silthus.template.pointer.Settings; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializer; + +public final class SettingsSerializer implements TypeSerializer { + @Override + public Settings deserialize(Type type, ConfigurationNode node) { + final Settings.Builder builder = Settings.settings(); + for (final String key : node.childrenMap().keySet().stream().map(Object::toString).toList()) { + builder.withUnknown(key, setting -> { + try { + return node.node(key).get(setting.getType()); + } catch (SerializationException e) { + throw new ConfigurationAdapter.LoadFailed(e); + } + }); + } + return builder.create(); + } + + @Override + public void serialize(Type type, @Nullable Settings settings, ConfigurationNode node) throws SerializationException { + if (settings == null) return; + for (final Setting setting : settings.getSettings()) { + node.node(setting.getKey()).set(setting.getType(), settings.get(setting)); + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/locale/Messages.java b/platform/src/main/java/net/silthus/template/platform/locale/Messages.java new file mode 100644 index 0000000..1d72010 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/locale/Messages.java @@ -0,0 +1,147 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.locale; + +import java.util.Collection; +import java.util.Iterator; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import net.kyori.adventure.text.TextComponent; +import net.silthus.template.platform.sender.Sender; + +import static net.kyori.adventure.text.Component.space; +import static net.kyori.adventure.text.Component.text; +import static net.kyori.adventure.text.Component.translatable; +import static net.kyori.adventure.text.format.NamedTextColor.AQUA; +import static net.kyori.adventure.text.format.NamedTextColor.DARK_AQUA; +import static net.kyori.adventure.text.format.NamedTextColor.GOLD; +import static net.kyori.adventure.text.format.NamedTextColor.GRAY; +import static net.kyori.adventure.text.format.NamedTextColor.GREEN; +import static net.kyori.adventure.text.format.NamedTextColor.RED; +import static net.kyori.adventure.text.format.TextDecoration.BOLD; +import static net.kyori.adventure.text.format.TextDecoration.ITALIC; + +public interface Messages { + + TextComponent OPEN_BRACKET = Component.text('('); + TextComponent CLOSE_BRACKET = Component.text(')'); + TextComponent FULL_STOP = Component.text('.'); + + Component PREFIX_COMPONENT = text() + .color(GRAY) + .append(text('[')) + .append(text() + .decoration(BOLD, true) + .append(text('s', GOLD, ITALIC)) + .append(text("Chat", DARK_AQUA)) + ) + .append(text(']')) + .build(); + + static TextComponent prefixed(ComponentLike component) { + return text() + .append(PREFIX_COMPONENT) + .append(space()) + .append(component) + .build(); + } + + Args1 TEST_MESSAGE = text -> translatable() + .key("my-plugin.command.test") + .color(GREEN) + .args(text(text)) + .append(FULL_STOP) + .build(); + + static Component formatStringList(Collection strings) { + Iterator it = strings.iterator(); + if (!it.hasNext()) { + return translatable("schat.command.misc.none", AQUA); // "&bNone" + } + + TextComponent.Builder builder = text().color(DARK_AQUA).content(it.next()); + while (it.hasNext()) { + builder.append(text(", ", GRAY)); + builder.append(text(it.next())); + } + + return builder.build(); + } + + static Component formatBoolean(boolean bool) { + return bool ? text("true", GREEN) : text("false", RED); + } + + interface Args0 { + Component build(); + + default void send(Sender sender) { + sender.sendMessage(build()); + } + } + + interface Args1 { + Component build(A0 arg0); + + default void send(Sender sender, A0 arg0) { + sender.sendMessage(build(arg0)); + } + } + + interface Args2 { + Component build(A0 arg0, A1 arg1); + + default void send(Sender sender, A0 arg0, A1 arg1) { + sender.sendMessage(build(arg0, arg1)); + } + } + + interface Args3 { + Component build(A0 arg0, A1 arg1, A2 arg2); + + default void send(Sender sender, A0 arg0, A1 arg1, A2 arg2) { + sender.sendMessage(build(arg0, arg1, arg2)); + } + } + + interface Args4 { + Component build(A0 arg0, A1 arg1, A2 arg2, A3 arg3); + + default void send(Sender sender, A0 arg0, A1 arg1, A2 arg2, A3 arg3) { + sender.sendMessage(build(arg0, arg1, arg2, arg3)); + } + } + + interface Args5 { + Component build(A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4); + + default void send(Sender sender, A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4) { + sender.sendMessage(build(arg0, arg1, arg2, arg3, arg4)); + } + } + + interface Args6 { + Component build(A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5); + + default void send(Sender sender, A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) { + sender.sendMessage(build(arg0, arg1, arg2, arg3, arg4, arg5)); + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/AbstractTemplatePlugin.java b/platform/src/main/java/net/silthus/template/platform/plugin/AbstractTemplatePlugin.java new file mode 100644 index 0000000..616dee0 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/AbstractTemplatePlugin.java @@ -0,0 +1,105 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin; + +import cloud.commandframework.CommandManager; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import lombok.Getter; +import net.silthus.template.platform.command.Commands; +import net.silthus.template.platform.config.TemplateConfig; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; +import net.silthus.template.platform.sender.Sender; +import org.jetbrains.annotations.ApiStatus; + +@Getter +public abstract class AbstractTemplatePlugin implements TemplatePlugin { + + private TemplateConfig config; + private Commands commands; + + @Override + public final void load() { + + } + + @Override + public final void enable() { + setupSenderFactory(); + + config = new TemplateConfig(provideConfigurationAdapter()); + config.load(); + + commands = new Commands(provideCommandManager()); + registerCommands(); + } + + @Override + public final void disable() { + + } + + protected abstract ConfigurationAdapter provideConfigurationAdapter(); + + protected abstract void setupSenderFactory(); + + protected abstract CommandManager provideCommandManager(); + + private void registerCommands() { + registerNativeCommands(); + registerCustomCommands(commands); + } + + private void registerNativeCommands() { + commands.register(); + } + + @ApiStatus.OverrideOnly + protected void registerCustomCommands(Commands commands) { + } + + protected final Path resolveConfig(String fileName) { + Path configFile = getBootstrap().getConfigDirectory().resolve(fileName); + + if (!Files.exists(configFile)) { + createConfigDirectory(configFile); + copyDefaultConfig(fileName, configFile); + } + + return configFile; + } + + private void copyDefaultConfig(String fileName, Path configFile) { + try (InputStream is = getBootstrap().getResourceStream(fileName)) { + Files.copy(is, configFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void createConfigDirectory(Path configFile) { + try { + Files.createDirectories(configFile.getParent()); + } catch (IOException ignored) { + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/TemplatePlugin.java b/platform/src/main/java/net/silthus/template/platform/plugin/TemplatePlugin.java new file mode 100644 index 0000000..8cd048f --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/TemplatePlugin.java @@ -0,0 +1,41 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin; + +import net.silthus.template.platform.config.TemplateConfig; +import net.silthus.template.platform.plugin.bootstrap.Bootstrap; +import net.silthus.template.platform.plugin.logging.PluginLogger; + +public interface TemplatePlugin { + + void load(); + + void enable(); + + void disable(); + + Bootstrap getBootstrap(); + + default PluginLogger getLogger() { + return getBootstrap().getPluginLogger(); + } + + TemplateConfig getConfig(); +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/Bootstrap.java b/platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/Bootstrap.java new file mode 100644 index 0000000..551dd20 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/Bootstrap.java @@ -0,0 +1,68 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin.bootstrap; + +import java.io.InputStream; +import java.nio.file.Path; +import net.silthus.template.platform.plugin.logging.PluginLogger; +import net.silthus.template.platform.plugin.scheduler.SchedulerAdapter; + +public interface Bootstrap { + + PluginLogger getPluginLogger(); + + /** + * Gets an adapter for the platforms scheduler. + * + * @return the scheduler + */ + SchedulerAdapter getScheduler(); + + /** + * Gets the plugins main data storage directory. + * + *

Bukkit: /root/plugins/sChat

+ *

Bungee: /root/plugins/sChat

+ *

Sponge: /root/schat/

+ *

Fabric: /root/mods/sChat

+ * + * @return the platforms data folder + */ + Path getDataDirectory(); + + /** + * Gets the plugins configuration directory. + * + * @return the config directory + */ + default Path getConfigDirectory() { + return getDataDirectory(); + } + + /** + * Gets a bundled resource file from the jar. + * + * @param path the path of the file + * @return the file as an input stream + */ + default InputStream getResourceStream(String path) { + return getClass().getClassLoader().getResourceAsStream(path); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/LoaderBootstrap.java b/platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/LoaderBootstrap.java new file mode 100644 index 0000000..1aa4d50 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/bootstrap/LoaderBootstrap.java @@ -0,0 +1,33 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin.bootstrap; + +/** + * Minimal bootstrap plugin, called by the loader plugin. + */ +public interface LoaderBootstrap { + + void onLoad(); + + void onEnable(); + + void onDisable(); + +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/logging/JavaPluginLogger.java b/platform/src/main/java/net/silthus/template/platform/plugin/logging/JavaPluginLogger.java new file mode 100644 index 0000000..127fce6 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/logging/JavaPluginLogger.java @@ -0,0 +1,57 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin.logging; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class JavaPluginLogger implements PluginLogger { + + private final Logger logger; + + public JavaPluginLogger(Logger logger) { + this.logger = logger; + } + + @Override + public void info(String s) { + this.logger.info(s); + } + + @Override + public void warn(String s) { + this.logger.warning(s); + } + + @Override + public void warn(String s, Throwable t) { + this.logger.log(Level.WARNING, s, t); + } + + @Override + public void severe(String s) { + this.logger.severe(s); + } + + @Override + public void severe(String s, Throwable t) { + this.logger.log(Level.SEVERE, s, t); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/logging/PluginLogger.java b/platform/src/main/java/net/silthus/template/platform/plugin/logging/PluginLogger.java new file mode 100644 index 0000000..6a48e82 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/logging/PluginLogger.java @@ -0,0 +1,40 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin.logging; + +/** + * Represents the logger instance being used by sChat on the platform. + * + *

Messages sent using the logger are sent prefixed with the sChat tag, + * and on some implementations will be colored depending on the message type.

+ */ +public interface PluginLogger { + + void info(String s); + + void warn(String s); + + void warn(String s, Throwable t); + + void severe(String s); + + void severe(String s, Throwable t); + +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/AbstractJavaScheduler.java b/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/AbstractJavaScheduler.java new file mode 100644 index 0000000..145dab9 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/AbstractJavaScheduler.java @@ -0,0 +1,124 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin.scheduler; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Abstract implementation of {@link SchedulerAdapter} using a {@link ScheduledExecutorService}. + */ +public abstract class AbstractJavaScheduler implements SchedulerAdapter { + private final ScheduledThreadPoolExecutor scheduler; + private final ErrorReportingExecutor schedulerWorkerPool; + private final ForkJoinPool worker; + + public AbstractJavaScheduler() { + this.scheduler = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("schat-scheduler") + .build() + ); + this.scheduler.setRemoveOnCancelPolicy(true); + this.schedulerWorkerPool = new ErrorReportingExecutor(Executors.newCachedThreadPool(new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("schat-scheduler-worker-%d") + .build() + )); + this.worker = new ForkJoinPool(32, ForkJoinPool.defaultForkJoinWorkerThreadFactory, (t, e) -> e.printStackTrace(), false); + } + + @Override + public Executor async() { + return this.worker; + } + + @Override + public SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit) { + ScheduledFuture future = this.scheduler.schedule(() -> this.schedulerWorkerPool.execute(task), delay, unit); + return () -> future.cancel(false); + } + + @Override + public SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit) { + ScheduledFuture future = this.scheduler.scheduleAtFixedRate(() -> this.schedulerWorkerPool.execute(task), interval, interval, unit); + return () -> future.cancel(false); + } + + @Override + @SuppressWarnings("ResultOfMethodCallIgnored") + public void shutdownScheduler() { + this.scheduler.shutdown(); + try { + this.scheduler.awaitTermination(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + @SuppressWarnings("ResultOfMethodCallIgnored") + public void shutdownExecutor() { + this.schedulerWorkerPool.delegate.shutdown(); + try { + this.schedulerWorkerPool.delegate.awaitTermination(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private static final class ErrorReportingExecutor implements Executor { + private final ExecutorService delegate; + + private ErrorReportingExecutor(ExecutorService delegate) { + this.delegate = delegate; + } + + @Override + public void execute(@NonNull Runnable command) { + this.delegate.execute(new ErrorReportingRunnable(command)); + } + } + + private static final class ErrorReportingRunnable implements Runnable { + private final Runnable delegate; + + private ErrorReportingRunnable(Runnable delegate) { + this.delegate = delegate; + } + + @Override + public void run() { + try { + this.delegate.run(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerAdapter.java b/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerAdapter.java new file mode 100644 index 0000000..3ca30bc --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerAdapter.java @@ -0,0 +1,96 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin.scheduler; + +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +/** + * A scheduler for running tasks using the systems provided by the platform. + */ +public interface SchedulerAdapter { + + /** + * Gets an async executor instance. + * + * @return an async executor instance + */ + Executor async(); + + /** + * Gets a sync executor instance. + * + * @return a sync executor instance + */ + Executor sync(); + + /** + * Executes a task async. + * + * @param task the task + */ + default void executeAsync(Runnable task) { + async().execute(task); + } + + /** + * Executes a task sync. + * + * @param task the task + */ + default void executeSync(Runnable task) { + sync().execute(task); + } + + /** + * Executes the given task with a delay. + * + * @param task the task + * @param delay the delay + * @param unit the unit of delay + * @return the resultant task instance + */ + SchedulerTask asyncLater(Runnable task, long delay, TimeUnit unit); + + /** + * Executes the given task repeatedly at a given interval. + * + * @param task the task + * @param interval the interval + * @param unit the unit of interval + * @return the resultant task instance + */ + SchedulerTask asyncRepeating(Runnable task, long interval, TimeUnit unit); + + /** + * Shuts down the scheduler instance. + * + *

{@link #asyncLater(Runnable, long, TimeUnit)} and {@link #asyncRepeating(Runnable, long, TimeUnit)}.

+ */ + void shutdownScheduler(); + + /** + * Shuts down the executor instance. + * + *

{@link #async()} and {@link #executeAsync(Runnable)}.

+ */ + void shutdownExecutor(); + +} diff --git a/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerTask.java b/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerTask.java new file mode 100644 index 0000000..1643ca7 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/plugin/scheduler/SchedulerTask.java @@ -0,0 +1,31 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin.scheduler; + +/** + * Represents a scheduled task. + */ +public interface SchedulerTask { + + /** + * Cancels the task. + */ + void cancel(); +} diff --git a/platform/src/main/java/net/silthus/template/platform/sender/DummyConsoleSender.java b/platform/src/main/java/net/silthus/template/platform/sender/DummyConsoleSender.java new file mode 100644 index 0000000..25b7043 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/sender/DummyConsoleSender.java @@ -0,0 +1,47 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.sender; + +import lombok.Getter; +import net.silthus.template.identity.Identity; + +public abstract class DummyConsoleSender implements Sender { + + @Getter + private final Identity identity = CONSOLE; + + protected DummyConsoleSender() { + } + + @Override + public boolean hasPermission(String permission) { + return true; + } + + @Override + public void performCommand(String commandLine) { + + } + + @Override + public boolean isConsole() { + return true; + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/sender/FactorySender.java b/platform/src/main/java/net/silthus/template/platform/sender/FactorySender.java new file mode 100644 index 0000000..584e9d5 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/sender/FactorySender.java @@ -0,0 +1,118 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.sender; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.silthus.template.identity.Identity; + +import static net.kyori.adventure.text.JoinConfiguration.noSeparators; + +/** + * Simple implementation of {@link Sender} using a {@link SenderFactory}. + * + * @param the command sender type + */ +@EqualsAndHashCode(of = {"identity"}) +final class FactorySender implements Sender { + + private final SenderFactory factory; + @Getter(AccessLevel.PROTECTED) + private final T handle; + @Getter + private final Identity identity; + @Getter + private final boolean console; + + FactorySender(SenderFactory factory, T sender) { + this.factory = factory; + this.handle = sender; + this.console = factory.isConsole(sender); + this.identity = factory.getIdentity(sender); + } + + @Override + public void sendMessage(Component message) { + if (isConsole()) { + for (Component line : splitNewlines(message)) { + factory.sendMessage(handle, line); + } + } else { + factory.sendMessage(handle, message); + } + } + + @Override + public boolean hasPermission(String permission) { + return isConsole() || factory.hasPermission(handle, permission); + } + + @Override + public void performCommand(String commandLine) { + factory.performCommand(handle, commandLine); + } + + @Override + public boolean isValid() { + return isConsole() || factory.isPlayerOnline(getUniqueId()); + } + + // A small utility method which splits components built using + // > join(newLine(), components...) + // back into separate components. + private static Iterable splitNewlines(Component message) { + if (message instanceof TextComponent && message.style().isEmpty() && !message.children().isEmpty() && ((TextComponent) message).content().isEmpty()) { + LinkedList> split = new LinkedList<>(); + split.add(new ArrayList<>()); + + for (Component child : message.children()) { + if (Component.newline().equals(child)) { + split.add(new ArrayList<>()); + } else { + Iterator splitChildren = splitNewlines(child).iterator(); + if (splitChildren.hasNext()) { + split.getLast().add(splitChildren.next()); + } + while (splitChildren.hasNext()) { + split.add(new ArrayList<>()); + split.getLast().add(splitChildren.next()); + } + } + } + + return split.stream().map(input -> switch (input.size()) { + case 0 -> Component.empty(); + case 1 -> input.get(0); + default -> Component.join(noSeparators(), input); + }).collect(Collectors.toList()); + } + + return Collections.singleton(message); + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/sender/PlayerOnlineChecker.java b/platform/src/main/java/net/silthus/template/platform/sender/PlayerOnlineChecker.java new file mode 100644 index 0000000..240b28d --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/sender/PlayerOnlineChecker.java @@ -0,0 +1,28 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.sender; + +import java.util.UUID; + +@FunctionalInterface +public interface PlayerOnlineChecker { + + boolean isPlayerOnline(UUID playerId); +} diff --git a/platform/src/main/java/net/silthus/template/platform/sender/Sender.java b/platform/src/main/java/net/silthus/template/platform/sender/Sender.java new file mode 100644 index 0000000..c759ed7 --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/sender/Sender.java @@ -0,0 +1,90 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.sender; + +import java.util.UUID; +import net.kyori.adventure.text.Component; +import net.silthus.template.identity.Identified; +import net.silthus.template.identity.Identity; +import org.jetbrains.annotations.NotNull; + +/** + * Wrapper interface to represent a CommandSender/CommandSource within the common command implementations. + */ +public interface Sender extends Identified { + + UUID CONSOLE_ID = UUID.fromString("00000000-0000-0000-0000-000000000001"); + String CONSOLE_NAME = "Console"; + + Identity CONSOLE = Identity.identity( + CONSOLE_ID, + CONSOLE_NAME + ); + + default @NotNull UUID getUniqueId() { + return getIdentity().getUniqueId(); + } + + default @NotNull String getName() { + return getIdentity().getName(); + } + + default @NotNull Component getDisplayName() { + return getIdentity().getDisplayName(); + } + + /** + * Send a json message to the Sender. + * + * @param message the message to send. + */ + void sendMessage(Component message); + + /** + * Check if the Sender has a permission. + * + * @param permission the permission to check for + * @return true if the sender has the permission + */ + boolean hasPermission(String permission); + + /** + * Makes the sender perform a command. + * + * @param commandLine the command + */ + void performCommand(String commandLine); + + /** + * Gets whether this sender is the console. + * + * @return if the sender is the console + */ + boolean isConsole(); + + /** + * Gets whether this sender is still valid & receiving messages. + * + * @return if this sender is valid + */ + default boolean isValid() { + return true; + } +} diff --git a/platform/src/main/java/net/silthus/template/platform/sender/SenderFactory.java b/platform/src/main/java/net/silthus/template/platform/sender/SenderFactory.java new file mode 100644 index 0000000..7cfa00f --- /dev/null +++ b/platform/src/main/java/net/silthus/template/platform/sender/SenderFactory.java @@ -0,0 +1,65 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.sender; + +import net.kyori.adventure.text.Component; +import net.silthus.template.identity.Identity; +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * Factory class to make a thread-safe sender instance. + * + * @param the command sender type + */ +public abstract class SenderFactory implements AutoCloseable, PlayerOnlineChecker { + + protected abstract Class getSenderType(); + + protected abstract Identity getIdentity(T sender); + + protected abstract void sendMessage(T sender, Component message); + + protected abstract boolean hasPermission(T sender, String node); + + protected abstract void performCommand(T sender, String command); + + protected abstract boolean isConsole(T sender); + + public final Sender wrap(@NonNull T sender) { + if (!getSenderType().isInstance(sender)) + throw new IllegalSenderType(); + return new FactorySender<>(this, sender); + } + + @SuppressWarnings("unchecked") + public final T unwrap(@NonNull Sender sender) { + if (sender instanceof FactorySender factorySender) + return (T) factorySender.getHandle(); + throw new IllegalSenderType(); + } + + @Override + public void close() { + + } + + public static final class IllegalSenderType extends RuntimeException { + } +} diff --git a/platform/src/test/java/net/silthus/template/platform/command/CommandTest.java b/platform/src/test/java/net/silthus/template/platform/command/CommandTest.java new file mode 100644 index 0000000..a3f4e83 --- /dev/null +++ b/platform/src/test/java/net/silthus/template/platform/command/CommandTest.java @@ -0,0 +1,67 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.command; + +import cloud.commandframework.CommandManager; +import lombok.SneakyThrows; +import net.kyori.adventure.text.Component; +import net.silthus.template.platform.sender.Sender; +import net.silthus.template.platform.sender.SenderMock; +import org.junit.jupiter.api.BeforeEach; + +import static net.silthus.template.platform.command.CommandTestUtils.createCommandManager; +import static net.silthus.template.platform.sender.SenderMock.senderMock; +import static org.assertj.core.api.Assertions.assertThat; + +public abstract class CommandTest { + + protected CommandManager commandManager; + protected SenderMock sender; + protected Commands commands; + + @BeforeEach + void setUpBase() { + commandManager = createCommandManager(); + commands = new Commands(commandManager); + sender = senderMock(); + } + + protected void register(Command command) { + commands.register(command); + } + + @SneakyThrows + protected Sender cmd(String command) { + return commandManager.executeCommand(sender, command).get().getCommandContext().getSender(); + } + + protected void cmdFails(String command, Class expectedException) { + try { + cmd(command); + } catch (Exception e) { + assertThat(e).getRootCause().isInstanceOf(expectedException); + } + } + + protected void assertLastMessageIs(Component component) { + sender.assertLastMessageIs(component); + } + +} diff --git a/platform/src/test/java/net/silthus/template/platform/command/commands/ExampleCommandTest.java b/platform/src/test/java/net/silthus/template/platform/command/commands/ExampleCommandTest.java new file mode 100644 index 0000000..6eb82c6 --- /dev/null +++ b/platform/src/test/java/net/silthus/template/platform/command/commands/ExampleCommandTest.java @@ -0,0 +1,39 @@ +package net.silthus.template.platform.command.commands; + +import net.silthus.template.platform.command.CommandTest; +import net.silthus.template.platform.config.TemplateConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static net.silthus.template.platform.config.ConfigKeys.TEST; +import static net.silthus.template.platform.config.TestConfigurationAdapter.testConfig; +import static net.silthus.template.platform.locale.Messages.TEST_MESSAGE; + +class ExampleCommandTest extends CommandTest { + + private TemplateConfig config; + + @BeforeEach + void setUp() { + config = testConfig(); + register(new ExampleCommand(config)); + } + + @DisplayName("/template test ") + @Nested + class testCommand { + @Test + void sends_input_message() { + cmd("template test Hi!"); + assertLastMessageIs(TEST_MESSAGE.build("Hi!")); + } + + @Test + void given_no_input_uses_config_value() { + cmd("template test"); + assertLastMessageIs(TEST_MESSAGE.build(config.get(TEST))); + } + } +} \ No newline at end of file diff --git a/platform/src/test/java/net/silthus/template/platform/config/ConfigTests.java b/platform/src/test/java/net/silthus/template/platform/config/ConfigTests.java new file mode 100644 index 0000000..7890ee8 --- /dev/null +++ b/platform/src/test/java/net/silthus/template/platform/config/ConfigTests.java @@ -0,0 +1,53 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config; + +import java.io.File; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static net.silthus.template.platform.config.ConfigKeys.TEST; +import static net.silthus.template.platform.config.TestConfigurationAdapter.testConfigAdapter; +import static org.assertj.core.api.Assertions.assertThat; + +class ConfigTests { + private TemplateConfig config; + + @BeforeEach + void setUp(@TempDir File temp) { + final ConfigurationAdapter adapter = testConfigAdapter(new File(temp, "test-config.yaml")); + config = new TemplateConfig(adapter); + config.load(); + } + + @Test + void values_are_loaded() { + assertThat(config.get(TEST)).isEqualTo("Hi from the config!"); + } + + @Test + void given_modified_value_then_it_is_loaded_on_reload() { + config.set(TEST, "test"); + config.reload(); + assertThat(config.get(TEST)).isEqualTo("test"); + } +} diff --git a/platform/src/test/java/net/silthus/template/platform/plugin/PluginTests.java b/platform/src/test/java/net/silthus/template/platform/plugin/PluginTests.java new file mode 100644 index 0000000..237f9e5 --- /dev/null +++ b/platform/src/test/java/net/silthus/template/platform/plugin/PluginTests.java @@ -0,0 +1,97 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.plugin; + +import cloud.commandframework.CommandManager; +import net.silthus.template.platform.command.Command; +import net.silthus.template.platform.command.Commands; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; +import net.silthus.template.platform.plugin.bootstrap.Bootstrap; +import net.silthus.template.platform.sender.Sender; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static net.silthus.template.platform.command.CommandTestUtils.createCommandManager; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class PluginTests { + + @Nested + class given_new_plugin { + private TestPlugin plugin; + + @BeforeEach + void setUp() { + plugin = new TestPlugin(); + } + + @Nested + class when_enable_is_called { + @BeforeEach + void setUp() { + plugin.enable(); + } + + @Test + void then_commands_are_registered() { + verify(TestPlugin.command).register(any(), any()); + } + + @Test + void then_config_is_loaded() { + assertThat(plugin.getConfig()).isNotNull(); + } + } + } + + private static class TestPlugin extends AbstractTemplatePlugin { + + static Command command = mock(Command.class); + + @Override + protected ConfigurationAdapter provideConfigurationAdapter() { + return mock(ConfigurationAdapter.class); + } + + @Override + protected void setupSenderFactory() { + + } + + @Override + protected CommandManager provideCommandManager() { + return createCommandManager(); + } + + @Override + protected void registerCustomCommands(Commands commands) { + commands.register(command); + } + + @Override + public Bootstrap getBootstrap() { + return mock(Bootstrap.class); + } + } +} diff --git a/platform/src/test/resources/junit-platform.properties b/platform/src/test/resources/junit-platform.properties new file mode 100644 index 0000000..5d02964 --- /dev/null +++ b/platform/src/test/resources/junit-platform.properties @@ -0,0 +1,19 @@ +# +# sChat, a Supercharged Minecraft Chat Plugin +# Copyright (C) Silthus +# Copyright (C) sChat team and contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +junit.jupiter.displayname.generator.default=org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores \ No newline at end of file diff --git a/platform/src/test/resources/test-config.yaml b/platform/src/test/resources/test-config.yaml new file mode 100644 index 0000000..f49520b --- /dev/null +++ b/platform/src/test/resources/test-config.yaml @@ -0,0 +1 @@ +test: "Hi from the config!" \ No newline at end of file diff --git a/platform/src/testFixtures/java/net/silthus/template/platform/command/CommandTestUtils.java b/platform/src/testFixtures/java/net/silthus/template/platform/command/CommandTestUtils.java new file mode 100644 index 0000000..9102a91 --- /dev/null +++ b/platform/src/testFixtures/java/net/silthus/template/platform/command/CommandTestUtils.java @@ -0,0 +1,78 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.command; + +import cloud.commandframework.CommandManager; +import cloud.commandframework.CommandTree; +import cloud.commandframework.execution.CommandExecutionCoordinator; +import cloud.commandframework.internal.CommandRegistrationHandler; +import cloud.commandframework.meta.SimpleCommandMeta; +import java.util.function.Function; +import net.silthus.template.platform.sender.Sender; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; + +public final class CommandTestUtils { + + /** + * A permission value which always returns {@code false}. + */ + public static final String FAILING_PERMISSION = "no"; + + private CommandTestUtils() { + } + + private abstract static class TestCommandSenderCommandManager extends CommandManager { + + protected TestCommandSenderCommandManager( + final Function, CommandExecutionCoordinator> commandExecutionCoordinator, + final CommandRegistrationHandler commandRegistrationHandler + ) { + super(commandExecutionCoordinator, commandRegistrationHandler); + } + + } + + public static CommandManager createCommandManager() { + final CommandManager manager = mock( + TestCommandSenderCommandManager.class, + withSettings().useConstructor( + CommandExecutionCoordinator.simpleCoordinator(), + CommandRegistrationHandler.nullCommandRegistrationHandler() + ).defaultAnswer(Mockito.CALLS_REAL_METHODS) + ); + + // We don't care about the actual command meta. + when(manager.createDefaultCommandMeta()).thenReturn(SimpleCommandMeta.empty()); + + // The permission check should always return true, unless "no" is the parameter. + when(manager.hasPermission(any(), anyString())).thenReturn(true); + when(manager.hasPermission(any(), eq(FAILING_PERMISSION))).thenReturn(false); + + return manager; + } + +} diff --git a/platform/src/testFixtures/java/net/silthus/template/platform/command/ParserTest.java b/platform/src/testFixtures/java/net/silthus/template/platform/command/ParserTest.java new file mode 100644 index 0000000..a33d2be --- /dev/null +++ b/platform/src/testFixtures/java/net/silthus/template/platform/command/ParserTest.java @@ -0,0 +1,78 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.command; + +import cloud.commandframework.CommandManager; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.captions.Caption; +import cloud.commandframework.context.CommandContext; +import java.util.ArrayDeque; +import java.util.List; +import java.util.Optional; +import lombok.Getter; +import lombok.Setter; +import net.silthus.template.platform.sender.Sender; +import org.jetbrains.annotations.NotNull; + +import static cloud.commandframework.arguments.parser.ParserParameters.empty; +import static io.leangen.geantyref.TypeToken.get; +import static net.silthus.template.platform.sender.SenderMock.senderMock; +import static org.assertj.core.api.Assertions.assertThat; + +@Getter +@Setter +public abstract class ParserTest { + + private final CommandManager commandManager; + private ArgumentParser parser; + + protected ParserTest() { + this.commandManager = CommandTestUtils.createCommandManager(); + } + + @NotNull + private CommandContext createContext() { + return new CommandContext<>(senderMock(), commandManager); + } + + protected ArgumentParseResult parse(String... input) { + return parser.parse(createContext(), new ArrayDeque<>(List.of(input))); + } + + protected void assertParseFailure(Class exception, String... input) { + final ArgumentParseResult result = parse(input); + assertThat(result.getFailure()).isPresent().get().isInstanceOf(exception); + } + + protected void assertParseSuccessful(String input, T expected) { + assertThat(parse(input).getParsedValue()).isPresent().get().isEqualTo(expected); + } + + @NotNull + protected String getCaption(Caption caption) { + return commandManager.getCaptionRegistry().getCaption(caption, senderMock()); + } + + @NotNull + protected Optional> getParser(Class type) { + return commandManager.getParserRegistry().createParser(get(type), empty()); + } +} diff --git a/platform/src/testFixtures/java/net/silthus/template/platform/config/TestConfigurationAdapter.java b/platform/src/testFixtures/java/net/silthus/template/platform/config/TestConfigurationAdapter.java new file mode 100644 index 0000000..4665017 --- /dev/null +++ b/platform/src/testFixtures/java/net/silthus/template/platform/config/TestConfigurationAdapter.java @@ -0,0 +1,62 @@ +/* + * sChat, a Supercharged Minecraft Chat Plugin + * Copyright (C) Silthus + * Copyright (C) sChat team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.silthus.template.platform.config; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Objects; +import lombok.SneakyThrows; +import net.silthus.template.platform.config.adapter.ConfigurationAdapter; +import net.silthus.template.platform.config.adapter.ConfigurationAdapters; + +public final class TestConfigurationAdapter { + + public static final String TEST_CONFIG_NAME = "test-config.yaml"; + + @SneakyThrows + public static TemplateConfig testConfig() { + return new TemplateConfig(testConfigAdapter(File.createTempFile("template-config-", ".yaml"))); + } + + @SneakyThrows + public static ConfigurationAdapter testConfigAdapter(File target) { + return testConfigAdapter(getTestConfigAsStream(), target); + } + + @SneakyThrows + public static ConfigurationAdapter testConfigAdapter(InputStream source, File target) { + copyConfig(source, target); + return ConfigurationAdapters.YAML.create(target); + } + + private static InputStream getTestConfigAsStream() { + return Objects.requireNonNull(TestConfigurationAdapter.class.getClassLoader().getResourceAsStream(TEST_CONFIG_NAME)); + } + + private static void copyConfig(InputStream source, File target) throws IOException { + Files.copy(source, target.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + + private TestConfigurationAdapter() { + } +} diff --git a/platform/src/testFixtures/java/net/silthus/template/platform/sender/SenderMock.java b/platform/src/testFixtures/java/net/silthus/template/platform/sender/SenderMock.java new file mode 100644 index 0000000..4e6d43e --- /dev/null +++ b/platform/src/testFixtures/java/net/silthus/template/platform/sender/SenderMock.java @@ -0,0 +1,53 @@ +package net.silthus.template.platform.sender; + +import java.util.LinkedList; +import java.util.Queue; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.silthus.template.identity.Identity; + +import static net.silthus.template.IdentityHelper.randomIdentity; +import static org.assertj.core.api.Assertions.assertThat; + +@Getter +public class SenderMock implements Sender { + + public static SenderMock senderMock() { + return new SenderMock(randomIdentity()); + } + + public static SenderMock senderMock(Identity identity) { + return new SenderMock(identity); + } + + private final Identity identity; + private final Queue messages = new LinkedList<>(); + + public SenderMock(Identity identity) { + this.identity = identity; + } + + @Override + public void sendMessage(Component message) { + messages.add(message); + } + + @Override + public boolean hasPermission(String permission) { + return false; + } + + @Override + public void performCommand(String commandLine) { + + } + + @Override + public boolean isConsole() { + return false; + } + + public void assertLastMessageIs(Component component) { + assertThat(messages.peek()).isEqualTo(component); + } +}