diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/ChannelLockingConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/ChannelLockingConfig.java index db8c8941..ea0570d8 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/ChannelLockingConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/ChannelLockingConfig.java @@ -18,6 +18,7 @@ package com.discordsrv.common.config.main.channels; +import com.discordsrv.common.config.util.ConfigUtil; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.meta.Comment; @@ -27,6 +28,10 @@ import java.util.List; @ConfigSerializable public class ChannelLockingConfig { + public ChannelLockingConfig() { + ConfigUtil.nullAllFields(this); + } + public Channels channels = new Channels(); public Threads threads = new Threads(); diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/DiscordToMinecraftChatConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/DiscordToMinecraftChatConfig.java index f20f6f75..03091bb9 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/DiscordToMinecraftChatConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/DiscordToMinecraftChatConfig.java @@ -18,6 +18,7 @@ package com.discordsrv.common.config.main.channels; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.DiscordIgnoresConfig; import com.discordsrv.common.config.main.generic.MentionsConfig; @@ -31,11 +32,18 @@ import java.util.regex.Pattern; @ConfigSerializable public class DiscordToMinecraftChatConfig { + public DiscordToMinecraftChatConfig() { + ConfigUtil.nullAllFields(this); + } + @Comment("Requires the \"Message Content Intent\"") - public boolean enabled = true; + public Boolean enabled = true; @Comment("The Discord to Minecraft message format for regular users and bots") - public String format = "[[color:#5865F2]Discord[color]] [hover:show_text:Username: @%user_tag% [italics:on][color:gray](Shift+Click to mention)[color][italics:off]\nRoles: %user_roles:', '|text:'[color:gray][italics:on]None[color][italics]'%][insert:@%user_tag%]%user_color%%user_effective_server_name%[color][hover]%message_reply% » %message%%message_attachments%"; + public String format = "[[color:#5865F2]Discord[color]] " + + "[hover:show_text:Username: @%user_tag% [italics:on][color:gray](Shift+Click to mention)[color][italics:off]\nRoles: %user_roles:', '|text:'[color:gray][italics:on]None[color][italics]'%]" + + "[insert:@%user_tag%]%user_color%%user_effective_server_name%[color][insert]" + + "[hover]%message_reply% » %message%%message_attachments%"; @Comment("The Discord to Minecraft message format for webhook messages (if enabled)") public String webhookFormat = "[[color:#5865F2]Discord[color]] [hover:show_text:Bot message]%user_effective_name%[hover] » %message%%message_attachments%"; @@ -74,6 +82,6 @@ public class DiscordToMinecraftChatConfig { @Comment("The amount of milliseconds to delay processing Discord messages, if the message is deleted in that time it will not be processed.\n" + "This can be used together with Discord moderation bots, to filter forwarded messages") - public long delayMillis = 0L; + public Long delayMillis = 0L; } diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/JoinMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/JoinMessageConfig.java index c25f611d..1fffbd25 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/JoinMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/JoinMessageConfig.java @@ -21,6 +21,7 @@ package com.discordsrv.common.config.main.channels; import com.discordsrv.api.discord.entity.message.DiscordMessageEmbed; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; import com.discordsrv.api.event.events.message.receive.game.JoinMessageReceiveEvent; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Constants; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; @@ -31,7 +32,11 @@ import org.spongepowered.configurate.objectmapping.meta.Comment; @ConfigSerializable public class JoinMessageConfig implements IMessageConfig { - public boolean enabled = true; + public JoinMessageConfig() { + ConfigUtil.nullAllFields(this); + } + + public Boolean enabled = true; @Untranslated(Untranslated.Type.VALUE) public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder() @@ -44,10 +49,10 @@ public class JoinMessageConfig implements IMessageConfig { @Comment("If the \"%1\" permission should determine if join messages are sent") @Constants.Comment("discordsrv.silentjoin") - public boolean enableSilentPermission = true; + public Boolean enableSilentPermission = true; @Comment("Ignore if the player leaves within the given amount of milliseconds. This will delay sending the join message") - public long ignoreIfLeftWithinMS = 250; + public Long ignoreIfLeftWithinMS = 250L; @Override public boolean enabled() { diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/LeaveMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/LeaveMessageConfig.java index e5371d79..839c7024 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/LeaveMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/LeaveMessageConfig.java @@ -20,6 +20,7 @@ package com.discordsrv.common.config.main.channels; import com.discordsrv.api.discord.entity.message.DiscordMessageEmbed; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Constants; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; @@ -29,7 +30,11 @@ import org.spongepowered.configurate.objectmapping.meta.Comment; @ConfigSerializable public class LeaveMessageConfig implements IMessageConfig { - public boolean enabled = true; + public LeaveMessageConfig() { + ConfigUtil.nullAllFields(this); + } + + public Boolean enabled = true; @Untranslated(Untranslated.Type.VALUE) public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder() @@ -42,10 +47,10 @@ public class LeaveMessageConfig implements IMessageConfig { @Comment("If the \"%1\" permission should determine if leave messages are sent") @Constants.Comment("discordsrv.silentquit") - public boolean enableSilentPermission = true; + public Boolean enableSilentPermission = true; @Comment("Ignore if the player joined within the given amount of milliseconds") - public long ignoreIfJoinedWithinMS = 250; + public Long ignoreIfJoinedWithinMS = 250L; @Override public boolean enabled() { diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/MinecraftToDiscordChatConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/MinecraftToDiscordChatConfig.java index 607e28ed..a51241ad 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/MinecraftToDiscordChatConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/MinecraftToDiscordChatConfig.java @@ -19,6 +19,7 @@ package com.discordsrv.common.config.main.channels; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.DefaultOnly; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; @@ -32,7 +33,11 @@ import java.util.regex.Pattern; @ConfigSerializable public class MinecraftToDiscordChatConfig implements IMessageConfig { - public boolean enabled = true; + public MinecraftToDiscordChatConfig() { + ConfigUtil.nullAllFields(this); + } + + public Boolean enabled = true; @Untranslated(Untranslated.Type.VALUE) @DefaultOnly diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/MirroringConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/MirroringConfig.java index cfafea3b..7780a4e6 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/MirroringConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/MirroringConfig.java @@ -18,6 +18,7 @@ package com.discordsrv.common.config.main.channels; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.main.generic.DiscordIgnoresConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.meta.Comment; @@ -25,8 +26,12 @@ import org.spongepowered.configurate.objectmapping.meta.Comment; @ConfigSerializable public class MirroringConfig { + public MirroringConfig() { + ConfigUtil.nullAllFields(this); + } + @Comment("Requires the \"Message Content Intent\"") - public boolean enabled = true; + public Boolean enabled = true; @Comment("Users, bots, roles and webhooks to ignore when mirroring") public DiscordIgnoresConfig ignores = new DiscordIgnoresConfig(); diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/StartMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/StartMessageConfig.java index 88bf4076..a96c3534 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/StartMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/StartMessageConfig.java @@ -19,6 +19,7 @@ package com.discordsrv.common.config.main.channels; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -26,7 +27,11 @@ import org.spongepowered.configurate.objectmapping.ConfigSerializable; @ConfigSerializable public class StartMessageConfig implements IMessageConfig { - public boolean enabled = true; + public StartMessageConfig() { + ConfigUtil.nullAllFields(this); + } + + public Boolean enabled = true; @Untranslated(Untranslated.Type.VALUE) public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder() diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/StopMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/StopMessageConfig.java index dfbb07f5..d82be4ac 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/StopMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/StopMessageConfig.java @@ -19,6 +19,7 @@ package com.discordsrv.common.config.main.channels; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -26,7 +27,11 @@ import org.spongepowered.configurate.objectmapping.ConfigSerializable; @ConfigSerializable public class StopMessageConfig implements IMessageConfig { - public boolean enabled = true; + public StopMessageConfig() { + ConfigUtil.nullAllFields(this); + } + + public Boolean enabled = true; @Untranslated(Untranslated.Type.VALUE) public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder() diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/base/ChannelConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/base/ChannelConfig.java index 0dd596de..629a486a 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/base/ChannelConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/base/ChannelConfig.java @@ -18,6 +18,7 @@ package com.discordsrv.common.config.main.channels.base; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.main.generic.DestinationConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.meta.Setting; @@ -26,7 +27,7 @@ import org.spongepowered.configurate.objectmapping.meta.Setting; public class ChannelConfig extends BaseChannelConfig implements IChannelConfig { public ChannelConfig() { - initialize(); + ConfigUtil.nullAllFields(this); } @Setting(nodeFromParent = true) diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/base/IChannelConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/base/IChannelConfig.java index bce153a9..da85cd06 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/base/IChannelConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/base/IChannelConfig.java @@ -25,8 +25,6 @@ import org.spongepowered.configurate.objectmapping.ObjectMapper; import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.serialize.TypeSerializer; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.lang.reflect.Type; public interface IChannelConfig { @@ -35,24 +33,6 @@ public interface IChannelConfig { DestinationConfig destination(); - default void initialize() { - // Clear everything besides channelIds by default (these will be filled back in by Configurate if they are in the config itself) - Class clazz = getClass(); - while (clazz != null) { - for (Field field : clazz.getFields()) { - int modifiers = field.getModifiers(); - if (!Modifier.isPublic(modifiers) || Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) { - continue; - } - - try { - field.set(this, null); - } catch (IllegalAccessException ignored) {} - } - clazz = clazz.getSuperclass(); - } - } - class Serializer implements TypeSerializer { private final ObjectMapper.Factory mapperFactory; diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/base/proxy/ProxyChannelConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/base/proxy/ProxyChannelConfig.java index a5bef9e0..3448b745 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/base/proxy/ProxyChannelConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/base/proxy/ProxyChannelConfig.java @@ -18,6 +18,7 @@ package com.discordsrv.common.config.main.channels.base.proxy; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.main.channels.base.IChannelConfig; import com.discordsrv.common.config.main.generic.DestinationConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -27,7 +28,7 @@ import org.spongepowered.configurate.objectmapping.meta.Setting; public class ProxyChannelConfig extends ProxyBaseChannelConfig implements IChannelConfig { public ProxyChannelConfig() { - initialize(); + ConfigUtil.nullAllFields(this); } @Setting(nodeFromParent = true) diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/base/server/ServerChannelConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/base/server/ServerChannelConfig.java index 4ea77703..e0f253e8 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/base/server/ServerChannelConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/base/server/ServerChannelConfig.java @@ -18,6 +18,7 @@ package com.discordsrv.common.config.main.channels.base.server; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.main.channels.base.IChannelConfig; import com.discordsrv.common.config.main.generic.DestinationConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -27,7 +28,7 @@ import org.spongepowered.configurate.objectmapping.meta.Setting; public class ServerChannelConfig extends ServerBaseChannelConfig implements IChannelConfig { public ServerChannelConfig() { - initialize(); + ConfigUtil.nullAllFields(this); } @Setting(nodeFromParent = true) diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/proxy/ServerSwitchMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/proxy/ServerSwitchMessageConfig.java index 2281b0d8..d4016c6d 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/proxy/ServerSwitchMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/proxy/ServerSwitchMessageConfig.java @@ -20,6 +20,7 @@ package com.discordsrv.common.config.main.channels.proxy; import com.discordsrv.api.discord.entity.message.DiscordMessageEmbed; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -27,7 +28,11 @@ import org.spongepowered.configurate.objectmapping.ConfigSerializable; @ConfigSerializable public class ServerSwitchMessageConfig implements IMessageConfig { - public boolean enabled = false; + public ServerSwitchMessageConfig() { + ConfigUtil.nullAllFields(true); + } + + public Boolean enabled = false; @Untranslated(Untranslated.Type.VALUE) public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder() diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/server/AwardMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/server/AwardMessageConfig.java index ce5b6bc1..ebf3ba9b 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/server/AwardMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/server/AwardMessageConfig.java @@ -20,6 +20,7 @@ package com.discordsrv.common.config.main.channels.server; import com.discordsrv.api.discord.entity.message.DiscordMessageEmbed; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -27,7 +28,11 @@ import org.spongepowered.configurate.objectmapping.ConfigSerializable; @ConfigSerializable public class AwardMessageConfig implements IMessageConfig { - public boolean enabled = true; + public AwardMessageConfig() { + ConfigUtil.nullAllFields(this); + } + + public Boolean enabled = true; @Untranslated(Untranslated.Type.VALUE) public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder() diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/server/DeathMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/server/DeathMessageConfig.java index a8863407..724346ba 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/server/DeathMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/server/DeathMessageConfig.java @@ -20,6 +20,7 @@ package com.discordsrv.common.config.main.channels.server; import com.discordsrv.api.discord.entity.message.DiscordMessageEmbed; import com.discordsrv.api.discord.entity.message.SendableDiscordMessage; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Untranslated; import com.discordsrv.common.config.main.generic.IMessageConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @@ -27,7 +28,11 @@ import org.spongepowered.configurate.objectmapping.ConfigSerializable; @ConfigSerializable public class DeathMessageConfig implements IMessageConfig { - public boolean enabled = true; + public DeathMessageConfig() { + ConfigUtil.nullAllFields(this); + } + + public Boolean enabled = true; @Untranslated(Untranslated.Type.VALUE) public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder() diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/server/ServerJoinMessageConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/server/ServerJoinMessageConfig.java index f1aea093..e7cb1b75 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/server/ServerJoinMessageConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/server/ServerJoinMessageConfig.java @@ -18,12 +18,17 @@ package com.discordsrv.common.config.main.channels.server; +import com.discordsrv.common.config.util.ConfigUtil; import com.discordsrv.common.config.configurate.annotation.Order; import com.discordsrv.common.config.main.channels.JoinMessageConfig; import org.jetbrains.annotations.Nullable; public class ServerJoinMessageConfig extends JoinMessageConfig { + public ServerJoinMessageConfig() { + ConfigUtil.nullAllFields(this); + } + @Order(10) public FirstJoin firstJoin = new FirstJoin(); diff --git a/common/src/main/java/com/discordsrv/common/config/util/ConfigUtil.java b/common/src/main/java/com/discordsrv/common/config/util/ConfigUtil.java new file mode 100644 index 00000000..27c877a8 --- /dev/null +++ b/common/src/main/java/com/discordsrv/common/config/util/ConfigUtil.java @@ -0,0 +1,48 @@ +/* + * This file is part of DiscordSRV, licensed under the GPLv3 License + * Copyright (c) 2016-2024 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.discordsrv.common.config.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public final class ConfigUtil { + + private ConfigUtil() {} + + public static void nullAllFields(Object object) { + Class clazz = object.getClass(); + while (clazz != null) { + for (Field field : clazz.getFields()) { + if (field.getType().isPrimitive()) { + continue; + } + + int modifiers = field.getModifiers(); + if (!Modifier.isPublic(modifiers) || Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) { + continue; + } + + try { + field.set(object, null); + } catch (IllegalAccessException ignored) {} + } + clazz = clazz.getSuperclass(); + } + } +} diff --git a/common/src/main/java/com/discordsrv/common/destination/DestinationLookupHelper.java b/common/src/main/java/com/discordsrv/common/destination/DestinationLookupHelper.java index eb72bb53..8add7ca6 100644 --- a/common/src/main/java/com/discordsrv/common/destination/DestinationLookupHelper.java +++ b/common/src/main/java/com/discordsrv/common/destination/DestinationLookupHelper.java @@ -181,11 +181,18 @@ public class DestinationLookupHelper { boolean forum = threadContainer instanceof DiscordForumChannel; boolean privateThread = !forum && threadConfig.privateThread; + Permission createPermission; + if (forum) { + createPermission = Permission.MESSAGE_SEND; + } else { + createPermission = privateThread ? Permission.CREATE_PRIVATE_THREADS : Permission.CREATE_PUBLIC_THREADS; + } + IThreadContainer container = threadContainer.getAsJDAThreadContainer(); String missingPermissions = DiscordPermissionUtil.missingPermissionsString( container, Permission.VIEW_CHANNEL, - privateThread ? Permission.CREATE_PRIVATE_THREADS : Permission.CREATE_PUBLIC_THREADS + createPermission ); if (missingPermissions != null) { if (logFailures) {