From b3f4d99a6040fe7430189f1717e8eec4bb67c624 Mon Sep 17 00:00:00 2001 From: Rollczi Date: Tue, 21 Oct 2025 20:21:39 +0200 Subject: [PATCH 1/2] Reformat placeholder definitions --- .../core/bridge/BridgeManager.java | 2 +- .../PlaceholderApiReplacer.java | 4 +- .../afk/placeholder/AfkPlaceholderSetup.java | 143 +++++++----------- .../feature/home/HomePlaceholderSetup.java | 140 +++++++---------- .../core/placeholder/Placeholder.java | 35 +++++ .../PlaceholderBukkitRegistryImpl.java | 6 +- .../core/placeholder/PlaceholderRaw.java | 10 +- .../core/placeholder/PlaceholderRegistry.java | 2 +- .../core/placeholder/PlaceholderReplacer.java | 23 --- .../core/placeholder/PlaceholdersSetup.java | 27 +++- .../scan/GroupAnnotationScanResolver.java | 33 ++++ .../scan/SingleAnnotationScanResolver.java | 33 +--- .../scan/placeholder/PlaceholderDocs.java | 42 ----- .../scan/placeholder/PlaceholderResult.java | 1 - .../placeholder/PlaceholderScanResolver.java | 20 +-- .../scan/placeholder/PlaceholdersDocs.java | 58 +++++++ .../scan/reflect/AnnotationUtil.java | 39 +++++ 17 files changed, 314 insertions(+), 304 deletions(-) create mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/placeholder/Placeholder.java delete mode 100644 eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderReplacer.java create mode 100644 eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java delete mode 100644 eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderDocs.java create mode 100644 eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java create mode 100644 eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/BridgeManager.java b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/BridgeManager.java index b76f09191..b1a23aa70 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/BridgeManager.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/BridgeManager.java @@ -38,7 +38,7 @@ class BridgeManager { void init() { this.setupBridge("PlaceholderAPI", () -> { - this.placeholderRegistry.registerPlaceholder(new PlaceholderApiReplacer()); + this.placeholderRegistry.register(new PlaceholderApiReplacer()); new PlaceholderApiExtension(this.placeholderRegistry, this.pluginDescriptionFile).initialize(); }); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/placeholderapi/PlaceholderApiReplacer.java b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/placeholderapi/PlaceholderApiReplacer.java index 8d4dfb08b..232775b53 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/bridge/placeholderapi/PlaceholderApiReplacer.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/bridge/placeholderapi/PlaceholderApiReplacer.java @@ -1,11 +1,11 @@ package com.eternalcode.core.bridge.placeholderapi; -import com.eternalcode.core.placeholder.PlaceholderReplacer; +import com.eternalcode.core.placeholder.Placeholder; import me.clip.placeholderapi.PlaceholderAPI; import org.bukkit.entity.Player; -public class PlaceholderApiReplacer implements PlaceholderReplacer { +public class PlaceholderApiReplacer implements Placeholder { @Override public String apply(String text, Player targetPlayer) { diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/afk/placeholder/AfkPlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/afk/placeholder/AfkPlaceholderSetup.java index 719ea7612..6a3215a83 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/afk/placeholder/AfkPlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/afk/placeholder/AfkPlaceholderSetup.java @@ -1,12 +1,14 @@ package com.eternalcode.core.feature.afk.placeholder; -import com.eternalcode.annotations.scan.placeholder.PlaceholderDocs; +import com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs; +import com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs.Entry; +import static com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs.Entry.*; import com.eternalcode.core.feature.afk.Afk; import com.eternalcode.core.feature.afk.AfkService; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Controller; import com.eternalcode.core.placeholder.PlaceholderRegistry; -import com.eternalcode.core.placeholder.PlaceholderReplacer; +import com.eternalcode.core.placeholder.Placeholder; import com.eternalcode.core.publish.Subscribe; import com.eternalcode.core.publish.event.EternalInitializeEvent; import com.eternalcode.core.translation.Translation; @@ -17,6 +19,35 @@ import java.util.Optional; import org.bukkit.Server; +@PlaceholdersDocs( + category = "AFK", + placeholders = { + @Entry( + name = "afk", + description = "Returns `true` if the player is AFK, `false` otherwise", + returnType = Type.BOOLEAN, + requiresPlayer = true + ), + @Entry( + name = "afk_formatted", + description = "Returns a formatted AFK status message based on player's language settings e.g. `[AFK]` or ``", + returnType = Type.STRING, + requiresPlayer = true + ), + @Entry( + name = "afk_time", + description = "Returns the duration the player has been AFK in a formatted string e.g. `5m 30s`", + returnType = Type.STRING, + requiresPlayer = true + ), + @Entry( + name = "afk_playercount", + description = "Returns the total number of AFK players on the server", + returnType = Type.INT, + requiresPlayer = false + ) + } +) @Controller class AfkPlaceholderSetup { @@ -30,91 +61,31 @@ class AfkPlaceholderSetup { } @Subscribe(EternalInitializeEvent.class) - void setUpPlaceholders(PlaceholderRegistry placeholderRegistry, AfkService afkService) { - placeholderRegistry.registerPlaceholder(this.createAfkPlaceholder(afkService)); - placeholderRegistry.registerPlaceholder(this.createAfkFormattedPlaceholder(afkService)); - placeholderRegistry.registerPlaceholder(this.createAfkTimePlaceholder(afkService)); - placeholderRegistry.registerPlaceholder(this.createAfkPlayerCountPlaceholder(afkService)); - } - - @PlaceholderDocs( - name = "afk", - description = "Returns true if the player is AFK, false otherwise", - example = "true", - returnType = "boolean", - category = "AFK", - requiresPlayer = true - ) - private PlaceholderReplacer createAfkPlaceholder(AfkService afkService) { - return PlaceholderReplacer.of( - "afk", - player -> String.valueOf(afkService.isAfk(player.getUniqueId())) - ); - } - - @PlaceholderDocs( - name = "afk_formatted", - description = "Returns a formatted AFK status message based on player's language settings", - example = "[AFK]", - returnType = "String", - category = "AFK", - requiresPlayer = true - ) - private PlaceholderReplacer createAfkFormattedPlaceholder(AfkService afkService) { - return PlaceholderReplacer.of( - "afk_formatted", - player -> { - Translation messages = this.translationManager.getMessages(player.getUniqueId()); - return afkService.isAfk(player.getUniqueId()) ? - messages.afk().afkEnabledPlaceholder() : messages.afk().afkDisabledPlaceholder(); + void setUpPlaceholders(PlaceholderRegistry placeholders, AfkService afkService) { + placeholders.register(Placeholder.ofBoolean("afk", player -> afkService.isAfk(player.getUniqueId()))); + placeholders.register(Placeholder.of("afk_formatted", player -> { + Translation messages = this.translationManager.getMessages(); + return afkService.isAfk(player.getUniqueId()) ? + messages.afk().afkEnabledPlaceholder() : messages.afk().afkDisabledPlaceholder(); + })); + placeholders.register(Placeholder.of("afk_time", player -> { + Optional afkOptional = afkService.getAfk(player.getUniqueId()); + if (afkOptional.isEmpty()) { + return ""; } - ); - } - @PlaceholderDocs( - name = "afk_time", - description = "Returns the duration the player has been AFK in a formatted string", - example = "5m 30s", - returnType = "String", - category = "AFK", - requiresPlayer = true - ) - private PlaceholderReplacer createAfkTimePlaceholder(AfkService afkService) { - return PlaceholderReplacer.of( - "afk_time", - player -> { - Optional afkOptional = afkService.getAfk(player.getUniqueId()); - if (afkOptional.isEmpty()) { - return ""; - } - - Afk afk = afkOptional.get(); - Instant start = afk.getStart(); - Instant now = Instant.now(); - Duration afkDuration = Duration.between(start, now); - return DurationUtil.format(afkDuration, true); - } - ); - } - - @PlaceholderDocs( - name = "afk_playercount", - description = "Returns the total number of AFK players on the server", - example = "3", - returnType = "int", - category = "AFK", - requiresPlayer = false - ) - private PlaceholderReplacer createAfkPlayerCountPlaceholder(AfkService afkService) { - return PlaceholderReplacer.of( - "afk_playercount", - ignoredPlayer -> { - long afkPlayerCount = this.server.getOnlinePlayers() - .stream() - .filter(onlinePlayer -> afkService.isAfk(onlinePlayer.getUniqueId())) - .count(); - return String.valueOf(afkPlayerCount); - } - ); + Afk afk = afkOptional.get(); + Instant start = afk.getStart(); + Instant now = Instant.now(); + Duration afkDuration = Duration.between(start, now); + return DurationUtil.format(afkDuration, true); + })); + placeholders.register(Placeholder.ofLong("afk_playercount", player -> { + long afkPlayerCount = this.server.getOnlinePlayers() + .stream() + .filter(onlinePlayer -> afkService.isAfk(onlinePlayer.getUniqueId())) + .count(); + return afkPlayerCount; + })); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomePlaceholderSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomePlaceholderSetup.java index 1a40d4182..86f302c84 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomePlaceholderSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/feature/home/HomePlaceholderSetup.java @@ -1,19 +1,47 @@ package com.eternalcode.core.feature.home; -import com.eternalcode.annotations.scan.placeholder.PlaceholderDocs; +import com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs; +import com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs.Entry.Type; import com.eternalcode.core.injector.annotations.Inject; import com.eternalcode.core.injector.annotations.component.Controller; import com.eternalcode.core.placeholder.PlaceholderRegistry; -import com.eternalcode.core.placeholder.PlaceholderReplacer; +import com.eternalcode.core.placeholder.Placeholder; import com.eternalcode.core.publish.Subscribe; import com.eternalcode.core.publish.event.EternalInitializeEvent; import com.eternalcode.core.translation.Translation; import com.eternalcode.core.translation.TranslationManager; import java.util.Collection; import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.bukkit.entity.Player; +@PlaceholdersDocs( + category = "Home", + placeholders = { + @PlaceholdersDocs.Entry( + name = "homes_owned", + description = "Returns a comma-separated list of all homes owned by the player. If the player has no homes, returns a localized message. e.g. `home1, home2, domek`", + returnType = Type.STRING, + requiresPlayer = true + ), + @PlaceholdersDocs.Entry( + name = "homes_count", + description = "Returns the number of homes the player currently owns.", + returnType = Type.INT, + requiresPlayer = true + ), + @PlaceholdersDocs.Entry( + name = "homes_limit", + description = "Returns the maximum number of homes the player can have.", + returnType = Type.INT, + requiresPlayer = true + ), + @PlaceholdersDocs.Entry( + name = "homes_left", + description = "Returns how many more homes the player can create before reaching the limit.", + returnType = Type.INT, + requiresPlayer = true + ) + } +) @Controller class HomePlaceholderSetup { @@ -27,94 +55,30 @@ class HomePlaceholderSetup { } @Subscribe(EternalInitializeEvent.class) - void setUp(PlaceholderRegistry placeholderRegistry) { - Stream.of( - this.createHomesOwnedPlaceholder(), - this.createHomesCountPlaceholder(), - this.createHomesLimitPlaceholder(), - this.createHomesLeftPlaceholder() - ).forEach(placeholderRegistry::registerPlaceholder); - } - - @PlaceholderDocs( - name = "homes_owned", - description = "Returns a comma-separated list of all homes owned by the player. If the player has no homes, returns a localized message.", - example = "home1, home2, domek", - returnType = "String", - category = "Home", - requiresPlayer = true - ) - private PlaceholderReplacer createHomesOwnedPlaceholder() { - return PlaceholderReplacer.of( - "homes_owned", - (text, targetPlayer) -> { - Collection homes = this.homeService.getHomes(targetPlayer.getUniqueId()); - Translation translation = this.translationManager.getMessages(targetPlayer.getUniqueId()); + void setUp(PlaceholderRegistry placeholders) { + placeholders.register(Placeholder.of("homes_owned", target -> { + Collection homes = this.homeService.getHomes(target.getUniqueId()); + Translation translation = this.translationManager.getMessages(target.getUniqueId()); - if (homes.isEmpty()) { - return translation.home().noHomesOwnedPlaceholder(); - } - - return homes.stream() - .map(Home::getName) - .collect(Collectors.joining(", ")); + if (homes.isEmpty()) { + return translation.home().noHomesOwnedPlaceholder(); } - ); - } - @PlaceholderDocs( - name = "homes_count", - description = "Returns the number of homes the player currently owns.", - example = "3", - returnType = "int", - category = "Home", - requiresPlayer = true - ) - private PlaceholderReplacer createHomesCountPlaceholder() { - return PlaceholderReplacer.of( - "homes_count", - (text, targetPlayer) -> - String.valueOf(this.homeService.getAmountOfHomes(targetPlayer.getUniqueId())) - ); - } + return homes.stream() + .map(Home::getName) + .collect(Collectors.joining(", ")); + })); + placeholders.register(Placeholder.ofInt("homes_count", target -> this.homeService.getAmountOfHomes(target.getUniqueId()))); + placeholders.register(Placeholder.ofInt("homes_limit", target -> this.homeService.getHomeLimit(target))); + placeholders.register(Placeholder.ofInt("homes_left", target -> { + int homesLimit = this.homeService.getHomeLimit(target); + int amountOfHomes = this.homeService.getAmountOfHomes(target.getUniqueId()); - @PlaceholderDocs( - name = "homes_limit", - description = "Returns the maximum number of homes the player can have.", - example = "5", - returnType = "int", - category = "Home", - requiresPlayer = true - ) - private PlaceholderReplacer createHomesLimitPlaceholder() { - return PlaceholderReplacer.of( - "homes_limit", - (text, targetPlayer) -> - String.valueOf(this.homeService.getHomeLimit(targetPlayer)) - ); - } - - @PlaceholderDocs( - name = "homes_left", - description = "Returns how many more homes the player can create before reaching the limit.", - example = "2", - returnType = "int", - category = "Home", - requiresPlayer = true - ) - private PlaceholderReplacer createHomesLeftPlaceholder() { - return PlaceholderReplacer.of( - "homes_left", - (text, targetPlayer) -> { - int homesLimit = this.homeService.getHomeLimit(targetPlayer); - int amountOfHomes = this.homeService.getAmountOfHomes(targetPlayer.getUniqueId()); - - if (homesLimit < -1 || amountOfHomes > homesLimit) { - return "0"; - } - - return String.valueOf(homesLimit - amountOfHomes); + if (homesLimit < -1 || amountOfHomes > homesLimit) { + return 0; } - ); + + return homesLimit - amountOfHomes; + })); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/Placeholder.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/Placeholder.java new file mode 100644 index 000000000..84a12928d --- /dev/null +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/Placeholder.java @@ -0,0 +1,35 @@ +package com.eternalcode.core.placeholder; + +import org.bukkit.entity.Player; + +import java.util.function.Function; + +public interface Placeholder { + + String apply(String text, Player targetPlayer); + + static Placeholder of(String target, String replacement) { + return new PlaceholderRaw(target, player -> replacement); + } + + static Placeholder of(String target, Function replacement) { + return new PlaceholderRaw(target, replacement); + } + + static Placeholder ofInt(String target, Function replacement) { + return new PlaceholderRaw(target, player -> String.valueOf(replacement.apply(player))); + } + + static Placeholder ofBoolean(String target, Function replacement) { + return new PlaceholderRaw(target, player -> String.valueOf(replacement.apply(player))); + } + + static Placeholder ofLong(String target, Function replacement) { + return new PlaceholderRaw(target, player -> String.valueOf(replacement.apply(player))); + } + + static Placeholder of(String target, Placeholder placeholder) { + return new PlaceholderRaw(target, player -> placeholder.apply(target, player)); + } + +} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderBukkitRegistryImpl.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderBukkitRegistryImpl.java index 2c733baaa..2e376f19a 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderBukkitRegistryImpl.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderBukkitRegistryImpl.java @@ -16,7 +16,7 @@ public class PlaceholderBukkitRegistryImpl implements PlaceholderRegistry { private final Server server; - private final Set replacerPlayers = new HashSet<>(); + private final Set replacerPlayers = new HashSet<>(); private final Map rawPlaceholders = new HashMap<>(); @Inject @@ -25,7 +25,7 @@ public PlaceholderBukkitRegistryImpl(Server server) { } @Override - public void registerPlaceholder(PlaceholderReplacer stack) { + public void register(Placeholder stack) { this.replacerPlayers.add(stack); if (stack instanceof PlaceholderRaw raw) { @@ -39,7 +39,7 @@ public String format(String text, Viewer target) { Player playerTarget = this.server.getPlayer(target.getUniqueId()); if (playerTarget != null) { - for (PlaceholderReplacer replacer : this.replacerPlayers) { + for (Placeholder replacer : this.replacerPlayers) { text = replacer.apply(text, playerTarget); } } diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRaw.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRaw.java index 3e3febdaf..3e3bcf0ec 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRaw.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRaw.java @@ -4,15 +4,7 @@ import java.util.function.Function; -public final class PlaceholderRaw implements PlaceholderReplacer { - - private final String target; - private final Function replacement; - - PlaceholderRaw(String target, Function replacement) { - this.target = target; - this.replacement = replacement; - } +public record PlaceholderRaw(String target, Function replacement) implements Placeholder { @Override public String apply(String text, Player targetPlayer) { diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRegistry.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRegistry.java index 82b6d0a8e..b7d3bcaa4 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRegistry.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderRegistry.java @@ -6,7 +6,7 @@ public interface PlaceholderRegistry { - void registerPlaceholder(PlaceholderReplacer stack); + void register(Placeholder stack); String format(String text, Viewer target); diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderReplacer.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderReplacer.java deleted file mode 100644 index 3c00c992b..000000000 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholderReplacer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.eternalcode.core.placeholder; - -import org.bukkit.entity.Player; - -import java.util.function.Function; - -public interface PlaceholderReplacer { - - String apply(String text, Player targetPlayer); - - static PlaceholderReplacer of(String target, String replacement) { - return new PlaceholderRaw(target, player -> replacement); - } - - static PlaceholderReplacer of(String target, Function replacement) { - return new PlaceholderRaw(target, replacement); - } - - static PlaceholderReplacer of(String target, PlaceholderReplacer placeholder) { - return new PlaceholderRaw(target, player -> placeholder.apply(target, player)); - } - -} diff --git a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholdersSetup.java b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholdersSetup.java index 1ddc827ce..e5e6a74bd 100644 --- a/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholdersSetup.java +++ b/eternalcore-core/src/main/java/com/eternalcode/core/placeholder/PlaceholdersSetup.java @@ -1,5 +1,8 @@ package com.eternalcode.core.placeholder; +import com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs; +import com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs.Entry; +import com.eternalcode.annotations.scan.placeholder.PlaceholdersDocs.Entry.Type; import com.eternalcode.core.configuration.implementation.PlaceholdersConfiguration; import com.eternalcode.core.feature.vanish.VanishService; import com.eternalcode.core.injector.annotations.component.Controller; @@ -7,23 +10,33 @@ import com.eternalcode.core.publish.Subscribe; import org.bukkit.Server; +@PlaceholdersDocs( + placeholders = { + @Entry( + name = "online", + description = "Returns the number of online players who are not vanished", + returnType = Type.INT, + requiresPlayer = false + ) + } +) @Controller class PlaceholdersSetup { @Subscribe(EternalInitializeEvent.class) - void setUp(PlaceholderRegistry placeholderRegistry, PlaceholdersConfiguration placeholdersConfiguration) { - placeholdersConfiguration.placeholders.forEach((key, value) -> { - placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of(key, value)); - }); + void setUp(PlaceholderRegistry placeholders, PlaceholdersConfiguration config) { + for (String key : config.placeholders.keySet()) { + placeholders.register(Placeholder.of(key, player -> config.placeholders.getOrDefault(key, "{" + key + "}"))); + } } @Subscribe(EternalInitializeEvent.class) - void setUpPlaceholders(PlaceholderRegistry placeholderRegistry, Server server, VanishService vanishService) { - placeholderRegistry.registerPlaceholder(PlaceholderReplacer.of("online", player -> String.valueOf( + void setUpPlaceholders(PlaceholderRegistry placeholders, Server server, VanishService vanishService) { + placeholders.register(Placeholder.ofLong("online", player -> server.getOnlinePlayers() .stream() .filter(onlinePlayer -> !vanishService.isVanished(onlinePlayer)) - .count()) + .count() ) ); } diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java new file mode 100644 index 000000000..f691ec824 --- /dev/null +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java @@ -0,0 +1,33 @@ +package com.eternalcode.annotations.scan; + +import com.eternalcode.annotations.scan.reflect.AnnotationUtil; +import java.lang.annotation.Annotation; +import java.util.List; + +public abstract class GroupAnnotationScanResolver implements EternalScanResolver { + + private final Class annotationClass; + private final Class annotationGroupClass; + + public GroupAnnotationScanResolver(Class annotationClass, Class annotationGroupClass) { + this.annotationClass = annotationClass; + this.annotationGroupClass = annotationGroupClass; + } + + @Override + public final List resolve(EternalScanRecord record) { + return AnnotationUtil.scanForAnnotations(record.clazz(), this.annotationGroupClass).stream() + .flatMap(group -> this.resolveGroup(record, group).stream()) + .toList(); + } + + private List resolveGroup(EternalScanRecord record, G group) { + return AnnotationUtil.scanForAnnotations(record.clazz(), this.annotationClass).stream() + .map(annotation -> this.resolve(record, group, annotation)) + .toList(); + } + + protected abstract RESULT resolve(EternalScanRecord record, G group, A annotation); + + +} diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/SingleAnnotationScanResolver.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/SingleAnnotationScanResolver.java index eb5900db2..d8d24d401 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/SingleAnnotationScanResolver.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/SingleAnnotationScanResolver.java @@ -1,8 +1,7 @@ package com.eternalcode.annotations.scan; +import com.eternalcode.annotations.scan.reflect.AnnotationUtil; import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -17,7 +16,7 @@ public SingleAnnotationScanResolver(Class annotationClass) { @Override public final List resolve(EternalScanRecord record) { List results = new ArrayList<>(); - List annotations = this.scanForAnnotations(record.clazz(), this.annotationClass); + List annotations = AnnotationUtil.scanForAnnotations(record.clazz(), this.annotationClass); for (A annotation : annotations) { results.add(this.resolve(record, annotation)); @@ -28,32 +27,4 @@ public final List resolve(EternalScanRecord record) { protected abstract RESULT resolve(EternalScanRecord record, A annotation); - private List scanForAnnotations(Class classToScan, Class annotationClass) { - List annotations = new ArrayList<>(); - - A annotation = classToScan.getAnnotation(annotationClass); - - if (annotation != null) { - annotations.add(annotation); - } - - for (Method method : classToScan.getDeclaredMethods()) { - A methodAnnotation = method.getAnnotation(annotationClass); - - if (methodAnnotation != null) { - annotations.add(methodAnnotation); - } - } - - for (Field field : classToScan.getDeclaredFields()) { - A fieldAnnotation = field.getAnnotation(annotationClass); - - if (fieldAnnotation != null) { - annotations.add(fieldAnnotation); - } - } - - return annotations; - } - } diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderDocs.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderDocs.java deleted file mode 100644 index fad6c73b7..000000000 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderDocs.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.eternalcode.annotations.scan.placeholder; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.METHOD, ElementType.FIELD }) -public @interface PlaceholderDocs { - - /** - * The name of the placeholder (without % symbols) - * Example: "afk" for %afk% - */ - String name(); - - /** - * Description of what the placeholder does - */ - String description(); - - /** - * Example output of the placeholder - */ - String example(); - - /** - * Return type of the placeholder - */ - String returnType(); - - /** - * Category for grouping placeholders - */ - String category() default "General"; - - /** - * Whether the placeholder requires a player context - */ - boolean requiresPlayer(); -} diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderResult.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderResult.java index d8ca68807..8a8c390a0 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderResult.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderResult.java @@ -3,7 +3,6 @@ public record PlaceholderResult( String name, String description, - String example, String returnType, String category, boolean requiresPlayer diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java index c5b441aeb..586496036 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java @@ -1,24 +1,24 @@ package com.eternalcode.annotations.scan.placeholder; import com.eternalcode.annotations.scan.EternalScanRecord; -import com.eternalcode.annotations.scan.SingleAnnotationScanResolver; +import com.eternalcode.annotations.scan.GroupAnnotationScanResolver; -public class PlaceholderScanResolver extends SingleAnnotationScanResolver { +public class PlaceholderScanResolver extends GroupAnnotationScanResolver { public PlaceholderScanResolver() { - super(PlaceholderDocs.class); + super(PlaceholdersDocs.Entry.class, PlaceholdersDocs.class); } @Override - public PlaceholderResult resolve(EternalScanRecord record, PlaceholderDocs annotation) { - String prefixedName = "%eternalcore_" + annotation.name() + "%"; + protected PlaceholderResult resolve(EternalScanRecord record, PlaceholdersDocs group, PlaceholdersDocs.Entry placeholder) { + String prefixedName = "%eternalcore_" + placeholder.name() + "%"; return new PlaceholderResult( prefixedName, - annotation.description(), - annotation.example(), - annotation.returnType(), - annotation.category(), - annotation.requiresPlayer() + placeholder.description(), + placeholder.returnType().getName(), + group.category(), + placeholder.requiresPlayer() ); } + } diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java new file mode 100644 index 000000000..48a0b4a1d --- /dev/null +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java @@ -0,0 +1,58 @@ +package com.eternalcode.annotations.scan.placeholder; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +public @interface PlaceholdersDocs { + + /** + * Category for grouping placeholders + */ + String category() default "General"; + + Entry[] placeholders(); + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE}) + @interface Entry { + + /** + * The name of the placeholder (without % symbols) + * Example: "afk" for %afk% + */ + String name(); + + /** + * Description of what the placeholder does + */ + String description(); + + /** + * Return type of the placeholder + */ + Type returnType(); + + enum Type { + STRING("string"), + BOOLEAN("boolean"), + INT("int"); + + private final String name; + + Type(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + /** + * Whether the placeholder requires a player context + */ + boolean requiresPlayer(); + } +} diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java new file mode 100644 index 000000000..159426f39 --- /dev/null +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java @@ -0,0 +1,39 @@ +package com.eternalcode.annotations.scan.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class AnnotationUtil { + + public static List scanForAnnotations(Class classToScan, Class annotationClass) { + List annotations = new ArrayList<>(); + + A annotation = classToScan.getAnnotation(annotationClass); + + if (annotation != null) { + annotations.add(annotation); + } + + for (Method method : classToScan.getDeclaredMethods()) { + A methodAnnotation = method.getAnnotation(annotationClass); + + if (methodAnnotation != null) { + annotations.add(methodAnnotation); + } + } + + for (Field field : classToScan.getDeclaredFields()) { + A fieldAnnotation = field.getAnnotation(annotationClass); + + if (fieldAnnotation != null) { + annotations.add(fieldAnnotation); + } + } + + return annotations; + } + +} From 5a01379491fc152fd72f38f95071ce422203d1c4 Mon Sep 17 00:00:00 2001 From: Rollczi Date: Sun, 26 Oct 2025 22:24:16 +0100 Subject: [PATCH 2/2] CR --- .../scan/GroupAnnotationScanResolver.java | 17 ++++++----- .../placeholder/PlaceholderScanResolver.java | 7 ++++- .../scan/placeholder/PlaceholdersDocs.java | 2 ++ .../scan/reflect/AnnotationUtil.java | 2 +- raw_eternalcore_placeholders.json | 29 +++++++++---------- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java index f691ec824..c86b14aa5 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/GroupAnnotationScanResolver.java @@ -3,14 +3,13 @@ import com.eternalcode.annotations.scan.reflect.AnnotationUtil; import java.lang.annotation.Annotation; import java.util.List; +import java.util.stream.Stream; -public abstract class GroupAnnotationScanResolver implements EternalScanResolver { +public abstract class GroupAnnotationScanResolver implements EternalScanResolver { - private final Class annotationClass; - private final Class annotationGroupClass; + private final Class annotationGroupClass; - public GroupAnnotationScanResolver(Class annotationClass, Class annotationGroupClass) { - this.annotationClass = annotationClass; + public GroupAnnotationScanResolver(Class annotationGroupClass) { this.annotationGroupClass = annotationGroupClass; } @@ -21,13 +20,15 @@ public final List resolve(EternalScanRecord record) { .toList(); } - private List resolveGroup(EternalScanRecord record, G group) { - return AnnotationUtil.scanForAnnotations(record.clazz(), this.annotationClass).stream() + private List resolveGroup(EternalScanRecord record, GROUP group) { + return Stream.of(getAnnotationsForGroup(group)) .map(annotation -> this.resolve(record, group, annotation)) .toList(); } - protected abstract RESULT resolve(EternalScanRecord record, G group, A annotation); + protected abstract A[] getAnnotationsForGroup(GROUP group); + + protected abstract RESULT resolve(EternalScanRecord record, GROUP group, A annotation); } diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java index 586496036..61706fb03 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholderScanResolver.java @@ -6,7 +6,12 @@ public class PlaceholderScanResolver extends GroupAnnotationScanResolver { public PlaceholderScanResolver() { - super(PlaceholdersDocs.Entry.class, PlaceholdersDocs.class); + super(PlaceholdersDocs.class); + } + + @Override + protected PlaceholdersDocs.Entry[] getAnnotationsForGroup(PlaceholdersDocs group) { + return group.placeholders(); } @Override diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java index 48a0b4a1d..3f10ffc19 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/placeholder/PlaceholdersDocs.java @@ -5,6 +5,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) public @interface PlaceholdersDocs { /** diff --git a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java index 159426f39..a82bf775c 100644 --- a/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java +++ b/eternalcore-docs-api/src/main/java/com/eternalcode/annotations/scan/reflect/AnnotationUtil.java @@ -8,7 +8,7 @@ public class AnnotationUtil { - public static List scanForAnnotations(Class classToScan, Class annotationClass) { + public static List scanForAnnotations(Class classToScan, Class annotationClass) { List annotations = new ArrayList<>(); A annotation = classToScan.getAnnotation(annotationClass); diff --git a/raw_eternalcore_placeholders.json b/raw_eternalcore_placeholders.json index 0fe107af9..e9727add4 100644 --- a/raw_eternalcore_placeholders.json +++ b/raw_eternalcore_placeholders.json @@ -1,40 +1,35 @@ [ { "name": "%eternalcore_afk%", - "description": "Returns true if the player is AFK, false otherwise", - "example": "true", + "description": "Returns `true` if the player is AFK, `false` otherwise", "returnType": "boolean", "category": "AFK", "requiresPlayer": true }, { "name": "%eternalcore_afk_formatted%", - "description": "Returns a formatted AFK status message based on player's language settings", - "example": "[AFK]", - "returnType": "String", + "description": "Returns a formatted AFK status message based on player's language settings e.g. `[AFK]` or ``", + "returnType": "string", "category": "AFK", "requiresPlayer": true }, { "name": "%eternalcore_afk_playercount%", "description": "Returns the total number of AFK players on the server", - "example": "3", "returnType": "int", "category": "AFK", "requiresPlayer": false }, { "name": "%eternalcore_afk_time%", - "description": "Returns the duration the player has been AFK in a formatted string", - "example": "5m 30s", - "returnType": "String", + "description": "Returns the duration the player has been AFK in a formatted string e.g. `5m 30s`", + "returnType": "string", "category": "AFK", "requiresPlayer": true }, { "name": "%eternalcore_homes_count%", "description": "Returns the number of homes the player currently owns.", - "example": "3", "returnType": "int", "category": "Home", "requiresPlayer": true @@ -42,7 +37,6 @@ { "name": "%eternalcore_homes_left%", "description": "Returns how many more homes the player can create before reaching the limit.", - "example": "2", "returnType": "int", "category": "Home", "requiresPlayer": true @@ -50,17 +44,22 @@ { "name": "%eternalcore_homes_limit%", "description": "Returns the maximum number of homes the player can have.", - "example": "5", "returnType": "int", "category": "Home", "requiresPlayer": true }, { "name": "%eternalcore_homes_owned%", - "description": "Returns a comma-separated list of all homes owned by the player. If the player has no homes, returns a localized message.", - "example": "home1, home2, domek", - "returnType": "String", + "description": "Returns a comma-separated list of all homes owned by the player. If the player has no homes, returns a localized message. e.g. `home1, home2, domek`", + "returnType": "string", "category": "Home", "requiresPlayer": true + }, + { + "name": "%eternalcore_online%", + "description": "Returns the number of online players who are not vanished", + "returnType": "int", + "category": "General", + "requiresPlayer": false } ] \ No newline at end of file