use of net.dv8tion.jda.api.requests.RestAction in project DiscordSRV by Scarsz.
the class DiscordSRV method init.
public void init() {
if (Bukkit.getPluginManager().isPluginEnabled("PlugMan")) {
Plugin plugMan = Bukkit.getPluginManager().getPlugin("PlugMan");
try {
List<String> ignoredPlugins = (List<String>) plugMan.getClass().getMethod("getIgnoredPlugins").invoke(plugMan);
if (!ignoredPlugins.contains("DiscordSRV")) {
ignoredPlugins.add("DiscordSRV");
}
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ignored) {
}
}
// check if the person is trying to use the plugin without updating to ASM 5
try {
File specialSourceFile = new File("libraries/net/md-5/SpecialSource/1.7-SNAPSHOT/SpecialSource-1.7-SNAPSHOT.jar");
if (!specialSourceFile.exists())
specialSourceFile = new File("bin/net/md-5/SpecialSource/1.7-SNAPSHOT/SpecialSource-1.7-SNAPSHOT.jar");
if (specialSourceFile.exists() && DigestUtils.md5Hex(FileUtils.readFileToByteArray(specialSourceFile)).equalsIgnoreCase("096777a1b6098130d6c925f1c04050a3")) {
DiscordSRV.warning(LangUtil.InternalMessage.ASM_WARNING.toString().replace("{specialsourcefolder}", specialSourceFile.getParentFile().getPath()));
}
} catch (IOException e) {
error(e);
}
requireLinkModule = new RequireLinkModule();
// start the update checker (will skip if disabled)
if (!isUpdateCheckDisabled()) {
if (updateChecker == null) {
final ThreadFactory gatewayThreadFactory = new ThreadFactoryBuilder().setNameFormat("DiscordSRV - Update Checker").build();
updateChecker = Executors.newScheduledThreadPool(1);
}
updateChecker.schedule(() -> {
DiscordSRV.updateIsAvailable = UpdateUtil.checkForUpdates();
DiscordSRV.updateChecked = true;
}, 0, TimeUnit.SECONDS);
updateChecker.scheduleAtFixedRate(() -> DiscordSRV.updateIsAvailable = UpdateUtil.checkForUpdates(false), 6, 6, TimeUnit.HOURS);
}
// shutdown previously existing jda if plugin gets reloaded
if (jda != null)
try {
jda.shutdown();
jda = null;
} catch (Exception e) {
error(e);
}
reloadAllowedMentions();
// set proxy just in case this JVM doesn't have a proxy selector for some reason
if (ProxySelector.getDefault() == null) {
ProxySelector.setDefault(new ProxySelector() {
private final List<Proxy> DIRECT_CONNECTION = Collections.unmodifiableList(Collections.singletonList(Proxy.NO_PROXY));
public void connectFailed(URI arg0, SocketAddress arg1, IOException arg2) {
}
public List<Proxy> select(URI uri) {
return DIRECT_CONNECTION;
}
});
}
// set ssl to TLSv1.2
if (config().getBoolean("ForceTLSv12")) {
try {
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, null, null);
SSLContext.setDefault(context);
} catch (Exception ignored) {
}
}
// check log4j capabilities
boolean serverIsLog4jCapable = false;
boolean serverIsLog4j21Capable = false;
try {
serverIsLog4jCapable = Class.forName("org.apache.logging.log4j.core.Logger") != null;
} catch (ClassNotFoundException e) {
error("Log4j classes are NOT available, console channel will not be attached");
}
try {
serverIsLog4j21Capable = Class.forName("org.apache.logging.log4j.core.Filter") != null;
} catch (ClassNotFoundException e) {
error("Log4j 2.1 classes are NOT available, JDA messages will NOT be formatted properly");
}
// add log4j filter for JDA messages
if (serverIsLog4j21Capable && jdaFilter == null) {
try {
Class<?> jdaFilterClass = Class.forName("github.scarsz.discordsrv.objects.log4j.JdaFilter");
jdaFilter = (JdaFilter) jdaFilterClass.newInstance();
((org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager.getRootLogger()).addFilter((org.apache.logging.log4j.core.Filter) jdaFilter);
debug("JdaFilter applied");
} catch (Exception e) {
error("Failed to attach JDA message filter to root logger", e);
}
}
if (Debug.JDA.isVisible()) {
LoggerContext config = ((LoggerContext) LogManager.getContext(false));
config.getConfiguration().getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(Level.ALL);
config.updateLoggers();
}
if (Debug.JDA_REST_ACTIONS.isVisible()) {
RestAction.setPassContext(true);
}
// http client for JDA
Dns dns = Dns.SYSTEM;
try {
List<InetAddress> fallbackDnsServers = new CopyOnWriteArrayList<>(Arrays.asList(// CloudFlare resolvers
InetAddress.getByName("1.1.1.1"), InetAddress.getByName("1.0.0.1"), // Google resolvers
InetAddress.getByName("8.8.8.8"), InetAddress.getByName("8.8.4.4")));
dns = new Dns() {
// maybe drop minidns in favor of something else
// https://github.com/dnsjava/dnsjava/blob/master/src/main/java/org/xbill/DNS/SimpleResolver.java
// https://satreth.blogspot.com/2015/01/java-dns-query.html
private final DnsClient client = new DnsClient();
private int failedRequests = 0;
@NotNull
@Override
public List<InetAddress> lookup(@NotNull String host) throws UnknownHostException {
int max = config.getInt("MaximumAttemptsForSystemDNSBeforeUsingFallbackDNS");
// >0 = falls back if goes past that amount of failed requests in a row
if (max < 0 || (max > 0 && failedRequests < max)) {
try {
List<InetAddress> result = Dns.SYSTEM.lookup(host);
// reset on successful lookup
failedRequests = 0;
return result;
} catch (Exception e) {
failedRequests++;
DiscordSRV.error("System DNS FAILED to resolve hostname " + host + ", " + (max == 0 ? "" : failedRequests >= max ? "using fallback DNS for this request" : "switching to fallback DNS servers") + "!");
if (max == 0) {
// not using fallback
if (e instanceof UnknownHostException) {
throw e;
} else {
return null;
}
}
}
}
return lookupPublic(host);
}
private List<InetAddress> lookupPublic(String host) throws UnknownHostException {
for (InetAddress dnsServer : fallbackDnsServers) {
try {
DnsMessage query = client.query(host, Record.TYPE.A, Record.CLASS.IN, dnsServer).response;
if (query.responseCode != DnsMessage.RESPONSE_CODE.NO_ERROR) {
DiscordSRV.error("DNS server " + dnsServer.getHostAddress() + " failed our DNS query for " + host + ": " + query.responseCode.name());
}
List<InetAddress> resolved = query.answerSection.stream().map(record -> record.payloadData.toString()).map(s -> {
try {
return InetAddress.getByName(s);
} catch (UnknownHostException e) {
// impossible
error(e);
return null;
}
}).filter(Objects::nonNull).distinct().collect(Collectors.toList());
if (resolved.size() > 0) {
return resolved;
} else {
DiscordSRV.error("DNS server " + dnsServer.getHostAddress() + " failed to resolve " + host + ": no results");
}
} catch (Exception e) {
DiscordSRV.error("DNS server " + dnsServer.getHostAddress() + " failed to resolve " + host, e);
}
// this dns server gave us an error so we move this dns server to the end of the
// list, effectively making it the last resort for future requests
fallbackDnsServers.remove(dnsServer);
fallbackDnsServers.add(dnsServer);
}
// spitting errors into the console and consuming 100% cpu
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
UnknownHostException exception = new UnknownHostException("All DNS resolvers failed to resolve hostname " + host + ". Not good.");
exception.setStackTrace(new StackTraceElement[] { exception.getStackTrace()[0] });
throw exception;
}
};
} catch (Exception e) {
DiscordSRV.error("Failed to make custom DNS client", e);
}
Optional<Boolean> noopHostnameVerifier = config().getOptionalBoolean("NoopHostnameVerifier");
OkHttpClient httpClient = IOUtil.newHttpClientBuilder().dns(dns).connectTimeout(20, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS).writeTimeout(20, TimeUnit.SECONDS).hostnameVerifier(noopHostnameVerifier.isPresent() && noopHostnameVerifier.get() ? (hostname, sslSession) -> true : OkHostnameVerifier.INSTANCE).build();
// set custom RestAction failure handler
Consumer<? super Throwable> defaultFailure = RestAction.getDefaultFailure();
RestAction.setDefaultFailure(throwable -> {
if (throwable instanceof HierarchyException) {
DiscordSRV.error("DiscordSRV failed to perform an action due to being lower in hierarchy than the action's target: " + throwable.getMessage());
} else if (throwable instanceof PermissionException) {
DiscordSRV.error("DiscordSRV failed to perform an action because the bot is missing the " + ((PermissionException) throwable).getPermission().name() + " permission: " + throwable.getMessage());
} else if (throwable instanceof RateLimitedException) {
DiscordSRV.error("DiscordSRV encountered rate limiting. If you are running multiple DiscordSRV instances on the same token, this is considered API abuse and risks your server being IP banned from Discord. Make one bot per server.");
} else if (throwable instanceof ErrorResponseException) {
if (((ErrorResponseException) throwable).getErrorCode() == 50013) {
// Missing Permissions, too bad we don't know which one
DiscordSRV.error("DiscordSRV received a permission error response (50013) from Discord. Unfortunately the specific error isn't provided in that response.");
DiscordSRV.debug(Debug.JDA_REST_ACTIONS, throwable.getCause());
return;
}
DiscordSRV.error("DiscordSRV encountered an unknown Discord error: " + throwable.getMessage());
} else {
DiscordSRV.error("DiscordSRV encountered an unknown exception: " + throwable.getMessage() + "\n" + ExceptionUtils.getStackTrace(throwable));
}
if (Debug.JDA_REST_ACTIONS.isVisible()) {
Throwable cause = throwable.getCause();
error(cause);
}
});
File tokenFile = new File(getDataFolder(), ".token");
String token;
if (StringUtils.isNotBlank(System.getProperty("DISCORDSRV_TOKEN"))) {
token = System.getProperty("DISCORDSRV_TOKEN");
DiscordSRV.debug("Using bot token supplied from JVM property DISCORDSRV_TOKEN");
} else if (StringUtils.isNotBlank(System.getenv("DISCORDSRV_TOKEN"))) {
token = System.getenv("DISCORDSRV_TOKEN");
DiscordSRV.debug("Using bot token supplied from environment variable DISCORDSRV_TOKEN");
} else if (tokenFile.exists()) {
try {
token = FileUtils.readFileToString(tokenFile, StandardCharsets.UTF_8);
DiscordSRV.debug("Using bot token supplied from " + tokenFile.getPath());
} catch (IOException e) {
error(".token file could not be read: " + e.getMessage());
token = null;
}
} else {
token = config.getString("BotToken");
DiscordSRV.debug("Using bot token supplied from config");
}
if (StringUtils.isBlank(token) || "BOTTOKEN".equalsIgnoreCase(token)) {
disablePlugin();
error("No bot token has been set in the config; a bot token is required to connect to Discord.");
invalidBotToken = true;
return;
} else if (token.length() < 59) {
disablePlugin();
error("An invalid length bot token (" + token.length() + ") has been set in the config; a valid bot token is required to connect to Discord." + (token.length() == 32 ? " Did you copy the \"Client Secret\" instead of the \"Bot Token\" into the config?" : ""));
invalidBotToken = true;
return;
} else {
// remove invalid characters
token = token.replaceAll("[^\\w\\d-_.]", "");
}
callbackThreadPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors(), pool -> {
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
worker.setName("DiscordSRV - JDA Callback " + worker.getPoolIndex());
return worker;
}, null, true);
final ThreadFactory gatewayThreadFactory = new ThreadFactoryBuilder().setNameFormat("DiscordSRV - JDA Gateway").build();
final ScheduledExecutorService gatewayThreadPool = Executors.newSingleThreadScheduledExecutor(gatewayThreadFactory);
final ThreadFactory rateLimitThreadFactory = new ThreadFactoryBuilder().setNameFormat("DiscordSRV - JDA Rate Limit").build();
final ScheduledExecutorService rateLimitThreadPool = new ScheduledThreadPoolExecutor(5, rateLimitThreadFactory);
// log in to discord
if (config.getBooleanElse("EnablePresenceInformation", false)) {
DiscordSRV.api.requireIntent(GatewayIntent.GUILD_PRESENCES);
DiscordSRV.api.requireCacheFlag(CacheFlag.ACTIVITY);
DiscordSRV.api.requireCacheFlag(CacheFlag.CLIENT_STATUS);
}
try {
// see ApiManager for our default intents & cache flags
jda = JDABuilder.create(api.getIntents()).disableCache(Arrays.stream(CacheFlag.values()).filter(cacheFlag -> !api.getCacheFlags().contains(cacheFlag)).collect(Collectors.toList())).setMemberCachePolicy(MemberCachePolicy.ALL).setCallbackPool(callbackThreadPool, false).setGatewayPool(gatewayThreadPool, true).setRateLimitPool(rateLimitThreadPool, true).setWebsocketFactory(new WebSocketFactory().setDualStackMode(DualStackMode.IPV4_ONLY)).setHttpClient(httpClient).setAutoReconnect(true).setBulkDeleteSplittingEnabled(false).setToken(token).addEventListeners(new DiscordBanListener()).addEventListeners(new DiscordChatListener()).addEventListeners(new DiscordConsoleListener()).addEventListeners(new DiscordAccountLinkListener()).addEventListeners(new DiscordDisconnectListener()).addEventListeners(groupSynchronizationManager).setContextEnabled(false).build();
// let JDA be assigned as soon as we can, but wait until it's ready
jda.awaitReady();
for (Guild guild : jda.getGuilds()) {
guild.retrieveOwner(true).queue();
guild.loadMembers().onSuccess(members -> DiscordSRV.debug("Loaded " + members.size() + " members in guild " + guild)).onError(throwable -> DiscordSRV.error("Failed to retrieve members of guild " + guild, throwable)).get();
}
} catch (LoginException e) {
disablePlugin();
if (e.getMessage().toLowerCase().contains("the provided token is invalid")) {
invalidBotToken = true;
DiscordDisconnectListener.printDisconnectMessage(true, "The bot token is invalid");
} else {
DiscordDisconnectListener.printDisconnectMessage(true, e.getMessage());
}
return;
} catch (Exception e) {
if (e instanceof IllegalStateException && e.getMessage().equals("Was shutdown trying to await status")) {
// already logged by JDA
return;
}
DiscordSRV.error("An unknown error occurred building JDA...", e);
return;
}
// start presence updater thread
if (presenceUpdater != null) {
if (presenceUpdater.getState() != Thread.State.NEW) {
presenceUpdater.interrupt();
presenceUpdater = new PresenceUpdater();
}
Bukkit.getScheduler().runTaskLater(this, () -> presenceUpdater.start(), 5 * 20);
} else {
presenceUpdater = new PresenceUpdater();
presenceUpdater.start();
}
// start nickname updater thread
if (nicknameUpdater != null) {
if (nicknameUpdater.getState() != Thread.State.NEW) {
nicknameUpdater.interrupt();
nicknameUpdater = new NicknameUpdater();
}
Bukkit.getScheduler().runTaskLater(this, () -> nicknameUpdater.start(), 5 * 20);
} else {
nicknameUpdater = new NicknameUpdater();
nicknameUpdater.start();
}
// print the things the bot can see
if (config().getBoolean("PrintGuildsAndChannels")) {
for (Guild server : jda.getGuilds()) {
DiscordSRV.info(LangUtil.InternalMessage.FOUND_SERVER + " " + server);
for (TextChannel channel : server.getTextChannels()) DiscordSRV.info("- " + channel);
}
}
// show warning if bot wasn't in any guilds
if (jda.getGuilds().size() == 0) {
DiscordSRV.error(LangUtil.InternalMessage.BOT_NOT_IN_ANY_SERVERS);
DiscordSRV.error(jda.getInviteUrl(Permission.ADMINISTRATOR));
return;
}
// see if console channel exists; if it does, tell user where it's been assigned & add console appender
if (serverIsLog4jCapable) {
DiscordSRV.info(getConsoleChannel() != null ? LangUtil.InternalMessage.CONSOLE_FORWARDING_ASSIGNED_TO_CHANNEL + " " + getConsoleChannel() : LangUtil.InternalMessage.NOT_FORWARDING_CONSOLE_OUTPUT.toString());
// attach appender to queue console messages
consoleAppender = new ConsoleAppender();
// start console message queue worker thread
if (consoleMessageQueueWorker != null) {
if (consoleMessageQueueWorker.getState() != Thread.State.NEW) {
consoleMessageQueueWorker.interrupt();
consoleMessageQueueWorker = new ConsoleMessageQueueWorker();
}
} else {
consoleMessageQueueWorker = new ConsoleMessageQueueWorker();
}
consoleMessageQueueWorker.start();
}
reloadChannels();
reloadRegexes();
reloadRoleAliases();
// warn if the console channel is connected to a chat channel
if (getMainTextChannel() != null && getConsoleChannel() != null && getMainTextChannel().getId().equals(getConsoleChannel().getId()))
DiscordSRV.warning(LangUtil.InternalMessage.CONSOLE_CHANNEL_ASSIGNED_TO_LINKED_CHANNEL);
// send server startup message
Bukkit.getScheduler().runTaskLater(this, () -> {
DiscordUtil.queueMessage(getOptionalTextChannel("status"), PlaceholderUtil.replacePlaceholdersToDiscord(LangUtil.Message.SERVER_STARTUP_MESSAGE.toString()), true);
}, 20);
// big warning about respect chat plugins
if (!config().getBooleanElse("RespectChatPlugins", true))
DiscordSRV.warning(LangUtil.InternalMessage.RESPECT_CHAT_PLUGINS_DISABLED);
// extra enabled check before doing bukkit api stuff
if (!isEnabled())
return;
// start server watchdog
if (serverWatchdog != null && serverWatchdog.getState() != Thread.State.NEW)
serverWatchdog.interrupt();
serverWatchdog = new ServerWatchdog();
serverWatchdog.start();
// start lag (tps) monitor
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Lag(), 100L, 1L);
// cancellation detector
reloadCancellationDetector();
// load account links
if (JdbcAccountLinkManager.shouldUseJdbc()) {
try {
JdbcAccountLinkManager jdbcManager = new JdbcAccountLinkManager();
accountLinkManager = jdbcManager;
jdbcManager.migrateJSON();
} catch (SQLException e) {
StringBuilder stringBuilder = new StringBuilder("JDBC account link backend failed to initialize: ");
Throwable selected = e;
do {
stringBuilder.append("\n").append("Caused by: ").append(selected instanceof UnknownHostException ? "UnknownHostException" : ExceptionUtils.getMessage(selected));
selected = selected.getCause();
} while (selected != null);
String message = stringBuilder.toString().replace(config.getString("Experiment_JdbcAccountLinkBackend"), "<jdbc url>").replace(config.getString("Experiment_JdbcUsername"), "<jdbc username>");
if (!StringUtils.isEmpty(config.getString("Experiment_JdbcPassword"))) {
message = message.replace(config.getString("Experiment_JdbcPassword"), "");
}
for (String line : message.split("\n")) {
DiscordSRV.warning(line);
}
DiscordSRV.warning("Account link manager falling back to flat file");
accountLinkManager = new FileAccountLinkManager();
}
} else {
accountLinkManager = new FileAccountLinkManager();
}
Bukkit.getPluginManager().registerEvents(accountLinkManager, this);
// register events
new PlayerBanListener();
new PlayerDeathListener();
new PlayerJoinLeaveListener();
try {
Class.forName("org.bukkit.event.player.PlayerAdvancementDoneEvent");
new PlayerAdvancementDoneListener();
} catch (Exception ignored) {
new PlayerAchievementsListener();
}
// plugin hooks
for (String hookClassName : new String[] { // chat plugins
"github.scarsz.discordsrv.hooks.chat.ChattyChatHook", "github.scarsz.discordsrv.hooks.chat.FancyChatHook", "github.scarsz.discordsrv.hooks.chat.HerochatHook", "github.scarsz.discordsrv.hooks.chat.LegendChatHook", "github.scarsz.discordsrv.hooks.chat.LunaChatHook", "github.scarsz.discordsrv.hooks.chat.TownyChatHook", "github.scarsz.discordsrv.hooks.chat.VentureChatHook", // vanish plugins
"github.scarsz.discordsrv.hooks.vanish.EssentialsHook", "github.scarsz.discordsrv.hooks.vanish.PhantomAdminHook", "github.scarsz.discordsrv.hooks.vanish.SuperVanishHook", "github.scarsz.discordsrv.hooks.vanish.VanishNoPacketHook", // dynmap
"github.scarsz.discordsrv.hooks.DynmapHook", // luckperms
"github.scarsz.discordsrv.hooks.permissions.LuckPermsHook" }) {
try {
Class<?> hookClass = Class.forName(hookClassName);
PluginHook pluginHook = (PluginHook) hookClass.getDeclaredConstructor().newInstance();
if (pluginHook.isEnabled()) {
DiscordSRV.info(LangUtil.InternalMessage.PLUGIN_HOOK_ENABLING.toString().replace("{plugin}", pluginHook.getPlugin().getName()));
Bukkit.getPluginManager().registerEvents(pluginHook, this);
try {
pluginHook.hook();
pluginHooks.add(pluginHook);
} catch (Throwable t) {
error("Failed to hook " + hookClassName, t);
}
}
} catch (Throwable e) {
// ignore class not found errors
if (!(e instanceof ClassNotFoundException) && !(e instanceof NoClassDefFoundError)) {
DiscordSRV.error("Failed to load " + hookClassName, e);
}
}
}
if (pluginHooks.stream().noneMatch(pluginHook -> pluginHook instanceof ChatHook)) {
DiscordSRV.info(LangUtil.InternalMessage.NO_CHAT_PLUGIN_HOOKED);
try {
Class.forName("io.papermc.paper.event.player.AsyncChatEvent");
getServer().getPluginManager().registerEvents(new ModernPlayerChatListener(), this);
modernChatEventAvailable = true;
} catch (ClassNotFoundException ignored) {
}
boolean configOption = config().getBoolean("UseModernPaperChatEvent");
@SuppressWarnings("deprecation") Warning warning = AsyncPlayerChatEvent.class.getAnnotation(Warning.class);
// check if the event has a nag
boolean isWarning = warning != null && getServer().getWarningState().printFor(warning);
Runnable registerLegacy = () -> getServer().getPluginManager().registerEvents(new PlayerChatListener(), this);
if (isWarning) {
if (!configOption) {
if (modernChatEventAvailable) {
warning("AsyncPlayerChatEvent will be registered because the UseModernPaperChatEvent config option is set to false");
warning("You should enable UseModernPaperChatEvent if your chat plugins have updated to using the new event");
} else {
warning("AsyncPlayerChatEvent has a nag but Paper's modern PlayerChatEvent is not available.");
warning("Your server platform's chat event isn't supported currently");
}
registerLegacy.run();
}
} else {
// there won't be a nag
registerLegacy.run();
}
debug(Debug.MINECRAFT_TO_DISCORD, "Modern PlayerChatEvent (Paper) is " + (modernChatEventAvailable ? "" : "not ") + "available");
}
pluginHooks.add(new VanishHook() {
@Override
public boolean isVanished(Player player) {
boolean vanished = false;
for (MetadataValue metadataValue : player.getMetadata("vanished")) {
if (metadataValue.asBoolean()) {
vanished = true;
break;
}
}
return vanished;
}
@Override
public Plugin getPlugin() {
return null;
}
@Override
public boolean isEnabled() {
return true;
}
});
if (PluginUtil.pluginHookIsEnabled("PlaceholderAPI", false)) {
try {
DiscordSRV.info(LangUtil.InternalMessage.PLUGIN_HOOK_ENABLING.toString().replace("{plugin}", "PlaceholderAPI"));
Bukkit.getScheduler().runTask(this, () -> {
try {
if (me.clip.placeholderapi.PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().findExpansionByIdentifier("discordsrv").isPresent()) {
getLogger().warning("The DiscordSRV PlaceholderAPI expansion is no longer required.");
getLogger().warning("The expansion is now integrated in DiscordSRV.");
}
new github.scarsz.discordsrv.hooks.PlaceholderAPIExpansion().register();
} catch (Throwable ignored) {
getLogger().severe("Failed to hook into PlaceholderAPI, please check your PlaceholderAPI version");
}
});
} catch (Exception e) {
if (!(e instanceof ClassNotFoundException)) {
DiscordSRV.error("Failed to load PlaceholderAPI expansion", e);
}
}
}
// start channel topic updater
if (channelTopicUpdater != null) {
if (channelTopicUpdater.getState() != Thread.State.NEW) {
channelTopicUpdater.interrupt();
channelTopicUpdater = new ChannelTopicUpdater();
}
} else {
channelTopicUpdater = new ChannelTopicUpdater();
}
channelTopicUpdater.start();
// enable metrics
if (!config().getBooleanElse("MetricsDisabled", false)) {
Metrics bStats = new Metrics(this, 387);
bStats.addCustomChart(new SimplePie("linked_channels", () -> String.valueOf(channels.size())));
bStats.addCustomChart(new AdvancedPie("hooked_plugins", () -> new HashMap<String, Integer>() {
{
if (pluginHooks.size() == 0) {
put("none", 1);
} else {
for (PluginHook hookedPlugin : pluginHooks) {
Plugin plugin = hookedPlugin.getPlugin();
if (plugin == null)
continue;
put(plugin.getName(), 1);
}
}
}
}));
bStats.addCustomChart(new SingleLineChart("minecraft-discord_account_links", () -> accountLinkManager.getLinkedAccountCount()));
bStats.addCustomChart(new SimplePie("server_language", () -> DiscordSRV.config().getLanguage().getName()));
bStats.addCustomChart(new AdvancedPie("features", () -> new HashMap<String, Integer>() {
{
if (getConsoleChannel() != null)
put("Console channel", 1);
if (StringUtils.isNotBlank(config().getString("DiscordChatChannelPrefixRequiredToProcessMessage")))
put("Chatting prefix", 1);
if (JdbcAccountLinkManager.shouldUseJdbc(true))
put("JDBC", 1);
if (config().getBoolean("Experiment_MCDiscordReserializer_ToMinecraft"))
put("Discord -> MC Reserializer", 1);
if (config().getBoolean("Experiment_MCDiscordReserializer_ToDiscord"))
put("MC -> Discord Reserializer", 1);
if (config().getBoolean("Experiment_MCDiscordReserializer_InBroadcast"))
put("Broadcast Reserializer", 1);
if (config().getBoolean("Experiment_WebhookChatMessageDelivery"))
put("Webhooks", 1);
if (config().getMap("GroupRoleSynchronizationGroupsAndRolesToSync").values().stream().anyMatch(s -> s.toString().replace("0", "").length() > 0))
put("Group -> role synchronization", 1);
if (config().getBoolean("Voice enabled"))
put("Voice", 1);
if (config().getBoolean("Require linked account to play.Enabled")) {
put("Require linked account to play", 1);
if (config().getBoolean("Require linked account to play.Subscriber role.Require subscriber role to join")) {
put("Required subscriber role to play", 1);
}
}
}
}));
bStats.addCustomChart(new SingleLineChart("atleast_1player_online", () -> PlayerUtil.getOnlinePlayers().isEmpty() ? 0 : 1));
bStats.addCustomChart(new SimplePie("better_online_mode", () -> {
boolean onlineMode = Bukkit.getOnlineMode();
try {
Class<?> spigotConfig = Class.forName("org.spigotmc.SpigotConfig");
Field bungee = spigotConfig.getField("bungee");
if (bungee.getBoolean(null)) {
return "bungee";
}
} catch (Throwable ignored) {
}
try {
Class<?> paperConfig = Class.forName("com.destroystokyo.paper.PaperConfig");
Field velocitySupport = paperConfig.getField("velocitySupport");
Field velocityOnlineMode = paperConfig.getField("velocityOnlineMode");
if (velocitySupport.getBoolean(null) && velocityOnlineMode.getBoolean(null)) {
return "velocity";
}
} catch (Throwable ignored) {
}
return onlineMode ? "online" : "offline";
}));
bStats.addCustomChart(new DrilldownPie("server_plugins", () -> {
int pluginCount = Bukkit.getPluginManager().getPlugins().length;
Map<String, Integer> count = new HashMap<>();
count.put(String.valueOf(pluginCount), 1);
String key;
if (pluginCount <= 5) {
key = "1-5";
} else if (pluginCount <= 10) {
key = "6-10";
} else if (pluginCount <= 20) {
key = "11-20";
} else if (pluginCount <= 50) {
key = "21-50";
} else if (pluginCount <= 100) {
key = "51-100";
} else {
key = ((int) (Math.floor(pluginCount / 100F) * 100F)) + "+";
}
Map<String, Map<String, Integer>> plugins = new HashMap<>();
plugins.put(key, count);
return plugins;
}));
}
// metrics file deprecated since v1.18.1
File metricsFile = new File(getDataFolder(), "metrics.json");
if (metricsFile.exists() && !metricsFile.delete())
metricsFile.deleteOnExit();
// start the group synchronization task
if (isGroupRoleSynchronizationEnabled()) {
int cycleTime = DiscordSRV.config().getInt("GroupRoleSynchronizationCycleTime") * 20 * 60;
if (cycleTime < 20 * 60)
cycleTime = 20 * 60;
try {
groupSynchronizationManager.resync(GroupSynchronizationManager.SyncDirection.AUTHORITATIVE, GroupSynchronizationManager.SyncCause.TIMER);
} catch (Exception e) {
error("Failed to resync\n" + ExceptionUtils.getMessage(e));
}
Bukkit.getPluginManager().registerEvents(groupSynchronizationManager, this);
Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> groupSynchronizationManager.resync(GroupSynchronizationManager.SyncDirection.AUTHORITATIVE, GroupSynchronizationManager.SyncCause.TIMER), cycleTime, cycleTime);
}
voiceModule = new VoiceModule();
PluginCommand discordCommand = getCommand("discord");
if (discordCommand != null && discordCommand.getPlugin() != this) {
DiscordSRV.warning("/discord command is being handled by plugin other than DiscordSRV. You must use /discordsrv instead.");
}
alertListener = new AlertListener();
jda.addEventListener(alertListener);
api.subscribe(alertListener);
// set ready status
if (jda.getStatus() == JDA.Status.CONNECTED) {
isReady = true;
api.callEvent(new DiscordReadyEvent());
}
}
Aggregations