From 2d18ede343b109bb2be10d4fe06ebb214619dcb6 Mon Sep 17 00:00:00 2001 From: phinner <62483793+phinner@users.noreply.github.com> Date: Fri, 10 May 2024 22:55:16 +0200 Subject: [PATCH] chore: Some more docs and code changes --- .../api/command/cloud/CloudCommandFacade.java | 6 --- .../cloud/MindustryCommandManager.java | 25 ++++++++- .../command/cloud/parser/ContentParser.java | 17 ++++++ .../command/cloud/parser/PlayerParser.java | 27 ++++++---- .../api/command/cloud/parser/TeamParser.java | 11 ++-- .../api/command/CommandSender.java | 25 ++++++--- .../api/command/DescriptionFacade.java | 11 ++-- .../api/command/PlayerCommandSender.java | 6 +-- .../api/command/ServerCommandSender.java | 6 +-- .../command/TranslatedDescriptionFacade.java | 11 ++-- .../api/content/BlockRotation.java | 26 +++++++-- .../api/content/ImmutableSchematic.java | 5 +- .../api/permission/MutablePermissionTree.java | 54 ++++++++++++++++--- .../permission/MutablePermissionTreeImpl.java | 7 ++- .../api/permission/PermissionHolder.java | 24 --------- .../api/permission/PermissionReader.java | 29 +++++----- .../api/permission/PermissionTree.java | 49 ++++++++++++++++- .../distributor/api/permission/TriState.java | 2 +- .../distributor/api/player/MUUID.java | 2 +- .../distributor/api/player/PlayerLookup.java | 47 +++++++++++++++- .../api/player/PlayerLookupImpl.java | 2 +- .../api/plugin/MindustryPlugin.java | 2 +- .../api/scheduler/MindustryTimeUnit.java | 2 +- .../distributor/api/scheduler/PluginTask.java | 2 +- .../api/translation/LocaleHolder.java | 26 --------- .../translation/RouterTranslationSource.java | 7 +-- .../api/translation/TranslationSource.java | 18 +++---- .../rank/YamlRankPermissionSource.java | 4 +- 28 files changed, 299 insertions(+), 154 deletions(-) delete mode 100644 distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionHolder.java delete mode 100644 distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/LocaleHolder.java diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/CloudCommandFacade.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/CloudCommandFacade.java index cf2af751..7f505153 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/CloudCommandFacade.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/CloudCommandFacade.java @@ -63,9 +63,6 @@ final class CloudCommandFacade extends CommandHandler.Command implements Comm this.cloudDescription = description; } - /** - * Returns the real name of the command, without the prefix. - */ @Override public String getRealName() { return this.realName; @@ -81,9 +78,6 @@ public DescriptionFacade getDescription() { return this.manager.descriptionMapper().map(this.cloudDescription); } - /** - * Returns whether this command is an alias. - */ @Override public boolean isAlias() { return this.alias; diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/MindustryCommandManager.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/MindustryCommandManager.java index 880577d2..00f7a098 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/MindustryCommandManager.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/MindustryCommandManager.java @@ -46,6 +46,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * A command manager for Mindustry plugins. + * + * @param the command sender type + */ public class MindustryCommandManager extends CommandManager implements PluginAware, SenderMapperHolder { @@ -55,6 +60,14 @@ public class MindustryCommandManager extends CommandManager private DescriptionMapper descriptionMapper = DescriptionMapper.text(Description::textDescription); private @Nullable CommandHandler handler = null; + /** + * Constructs a new {@link MindustryCommandManager}. + * + * @param plugin the owning plugin + * @param coordinator the execution coordinator + * @param senderMapper the sender mapper + * @see CommandManager#CommandManager(ExecutionCoordinator, CommandRegistrationHandler) + */ public MindustryCommandManager( final MindustryPlugin plugin, final ExecutionCoordinator coordinator, @@ -109,12 +122,17 @@ public final void initialize(final CommandHandler handler) { } /** - * Returns the {@code DescriptionMapper} of this command manager. + * Returns the {@link DescriptionMapper} of this command manager. */ public final DescriptionMapper descriptionMapper() { return this.descriptionMapper; } + /** + * Sets the {@link DescriptionMapper} of this command manager. + * + * @param descriptionMapper the new description mapper + */ public final void descriptionMapper(final DescriptionMapper descriptionMapper) { this.descriptionMapper = descriptionMapper; } @@ -135,13 +153,16 @@ public final MindustryPlugin getPlugin() { return this.senderMapper; } + /** + * Registers the default exception handlers for this command manager. + */ protected void registerDefaultExceptionHandlers() { this.registerDefaultExceptionHandlers( triplet -> { final var context = triplet.first(); senderMapper() .reverse(context.sender()) - .sendWarning(context.formatCaption(triplet.second(), triplet.third())); + .error(context.formatCaption(triplet.second(), triplet.third())); }, pair -> logger.error(pair.first(), pair.second())); } diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/ContentParser.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/ContentParser.java index 8e585860..b1ac98e7 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/ContentParser.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/ContentParser.java @@ -32,6 +32,13 @@ import org.incendo.cloud.parser.ArgumentParser; import org.incendo.cloud.parser.ParserDescriptor; +/** + * A parser for {@link MappableContent content} arguments. + * Will only succeed on exact matches. + * + * @param the command sender type + * @param the content type + */ public final class ContentParser implements ArgumentParser { public static ParserDescriptor contentParser( @@ -60,11 +67,21 @@ public ArgumentParseResult parse(final CommandContext ctx, final CommandIn : ArgumentParseResult.success((T) content); } + /** + * An exception thrown when a content argument could not be parsed. + */ public static final class ContentParseException extends ParserException { private final String input; private final ContentTypeKey contentType; + /** + * Creates a new {@link ContentParseException}. + * + * @param input the input string + * @param ctx the command context + * @param contentType the content type + */ public ContentParseException( final CommandContext ctx, final String input, final ContentTypeKey contentType) { super( diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/PlayerParser.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/PlayerParser.java index fd7ae414..76314588 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/PlayerParser.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/PlayerParser.java @@ -19,6 +19,7 @@ package com.xpdustry.distributor.api.command.cloud.parser; import arc.Core; +import com.xpdustry.distributor.api.Distributor; import com.xpdustry.distributor.api.DistributorProvider; import com.xpdustry.distributor.api.collection.MindustryCollections; import com.xpdustry.distributor.api.command.cloud.MindustryCaptionKeys; @@ -41,6 +42,12 @@ import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; +/** + * A parser for {@link Player} arguments. + * Uses {@link Distributor#getPlayerLookup()} to find players. + * + * @param the command sender type + */ public final class PlayerParser implements ArgumentParser { public static ParserDescriptor playerParser() { @@ -63,9 +70,9 @@ public ArgumentParseResult parse(final CommandContext ctx, final Comm final var query = queryBuilder.setFields(fields).build(); final var players = DistributorProvider.get().getPlayerLookup().findOnlinePlayers(query); if (players.isEmpty()) { - return ArgumentParseResult.failure(new PlayerParseException.PlayerNotFound(query.getInput(), ctx)); + return ArgumentParseResult.failure(new PlayerParseException.PlayerNotFound(ctx, query.getInput())); } else if (players.size() > 1) { - return ArgumentParseResult.failure(new PlayerParseException.TooManyPlayers(query.getInput(), ctx)); + return ArgumentParseResult.failure(new PlayerParseException.TooManyPlayers(ctx, query.getInput())); } else { return ArgumentParseResult.success(players.iterator().next()); } @@ -97,11 +104,11 @@ public static sealed class PlayerParseException extends ParserException { /** * Creates a new {@link PlayerParseException}. * - * @param input the input string * @param ctx the command context + * @param input the input string * @param caption the error caption of this exception */ - public PlayerParseException(final String input, final CommandContext ctx, final Caption caption) { + public PlayerParseException(final CommandContext ctx, final String input, final Caption caption) { super(PlayerParser.class, ctx, caption, CaptionVariable.of("input", input)); this.input = input; } @@ -121,11 +128,11 @@ public static final class TooManyPlayers extends PlayerParseException { /** * Creates a new {@link TooManyPlayers}. * - * @param input the input string * @param ctx the command context + * @param input the input string */ - public TooManyPlayers(final String input, final CommandContext ctx) { - super(input, ctx, MindustryCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER_TOO_MANY); + public TooManyPlayers(final CommandContext ctx, final String input) { + super(ctx, input, MindustryCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER_TOO_MANY); } } @@ -137,11 +144,11 @@ public static final class PlayerNotFound extends PlayerParseException { /** * Creates a new {@link PlayerNotFound}. * - * @param input the input string * @param ctx the command context + * @param input the input string */ - public PlayerNotFound(final String input, final CommandContext ctx) { - super(input, ctx, MindustryCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER_NOT_FOUND); + public PlayerNotFound(final CommandContext ctx, final String input) { + super(ctx, input, MindustryCaptionKeys.ARGUMENT_PARSE_FAILURE_PLAYER_NOT_FOUND); } } } diff --git a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/TeamParser.java b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/TeamParser.java index c4597783..d20e1bad 100644 --- a/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/TeamParser.java +++ b/distributor-command-cloud/src/main/java/com/xpdustry/distributor/api/command/cloud/parser/TeamParser.java @@ -36,6 +36,11 @@ import org.incendo.cloud.parser.ParserDescriptor; import org.incendo.cloud.suggestion.SuggestionProvider; +/** + * A parser for {@link Team} arguments. + * + * @param the command sender type + */ public final class TeamParser implements ArgumentParser { public static ParserDescriptor teamParser() { @@ -66,7 +71,7 @@ public ArgumentParseResult parse(final CommandContext ctx, final Comman if (this.getTeamIndex().containsKey(name)) { return ArgumentParseResult.success(this.getTeamIndex().get(name)); } else { - return ArgumentParseResult.failure(new TeamParseException(name, ctx, this.teamMode)); + return ArgumentParseResult.failure(new TeamParseException(ctx, name, this.teamMode)); } } @@ -114,11 +119,11 @@ public static final class TeamParseException extends ParserException { /** * Creates a new {@link TeamParseException}. * - * @param input the input string * @param ctx the command context + * @param input the input string * @param teamMode the team mode */ - public TeamParseException(final String input, final CommandContext ctx, final TeamMode teamMode) { + public TeamParseException(final CommandContext ctx, final String input, final TeamMode teamMode) { super( TeamParser.class, ctx, diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/CommandSender.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/CommandSender.java index 74ab66f1..9915b1dd 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/CommandSender.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/CommandSender.java @@ -18,14 +18,14 @@ */ package com.xpdustry.distributor.api.command; -import com.xpdustry.distributor.api.permission.PermissionHolder; -import com.xpdustry.distributor.api.translation.LocaleHolder; +import com.xpdustry.distributor.api.permission.TriState; +import java.util.Locale; import mindustry.gen.Player; /** * Represents an entity that can send commands. */ -public interface CommandSender extends PermissionHolder, LocaleHolder { +public interface CommandSender { /** * Wraps a player into a command sender. @@ -54,14 +54,14 @@ static CommandSender server() { * * @param text the message to send */ - void sendMessage(final String text); + void reply(final String text); /** - * Sends a warning message to the sender. + * Sends a error message to the sender. * * @param text the message to send */ - void sendWarning(final String text); + void error(final String text); /** * Returns whether this sender is a player. @@ -80,4 +80,17 @@ static CommandSender server() { * @throws UnsupportedOperationException if this sender is not a player */ Player getPlayer(); + + /** + * Returns the permission state of the given permission. + * + * @param permission the permission to check + * @return the permission state + */ + TriState getPermission(final String permission); + + /** + * Returns the locale of this command sender. + */ + Locale getLocale(); } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/DescriptionFacade.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/DescriptionFacade.java index 2124801a..f10f92f7 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/DescriptionFacade.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/DescriptionFacade.java @@ -18,7 +18,6 @@ */ package com.xpdustry.distributor.api.command; -import com.xpdustry.distributor.api.translation.LocaleHolder; import com.xpdustry.distributor.internal.annotation.DistributorDataClass; import java.util.Locale; import org.immutables.value.Value; @@ -62,10 +61,10 @@ static DescriptionFacade translated(final String key, final Locale defaultLocale /** * Returns the description text for the given locale holder. * - * @param holder the locale holder + * @param sender the command sender * @return the description text */ - default String getText(final LocaleHolder holder) { + default String getText(final CommandSender sender) { return this.getText(); } @@ -79,10 +78,10 @@ default boolean isEmpty() { /** * Returns whether this description is empty for the given locale holder. * - * @param holder the locale holder + * @param sender the command sender * @return whether this description is empty */ - default boolean isEmpty(final LocaleHolder holder) { - return this.getText(holder).isEmpty(); + default boolean isEmpty(final CommandSender sender) { + return this.getText(sender).isEmpty(); } } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/PlayerCommandSender.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/PlayerCommandSender.java index a9926ef1..e521232e 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/PlayerCommandSender.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/PlayerCommandSender.java @@ -27,16 +27,16 @@ record PlayerCommandSender(Player player) implements CommandSender { @Override public String getName() { - return this.player.name(); + return this.player.coloredName(); } @Override - public void sendMessage(final String text) { + public void reply(final String text) { this.player.sendMessage(text); } @Override - public void sendWarning(final String text) { + public void error(final String text) { this.player.sendMessage("[red]" + text); } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/ServerCommandSender.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/ServerCommandSender.java index 6887788a..ae289ca8 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/ServerCommandSender.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/ServerCommandSender.java @@ -35,14 +35,14 @@ public String getName() { } @Override - public void sendMessage(final String text) { + public void reply(final String text) { for (final var line : text.split("\n", -1)) { Log.info(line); } } @Override - public void sendWarning(final String text) { + public void error(final String text) { for (final var line : text.split("\n", -1)) { Log.warn(line); } @@ -60,7 +60,7 @@ public boolean isServer() { @Override public Player getPlayer() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Cannot get player from server command sender"); } @Override diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/TranslatedDescriptionFacade.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/TranslatedDescriptionFacade.java index 9c1889fe..fdbd3452 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/TranslatedDescriptionFacade.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/command/TranslatedDescriptionFacade.java @@ -19,7 +19,6 @@ package com.xpdustry.distributor.api.command; import com.xpdustry.distributor.api.DistributorProvider; -import com.xpdustry.distributor.api.translation.LocaleHolder; import java.util.Locale; record TranslatedDescriptionFacade(String key, Locale defaultLocale) implements DescriptionFacade { @@ -28,15 +27,15 @@ record TranslatedDescriptionFacade(String key, Locale defaultLocale) implements public String getText() { return DistributorProvider.get() .getGlobalTranslationSource() - .getTranslationOrDefault(key, this.defaultLocale) + .getTranslationOrMissing(key, this.defaultLocale) .formatEmpty(); } @Override - public String getText(final LocaleHolder holder) { + public String getText(final CommandSender sender) { return DistributorProvider.get() .getGlobalTranslationSource() - .getTranslationOrDefault(key, holder.getLocale()) + .getTranslationOrMissing(key, sender.getLocale()) .formatEmpty(); } @@ -46,7 +45,7 @@ public boolean isEmpty() { } @Override - public boolean isEmpty(final LocaleHolder holder) { - return DistributorProvider.get().getGlobalTranslationSource().getTranslation(key, holder.getLocale()) == null; + public boolean isEmpty(final CommandSender sender) { + return DistributorProvider.get().getGlobalTranslationSource().getTranslation(key, sender.getLocale()) == null; } } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/BlockRotation.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/BlockRotation.java index ac47e149..fe55d23e 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/BlockRotation.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/BlockRotation.java @@ -18,17 +18,35 @@ */ package com.xpdustry.distributor.api.content; +import java.util.stream.Stream; + +/** + * Represents the rotation of a block. + */ public enum BlockRotation { RIGHT, TOP, LEFT, BOTTOM; - public static BlockRotation from(final int rotation) { - return values()[rotation % 4]; + /** + * Returns the serializable integer representation of this rotation. + */ + @SuppressWarnings("EnumOrdinal") + public int asInt() { + return ordinal(); } - public static BlockRotation from(final byte rotation) { - return values()[rotation % 4]; + /** + * Returns the rotation from the given integer. + * + * @param rotation the integer to convert + * @return the rotation + */ + public static BlockRotation from(final int rotation) { + return Stream.of(values()) + .filter(value -> value.asInt() == (rotation % 4)) + .findFirst() + .orElseThrow(); } } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/ImmutableSchematic.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/ImmutableSchematic.java index 8cbf51f8..9cf16c65 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/ImmutableSchematic.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/content/ImmutableSchematic.java @@ -33,6 +33,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.immutables.value.Value; +/** + * Immutable and safe representation of a {@link Schematic}. + */ @DistributorDataClassWithBuilder @Value.Immutable public sealed interface ImmutableSchematic permits ImmutableSchematicImpl { @@ -152,7 +155,7 @@ sealed interface Tile permits TileImpl { static Schematic.Stile toStile(final Tile tile) { return new Schematic.Stile(tile.getBlock(), tile.getX(), tile.getY(), tile.getConfig(), (byte) - tile.getRotation().ordinal()); + tile.getRotation().asInt()); } static Tile from(final Schematic.Stile stile) { diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTree.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTree.java index 95ee163c..2e8152d5 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTree.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTree.java @@ -18,35 +18,73 @@ */ package com.xpdustry.distributor.api.permission; +/** + * A mutable permission tree. + */ public interface MutablePermissionTree extends PermissionTree { + /** + * Creates a new mutable permission tree. + */ static MutablePermissionTree create() { return new MutablePermissionTreeImpl(); } - static MutablePermissionTree from(final PermissionTree tree) { - final var mutable = create(); - mutable.setPermissions(tree); - return mutable; - } - + /** + * Sets the permission with the given state. + * + * @param permission the permission + * @param state the state + */ default void setPermission(final String permission, final boolean state) { setPermission(permission, state, false); } + /** + * Sets the permission with the given state. + * + * @param permission the permission + * @param state the state + * @param override whether to override the child permissions with the new state + */ void setPermission(final String permission, final boolean state, final boolean override); + /** + * Sets the permissions from the given permission tree. + * + * @param tree the permission tree + */ default void setPermissions(final PermissionTree tree) { setPermissions(tree, false); } + /** + * Sets the permissions from the given permission tree. + * + * @param tree the permission tree + * @param override whether to override the child permissions with the new state + */ default void setPermissions(final PermissionTree tree, final boolean override) { for (final var entry : tree.getPermissions().entrySet()) { setPermission(entry.getKey(), entry.getValue(), override); } } - void clearPermissions(); + /** + * Removes the given permission from the tree. Essentially making it {@link TriState#UNDEFINED}. + * + * @param permission the permission + */ + default void removePermission(final String permission) { + removePermission(permission, false); + } + + void removePermission(final String permission, final boolean all); - void removePermission(final String permission); + /** + * Clears all permissions. + */ + default void clearPermissions() { + removePermission("*", true); + } } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTreeImpl.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTreeImpl.java index 20a33b02..601d7440 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTreeImpl.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/MutablePermissionTreeImpl.java @@ -88,7 +88,7 @@ public void setPermission(final String permission, final boolean state, final bo } @Override - public void removePermission(final String permission) { + public void removePermission(final String permission, final boolean all) { checkPermission(permission); final var parts = permission.split("\\.", -1); var node = this; @@ -99,6 +99,9 @@ public void removePermission(final String permission) { } } node.value = TriState.UNDEFINED; + if (all) { + node.children.clear(); + } var index = parts.length - 1; while (node.parent != null && node.children.isEmpty()) { node = node.parent; @@ -131,7 +134,7 @@ public int hashCode() { } private void checkPermission(final String permission) { - if (!PermissionReader.PERMISSION_PATTERN.matcher(permission).matches()) { + if (!PermissionTree.PERMISSION_PATTERN.matcher(permission).matches()) { throw new IllegalArgumentException("The permission is not valid: " + permission); } } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionHolder.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionHolder.java deleted file mode 100644 index 4e933142..00000000 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionHolder.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Distributor, a feature-rich framework for Mindustry plugins. - * - * Copyright (C) 2024 Xpdustry - * - * 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 com.xpdustry.distributor.api.permission; - -public interface PermissionHolder { - - TriState getPermission(final String permission); -} diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionReader.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionReader.java index 2a3df07f..91298e71 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionReader.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionReader.java @@ -18,32 +18,27 @@ */ package com.xpdustry.distributor.api.permission; -import java.util.regex.Pattern; import mindustry.gen.Player; +/** + * A simple interface for getting the permissions of online players. + */ +@FunctionalInterface public interface PermissionReader { /** - * Regex pattern used to validate permission strings. - *

- * Notes: - *

- * Permission strings are composed of a series of nodes separated by dots with alphanumeric characters and minus - * signs, such as {@code "plugin.command"}. - *
- * A parent node is always overridden by a child node, such as {@code "plugin.command"} overriding {@code "plugin"}. - *
- * Wildcards are also allowed, but they currently have the same effect as a normal node, such as {@code "plugin.command.*"} equals {@code "plugin.command"}. - *
- * The only relevant use of wildcards is the root permission {@code "*"} permission. It - * allows you to set a default value for all permissions. - *
+ * Returns an empty permission reader. */ - Pattern PERMISSION_PATTERN = Pattern.compile("^(\\*|\\w+)(\\.(\\*|\\w+))*$"); - static PermissionReader empty() { return EmptyPermissionReader.INSTANCE; } + /** + * Gets the permission of the given player. + * + * @param player the player + * @param permission the permission + * @return the permission + */ TriState getPermission(final Player player, final String permission); } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionTree.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionTree.java index ac9c72fa..b083975e 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionTree.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/PermissionTree.java @@ -19,27 +19,72 @@ package com.xpdustry.distributor.api.permission; import java.util.Map; +import java.util.regex.Pattern; +/** + * A tree of permissions. A fancy radix tree if you will. + */ public interface PermissionTree { + /** + * Regex pattern used to validate permission strings. + *

+ * Notes: + *

+ * Permission strings are composed of a series of nodes separated by dots with alphanumeric characters and minus + * signs, such as {@code "plugin.command"}. + *
+ * A parent node is always overridden by a child node, such as {@code "plugin.command"} overriding {@code "plugin"}. + *
+ * Wildcards are also allowed, but they currently have the same effect as a normal node, such as {@code "plugin.command.*"} equals {@code "plugin.command"}. + *
+ * The only relevant use of wildcards is the root permission {@code "*"} permission. It + * allows you to set a default value for all permissions. + *
+ */ + Pattern PERMISSION_PATTERN = Pattern.compile("^(\\*|\\w+)(\\.(\\*|\\w+))*$"); + + /** + * Returns an immutable empty permission tree. + */ static PermissionTree empty() { return EmptyPermissionTree.INSTANCE; } + /** + * Returns an immutable permission tree with all permissions. + */ static PermissionTree all() { final var tree = MutablePermissionTree.create(); tree.setPermission("*", true); return new ImmutablePermissionTree(tree); } - static PermissionTree immutable(final PermissionTree tree) { + /** + * Creates an immutable permission tree with the given tree. + * + * @param tree the tree + * @return the immutable tree + */ + static PermissionTree from(final PermissionTree tree) { if (tree instanceof ImmutablePermissionTree || tree instanceof EmptyPermissionTree) { return tree; } - return new ImmutablePermissionTree(MutablePermissionTree.from(tree)); + final var mutable = MutablePermissionTree.create(); + mutable.setPermissions(tree); + return new ImmutablePermissionTree(mutable); } + /** + * Get the permission state for a given permission. + * + * @param permission the permission + * @return the permission state + */ TriState getPermission(final String permission); + /** + * A flattened map of permissions. + */ Map getPermissions(); } diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/TriState.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/TriState.java index 11126916..509a0567 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/TriState.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/permission/TriState.java @@ -21,7 +21,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** - * A ternary boolean type. + * A ternary boolean type. Equivalent to {@code @Nullable Boolean}, but safer. */ public enum TriState { FALSE(false), diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/MUUID.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/MUUID.java index 73a3ab79..ec9d44c0 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/MUUID.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/MUUID.java @@ -139,7 +139,7 @@ default byte[] getDecodedUsid() { } /** - * TODO important doc + * Converts the uuid of this muuid into a real {@link UUID}, version 8. * @see UUID v8 spec */ default UUID toRealUUID() { diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookup.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookup.java index 134c7733..ac20d7cc 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookup.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookup.java @@ -24,6 +24,7 @@ import java.text.Normalizer; import java.util.Collection; import java.util.EnumSet; +import java.util.List; import java.util.Locale; import java.util.Set; import java.util.function.Function; @@ -32,6 +33,9 @@ import mindustry.gen.Player; import org.immutables.value.Value; +/** + * A simple interface for looking up online players. + */ public interface PlayerLookup { Supplier> DEFAULT_PROVIDER = () -> MindustryCollections.immutableList(Groups.player); @@ -42,35 +46,71 @@ public interface PlayerLookup { .replaceAll("\\p{InCombiningDiacriticalMarks}+", "") .toLowerCase(Locale.ROOT); + /** + * Creates a new player lookup with the default provider and normalizer. + */ static PlayerLookup create() { return new PlayerLookupImpl(DEFAULT_PROVIDER, DEFAULT_NORMALIZER); } + /** + * Creates a new player lookup with the given provider and normalizer. + * + * @param provider the player provider + * @param normalizer the normalizer + * @return the player lookup + */ static PlayerLookup create(final Supplier> provider, final Function normalizer) { return new PlayerLookupImpl(provider, normalizer); } - Collection findOnlinePlayers(final Query query); - + /** + * Finds online players matching the given query. + * + * @param query the query + * @return the matching players + */ + List findOnlinePlayers(final Query query); + + /** + * A query for looking up players. + */ @DistributorDataClassWithBuilder @Value.Immutable sealed interface Query permits QueryImpl { + /** + * Creates a simple query with the given input. + * + * @param input the input + * @return the created query + */ static Query of(final String input) { return builder().setInput(input).build(); } + /** + * Creates a new query builder. + */ static Query.Builder builder() { return QueryImpl.builder(); } String getInput(); + /** + * The fields to take into account when searching. + * Defaults to {@link Field#NAME} and {@link Field#ENTITY_ID}. + */ @Value.Default default Set getFields() { return EnumSet.of(Field.NAME, Field.ENTITY_ID); } + /** + * Whether to return a singular result if a exact match is found. + * Defaults to {@code true}. + */ @Value.Default default boolean isMatchExact() { return true; @@ -96,6 +136,9 @@ default Builder setFields(final Field... fields) { } } + /** + * The fields to take into account when searching. + */ enum Field { NAME, UUID, diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookupImpl.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookupImpl.java index 75584ed6..1b2344cb 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookupImpl.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/player/PlayerLookupImpl.java @@ -39,7 +39,7 @@ final class PlayerLookupImpl implements PlayerLookup { } @Override - public Collection findOnlinePlayers(final Query query) { + public List findOnlinePlayers(final Query query) { final var players = this.provider.get(); final List result = new ArrayList<>(); diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/plugin/MindustryPlugin.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/plugin/MindustryPlugin.java index 123341d3..0c573890 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/plugin/MindustryPlugin.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/plugin/MindustryPlugin.java @@ -64,7 +64,7 @@ default void onServerCommandsRegistration(final CommandHandler handler) {} default void onClientCommandsRegistration(final CommandHandler handler) {} /** - * Called after {@link #onClientCommandsRegistration(CommandHandler)} just before + * Called after {@link #onClientCommandsRegistration(CommandHandler)} just after * {@link mindustry.game.EventType.ServerLoadEvent}. * Hook into other plugins here since this method technically replaces {@link Plugin#init()}. */ diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/MindustryTimeUnit.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/MindustryTimeUnit.java index 5e1e8015..faaa0713 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/MindustryTimeUnit.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/MindustryTimeUnit.java @@ -70,7 +70,7 @@ public enum MindustryTimeUnit { *
    *
  • If it overflows, the result will be {@link Long#MAX_VALUE} if the duration is positive, * or {@link Long#MIN_VALUE} if it is negative.
  • - *
  • Conversions are floored so converting 999 milliseconds to seconds results in 0.
  • + *
  • Conversions are rounded so converting 999 milliseconds to seconds results in 0.
  • *
* * @param sourceDuration the duration to convert diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/PluginTask.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/PluginTask.java index 472cc9fe..82a18ba4 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/PluginTask.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/scheduler/PluginTask.java @@ -49,7 +49,7 @@ default void cancel() { * // Warn the players the server is close in 5 minutes. * Groups.player.each(p -> p.sendMessage("The server will restart in 5 minutes.")); * // Now schedule the closing task. - * scheduler.scheduleSync(plugin).delay(5L, MindustryTimeUnit.MINUTES).execute(() -> Core.app.exit()); + * scheduler.schedule(plugin).delay(5L, MindustryTimeUnit.MINUTES).execute(() -> Core.app.exit()); * } */ interface Builder { diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/LocaleHolder.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/LocaleHolder.java deleted file mode 100644 index fe9b047b..00000000 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/LocaleHolder.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Distributor, a feature-rich framework for Mindustry plugins. - * - * Copyright (C) 2024 Xpdustry - * - * 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 com.xpdustry.distributor.api.translation; - -import java.util.Locale; - -public interface LocaleHolder { - - Locale getLocale(); -} diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/RouterTranslationSource.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/RouterTranslationSource.java index 540906db..20a69f80 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/RouterTranslationSource.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/RouterTranslationSource.java @@ -21,15 +21,12 @@ import java.util.Locale; import org.checkerframework.checker.nullness.qual.Nullable; -final class RouterTranslationSource implements TranslationSource { - - static final RouterTranslationSource INSTANCE = new RouterTranslationSource(); +enum RouterTranslationSource implements TranslationSource { + INSTANCE; static final Locale ROUTER_LOCALE = new Locale("router"); private static final Translation ROUTER_TRANSLATION = TextTranslation.of("router"); - private RouterTranslationSource() {} - @Override public @Nullable Translation getTranslation(final String key, final Locale locale) { return locale.getLanguage().equals(ROUTER_LOCALE.getLanguage()) ? ROUTER_TRANSLATION : null; diff --git a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/TranslationSource.java b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/TranslationSource.java index 01d5bcc6..7e2df833 100644 --- a/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/TranslationSource.java +++ b/distributor-common-api/src/main/java/com/xpdustry/distributor/api/translation/TranslationSource.java @@ -24,14 +24,12 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** - * A helper class for adding localization support to your plugin. + * A helper class for adding translation support to your plugin. */ public interface TranslationSource { - Function DEFAULT_FALLBACK = key -> TextTranslation.of("???" + key + "???"); - /** - * Returns a {@code LocalizationSource} for the router language {@code :^)}. + * Returns a {@code TranslationSource} for the router language {@code :^)}. */ static TranslationSource router() { return RouterTranslationSource.INSTANCE; @@ -42,11 +40,11 @@ static TranslationSource router() { * *
 {@code
      *      // Send a localized message to every player
-     *      final LocalizationSource source = ...;
+     *      final TranslationSource source = ...;
      *      Groups.player.each(player -> {
      *          final var locale = Locale.forLanguageTag(player.locale().replace('_', '-'));
-     *          final var message = source.localize("example.key", locale);
-     *          player.sendMessage(message == null ? "???example.key???" : message);
+     *          final var message = source.getTranslationOrMissing("example.key", locale);
+     *          player.sendMessage(message.formatArray("Hello"));
      *      }
      * } 
* @@ -55,13 +53,13 @@ static TranslationSource router() { */ @Nullable Translation getTranslation(final String key, final Locale locale); - default Translation getTranslationOrDefault( + default Translation getTranslationOrMissing( final String key, final Locale locale, final Function fallback) { final var translation = getTranslation(key, locale); return translation != null ? translation : fallback.apply(key); } - default Translation getTranslationOrDefault(final String key, final Locale locale) { - return getTranslationOrDefault(key, locale, DEFAULT_FALLBACK); + default Translation getTranslationOrMissing(final String key, final Locale locale) { + return getTranslationOrMissing(key, locale, k -> TextTranslation.of("???" + k + "???")); } } diff --git a/distributor-permission-rank/src/main/java/com/xpdustry/distributor/api/permission/rank/YamlRankPermissionSource.java b/distributor-permission-rank/src/main/java/com/xpdustry/distributor/api/permission/rank/YamlRankPermissionSource.java index c002a135..88a58640 100644 --- a/distributor-permission-rank/src/main/java/com/xpdustry/distributor/api/permission/rank/YamlRankPermissionSource.java +++ b/distributor-permission-rank/src/main/java/com/xpdustry/distributor/api/permission/rank/YamlRankPermissionSource.java @@ -100,7 +100,7 @@ private PermissionTree getRankPermissions0(final RankNode node, final Set