From 39793e5b8b04852f024df359b957cd73885ca796 Mon Sep 17 00:00:00 2001 From: Triassic Date: Sun, 28 Sep 2025 20:40:37 +0300 Subject: [PATCH] Add a PlatformSpecific annotation to limit commands and configuration nodes to specific platforms --- .../dev/triassic/template/TemplateImpl.java | 7 +++-- .../template/annotation/PlatformSpecific.java | 30 ++++++++++++++++++ .../template/command/CommandRegistry.java | 26 ++++++++++++++-- .../command/defaults/ReloadCommand.java | 3 ++ .../configuration/ConfigurationManager.java | 31 +++++++++++++++++-- .../configuration/TemplateConfiguration.java | 6 ++++ 6 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 core/src/main/java/dev/triassic/template/annotation/PlatformSpecific.java diff --git a/core/src/main/java/dev/triassic/template/TemplateImpl.java b/core/src/main/java/dev/triassic/template/TemplateImpl.java index e787d92..60d189c 100644 --- a/core/src/main/java/dev/triassic/template/TemplateImpl.java +++ b/core/src/main/java/dev/triassic/template/TemplateImpl.java @@ -9,6 +9,7 @@ package dev.triassic.template; +import dev.triassic.template.annotation.PlatformSpecific; import dev.triassic.template.command.CommandRegistry; import dev.triassic.template.command.Commander; import dev.triassic.template.configuration.ConfigurationManager; @@ -49,18 +50,20 @@ public TemplateImpl(final TemplatePlugin plugin) { /** * Called when the bootstrapped plugin is done initializing. */ + @PlatformSpecific(PlatformType.BUKKIT) public void initialize() { final long startTime = System.currentTimeMillis(); try { - this.config = ConfigurationManager.load(dataDirectory, TemplateConfiguration.class); + this.config = ConfigurationManager.load( + dataDirectory, TemplateConfiguration.class, platformType); } catch (IOException e) { logger.error("Failed to load configuration", e); return; } this.commandRegistry = new CommandRegistry(this, commandManager); - commandRegistry.registerAll(); + commandRegistry.registerAll(platformType); logger.info("Enabled in {}ms", System.currentTimeMillis() - startTime); } diff --git a/core/src/main/java/dev/triassic/template/annotation/PlatformSpecific.java b/core/src/main/java/dev/triassic/template/annotation/PlatformSpecific.java new file mode 100644 index 0000000..f482cfa --- /dev/null +++ b/core/src/main/java/dev/triassic/template/annotation/PlatformSpecific.java @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: CC0-1.0 + * + * Dedicated to the public domain under CC0 1.0 Universal. + * + * You can obtain a full copy of the license at: + * https://creativecommons.org/publicdomain/zero/1.0/ + */ + +package dev.triassic.template.annotation; + +import dev.triassic.template.util.PlatformType; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a class, method, or field as being specific to one or more platforms. + * Can be used for runtime checks or documentation. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR}) +public @interface PlatformSpecific { + + /** + * The platforms this class/method/field is intended for. + */ + PlatformType[] value(); +} diff --git a/core/src/main/java/dev/triassic/template/command/CommandRegistry.java b/core/src/main/java/dev/triassic/template/command/CommandRegistry.java index 135f2c0..33c9871 100644 --- a/core/src/main/java/dev/triassic/template/command/CommandRegistry.java +++ b/core/src/main/java/dev/triassic/template/command/CommandRegistry.java @@ -10,7 +10,9 @@ package dev.triassic.template.command; import dev.triassic.template.TemplateImpl; +import dev.triassic.template.annotation.PlatformSpecific; import dev.triassic.template.command.defaults.ReloadCommand; +import dev.triassic.template.util.PlatformType; import java.util.List; import lombok.RequiredArgsConstructor; import org.incendo.cloud.CommandManager; @@ -27,11 +29,31 @@ public final class CommandRegistry { /** * Registers all commands with the command manager. */ - public void registerAll() { + public void registerAll(PlatformType platform) { final List commands = List.of( new ReloadCommand(instance) ); - commands.forEach(command -> command.register(commandManager)); + commands.forEach(command -> { + if (isSupported(command.getClass(), platform)) { + command.register(commandManager); + } else { + System.out.println("Skipping " + command.getClass().getSimpleName() + + " (not supported on " + platform + ")"); + } + }); + } + + private static boolean isSupported(Class clazz, PlatformType platform) { + PlatformSpecific annotation = clazz.getAnnotation(PlatformSpecific.class); + if (annotation == null) { + return true; + } + for (PlatformType allowed : annotation.value()) { + if (allowed == platform) { + return true; + } + } + return false; } } diff --git a/core/src/main/java/dev/triassic/template/command/defaults/ReloadCommand.java b/core/src/main/java/dev/triassic/template/command/defaults/ReloadCommand.java index e0c3d28..e9fdbb0 100644 --- a/core/src/main/java/dev/triassic/template/command/defaults/ReloadCommand.java +++ b/core/src/main/java/dev/triassic/template/command/defaults/ReloadCommand.java @@ -10,10 +10,12 @@ package dev.triassic.template.command.defaults; import dev.triassic.template.TemplateImpl; +import dev.triassic.template.annotation.PlatformSpecific; import dev.triassic.template.command.Commander; import dev.triassic.template.command.TemplateCommand; import dev.triassic.template.configuration.ConfigurationManager; import dev.triassic.template.configuration.TemplateConfiguration; +import dev.triassic.template.util.PlatformType; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; @@ -23,6 +25,7 @@ /** * A command that reloads the plugin's configuration. */ +@PlatformSpecific({PlatformType.BUKKIT, PlatformType.PAPER}) public final class ReloadCommand extends TemplateCommand { private final Logger logger; diff --git a/core/src/main/java/dev/triassic/template/configuration/ConfigurationManager.java b/core/src/main/java/dev/triassic/template/configuration/ConfigurationManager.java index c9ce1dd..5ffc784 100644 --- a/core/src/main/java/dev/triassic/template/configuration/ConfigurationManager.java +++ b/core/src/main/java/dev/triassic/template/configuration/ConfigurationManager.java @@ -10,9 +10,12 @@ package dev.triassic.template.configuration; import dev.triassic.template.BuildParameters; +import dev.triassic.template.annotation.PlatformSpecific; +import dev.triassic.template.util.PlatformType; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.atomic.AtomicReference; @@ -20,6 +23,9 @@ import lombok.RequiredArgsConstructor; import org.spongepowered.configurate.CommentedConfigurationNode; import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.objectmapping.ObjectMapper; +import org.spongepowered.configurate.objectmapping.meta.Processor; +import org.spongepowered.configurate.serialize.TypeSerializerCollection; import org.spongepowered.configurate.yaml.NodeStyle; import org.spongepowered.configurate.yaml.YamlConfigurationLoader; @@ -57,14 +63,22 @@ public final class ConfigurationManager { */ public static ConfigurationManager load( Path path, - final Class clazz + final Class clazz, + final PlatformType platform ) throws IOException { path = path.resolve("config.yml"); final YamlConfigurationLoader loader = YamlConfigurationLoader.builder() .indent(2) .nodeStyle(NodeStyle.BLOCK) - .defaultOptions(opts -> opts.header(HEADER)) + .defaultOptions(opts -> opts + .header(HEADER) + .serializers(TypeSerializerCollection.defaults().childBuilder() + .registerAnnotatedObjects(ObjectMapper.factoryBuilder() + .addProcessor(PlatformSpecific.class, platformSpecific(platform)) + .build() + ) + .build())) .path(path) .build(); @@ -78,6 +92,19 @@ public static ConfigurationManager load( return new ConfigurationManager<>(clazz, loader, new AtomicReference<>(config)); } + private static Processor.Factory platformSpecific( + PlatformType currentPlatform + ) { + return (annotation, fieldType) -> (value, destination) -> { + boolean allowed = Arrays.asList(annotation.value()).contains(currentPlatform); + + if (!allowed) { + System.out.println("Removing " + destination.key()); + destination.parent().removeChild(destination.key()); + } + }; + } + /** * Asynchronously reloads the configuration from disk. * The current configuration object is updated with the newly loaded data. diff --git a/core/src/main/java/dev/triassic/template/configuration/TemplateConfiguration.java b/core/src/main/java/dev/triassic/template/configuration/TemplateConfiguration.java index 59f1d92..8480ff2 100644 --- a/core/src/main/java/dev/triassic/template/configuration/TemplateConfiguration.java +++ b/core/src/main/java/dev/triassic/template/configuration/TemplateConfiguration.java @@ -9,6 +9,8 @@ package dev.triassic.template.configuration; +import dev.triassic.template.annotation.PlatformSpecific; +import dev.triassic.template.util.PlatformType; import lombok.Getter; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.meta.Comment; @@ -21,6 +23,10 @@ @SuppressWarnings("FieldMayBeFinal") public class TemplateConfiguration { + @Comment("Should only appear on Bukkit-like platforms.") + @PlatformSpecific({PlatformType.BUKKIT, PlatformType.PAPER}) + private String exampleString = "hello, bukkit!"; + /** * The version of the configuration file. */