Add enum serializer and remove wacky loading of enum options

This commit is contained in:
Vankka 2023-09-10 01:01:36 +03:00
parent 75c76743f8
commit 09968ba8c2
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
12 changed files with 121 additions and 71 deletions

View File

@ -23,6 +23,7 @@ import com.discordsrv.bukkit.config.main.BukkitRequiredLinkingConfig;
import com.discordsrv.bukkit.requiredlinking.BukkitRequiredLinkingModule;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.component.util.ComponentUtil;
import com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig;
import com.discordsrv.common.player.IPlayer;
import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
import net.kyori.adventure.text.Component;
@ -141,7 +142,7 @@ public class BukkitRequiredLinkingListener implements Listener {
Consumer<String> disallow
) {
BukkitRequiredLinkingConfig config = discordSRV.config().requiredLinking;
if (!config.enabled || !config.action.equalsIgnoreCase("KICK")
if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK
|| !eventType.equals(config.kick.event) || !priority.name().equals(config.kick.priority)) {
return;
}
@ -185,7 +186,7 @@ public class BukkitRequiredLinkingListener implements Listener {
}
BukkitRequiredLinkingConfig config = discordSRV.config().requiredLinking;
if (!config.enabled || !config.action.equalsIgnoreCase("FREEZE")) {
if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.FREEZE) {
return;
}

View File

@ -673,13 +673,13 @@ public abstract class AbstractDiscordSRV<
if (flags.contains(ReloadFlag.LINKED_ACCOUNT_PROVIDER)) {
LinkedAccountConfig linkedAccountConfig = config().linkedAccounts;
if (linkedAccountConfig != null && linkedAccountConfig.enabled) {
String provider = linkedAccountConfig.provider;
LinkedAccountConfig.Provider provider = linkedAccountConfig.provider;
boolean permitMinecraftAuth = connectionConfig().minecraftAuth.allow;
if (provider.equals("auto")) {
provider = permitMinecraftAuth && onlineMode().isOnline() ? "minecraftauth" : "storage";
if (provider == LinkedAccountConfig.Provider.AUTO) {
provider = permitMinecraftAuth && onlineMode().isOnline() ? LinkedAccountConfig.Provider.MINECRAFTAUTH : LinkedAccountConfig.Provider.STORAGE;
}
switch (provider) {
case "minecraftauth":
case MINECRAFTAUTH:
if (!permitMinecraftAuth) {
linkProvider = null;
logger().error("minecraftauth.me is disabled in the " + ConnectionConfig.FILE_NAME + ", "
@ -690,7 +690,7 @@ public abstract class AbstractDiscordSRV<
linkProvider = new MinecraftAuthenticationLinker(this);
logger().info("Using minecraftauth.me for linked accounts");
break;
case "storage":
case STORAGE:
linkProvider = new StorageLinker(this);
logger().info("Using storage for linked accounts");
break;

View File

@ -89,7 +89,7 @@ public class ExecuteCommand implements Consumer<DiscordChatInputInteractionEvent
boolean ephemeral = config.ephemeral;
event.asJDA().reply("Executing command `" + command + "`")
.setEphemeral(ephemeral)
.queue(ih -> new ExecutionContext(discordSRV, ih, config.getOutputMode(), ephemeral).run(command));
.queue(ih -> new ExecutionContext(discordSRV, ih, config.outputMode, ephemeral).run(command));
}
@Override
@ -214,7 +214,7 @@ public class ExecuteCommand implements Consumer<DiscordChatInputInteractionEvent
private void send() {
boolean ansi = outputMode == DiscordCommandConfig.OutputMode.ANSI;
boolean plainBlock = outputMode == DiscordCommandConfig.OutputMode.PLAIN_BLOCK;
boolean plainBlock = outputMode == DiscordCommandConfig.OutputMode.CODEBLOCK;
String prefix = ansi ? "```ansi\n" : (plainBlock ? "```\n" : "");
String suffix = ansi ? "```" : (plainBlock ? "```" : "");
@ -234,7 +234,7 @@ public class ExecuteCommand implements Consumer<DiscordChatInputInteractionEvent
discord = discordSRV.componentFactory().ansiSerializer().serialize(component);
break;
case PLAIN:
case PLAIN_BLOCK:
case CODEBLOCK:
discord = discordSRV.componentFactory().plainSerializer().serialize(component);
break;
}

View File

@ -25,15 +25,14 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.configurate.annotation.DefaultOnly;
import com.discordsrv.common.config.configurate.annotation.Order;
import com.discordsrv.common.config.configurate.fielddiscoverer.OrderedFieldDiscovererProxy;
import com.discordsrv.common.config.configurate.manager.loader.ConfigLoaderProvider;
import com.discordsrv.common.config.configurate.serializer.*;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.config.main.channels.base.ChannelConfig;
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
import com.discordsrv.common.config.configurate.manager.loader.ConfigLoaderProvider;
import com.discordsrv.common.config.configurate.serializer.ColorSerializer;
import com.discordsrv.common.config.configurate.serializer.DiscordMessageEmbedSerializer;
import com.discordsrv.common.config.configurate.serializer.PatternSerializer;
import com.discordsrv.common.config.configurate.serializer.SendableDiscordMessageSerializer;
import com.discordsrv.common.exception.ConfigException;
import com.discordsrv.common.logging.Logger;
import com.discordsrv.common.logging.NamedLogger;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.configurate.*;
import org.spongepowered.configurate.loader.AbstractConfigurationLoader;
@ -69,6 +68,7 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
};
private final Path filePath;
private final Logger logger;
private final ObjectMapper.Factory objectMapper;
private final ObjectMapper.Factory cleanObjectMapper;
private LT loader;
@ -76,11 +76,12 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
protected T configuration;
public ConfigurateConfigManager(DiscordSRV discordSRV) {
this(discordSRV.dataDirectory());
this(discordSRV.dataDirectory(), new NamedLogger(discordSRV, "CONFIG"));
}
protected ConfigurateConfigManager(Path dataDirectory) {
protected ConfigurateConfigManager(Path dataDirectory, Logger logger) {
this.filePath = dataDirectory.resolve(fileName());
this.logger = logger;
this.objectMapper = objectMapperBuilder().build();
this.cleanObjectMapper = cleanObjectMapperBuilder().build();
}
@ -133,6 +134,8 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
}
});
builder.register(BaseChannelConfig.class, getChannelConfigSerializer(objectMapper));
//noinspection unchecked
builder.register((Class<Enum<?>>) (Object) Enum.class, new EnumSerializer(logger));
builder.register(Color.class, new ColorSerializer());
builder.register(Pattern.class, new PatternSerializer());
builder.register(DiscordMessageEmbed.Builder.class, new DiscordMessageEmbedSerializer(NAMING_SCHEME));

View File

@ -50,7 +50,7 @@ public abstract class TranslatedConfigManager<T extends Config, LT extends Abstr
}
protected TranslatedConfigManager(Path dataDirectory) {
super(dataDirectory);
super(dataDirectory, null);
this.discordSRV = null;
}

View File

@ -0,0 +1,54 @@
package com.discordsrv.common.config.configurate.serializer;
import com.discordsrv.common.logging.Logger;
import io.leangen.geantyref.GenericTypeReflector;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class EnumSerializer implements TypeSerializer<Enum<?>> {
private final Logger logger;
public EnumSerializer(Logger logger) {
this.logger = logger;
}
@SuppressWarnings("unchecked") // Enum generic
@Override
public Enum<?> deserialize(Type type, ConfigurationNode node) throws SerializationException {
Class<? extends Enum<?>> theEnum = (Class<? extends Enum<?>>) GenericTypeReflector.erase(type).asSubclass(Enum.class);
String configValue = node.getString();
if (configValue == null) {
return null;
}
configValue = configValue.toLowerCase(Locale.ROOT);
List<String> values = new ArrayList<>();
for (Enum<?> constant : theEnum.getEnumConstants()) {
String lower = constant.name().toLowerCase(Locale.ROOT);
if (lower.equals(configValue)) {
return constant;
}
values.add(lower);
}
logger.error(
"Option \"" + node.key() + "\" "
+ "has invalid value: \"" + configValue + "\", "
+ "acceptable values: " + String.join(", ", values)
);
return null;
}
@Override
public void serialize(Type type, @Nullable Enum<?> obj, ConfigurationNode node) throws SerializationException {
node.raw(obj != null ? obj.name().toLowerCase(Locale.ROOT) : null);
}
}

View File

@ -7,7 +7,6 @@ import org.spongepowered.configurate.objectmapping.meta.Comment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@ConfigSerializable
public class DiscordCommandConfig {
@ -36,20 +35,9 @@ public class DiscordCommandConfig {
+ "- markdown: Regular Discord markdown\n"
+ "- ansi: A colored ansi code block\n"
+ "- plain: Plain text\n"
+ "- codeblock: Plain code block\n"
+ "- code_block: Plain code block\n"
+ "- off: No command output")
public String outputMode = "markdown";
public OutputMode getOutputMode() {
switch (outputMode.toLowerCase(Locale.ROOT)) {
default:
case "markdown": return OutputMode.MARKDOWN;
case "ansi": return OutputMode.ANSI;
case "plain": return OutputMode.PLAIN;
case "codeblock": return OutputMode.PLAIN_BLOCK;
case "off": return OutputMode.OFF;
}
}
public OutputMode outputMode = OutputMode.MARKDOWN;
@Comment("At least one condition has to match to allow execution")
public List<GameCommandFilterConfig> filters = new ArrayList<>();
@ -66,7 +54,7 @@ public class DiscordCommandConfig {
MARKDOWN,
ANSI,
PLAIN,
PLAIN_BLOCK,
CODEBLOCK,
OFF
}
}

View File

@ -42,16 +42,8 @@ public class GroupSyncConfig {
public Long roleId = 0L;
@Comment("The direction this group-role pair will synchronize in.\n"
+ "Valid options: BIDIRECTIONAL, MINECRAFT_TO_DISCORD, DISCORD_TO_MINECRAFT")
public String direction = GroupSyncDirection.BIDIRECTIONAL.name();
public GroupSyncDirection direction() {
try {
return GroupSyncDirection.valueOf(direction);
} catch (IllegalArgumentException ignored) {
return null;
}
}
+ "Valid options: bidirectional, minecraft_to_discord, discord_to_minecraft")
public GroupSyncDirection direction = GroupSyncDirection.BIDIRECTIONAL;
@Comment("Timed resynchronization.\n"
+ "This is required if you're not using LuckPerms and want to use Minecraft to Discord synchronization")
@ -68,16 +60,8 @@ public class GroupSyncConfig {
}
@Comment("Decides which side takes priority when using timed synchronization or the resync command\n"
+ "Valid options: MINECRAFT, DISCORD")
public String tieBreaker = GroupSyncSide.MINECRAFT.name();
public GroupSyncSide tieBreaker() {
try {
return GroupSyncSide.valueOf(tieBreaker);
} catch (IllegalArgumentException ignored) {
return null;
}
}
+ "Valid options: minecraft, discord")
public GroupSyncSide tieBreaker = GroupSyncSide.MINECRAFT;
@Comment("The LuckPerms \"server\" context value, used when adding, removing and checking the groups of players.\n"
+ "Make this blank (\"\") to use the current server's value, or \"global\" to not use the context")
@ -90,7 +74,7 @@ public class GroupSyncConfig {
public boolean validate(DiscordSRV discordSRV) {
String label = "Group synchronization (" + groupName + ":" + Long.toUnsignedString(roleId) + ")";
boolean invalidTieBreaker, invalidDirection = false;
if ((invalidTieBreaker = (tieBreaker() == null)) || (invalidDirection = (direction == null))) {
if ((invalidTieBreaker = (tieBreaker == null)) || (invalidDirection = (direction == null))) {
if (invalidTieBreaker) {
discordSRV.logger().error(label + " has invalid tie-breaker: " + tieBreaker
+ ", should be one of " + Arrays.toString(GroupSyncSide.values()));
@ -100,10 +84,10 @@ public class GroupSyncConfig {
+ ", should be one of " + Arrays.toString(GroupSyncDirection.values()));
}
return false;
} else if (direction() != GroupSyncDirection.BIDIRECTIONAL) {
} else if (direction != GroupSyncDirection.BIDIRECTIONAL) {
boolean minecraft;
if ((direction() == GroupSyncDirection.MINECRAFT_TO_DISCORD) != (minecraft = (tieBreaker() == GroupSyncSide.MINECRAFT))) {
String opposite = (minecraft ? GroupSyncSide.DISCORD : GroupSyncSide.MINECRAFT).name();
if ((direction == GroupSyncDirection.MINECRAFT_TO_DISCORD) != (minecraft = (tieBreaker == GroupSyncSide.MINECRAFT))) {
GroupSyncSide opposite = (minecraft ? GroupSyncSide.DISCORD : GroupSyncSide.MINECRAFT);
discordSRV.logger().warning(label + " with direction "
+ direction + " with tie-breaker "
+ tieBreaker + " (should be " + opposite + ")");
@ -116,7 +100,7 @@ public class GroupSyncConfig {
@Override
public String toString() {
String arrow;
switch (direction()) {
switch (direction) {
default:
case BIDIRECTIONAL:
arrow = "<->";

View File

@ -68,8 +68,17 @@ public class JoinMessageConfig implements IMessageConfig {
@ConfigSerializable
public static class FirstJoin implements IMessageConfig {
@Comment("How first join should behave:\n- enabled (uses the format below)\n- disabled (first join messages are disabled)\n- use_regular (uses the format above)")
public String firstJoinPreference = "enabled";
@Comment("How first join should behave:\n"
+ "- enabled (uses the format below)\n"
+ "- disabled (first join messages are disabled)\n"
+ "- use_regular (uses the format above)")
public Preference preference = Preference.ENABLED;
public enum Preference {
ENABLED,
DISABLED,
USE_REGULAR
}
@Untranslated(Untranslated.Type.VALUE)
public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder()
@ -81,12 +90,12 @@ public class JoinMessageConfig implements IMessageConfig {
);
public boolean isRegular() {
return "use_regular".equalsIgnoreCase(firstJoinPreference);
return preference == Preference.USE_REGULAR;
}
@Override
public boolean enabled() {
return "enabled".equalsIgnoreCase(firstJoinPreference);
return preference == Preference.ENABLED;
}
@Override

View File

@ -33,5 +33,11 @@ public class LinkedAccountConfig {
+ " - auto: Uses \"minecraftauth\" if the " + ConnectionConfig.FILE_NAME + " permits it and the server is in online mode, otherwise \"storage\"\n"
+ " - minecraftauth: Uses minecraftauth.me as the linked account provider\n"
+ " - storage: Use the configured database for linked accounts")
public String provider = "auto";
public Provider provider = Provider.AUTO;
public enum Provider {
AUTO,
MINECRAFTAUTH,
STORAGE
}
}

View File

@ -26,8 +26,13 @@ import org.spongepowered.configurate.objectmapping.meta.Setting;
@ConfigSerializable
public class ServerRequiredLinkingConfig extends RequiredLinkingConfig {
@Comment("How the player should be blocked from joining the server.\nAvailable options: KICK, FREEZE")
public String action = "KICK";
@Comment("How the player should be blocked from joining the server.\nAvailable options: kick, freeze")
public Action action = Action.KICK;
public enum Action {
KICK,
FREEZE
}
@Setting(nodeFromParent = true)
@Order(10)

View File

@ -149,8 +149,8 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
for (Map.Entry<GroupSyncConfig.PairConfig, Future<?>> entry : pairs.entrySet()) {
GroupSyncConfig.PairConfig pair = entry.getKey();
builder.append("\n- ").append(pair)
.append(" (tie-breaker: ").append(pair.tieBreaker())
.append(", direction: ").append(pair.direction())
.append(" (tie-breaker: ").append(pair.tieBreaker)
.append(", direction: ").append(pair.direction)
.append(", server context: ").append(pair.serverContext).append(")");
if (entry.getValue() != null) {
builder.append(" [Timed]");
@ -343,8 +343,8 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
return;
}
GroupSyncSide side = pair.tieBreaker();
GroupSyncDirection direction = pair.direction();
GroupSyncSide side = pair.tieBreaker;
GroupSyncDirection direction = pair.direction;
CompletableFuture<Void> future;
GroupSyncResult result;
if (hasRole) {
@ -473,7 +473,7 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
Map<GroupSyncConfig.PairConfig, CompletableFuture<GroupSyncResult>> futures = new LinkedHashMap<>();
for (GroupSyncConfig.PairConfig pair : pairs) {
GroupSyncDirection direction = pair.direction();
GroupSyncDirection direction = pair.direction;
if (direction == GroupSyncDirection.MINECRAFT_TO_DISCORD) {
// Not going Discord -> Minecraft
futures.put(pair, CompletableFuture.completedFuture(GroupSyncResult.WRONG_DIRECTION));
@ -543,7 +543,7 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
PermissionDataProvider.Groups permissionProvider = getPermissionProvider();
Map<GroupSyncConfig.PairConfig, CompletableFuture<GroupSyncResult>> futures = new LinkedHashMap<>();
for (GroupSyncConfig.PairConfig pair : pairs) {
GroupSyncDirection direction = pair.direction();
GroupSyncDirection direction = pair.direction;
if (direction == GroupSyncDirection.DISCORD_TO_MINECRAFT) {
// Not going Minecraft -> Discord
futures.put(pair, CompletableFuture.completedFuture(GroupSyncResult.WRONG_DIRECTION));