mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-10-31 08:32:18 +01:00
Package reorganizing, and other minor changes
This commit is contained in:
parent
694a6191cd
commit
6c2c0c5134
@ -188,6 +188,9 @@ public interface SendableDiscordMessage {
|
||||
@NotNull
|
||||
Builder setWebhookAvatarUrl(String webhookAvatarUrl);
|
||||
|
||||
@NotNull
|
||||
Builder convertToNonWebhook();
|
||||
|
||||
/**
|
||||
* Builds a {@link SendableDiscordMessage} from this builder.
|
||||
* @return the new {@link SendableDiscordMessage}
|
||||
@ -252,6 +255,9 @@ public interface SendableDiscordMessage {
|
||||
@NotNull
|
||||
Formatter applyPlaceholderService();
|
||||
|
||||
@NotNull
|
||||
Formatter convertToNonWebhook();
|
||||
|
||||
@NotNull
|
||||
SendableDiscordMessage build();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public final class DiscordFormattingUtil {
|
||||
private DiscordFormattingUtil() {}
|
||||
|
||||
public static String escapeContent(String content) {
|
||||
content = escapeChars(content, '*', '_', '|', '`', '~');
|
||||
content = escapeChars(content, '*', '_', '|', '`', '~', ':');
|
||||
content = escapeQuote(content);
|
||||
content = escapeMentions(content);
|
||||
return content;
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.discordsrv.api.discord.events;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
|
||||
public class DiscordMessageReceiveEvent extends AbstractDiscordMessageEvent {
|
||||
|
||||
private final ReceivedDiscordMessage message;
|
||||
|
||||
public DiscordMessageReceiveEvent(DiscordMessageChannel channel, ReceivedDiscordMessage message) {
|
||||
super(channel);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ReceivedDiscordMessage getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.discordsrv.api.event.events.message.forward.game;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
|
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.discordsrv.api.event.events.message.receive.game;
|
||||
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
|
@ -22,7 +22,6 @@ import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
|
||||
import org.bukkit.event.Event;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@ -43,7 +42,7 @@ public final class PaperComponentUtil {
|
||||
|
||||
private PaperComponentUtil() {}
|
||||
|
||||
public static <T extends Event> MinecraftComponent getComponent(
|
||||
public static <T> MinecraftComponent getComponent(
|
||||
DiscordSRV discordSRV, T source, String methodName, Function<T, String> legacy) {
|
||||
if (!IS_PAPER_ADVENTURE) {
|
||||
return getLegacy(legacy.apply(source));
|
||||
|
@ -19,6 +19,7 @@
|
||||
package com.discordsrv.bukkit.player;
|
||||
|
||||
import com.discordsrv.bukkit.BukkitDiscordSRV;
|
||||
import com.discordsrv.bukkit.component.util.PaperComponentUtil;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.player.IPlayer;
|
||||
@ -29,21 +30,9 @@ import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@SuppressWarnings("NullableProblems") // BukkitOfflinePlayer nullability
|
||||
public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
|
||||
|
||||
private static final Method DISPLAY_NAME_METHOD; // Paper 1.16+
|
||||
|
||||
static {
|
||||
Method displayNameMethod = null;
|
||||
try {
|
||||
displayNameMethod = Player.class.getMethod("displayName");
|
||||
} catch (Throwable ignored) {}
|
||||
DISPLAY_NAME_METHOD = displayNameMethod;
|
||||
}
|
||||
|
||||
private final Player player;
|
||||
private final Audience audience;
|
||||
|
||||
@ -83,13 +72,8 @@ public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
|
||||
@SuppressWarnings("deprecation") // Paper
|
||||
@Override
|
||||
public @NotNull Component displayName() {
|
||||
if (DISPLAY_NAME_METHOD != null) {
|
||||
try {
|
||||
return ComponentUtil.fromUnrelocated(DISPLAY_NAME_METHOD.invoke(player));
|
||||
} catch (Throwable ignored) {}
|
||||
}
|
||||
|
||||
// Use the legacy method
|
||||
return BukkitComponentSerializer.legacy().deserialize(player.getDisplayName());
|
||||
return ComponentUtil.fromAPI(
|
||||
PaperComponentUtil.getComponent(discordSRV, player, "displayName", Player::getDisplayName)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.proxy.config.channels;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
|
||||
|
@ -1,22 +1,53 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.proxy.config.channels.base;
|
||||
|
||||
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.ThreadConfig;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Setting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ConfigSerializable
|
||||
public class ProxyChannelConfig extends ProxyBaseChannelConfig implements IChannelConfig {
|
||||
|
||||
public ProxyChannelConfig() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Setting(CHANNEL_IDS_OPTION_NAME)
|
||||
@Comment(CHANNEL_IDS_COMMENT)
|
||||
public List<Long> channelIds = new ArrayList<>();
|
||||
public List<Long> channelIds = CHANNEL_IDS_VALUE;
|
||||
|
||||
@Override
|
||||
public List<Long> ids() {
|
||||
public List<Long> channelIds() {
|
||||
return channelIds;
|
||||
}
|
||||
|
||||
@Setting(THREADS_OPTION_NAME)
|
||||
@Comment(THREADS_COMMENT)
|
||||
public List<ThreadConfig> threads = THREADS_VALUE;
|
||||
|
||||
@Override
|
||||
public List<ThreadConfig> threads() {
|
||||
return threads;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,26 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.proxy.config.manager;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.MainConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.ChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
|
||||
import com.discordsrv.common.config.manager.MainConfigManager;
|
||||
import com.discordsrv.proxy.config.channels.base.ProxyBaseChannelConfig;
|
||||
import com.discordsrv.proxy.config.channels.base.ProxyChannelConfig;
|
||||
@ -15,7 +33,7 @@ public abstract class ProxyConfigManager<T extends MainConfig> extends MainConfi
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelConfig.Serializer getChannelConfigSerializer(ObjectMapper.Factory mapperFactory) {
|
||||
return new ChannelConfig.Serializer(mapperFactory, ProxyBaseChannelConfig.class, ProxyChannelConfig.class);
|
||||
public IChannelConfig.Serializer getChannelConfigSerializer(ObjectMapper.Factory mapperFactory) {
|
||||
return new IChannelConfig.Serializer(mapperFactory, ProxyBaseChannelConfig.class, ProxyChannelConfig.class);
|
||||
}
|
||||
}
|
||||
|
@ -1 +1,19 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.proxy.config;
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.proxy.modules;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
@ -9,7 +27,7 @@ import com.discordsrv.api.event.events.message.receive.game.ServerSwitchMessageR
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import com.discordsrv.common.module.modules.message.AbstractGameMessageModule;
|
||||
import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule;
|
||||
import com.discordsrv.proxy.config.channels.ServerSwitchMessageConfig;
|
||||
import com.discordsrv.proxy.config.channels.base.ProxyBaseChannelConfig;
|
||||
|
||||
|
@ -19,10 +19,11 @@
|
||||
package com.discordsrv.common.server.config.channels.base;
|
||||
|
||||
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.ThreadConfig;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Setting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ConfigSerializable
|
||||
@ -32,11 +33,21 @@ public class ServerChannelConfig extends ServerBaseChannelConfig implements ICha
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Setting(CHANNEL_IDS_OPTION_NAME)
|
||||
@Comment(CHANNEL_IDS_COMMENT)
|
||||
public List<Long> channelIds = new ArrayList<>();
|
||||
public List<Long> channelIds = CHANNEL_IDS_VALUE;
|
||||
|
||||
@Override
|
||||
public List<Long> ids() {
|
||||
public List<Long> channelIds() {
|
||||
return channelIds;
|
||||
}
|
||||
|
||||
@Setting(THREADS_OPTION_NAME)
|
||||
@Comment(THREADS_COMMENT)
|
||||
public List<ThreadConfig> threads = THREADS_VALUE;
|
||||
|
||||
@Override
|
||||
public List<ThreadConfig> threads() {
|
||||
return threads;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ package com.discordsrv.common.server.config.manager;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.MainConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.ChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
|
||||
import com.discordsrv.common.config.manager.MainConfigManager;
|
||||
import com.discordsrv.common.server.config.channels.base.ServerBaseChannelConfig;
|
||||
import com.discordsrv.common.server.config.channels.base.ServerChannelConfig;
|
||||
@ -33,7 +33,7 @@ public abstract class ServerConfigManager<T extends MainConfig> extends MainConf
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelConfig.Serializer getChannelConfigSerializer(ObjectMapper.Factory mapperFactory) {
|
||||
return new ChannelConfig.Serializer(mapperFactory, ServerBaseChannelConfig.class, ServerChannelConfig.class);
|
||||
public IChannelConfig.Serializer getChannelConfigSerializer(ObjectMapper.Factory mapperFactory) {
|
||||
return new IChannelConfig.Serializer(mapperFactory, ServerBaseChannelConfig.class, ServerChannelConfig.class);
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
|
||||
import com.discordsrv.common.server.config.channels.DeathMessageConfig;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import com.discordsrv.common.module.modules.message.AbstractGameMessageModule;
|
||||
import com.discordsrv.common.messageforwarding.game.AbstractGameMessageModule;
|
||||
import com.discordsrv.common.server.config.channels.base.ServerBaseChannelConfig;
|
||||
|
||||
public class DeathMessageModule extends AbstractGameMessageModule<DeathMessageConfig> {
|
||||
|
@ -22,8 +22,11 @@ import com.discordsrv.api.discord.connection.DiscordConnectionDetails;
|
||||
import com.discordsrv.api.event.bus.EventBus;
|
||||
import com.discordsrv.api.event.events.lifecycle.DiscordSRVReloadEvent;
|
||||
import com.discordsrv.api.event.events.lifecycle.DiscordSRVShuttingDownEvent;
|
||||
import com.discordsrv.common.discord.api.DiscordAPIEventModule;
|
||||
import com.discordsrv.common.api.util.ApiInstanceUtil;
|
||||
import com.discordsrv.common.channel.ChannelConfigHelper;
|
||||
import com.discordsrv.common.channel.ChannelUpdaterModule;
|
||||
import com.discordsrv.common.channel.GlobalChannelLookupModule;
|
||||
import com.discordsrv.common.component.ComponentFactory;
|
||||
import com.discordsrv.common.config.connection.ConnectionConfig;
|
||||
import com.discordsrv.common.config.main.MainConfig;
|
||||
@ -35,22 +38,21 @@ import com.discordsrv.common.discord.connection.jda.JDAConnectionManager;
|
||||
import com.discordsrv.common.discord.details.DiscordConnectionDetailsImpl;
|
||||
import com.discordsrv.common.event.bus.EventBusImpl;
|
||||
import com.discordsrv.common.function.CheckedRunnable;
|
||||
import com.discordsrv.common.integration.LuckPermsIntegration;
|
||||
import com.discordsrv.common.logging.adapter.DependencyLoggerAdapter;
|
||||
import com.discordsrv.common.logging.dependency.DependencyLoggingHandler;
|
||||
import com.discordsrv.common.module.modules.message.JoinMessageModule;
|
||||
import com.discordsrv.common.module.modules.message.LeaveMessageModule;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
import com.discordsrv.common.module.type.Module;
|
||||
import com.discordsrv.common.messageforwarding.discord.DiscordChatMessageModule;
|
||||
import com.discordsrv.common.messageforwarding.discord.DiscordMessageMirroringModule;
|
||||
import com.discordsrv.common.messageforwarding.game.JoinMessageModule;
|
||||
import com.discordsrv.common.messageforwarding.game.LeaveMessageModule;
|
||||
import com.discordsrv.common.messageforwarding.game.MinecraftToDiscordChatModule;
|
||||
import com.discordsrv.common.module.ModuleInitializationFunction;
|
||||
import com.discordsrv.common.module.ModuleManager;
|
||||
import com.discordsrv.common.module.modules.DiscordAPIEventModule;
|
||||
import com.discordsrv.common.module.modules.message.DiscordToMinecraftChatModule;
|
||||
import com.discordsrv.common.module.modules.GlobalChannelLookupModule;
|
||||
import com.discordsrv.common.module.modules.message.MinecraftToDiscordChatModule;
|
||||
import com.discordsrv.common.module.modules.integration.LuckPermsIntegration;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
import com.discordsrv.common.module.type.Module;
|
||||
import com.discordsrv.common.placeholder.ComponentResultStringifier;
|
||||
import com.discordsrv.common.placeholder.PlaceholderServiceImpl;
|
||||
import com.discordsrv.common.placeholder.context.GlobalTextHandlingContext;
|
||||
import com.discordsrv.common.logging.adapter.DependencyLoggerAdapter;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -269,14 +271,19 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
|
||||
// Register modules
|
||||
moduleManager = new ModuleManager(this);
|
||||
for (ModuleInitializationFunction function : new ModuleInitializationFunction[]{
|
||||
ChannelUpdaterModule::new,
|
||||
GlobalChannelLookupModule::new,
|
||||
|
||||
DiscordAPIEventModule::new,
|
||||
|
||||
LuckPermsIntegration::new,
|
||||
|
||||
DiscordToMinecraftChatModule::new,
|
||||
DiscordChatMessageModule::new,
|
||||
DiscordMessageMirroringModule::new,
|
||||
|
||||
JoinMessageModule::new,
|
||||
LeaveMessageModule::new,
|
||||
MinecraftToDiscordChatModule::new,
|
||||
DiscordAPIEventModule::new,
|
||||
GlobalChannelLookupModule::new
|
||||
}) {
|
||||
try {
|
||||
registerModule(function.initialize(this));
|
||||
|
@ -19,7 +19,9 @@
|
||||
package com.discordsrv.common.channel;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordThreadChannel;
|
||||
import com.discordsrv.api.event.bus.Subscribe;
|
||||
import com.discordsrv.api.event.events.channel.GameChannelLookupEvent;
|
||||
import com.discordsrv.api.event.events.lifecycle.DiscordSRVReloadEvent;
|
||||
@ -27,9 +29,11 @@ import com.discordsrv.common.DiscordSRV;
|
||||
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.main.channels.base.ThreadConfig;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
@ -41,7 +45,8 @@ public class ChannelConfigHelper {
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final LoadingCache<String, GameChannel> nameToChannelCache;
|
||||
private final Map<Long, Map<String, BaseChannelConfig>> discordToConfigMap;
|
||||
private final Map<Long, Map<String, BaseChannelConfig>> textChannelToConfigMap;
|
||||
private final LoadingCache<Pair<Long, String>, Map<String, BaseChannelConfig>> threadToConfigCache;
|
||||
|
||||
public ChannelConfigHelper(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
@ -62,7 +67,33 @@ public class ChannelConfigHelper {
|
||||
return event.getChannelFromProcessing();
|
||||
}
|
||||
});
|
||||
this.discordToConfigMap = new ConcurrentHashMap<>();
|
||||
this.textChannelToConfigMap = new ConcurrentHashMap<>();
|
||||
this.threadToConfigCache = discordSRV.caffeineBuilder()
|
||||
.expireAfterWrite(60, TimeUnit.SECONDS)
|
||||
.expireAfterAccess(30, TimeUnit.SECONDS)
|
||||
.refreshAfterWrite(10, TimeUnit.SECONDS)
|
||||
.build(key -> {
|
||||
Map<String, BaseChannelConfig> map = new HashMap<>();
|
||||
for (Map.Entry<String, BaseChannelConfig> entry : channels().entrySet()) {
|
||||
String channelName = entry.getKey();
|
||||
BaseChannelConfig value = entry.getValue();
|
||||
if (value instanceof IChannelConfig) {
|
||||
IChannelConfig channelConfig = (IChannelConfig) value;
|
||||
List<ThreadConfig> threads = channelConfig.threads();
|
||||
if (threads == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (ThreadConfig thread : threads) {
|
||||
if (Objects.equals(thread.channelId, key.getKey())
|
||||
&& Objects.equals(thread.threadName, key.getValue())) {
|
||||
map.put(channelName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
});
|
||||
|
||||
discordSRV.eventBus().subscribe(this);
|
||||
}
|
||||
@ -79,16 +110,21 @@ public class ChannelConfigHelper {
|
||||
BaseChannelConfig value = entry.getValue();
|
||||
if (value instanceof IChannelConfig) {
|
||||
IChannelConfig channelConfig = (IChannelConfig) value;
|
||||
for (long channelId : channelConfig.ids()) {
|
||||
List<Long> channelIds = channelConfig.channelIds();
|
||||
if (channelIds == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (long channelId : channelIds) {
|
||||
newMap.computeIfAbsent(channelId, key -> new LinkedHashMap<>())
|
||||
.put(channelName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (discordToConfigMap) {
|
||||
discordToConfigMap.clear();
|
||||
discordToConfigMap.putAll(newMap);
|
||||
synchronized (textChannelToConfigMap) {
|
||||
textChannelToConfigMap.clear();
|
||||
textChannelToConfigMap.putAll(newMap);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,11 +185,11 @@ public class ChannelConfigHelper {
|
||||
return gameChannel != null ? get(gameChannel) : null;
|
||||
}
|
||||
|
||||
public Map<GameChannel, OrDefault<BaseChannelConfig>> orDefault(DiscordTextChannel discordTextChannel) {
|
||||
public Map<GameChannel, OrDefault<BaseChannelConfig>> orDefault(DiscordMessageChannel messageChannel) {
|
||||
BaseChannelConfig defaultConfig = getDefault();
|
||||
|
||||
Map<GameChannel, OrDefault<BaseChannelConfig>> channels = new HashMap<>();
|
||||
for (Map.Entry<GameChannel, BaseChannelConfig> entry : getDiscordResolved(discordTextChannel).entrySet()) {
|
||||
for (Map.Entry<GameChannel, BaseChannelConfig> entry : getDiscordResolved(messageChannel).entrySet()) {
|
||||
channels.put(
|
||||
entry.getKey(),
|
||||
new OrDefault<>(entry.getValue(), defaultConfig)
|
||||
@ -162,9 +198,14 @@ public class ChannelConfigHelper {
|
||||
return channels;
|
||||
}
|
||||
|
||||
public Map<GameChannel, BaseChannelConfig> getDiscordResolved(DiscordTextChannel channel) {
|
||||
Map<String, BaseChannelConfig> pairs = getDiscord(channel);
|
||||
if (pairs == null) {
|
||||
public Map<GameChannel, BaseChannelConfig> getDiscordResolved(DiscordMessageChannel channel) {
|
||||
Map<String, BaseChannelConfig> pairs = null;
|
||||
if (channel instanceof DiscordTextChannel) {
|
||||
pairs = getText((DiscordTextChannel) channel);
|
||||
} else if (channel instanceof DiscordThreadChannel) {
|
||||
pairs = getThread((DiscordThreadChannel) channel);
|
||||
}
|
||||
if (pairs == null || pairs.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@ -181,9 +222,11 @@ public class ChannelConfigHelper {
|
||||
return channels;
|
||||
}
|
||||
|
||||
public Map<String, BaseChannelConfig> getDiscord(DiscordTextChannel channel) {
|
||||
synchronized (discordToConfigMap) {
|
||||
return discordToConfigMap.get(channel.getId());
|
||||
}
|
||||
public Map<String, BaseChannelConfig> getText(DiscordTextChannel channel) {
|
||||
return textChannelToConfigMap.get(channel.getId());
|
||||
}
|
||||
|
||||
public Map<String, BaseChannelConfig> getThread(DiscordThreadChannel channel) {
|
||||
return threadToConfigCache.get(Pair.of(channel.getParentChannel().getId(), channel.getName()));
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.module.modules;
|
||||
package com.discordsrv.common.channel;
|
||||
|
||||
import com.discordsrv.api.event.bus.EventPriority;
|
||||
import com.discordsrv.api.event.bus.Subscribe;
|
||||
import com.discordsrv.api.event.events.channel.GameChannelLookupEvent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.channel.DefaultGlobalChannel;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
|
||||
public class GlobalChannelLookupModule extends AbstractModule {
|
@ -29,7 +29,6 @@ import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.config.main.channels.DiscordToMinecraftChatConfig;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import dev.vankka.mcdiscordreserializer.renderer.implementation.DefaultMinecraftRenderer;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.entities.GuildChannel;
|
||||
import net.dv8tion.jda.api.utils.MiscUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -62,14 +61,15 @@ public class DiscordSRVMinecraftRenderer extends DefaultMinecraftRenderer {
|
||||
OrDefault<DiscordToMinecraftChatConfig> config,
|
||||
Supplier<T> supplier
|
||||
) {
|
||||
Context oldValue = CONTEXT.get();
|
||||
CONTEXT.set(new Context(event, config));
|
||||
T output = supplier.get();
|
||||
CONTEXT.remove();
|
||||
CONTEXT.set(oldValue);
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component appendChannelMention(@NonNull Component component, @NonNull String id) {
|
||||
public @NotNull Component appendChannelMention(@NotNull Component component, @NotNull String id) {
|
||||
Context context = CONTEXT.get();
|
||||
DiscordToMinecraftChatConfig.Mentions.Format format =
|
||||
context != null ? context.config.map(cfg -> cfg.mentions).get(cfg -> cfg.channel) : null;
|
||||
@ -91,7 +91,7 @@ public class DiscordSRVMinecraftRenderer extends DefaultMinecraftRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component appendUserMention(@NonNull Component component, @NonNull String id) {
|
||||
public @NotNull Component appendUserMention(@NotNull Component component, @NotNull String id) {
|
||||
Context context = CONTEXT.get();
|
||||
DiscordToMinecraftChatConfig.Mentions.Format format =
|
||||
context != null ? context.config.map(cfg -> cfg.mentions).get(cfg -> cfg.user) : null;
|
||||
@ -124,7 +124,7 @@ public class DiscordSRVMinecraftRenderer extends DefaultMinecraftRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component appendRoleMention(@NonNull Component component, @NonNull String id) {
|
||||
public @NotNull Component appendRoleMention(@NotNull Component component, @NotNull String id) {
|
||||
Context context = CONTEXT.get();
|
||||
DiscordToMinecraftChatConfig.Mentions.Format format =
|
||||
context != null ? context.config.map(cfg -> cfg.mentions).get(cfg -> cfg.role) : null;
|
||||
|
@ -20,11 +20,9 @@ package com.discordsrv.common.config.main.channels.base;
|
||||
|
||||
import com.discordsrv.common.config.annotation.Order;
|
||||
import com.discordsrv.common.config.annotation.Untranslated;
|
||||
import com.discordsrv.common.config.main.channels.DiscordToMinecraftChatConfig;
|
||||
import com.discordsrv.common.config.main.channels.JoinMessageConfig;
|
||||
import com.discordsrv.common.config.main.channels.LeaveMessageConfig;
|
||||
import com.discordsrv.common.config.main.channels.MinecraftToDiscordChatConfig;
|
||||
import com.discordsrv.common.config.main.channels.*;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
|
||||
@ConfigSerializable
|
||||
public class BaseChannelConfig {
|
||||
@ -34,7 +32,11 @@ public class BaseChannelConfig {
|
||||
public JoinMessageConfig joinMessages = new JoinMessageConfig();
|
||||
public LeaveMessageConfig leaveMessages = new LeaveMessageConfig();
|
||||
|
||||
@Order(10)
|
||||
@Comment("Settings for synchronizing messages between the defined Discord channels and threads")
|
||||
public MirroringConfig mirroring = new MirroringConfig();
|
||||
|
||||
@Untranslated(Untranslated.Type.VALUE)
|
||||
@Order(5)
|
||||
@Order(50)
|
||||
public String avatarUrlProvider = "https://heads.discordsrv.com/head.png?texture=%texture%&uuid=%uuid%&name=%username%&overlay";
|
||||
}
|
||||
|
@ -18,16 +18,10 @@
|
||||
|
||||
package com.discordsrv.common.config.main.channels.base;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Setting;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ConfigSerializable
|
||||
@ -37,47 +31,22 @@ public class ChannelConfig extends BaseChannelConfig implements IChannelConfig {
|
||||
initialize();
|
||||
}
|
||||
|
||||
@Setting(CHANNEL_IDS_OPTION_NAME)
|
||||
@Comment(CHANNEL_IDS_COMMENT)
|
||||
public List<Long> channelIds = new ArrayList<>();
|
||||
public List<Long> channelIds = CHANNEL_IDS_VALUE;
|
||||
|
||||
@Override
|
||||
public List<Long> ids() {
|
||||
public List<Long> channelIds() {
|
||||
return channelIds;
|
||||
}
|
||||
|
||||
public static class Serializer implements TypeSerializer<BaseChannelConfig> {
|
||||
@Setting(THREADS_OPTION_NAME)
|
||||
@Comment(THREADS_COMMENT)
|
||||
public List<ThreadConfig> threads = THREADS_VALUE;
|
||||
|
||||
private final ObjectMapper.Factory mapperFactory;
|
||||
private final Class<?> baseConfigClass;
|
||||
private final Class<?> configClass;
|
||||
|
||||
public Serializer(ObjectMapper.Factory mapperFactory, Class<?> baseConfigClass, Class<?> configClass) {
|
||||
this.mapperFactory = mapperFactory;
|
||||
this.baseConfigClass = baseConfigClass;
|
||||
this.configClass = configClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseChannelConfig deserialize(Type type, ConfigurationNode node) throws SerializationException {
|
||||
return (BaseChannelConfig) mapperFactory.asTypeSerializer()
|
||||
.deserialize(
|
||||
ChannelConfig.DEFAULT_KEY.equals(node.key()) ? baseConfigClass : configClass,
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, @Nullable BaseChannelConfig obj, ConfigurationNode node) throws SerializationException {
|
||||
if (obj == null) {
|
||||
node.set(null);
|
||||
return;
|
||||
}
|
||||
|
||||
mapperFactory.asTypeSerializer().serialize(
|
||||
ChannelConfig.DEFAULT_KEY.equals(node.key()) ? baseConfigClass : configClass,
|
||||
obj,
|
||||
node
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public List<ThreadConfig> threads() {
|
||||
return threads;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,14 +18,38 @@
|
||||
|
||||
package com.discordsrv.common.config.main.channels.base;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Setting;
|
||||
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;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public interface IChannelConfig {
|
||||
|
||||
String DEFAULT_KEY = "default";
|
||||
|
||||
String CHANNEL_IDS_OPTION_NAME = "channelIds";
|
||||
String CHANNEL_IDS_COMMENT = "The channels this in-game channel will forward to in Discord";
|
||||
List<Long> CHANNEL_IDS_VALUE = new ArrayList<>();
|
||||
|
||||
List<Long> channelIds();
|
||||
|
||||
String THREADS_OPTION_NAME = "threads";
|
||||
String THREADS_COMMENT = "The threads that this in-game channel will forward to in Discord (this can be used instead of or with the channel-ids option)";
|
||||
List<ThreadConfig> THREADS_VALUE = new ArrayList<>(Collections.singletonList(new ThreadConfig()));
|
||||
|
||||
List<String> VALUES = Arrays.asList(CHANNEL_IDS_OPTION_NAME, THREADS_OPTION_NAME);
|
||||
|
||||
List<ThreadConfig> threads();
|
||||
|
||||
default void initialize() {
|
||||
// Clear everything besides channelIds by default (these will be filled back in by Configurate if they are in the config itself)
|
||||
@ -36,7 +60,9 @@ public interface IChannelConfig {
|
||||
if (!Modifier.isPublic(modifiers) || Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)) {
|
||||
continue;
|
||||
}
|
||||
if (field.getName().equals("channelIds")) {
|
||||
|
||||
Setting setting = field.getAnnotation(Setting.class);
|
||||
if (setting != null && VALUES.contains(setting.value())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -48,5 +74,39 @@ public interface IChannelConfig {
|
||||
}
|
||||
}
|
||||
|
||||
List<Long> ids();
|
||||
class Serializer implements TypeSerializer<BaseChannelConfig> {
|
||||
|
||||
private final ObjectMapper.Factory mapperFactory;
|
||||
private final Class<?> baseConfigClass;
|
||||
private final Class<?> configClass;
|
||||
|
||||
public Serializer(ObjectMapper.Factory mapperFactory, Class<?> baseConfigClass, Class<?> configClass) {
|
||||
this.mapperFactory = mapperFactory;
|
||||
this.baseConfigClass = baseConfigClass;
|
||||
this.configClass = configClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseChannelConfig deserialize(Type type, ConfigurationNode node) throws SerializationException {
|
||||
return (BaseChannelConfig) mapperFactory.asTypeSerializer()
|
||||
.deserialize(
|
||||
ChannelConfig.DEFAULT_KEY.equals(node.key()) ? baseConfigClass : configClass,
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, @Nullable BaseChannelConfig obj, ConfigurationNode node) throws SerializationException {
|
||||
if (obj == null) {
|
||||
node.set(null);
|
||||
return;
|
||||
}
|
||||
|
||||
mapperFactory.asTypeSerializer().serialize(
|
||||
ChannelConfig.DEFAULT_KEY.equals(node.key()) ? baseConfigClass : configClass,
|
||||
obj,
|
||||
node
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import com.discordsrv.common.config.annotation.Order;
|
||||
import com.discordsrv.common.config.fielddiscoverer.OrderedFieldDiscovererProxy;
|
||||
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.manager.loader.ConfigLoaderProvider;
|
||||
import com.discordsrv.common.config.serializer.ColorSerializer;
|
||||
import com.discordsrv.common.config.serializer.DiscordMessageEmbedSerializer;
|
||||
@ -93,8 +94,8 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
|
||||
|
||||
protected abstract String fileName();
|
||||
|
||||
public ChannelConfig.Serializer getChannelConfigSerializer( ObjectMapper.Factory mapperFactory) {
|
||||
return new ChannelConfig.Serializer(mapperFactory, BaseChannelConfig.class, ChannelConfig.class);
|
||||
public IChannelConfig.Serializer getChannelConfigSerializer(ObjectMapper.Factory mapperFactory) {
|
||||
return new IChannelConfig.Serializer(mapperFactory, BaseChannelConfig.class, ChannelConfig.class);
|
||||
}
|
||||
|
||||
public ConfigurationOptions defaultOptions() {
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.discord.api.message.util;
|
||||
package com.discordsrv.common.discord.api.entity.message.util;
|
||||
|
||||
import club.minnced.discord.webhook.send.WebhookMessage;
|
||||
import club.minnced.discord.webhook.send.WebhookMessageBuilder;
|
@ -27,13 +27,13 @@ import com.discordsrv.api.event.events.placeholder.PlaceholderLookupEvent;
|
||||
import com.discordsrv.api.placeholder.PlaceholderLookupResult;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.config.connection.ConnectionConfig;
|
||||
import com.discordsrv.common.discord.api.channel.DiscordDMChannelImpl;
|
||||
import com.discordsrv.common.discord.api.channel.DiscordTextChannelImpl;
|
||||
import com.discordsrv.common.discord.api.guild.DiscordGuildImpl;
|
||||
import com.discordsrv.common.discord.api.guild.DiscordGuildMemberImpl;
|
||||
import com.discordsrv.common.discord.api.guild.DiscordRoleImpl;
|
||||
import com.discordsrv.common.discord.api.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.discord.api.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.api.entity.channel.DiscordDMChannelImpl;
|
||||
import com.discordsrv.common.discord.api.entity.channel.DiscordTextChannelImpl;
|
||||
import com.discordsrv.common.discord.api.entity.guild.DiscordGuildImpl;
|
||||
import com.discordsrv.common.discord.api.entity.guild.DiscordGuildMemberImpl;
|
||||
import com.discordsrv.common.discord.api.entity.guild.DiscordRoleImpl;
|
||||
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageImpl;
|
||||
import com.discordsrv.common.discord.api.entity.DiscordUserImpl;
|
||||
import com.discordsrv.common.discord.connection.DiscordConnectionManager;
|
||||
import com.discordsrv.common.scheduler.Scheduler;
|
||||
import com.discordsrv.common.scheduler.threadfactory.CountingThreadFactory;
|
||||
@ -239,9 +239,9 @@ public class JDAConnectionManager implements DiscordConnectionManager {
|
||||
jdaBuilder.setMemberCachePolicy(membersIntent ? MemberCachePolicy.ALL : MemberCachePolicy.OWNER);
|
||||
jdaBuilder.setChunkingFilter(membersIntent ? ChunkingFilter.ALL : ChunkingFilter.NONE);
|
||||
|
||||
jdaBuilder.setEventManager(new EventManagerProxy(new JDAEventManager(discordSRV), discordSRV.scheduler().forkExecutor()));
|
||||
jdaBuilder.setEventManager(new EventManagerProxy(new JDAEventManager(discordSRV), discordSRV.scheduler().forkJoinPool()));
|
||||
|
||||
jdaBuilder.setCallbackPool(discordSRV.scheduler().forkExecutor());
|
||||
jdaBuilder.setCallbackPool(discordSRV.scheduler().forkJoinPool());
|
||||
jdaBuilder.setGatewayPool(gatewayPool);
|
||||
jdaBuilder.setRateLimitPool(rateLimitPool);
|
||||
|
||||
|
@ -195,7 +195,7 @@ public class EventBusImpl implements EventBus {
|
||||
} catch (IllegalAccessException e) {
|
||||
discordSRV.logger().error("Failed to access API listener method: " + eventListener.methodName(), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
discordSRV.logger().error("Failed to pass " + event.getClass().getSimpleName() + " to " + eventListener, e);
|
||||
discordSRV.logger().error("Failed to pass " + event.getClass().getSimpleName() + " to " + eventListener, e.getCause());
|
||||
}
|
||||
long timeTaken = System.currentTimeMillis() - startTime;
|
||||
discordSRV.logger().trace(eventListener + " took " + timeTaken + "ms to execute");
|
||||
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.function;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CheckedFunction<I, O> {
|
||||
|
||||
O apply(I input) throws Throwable;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.function;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CheckedSupplier<O> {
|
||||
|
||||
O get() throws Throwable;
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.module.modules.integration;
|
||||
package com.discordsrv.common.integration;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.module.type.PermissionDataProvider;
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.messageforwarding.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordThreadChannel;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.util.DiscordFormattingUtil;
|
||||
import com.discordsrv.api.event.events.message.receive.game.AbstractGameMessageReceiveEvent;
|
||||
import com.discordsrv.api.placeholder.FormattedText;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
|
||||
import com.discordsrv.common.discord.api.entity.message.ReceivedDiscordMessageClusterImpl;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public abstract class AbstractGameMessageModule<T> extends AbstractModule {
|
||||
|
||||
public AbstractGameMessageModule(DiscordSRV discordSRV) {
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
public abstract OrDefault<T> mapConfig(OrDefault<BaseChannelConfig> channelConfig);
|
||||
public abstract boolean isEnabled(OrDefault<T> config);
|
||||
public abstract SendableDiscordMessage.Builder getFormat(OrDefault<T> config);
|
||||
public abstract void postClusterToEventBus(ReceivedDiscordMessageCluster cluster);
|
||||
|
||||
public final void process(
|
||||
@NotNull AbstractGameMessageReceiveEvent event,
|
||||
@NotNull DiscordSRVPlayer player,
|
||||
@Nullable GameChannel channel
|
||||
) {
|
||||
if (channel == null) {
|
||||
// Send to all channels due to lack of specified channel
|
||||
for (OrDefault<BaseChannelConfig> channelConfig : discordSRV.channelConfig().getAllChannels()) {
|
||||
forwardToChannel(event, player, channelConfig);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
OrDefault<BaseChannelConfig> channelConfig = discordSRV.channelConfig().orDefault(channel);
|
||||
forwardToChannel(event, player, channelConfig);
|
||||
}
|
||||
|
||||
private void forwardToChannel(
|
||||
@NotNull AbstractGameMessageReceiveEvent event,
|
||||
@NotNull DiscordSRVPlayer player,
|
||||
@NotNull OrDefault<BaseChannelConfig> channelConfig
|
||||
) {
|
||||
OrDefault<T> config = mapConfig(channelConfig);
|
||||
if (!isEnabled(config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
IChannelConfig iChannelConfig = channelConfig.get(cfg -> cfg instanceof IChannelConfig ? (IChannelConfig) cfg : null);
|
||||
if (iChannelConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DiscordMessageChannel> messageChannels = new CopyOnWriteArrayList<>();
|
||||
List<CompletableFuture<DiscordThreadChannel>> futures = new ArrayList<>();
|
||||
|
||||
List<Long> channelIds = iChannelConfig.channelIds();
|
||||
if (channelIds != null) {
|
||||
for (Long channelId : iChannelConfig.channelIds()) {
|
||||
DiscordTextChannel textChannel = discordSRV.discordAPI().getTextChannelById(channelId).orElse(null);
|
||||
if (textChannel != null) {
|
||||
messageChannels.add(textChannel);
|
||||
} else if (channelId > 0) {
|
||||
discordSRV.logger().error("Unable to find channel with ID "
|
||||
+ Long.toUnsignedString(channelId)
|
||||
+ ", unable to forward message to Discord");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
discordSRV.discordAPI().findOrCreateThreads(iChannelConfig, messageChannels::add, futures);
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).whenComplete((v, t1) -> {
|
||||
SendableDiscordMessage.Builder format = getFormat(config);
|
||||
if (format == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String message = convertMessage(config, ComponentUtil.fromAPI(event.getMessage()));
|
||||
List<CompletableFuture<ReceivedDiscordMessage>> messageFutures;
|
||||
messageFutures = sendMessageToChannels(
|
||||
config, format, messageChannels, message,
|
||||
// Context
|
||||
channelConfig, player
|
||||
);
|
||||
|
||||
CompletableFuture.allOf(messageFutures.toArray(new CompletableFuture[0]))
|
||||
.whenComplete((vo, t2) -> {
|
||||
List<ReceivedDiscordMessage> messages = new ArrayList<>();
|
||||
for (CompletableFuture<ReceivedDiscordMessage> future : messageFutures) {
|
||||
if (future.isCompletedExceptionally()) {
|
||||
future.exceptionally(t -> {
|
||||
if (t instanceof InsufficientPermissionException) {
|
||||
discordSRV.logger().error(
|
||||
"Unable to send message to a Discord channel"
|
||||
+ " because the bot is lacking the "
|
||||
+ ((InsufficientPermissionException) t).getPermission().getName()
|
||||
+ " permission");
|
||||
} else {
|
||||
discordSRV.logger().error("Failed to deliver a message to Discord", t);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
// Ignore ones that failed
|
||||
continue;
|
||||
}
|
||||
|
||||
// They are all done, so joining will return the result instantly
|
||||
messages.add(future.join());
|
||||
}
|
||||
|
||||
if (message.isEmpty()) {
|
||||
// Nothing was delivered
|
||||
return;
|
||||
}
|
||||
|
||||
postClusterToEventBus(new ReceivedDiscordMessageClusterImpl(messages));
|
||||
})
|
||||
.exceptionally(t -> {
|
||||
if (t instanceof CompletionException) {
|
||||
return null;
|
||||
}
|
||||
discordSRV.logger().error("Failed to publish to event bus", t);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public String convertMessage(OrDefault<T> config, Component component) {
|
||||
return DiscordFormattingUtil.escapeContent(
|
||||
discordSRV.componentFactory().discordSerializer().serialize(component)
|
||||
);
|
||||
}
|
||||
|
||||
public List<CompletableFuture<ReceivedDiscordMessage>> sendMessageToChannels(
|
||||
OrDefault<T> config,
|
||||
SendableDiscordMessage.Builder format,
|
||||
List<DiscordMessageChannel> channels,
|
||||
String message,
|
||||
Object... context
|
||||
) {
|
||||
SendableDiscordMessage discordMessage = format.toFormatter()
|
||||
.addContext(context)
|
||||
.addReplacement("%message%", new FormattedText(message))
|
||||
.applyPlaceholderService()
|
||||
.build();
|
||||
|
||||
List<CompletableFuture<ReceivedDiscordMessage>> futures = new ArrayList<>();
|
||||
for (DiscordMessageChannel channel : channels) {
|
||||
futures.add(channel.sendMessage(discordMessage));
|
||||
}
|
||||
|
||||
return futures;
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.module.modules.message;
|
||||
package com.discordsrv.common.messageforwarding.game;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.module.modules.message;
|
||||
package com.discordsrv.common.messageforwarding.game;
|
||||
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
@ -16,10 +16,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.module.modules.message;
|
||||
package com.discordsrv.common.messageforwarding.game;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||
import com.discordsrv.api.discord.api.entity.channel.DiscordThreadChannel;
|
||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
@ -116,23 +118,30 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
|
||||
public List<CompletableFuture<ReceivedDiscordMessage>> sendMessageToChannels(
|
||||
OrDefault<MinecraftToDiscordChatConfig> config,
|
||||
SendableDiscordMessage.Builder format,
|
||||
List<Long> channelIds,
|
||||
List<DiscordMessageChannel> channels,
|
||||
String message,
|
||||
Object... context
|
||||
) {
|
||||
Map<DiscordGuild, Set<DiscordTextChannel>> channels = new LinkedHashMap<>();
|
||||
for (Long channelId : channelIds) {
|
||||
discordSRV.discordAPI().getTextChannelById(channelId)
|
||||
.ifPresent(textChannel -> channels
|
||||
.computeIfAbsent(textChannel.getGuild(), key -> new LinkedHashSet<>())
|
||||
.add(textChannel));
|
||||
Map<DiscordGuild, Set<DiscordMessageChannel>> channelMap = new LinkedHashMap<>();
|
||||
for (DiscordMessageChannel channel : channels) {
|
||||
DiscordGuild guild;
|
||||
if (channel instanceof DiscordTextChannel) {
|
||||
guild = ((DiscordTextChannel) channel).getGuild();
|
||||
} else if (channel instanceof DiscordThreadChannel) {
|
||||
guild = ((DiscordThreadChannel) channel).getParentChannel().getGuild();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
channelMap.computeIfAbsent(guild, key -> new LinkedHashSet<>())
|
||||
.add(channel);
|
||||
}
|
||||
|
||||
List<CompletableFuture<ReceivedDiscordMessage>> futures = new ArrayList<>();
|
||||
|
||||
OrDefault<MinecraftToDiscordChatConfig.Mentions> mentionConfig = config.map(cfg -> cfg.mentions);
|
||||
// Format messages per-Guild
|
||||
for (Map.Entry<DiscordGuild, Set<DiscordTextChannel>> entry : channels.entrySet()) {
|
||||
for (Map.Entry<DiscordGuild, Set<DiscordMessageChannel>> entry : channelMap.entrySet()) {
|
||||
Guild guild = entry.getKey().getAsJDAGuild();
|
||||
|
||||
Placeholders channelMessagePlaceholders = new Placeholders(message);
|
||||
@ -152,14 +161,32 @@ public class MinecraftToDiscordChatModule extends AbstractGameMessageModule<Mine
|
||||
.sorted(Comparator.comparingInt(mention -> ((CachedMention) mention).searchLength).reversed())
|
||||
.forEachOrdered(mention -> channelMessagePlaceholders.replaceAll(mention.search, mention.mention));
|
||||
|
||||
SendableDiscordMessage discordMessage = format.toFormatter()
|
||||
SendableDiscordMessage.Formatter discordMessage = format.toFormatter()
|
||||
.addContext(context)
|
||||
.addReplacement("%message%", new FormattedText(channelMessagePlaceholders.toString()))
|
||||
.applyPlaceholderService()
|
||||
.build();
|
||||
.applyPlaceholderService();
|
||||
|
||||
for (DiscordTextChannel textChannel : entry.getValue()) {
|
||||
futures.add(textChannel.sendMessage(discordMessage));
|
||||
List<DiscordMessageChannel> text = new ArrayList<>();
|
||||
List<DiscordMessageChannel> thread = new ArrayList<>();
|
||||
for (DiscordMessageChannel channel : entry.getValue()) {
|
||||
if (channel instanceof DiscordTextChannel) {
|
||||
text.add(channel);
|
||||
} else if (channel instanceof DiscordThreadChannel) {
|
||||
thread.add(channel);
|
||||
}
|
||||
}
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
SendableDiscordMessage finalMessage = discordMessage.build();
|
||||
for (DiscordMessageChannel channel : text) {
|
||||
futures.add(channel.sendMessage(finalMessage));
|
||||
}
|
||||
}
|
||||
if (!thread.isEmpty()) {
|
||||
SendableDiscordMessage finalMessage = discordMessage.convertToNonWebhook().build();
|
||||
for (DiscordMessageChannel channel : thread) {
|
||||
futures.add(channel.sendMessage(finalMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2021 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.discordsrv.common.module.modules.message;
|
||||
|
||||
import com.discordsrv.api.channel.GameChannel;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessageCluster;
|
||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||
import com.discordsrv.api.discord.api.util.DiscordFormattingUtil;
|
||||
import com.discordsrv.api.event.events.message.receive.game.AbstractGameMessageReceiveEvent;
|
||||
import com.discordsrv.api.placeholder.FormattedText;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
|
||||
import com.discordsrv.common.config.main.channels.base.IChannelConfig;
|
||||
import com.discordsrv.common.discord.api.message.ReceivedDiscordMessageClusterImpl;
|
||||
import com.discordsrv.common.function.OrDefault;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public abstract class AbstractGameMessageModule<T> extends AbstractModule {
|
||||
|
||||
public AbstractGameMessageModule(DiscordSRV discordSRV) {
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
public abstract OrDefault<T> mapConfig(OrDefault<BaseChannelConfig> channelConfig);
|
||||
public abstract boolean isEnabled(OrDefault<T> config);
|
||||
public abstract SendableDiscordMessage.Builder getFormat(OrDefault<T> config);
|
||||
public abstract void postClusterToEventBus(ReceivedDiscordMessageCluster cluster);
|
||||
|
||||
public final void process(
|
||||
@NotNull AbstractGameMessageReceiveEvent event,
|
||||
@NotNull DiscordSRVPlayer player,
|
||||
@Nullable GameChannel channel
|
||||
) {
|
||||
if (channel == null) {
|
||||
// Send to all channels due to lack of specified channel
|
||||
for (OrDefault<BaseChannelConfig> channelConfig : discordSRV.channelConfig().getAllChannels()) {
|
||||
forwardToChannel(event, player, channelConfig);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
OrDefault<BaseChannelConfig> channelConfig = discordSRV.channelConfig().orDefault(channel);
|
||||
forwardToChannel(event, player, channelConfig);
|
||||
}
|
||||
|
||||
private void forwardToChannel(
|
||||
@NotNull AbstractGameMessageReceiveEvent event,
|
||||
@NotNull DiscordSRVPlayer player,
|
||||
@NotNull OrDefault<BaseChannelConfig> channelConfig
|
||||
) {
|
||||
OrDefault<T> config = mapConfig(channelConfig);
|
||||
if (!isEnabled(config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Long> channelIds = channelConfig.get(cfg -> cfg instanceof IChannelConfig ? ((IChannelConfig) cfg).ids() : null);
|
||||
if (channelIds == null || channelIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SendableDiscordMessage.Builder format = getFormat(config);
|
||||
if (format == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String message = convertMessage(config, ComponentUtil.fromAPI(event.getMessage()));
|
||||
List<CompletableFuture<ReceivedDiscordMessage>> futures = sendMessageToChannels(
|
||||
config, format, channelIds, message,
|
||||
// Context
|
||||
channelConfig, player
|
||||
);
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||
.whenComplete((v, t) -> {
|
||||
if (t != null) {
|
||||
discordSRV.logger().error("Failed to deliver message to Discord", t);
|
||||
return;
|
||||
}
|
||||
|
||||
List<ReceivedDiscordMessage> messages = new ArrayList<>();
|
||||
for (CompletableFuture<ReceivedDiscordMessage> future : futures) {
|
||||
// They are all done
|
||||
messages.add(future.join());
|
||||
}
|
||||
|
||||
postClusterToEventBus(new ReceivedDiscordMessageClusterImpl(messages));
|
||||
});
|
||||
}
|
||||
|
||||
public String convertMessage(OrDefault<T> config, Component component) {
|
||||
return DiscordFormattingUtil.escapeContent(
|
||||
discordSRV.componentFactory().discordSerializer().serialize(component)
|
||||
);
|
||||
}
|
||||
|
||||
public List<CompletableFuture<ReceivedDiscordMessage>> sendMessageToChannels(
|
||||
OrDefault<T> config,
|
||||
SendableDiscordMessage.Builder format,
|
||||
List<Long> channelIds,
|
||||
String message,
|
||||
Object... context
|
||||
) {
|
||||
SendableDiscordMessage discordMessage = format.toFormatter()
|
||||
.addContext(context)
|
||||
.addReplacement("%message%", new FormattedText(message))
|
||||
.applyPlaceholderService()
|
||||
.build();
|
||||
|
||||
List<CompletableFuture<ReceivedDiscordMessage>> futures = new ArrayList<>();
|
||||
for (Long channelId : channelIds) {
|
||||
discordSRV.discordAPI().getTextChannelById(channelId)
|
||||
.ifPresent(channel -> futures.add(channel.sendMessage(discordMessage)));
|
||||
}
|
||||
|
||||
return futures;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user