mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-10-31 08:32:18 +01:00
Ban sync
This commit is contained in:
parent
1e9e1c53e2
commit
bc12809351
@ -23,7 +23,9 @@
|
||||
|
||||
package com.discordsrv.api.module.type;
|
||||
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.module.Module;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import com.discordsrv.api.punishment.Punishment;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@ -36,13 +38,14 @@ public interface PunishmentModule extends Module {
|
||||
|
||||
interface Bans extends PunishmentModule {
|
||||
CompletableFuture<@Nullable Punishment> getBan(@NotNull UUID playerUUID);
|
||||
CompletableFuture<Void> addBan(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable String reason, @NotNull String punisher);
|
||||
CompletableFuture<Void> addBan(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable MinecraftComponent reason, @NotNull MinecraftComponent punisher);
|
||||
CompletableFuture<Void> removeBan(@NotNull UUID playerUUID);
|
||||
CompletableFuture<Void> kickPlayer(@NotNull DiscordSRVPlayer player, @NotNull MinecraftComponent message);
|
||||
}
|
||||
|
||||
interface Mutes extends PunishmentModule {
|
||||
CompletableFuture<@Nullable Punishment> getMute(@NotNull UUID playerUUID);
|
||||
CompletableFuture<Void> addMute(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable String reason, @NotNull String punisher);
|
||||
CompletableFuture<Void> addMute(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable MinecraftComponent reason, @NotNull MinecraftComponent punisher);
|
||||
CompletableFuture<Void> removeMute(@NotNull UUID playerUUID);
|
||||
}
|
||||
}
|
||||
|
@ -23,31 +23,39 @@
|
||||
|
||||
package com.discordsrv.api.punishment;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.placeholder.annotation.Placeholder;
|
||||
import com.discordsrv.api.placeholder.annotation.PlaceholderPrefix;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@PlaceholderPrefix("punishment_")
|
||||
public class Punishment {
|
||||
|
||||
private final Instant until;
|
||||
private final String reason;
|
||||
private final String punisher;
|
||||
public static final Punishment UNKNOWN = new Punishment(null, null, null);
|
||||
|
||||
public Punishment(@Nullable Instant until, @Nullable String reason, @Nullable String punisher) {
|
||||
private final Instant until;
|
||||
private final MinecraftComponent reason;
|
||||
private final MinecraftComponent punisher;
|
||||
|
||||
public Punishment(Instant until, MinecraftComponent reason, MinecraftComponent punisher) {
|
||||
this.until = until;
|
||||
this.reason = reason;
|
||||
this.punisher = punisher;
|
||||
}
|
||||
|
||||
@Placeholder(value = "until", relookup = "date")
|
||||
public Instant until() {
|
||||
return until;
|
||||
}
|
||||
|
||||
public String reason() {
|
||||
@Placeholder("reason")
|
||||
public MinecraftComponent reason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public String punisher() {
|
||||
@Placeholder("punisher")
|
||||
public MinecraftComponent punisher() {
|
||||
return punisher;
|
||||
}
|
||||
}
|
||||
|
@ -18,16 +18,21 @@
|
||||
|
||||
package com.discordsrv.bukkit.ban;
|
||||
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.module.type.PunishmentModule;
|
||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||
import com.discordsrv.api.punishment.Punishment;
|
||||
import com.discordsrv.bukkit.BukkitDiscordSRV;
|
||||
import com.discordsrv.common.bansync.BanSyncModule;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.module.type.AbstractModule;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
|
||||
import org.bukkit.BanEntry;
|
||||
import org.bukkit.BanList;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -44,6 +49,16 @@ public class BukkitBanModule extends AbstractModule<BukkitDiscordSRV> implements
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
discordSRV.server().getPluginManager().registerEvents(this, discordSRV.plugin());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerKick(PlayerKickEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
@ -59,7 +74,7 @@ public class BukkitBanModule extends AbstractModule<BukkitDiscordSRV> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<com.discordsrv.api.punishment.Punishment> getBan(@NotNull UUID playerUUID) {
|
||||
public CompletableFuture<Punishment> getBan(@NotNull UUID playerUUID) {
|
||||
CompletableFuture<BanEntry> entryFuture;
|
||||
if (PaperBanList.IS_AVAILABLE) {
|
||||
entryFuture = CompletableFuture.completedFuture(PaperBanList.getBanEntry(discordSRV.server(), playerUUID));
|
||||
@ -74,20 +89,26 @@ public class BukkitBanModule extends AbstractModule<BukkitDiscordSRV> implements
|
||||
return null;
|
||||
}
|
||||
Date expiration = ban.getExpiration();
|
||||
return new Punishment(expiration != null ? expiration.toInstant() : null, ban.getReason(), ban.getSource());
|
||||
return new Punishment(
|
||||
expiration != null ? expiration.toInstant() : null,
|
||||
ComponentUtil.toAPI(BukkitComponentSerializer.legacy().deserialize(ban.getReason())),
|
||||
ComponentUtil.toAPI(BukkitComponentSerializer.legacy().deserialize(ban.getSource()))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> addBan(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable String reason, @NotNull String punisher) {
|
||||
public CompletableFuture<Void> addBan(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable MinecraftComponent reason, @NotNull MinecraftComponent punisher) {
|
||||
String reasonLegacy = reason != null ? BukkitComponentSerializer.legacy().serialize(ComponentUtil.fromAPI(reason)) : null;
|
||||
String punisherLegacy = BukkitComponentSerializer.legacy().serialize(ComponentUtil.fromAPI(punisher));
|
||||
if (PaperBanList.IS_AVAILABLE) {
|
||||
PaperBanList.addBan(discordSRV.server(), playerUUID, until, reason, punisher);
|
||||
PaperBanList.addBan(discordSRV.server(), playerUUID, until, reasonLegacy, punisherLegacy);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
BanList banList = discordSRV.server().getBanList(BanList.Type.NAME);
|
||||
return discordSRV.playerProvider().lookupOfflinePlayer(playerUUID).thenApply(offlinePlayer -> {
|
||||
banList.addBan(offlinePlayer.username(), reason, until != null ? Date.from(until) : null, punisher);
|
||||
banList.addBan(offlinePlayer.username(), reasonLegacy, until != null ? Date.from(until) : null, punisherLegacy);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@ -105,4 +126,17 @@ public class BukkitBanModule extends AbstractModule<BukkitDiscordSRV> implements
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> kickPlayer(@NotNull DiscordSRVPlayer srvPlayer, @NotNull MinecraftComponent message) {
|
||||
Player player = discordSRV.server().getPlayer(srvPlayer.uniqueId());
|
||||
if (player == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
return discordSRV.scheduler().executeOnMainThread(
|
||||
player,
|
||||
() -> player.kickPlayer(BukkitComponentSerializer.legacy().serialize(ComponentUtil.fromAPI(message)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -107,15 +107,20 @@ public class EssentialsXIntegration
|
||||
|
||||
@Override
|
||||
public CompletableFuture<com.discordsrv.api.punishment.Punishment> getMute(@NotNull UUID playerUUID) {
|
||||
return getUser(playerUUID).thenApply(user -> new Punishment(Instant.ofEpochMilli(user.getMuteTimeout()), user.getMuteReason(), null));
|
||||
return getUser(playerUUID).thenApply(user -> new Punishment(
|
||||
Instant.ofEpochMilli(user.getMuteTimeout()),
|
||||
ComponentUtil.toAPI(BukkitComponentSerializer.legacy().deserialize(user.getMuteReason())),
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> addMute(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable String reason, @NotNull String punisher) {
|
||||
public CompletableFuture<Void> addMute(@NotNull UUID playerUUID, @Nullable Instant until, @Nullable MinecraftComponent reason, @NotNull MinecraftComponent punisher) {
|
||||
String reasonLegacy = reason != null ? BukkitComponentSerializer.legacy().serialize(ComponentUtil.fromAPI(reason)) : null;
|
||||
return getUser(playerUUID).thenApply(user -> {
|
||||
user.setMuted(true);
|
||||
user.setMuteTimeout(until != null ? until.toEpochMilli() : 0);
|
||||
user.setMuteReason(reason);
|
||||
user.setMuteReason(reasonLegacy);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
@ -54,9 +55,20 @@ public class BukkitPlayerProvider extends ServerPlayerProvider<BukkitPlayer, Buk
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||
return;
|
||||
}
|
||||
addPlayer(event.getPlayer(), false);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (player(event.getPlayer()) == null) {
|
||||
// The player should already be added by this point, but just in case
|
||||
addPlayer(event.getPlayer(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void addPlayer(Player player, boolean initial) {
|
||||
addPlayer(player.getUniqueId(), new BukkitPlayer(discordSRV, player), initial);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package com.discordsrv.common.bansync;
|
||||
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
|
||||
import com.discordsrv.api.event.bus.Subscribe;
|
||||
import com.discordsrv.api.event.events.linking.AccountLinkedEvent;
|
||||
@ -26,6 +27,7 @@ import com.discordsrv.api.punishment.Punishment;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.bansync.enums.BanSyncCause;
|
||||
import com.discordsrv.common.bansync.enums.BanSyncResult;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
import com.discordsrv.common.config.main.BanSyncConfig;
|
||||
import com.discordsrv.common.future.util.CompletableFutureUtil;
|
||||
import com.discordsrv.common.player.IPlayer;
|
||||
@ -33,13 +35,14 @@ import com.discordsrv.common.someone.Someone;
|
||||
import com.discordsrv.common.sync.AbstractSyncModule;
|
||||
import com.discordsrv.common.sync.SyncFail;
|
||||
import com.discordsrv.common.sync.cause.GenericSyncCauses;
|
||||
import com.discordsrv.common.sync.result.ISyncResult;
|
||||
import com.discordsrv.common.sync.enums.SyncDirection;
|
||||
import com.discordsrv.common.sync.result.GenericSyncResults;
|
||||
import com.discordsrv.common.sync.result.ISyncResult;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.audit.ActionType;
|
||||
import net.dv8tion.jda.api.audit.AuditLogEntry;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.UserSnowflake;
|
||||
import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent;
|
||||
@ -57,7 +60,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig, Void, Long, Punishment> {
|
||||
public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig, BanSyncModule.Game, Long, Punishment> {
|
||||
|
||||
private final Map<Long, PunishmentEvent> events = new ConcurrentHashMap<>();
|
||||
|
||||
@ -65,22 +68,13 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
super(discordSRV, "BAN_SYNC");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
if (discordSRV.config().banSync.serverId == 0) {
|
||||
//return false; // TODO
|
||||
}
|
||||
|
||||
return super.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Collection<DiscordGatewayIntent> requiredIntents() {
|
||||
return Collections.singleton(DiscordGatewayIntent.GUILD_MODERATION);
|
||||
}
|
||||
|
||||
public void notifyBanned(IPlayer player, @Nullable Punishment punishment) {
|
||||
gameChanged(BanSyncCause.PLAYER_BANNED, Someone.of(player.uniqueId()), null, punishment);
|
||||
gameChanged(BanSyncCause.PLAYER_BANNED, Someone.of(player.uniqueId()), Game.INSTANCE, punishment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -95,12 +89,12 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
|
||||
@Override
|
||||
public String gameTerm() {
|
||||
return "ban";
|
||||
return "game ban";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String discordTerm() {
|
||||
return "ban";
|
||||
return "Discord ban";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,17 +109,19 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
return (oneActive == twoActive) ? GenericSyncResults.both(oneActive) : null;
|
||||
}
|
||||
|
||||
private PunishmentEvent upsertEvent(long userId, boolean newState) {
|
||||
return events.computeIfAbsent(userId, key -> new PunishmentEvent(userId, newState));
|
||||
private PunishmentEvent upsertEvent(long guildId, long userId, boolean newState) {
|
||||
return events.computeIfAbsent(userId, key -> new PunishmentEvent(guildId, userId, newState));
|
||||
}
|
||||
|
||||
private class PunishmentEvent {
|
||||
|
||||
private final long guildId;
|
||||
private final long userId;
|
||||
private final boolean newState;
|
||||
private final Future<?> future;
|
||||
|
||||
public PunishmentEvent(long userId, boolean newState) {
|
||||
public PunishmentEvent(long guildId, long userId, boolean newState) {
|
||||
this.guildId = guildId;
|
||||
this.userId = userId;
|
||||
this.newState = newState;
|
||||
|
||||
@ -139,25 +135,26 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
if (newState && punishment == null) {
|
||||
punishment = new Punishment(null, null, null);
|
||||
punishment = Punishment.UNKNOWN;
|
||||
}
|
||||
gameChanged(
|
||||
discordChanged(
|
||||
GenericSyncCauses.LINK,
|
||||
Someone.of(userId),
|
||||
null,
|
||||
guildId,
|
||||
punishment
|
||||
);
|
||||
events.remove(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGuildBan(GuildBanEvent event) {
|
||||
upsertEvent(event.getUser().getIdLong(), true);
|
||||
upsertEvent(event.getGuild().getIdLong(), event.getUser().getIdLong(), true);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGuildUnban(GuildUnbanEvent event) {
|
||||
upsertEvent(event.getUser().getIdLong(), false);
|
||||
upsertEvent(event.getGuild().getIdLong(), event.getUser().getIdLong(), false);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@ -168,18 +165,36 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
return;
|
||||
}
|
||||
|
||||
long punisherId = entry.getUserIdLong();
|
||||
User punisher = event.getJDA().getUserById(punisherId);
|
||||
String punishmentName = punisher != null ? punisher.getName() : Long.toUnsignedString(punisherId);
|
||||
Guild guild = event.getGuild();
|
||||
long guildId = guild.getIdLong();
|
||||
List<BanSyncConfig> configs = configsForDiscord.get(guildId);
|
||||
BanSyncConfig config = configs.isEmpty() ? null : configs.get(0);
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long punisherId = entry.getUserIdLong();
|
||||
|
||||
// This user should be cacheable as they just made an auditable action
|
||||
User punisher = event.getJDA().getUserById(punisherId);
|
||||
Member punisherMember = punisher != null ? guild.getMember(punisher) : null;
|
||||
|
||||
MinecraftComponent punisherName = discordSRV.componentFactory().textBuilder(config.gamePunisherFormat)
|
||||
.addContext(punisher, punisherMember)
|
||||
.applyPlaceholderService()
|
||||
.build();
|
||||
|
||||
Punishment punishment = new Punishment(null, entry.getReason(), punishmentName);
|
||||
long bannedUserId = entry.getTargetIdLong();
|
||||
|
||||
// Apply punishments instantly when audit log events arrive.
|
||||
if (actionType == ActionType.BAN) {
|
||||
upsertEvent(bannedUserId, true).applyPunishment(punishment);
|
||||
upsertEvent(guildId, bannedUserId, true).applyPunishment(new Punishment(
|
||||
null,
|
||||
ComponentUtil.fromPlain(entry.getReason()),
|
||||
punisherName
|
||||
));
|
||||
} else {
|
||||
upsertEvent(bannedUserId, false).applyPunishment(punishment);
|
||||
upsertEvent(guildId, bannedUserId, false).applyPunishment(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,7 +232,7 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
private Punishment punishment(Guild.Ban ban) {
|
||||
return ban != null ? new Punishment(null, ban.getReason(), ban.getUser().getName()) : null;
|
||||
return ban != null ? new Punishment(null, ComponentUtil.fromPlain(ban.getReason()), null) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -250,8 +265,7 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
UserSnowflake snowflake = UserSnowflake.fromId(userId);
|
||||
if (newState != null) {
|
||||
return guild.ban(snowflake, config.discordMessageHoursToDelete, TimeUnit.HOURS)
|
||||
.reason(discordSRV.placeholderService().replacePlaceholders(config.discordBanReasonFormat,
|
||||
newState))
|
||||
.reason(discordSRV.placeholderService().replacePlaceholders(config.discordBanReasonFormat, newState))
|
||||
.submit()
|
||||
.thenApply(v -> GenericSyncResults.ADD_DISCORD);
|
||||
} else {
|
||||
@ -274,15 +288,37 @@ public class BanSyncModule extends AbstractSyncModule<DiscordSRV, BanSyncConfig,
|
||||
}
|
||||
|
||||
if (newState != null) {
|
||||
String reason = discordSRV.placeholderService().replacePlaceholders(config.gameBanReasonFormat,
|
||||
newState);
|
||||
String punisher = discordSRV.placeholderService().replacePlaceholders(config.gamePunisherFormat,
|
||||
newState);
|
||||
MinecraftComponent reason = discordSRV.componentFactory().textBuilder(config.gameBanReasonFormat)
|
||||
.addContext(newState)
|
||||
.applyPlaceholderService()
|
||||
.build();
|
||||
MinecraftComponent punisher = discordSRV.componentFactory().textBuilder(config.gamePunisherFormat)
|
||||
.addContext(newState)
|
||||
.applyPlaceholderService()
|
||||
.build();
|
||||
return bans.addBan(playerUUID, null, reason, punisher)
|
||||
.thenCompose(v -> {
|
||||
IPlayer player = discordSRV.playerProvider().player(playerUUID);
|
||||
if (player == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
MinecraftComponent kickMessage = discordSRV.componentFactory()
|
||||
.textBuilder(config.gameKickReason)
|
||||
.addContext(newState)
|
||||
.applyPlaceholderService()
|
||||
.build();
|
||||
|
||||
return bans.kickPlayer(player, kickMessage);
|
||||
})
|
||||
.thenApply(v -> GenericSyncResults.ADD_GAME);
|
||||
} else {
|
||||
return bans.removeBan(playerUUID).thenApply(v -> GenericSyncResults.REMOVE_GAME);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Game {
|
||||
INSTANCE
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -54,6 +54,14 @@ public final class ComponentUtil {
|
||||
return component.asPlainString().isEmpty();
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
public static MinecraftComponent fromPlain(@Nullable String plainText) {
|
||||
if (plainText == null) {
|
||||
return null;
|
||||
}
|
||||
return toAPI(Component.text(plainText));
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
public static MinecraftComponent toAPI(Component component) {
|
||||
if (component == null) {
|
||||
|
@ -18,21 +18,25 @@
|
||||
|
||||
package com.discordsrv.common.config.main;
|
||||
|
||||
import com.discordsrv.common.bansync.BanSyncModule;
|
||||
import com.discordsrv.common.config.main.generic.AbstractSyncConfig;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||
|
||||
@ConfigSerializable
|
||||
public class BanSyncConfig extends AbstractSyncConfig<BanSyncConfig, Void, Long> {
|
||||
public class BanSyncConfig extends AbstractSyncConfig<BanSyncConfig, BanSyncModule.Game, Long> {
|
||||
|
||||
@Comment("The id for the Discord server where the bans should be synced from/to")
|
||||
public long serverId = 0L;
|
||||
|
||||
@Comment("The reason applied when creating new bans in Minecraft")
|
||||
public String gameBanReasonFormat = "%reason%";
|
||||
public String gameBanReasonFormat = "%punishment_reason%";
|
||||
|
||||
@Comment("The punisher applied when creating new bans in Minecraft")
|
||||
public String gamePunisherFormat = "@%user_effective_server_name%";
|
||||
public String gamePunisherFormat = "%user_color%@%user_name%";
|
||||
|
||||
@Comment("The kick reason when a ban is applied to a online player")
|
||||
public String gameKickReason = "&cYou have been banned for &f%punishment_reason% &cby &f%punishment_punisher%";
|
||||
|
||||
@Comment("The reason applied when creating new bans in Discord")
|
||||
public String discordBanReasonFormat = "Banned by %punishment_punisher% in Minecraft for %punishment_reason%, ends: %punishment_until:'YYYY-MM-dd HH:mm:ss zzz'|text:'Never'%";
|
||||
@ -52,8 +56,8 @@ public class BanSyncConfig extends AbstractSyncConfig<BanSyncConfig, Void, Long>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void gameId() {
|
||||
return null;
|
||||
public BanSyncModule.Game gameId() {
|
||||
return BanSyncModule.Game.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,22 +93,6 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
boolean any = false;
|
||||
for (GroupSyncConfig.PairConfig pair : discordSRV.config().groupSync.pairs) {
|
||||
if (pair.isSet()) {
|
||||
any = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!any) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.isEnabled();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onDebugGenerate(DebugGenerateEvent event) {
|
||||
StringBuilder builder = new StringBuilder("Active pairs:");
|
||||
@ -251,6 +235,8 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ISyncResult> applyDiscord(GroupSyncConfig.PairConfig config, long userId, Boolean newState) {
|
||||
boolean stateToApply = newState != null && newState;
|
||||
|
||||
DiscordRole role = discordSRV.discordAPI().getRoleById(config.roleId);
|
||||
if (role == null) {
|
||||
return CompletableFutureUtil.failed(new SyncFail(GroupSyncResult.ROLE_DOESNT_EXIST));
|
||||
@ -258,11 +244,11 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
|
||||
Map<Long, Boolean> expected = expectedDiscordChanges.get(userId, key -> new ConcurrentHashMap<>());
|
||||
if (expected != null) {
|
||||
expected.put(config.roleId, newState);
|
||||
expected.put(config.roleId, stateToApply);
|
||||
}
|
||||
|
||||
return role.getGuild().retrieveMemberById(userId)
|
||||
.thenCompose(member -> newState
|
||||
.thenCompose(member -> stateToApply
|
||||
? member.addRole(role).thenApply(v -> (ISyncResult) GenericSyncResults.ADD_DISCORD)
|
||||
: member.removeRole(role).thenApply(v -> GenericSyncResults.REMOVE_DISCORD)
|
||||
).whenComplete((r, t) -> {
|
||||
@ -275,13 +261,15 @@ public class GroupSyncModule extends AbstractSyncModule<DiscordSRV, GroupSyncCon
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ISyncResult> applyGame(GroupSyncConfig.PairConfig config, UUID playerUUID, Boolean newState) {
|
||||
boolean stateToApply = newState != null && newState;
|
||||
|
||||
Map<String, Boolean> expected = expectedMinecraftChanges.get(playerUUID, key -> new ConcurrentHashMap<>());
|
||||
if (expected != null) {
|
||||
expected.put(config.groupName, newState);
|
||||
expected.put(config.groupName, stateToApply);
|
||||
}
|
||||
|
||||
CompletableFuture<ISyncResult> future =
|
||||
newState
|
||||
stateToApply
|
||||
? addGroup(playerUUID, config).thenApply(v -> GenericSyncResults.ADD_GAME)
|
||||
: removeGroup(playerUUID, config).thenApply(v -> GenericSyncResults.REMOVE_GAME);
|
||||
return future.exceptionally(t -> {
|
||||
|
@ -209,7 +209,7 @@ public class DiscordChatMessageModule extends AbstractModule<DiscordSRV> {
|
||||
Component messageComponent = DiscordSRVMinecraftRenderer.getWithContext(guild, chatConfig, () ->
|
||||
discordSRV.componentFactory().minecraftSerializer().serialize(finalMessage));
|
||||
|
||||
if (discordSRV.componentFactory().plainSerializer().serialize(messageComponent).trim().isEmpty() && !attachments) {
|
||||
if (ComponentUtil.isEmpty(messageComponent) && !attachments) {
|
||||
// Check empty-ness again after rendering
|
||||
return;
|
||||
}
|
||||
|
@ -32,9 +32,10 @@ import com.discordsrv.common.someone.Someone;
|
||||
import com.discordsrv.common.sync.cause.GenericSyncCauses;
|
||||
import com.discordsrv.common.sync.cause.ISyncCause;
|
||||
import com.discordsrv.common.sync.enums.SyncDirection;
|
||||
import com.discordsrv.common.sync.result.GenericSyncResults;
|
||||
import com.discordsrv.common.sync.enums.SyncSide;
|
||||
import com.discordsrv.common.sync.result.GenericSyncResults;
|
||||
import com.discordsrv.common.sync.result.ISyncResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
@ -63,8 +64,8 @@ public abstract class AbstractSyncModule<
|
||||
> extends AbstractModule<DT> {
|
||||
|
||||
protected final Map<C, Future<?>> syncs = new LinkedHashMap<>();
|
||||
private final Map<G, List<C>> configsForGame = new ConcurrentHashMap<>();
|
||||
private final Map<D, List<C>> configsForDiscord = new ConcurrentHashMap<>();
|
||||
protected final Map<G, List<C>> configsForGame = new ConcurrentHashMap<>();
|
||||
protected final Map<D, List<C>> configsForDiscord = new ConcurrentHashMap<>();
|
||||
|
||||
public AbstractSyncModule(DT discordSRV, String loggerName) {
|
||||
super(discordSRV, new NamedLogger(discordSRV, loggerName));
|
||||
@ -82,6 +83,22 @@ public abstract class AbstractSyncModule<
|
||||
*/
|
||||
protected abstract List<C> configs();
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
boolean any = false;
|
||||
for (C config : configs()) {
|
||||
if (config.isSet()) {
|
||||
any = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!any) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Consumer<DiscordSRVApi.ReloadResult> resultConsumer) {
|
||||
synchronized (syncs) {
|
||||
@ -182,9 +199,9 @@ public abstract class AbstractSyncModule<
|
||||
* @param newState the newState to apply
|
||||
* @return a future with the result of the synchronization
|
||||
*/
|
||||
protected abstract CompletableFuture<ISyncResult> applyDiscord(C config, long userId, S newState);
|
||||
protected abstract CompletableFuture<ISyncResult> applyDiscord(C config, long userId, @Nullable S newState);
|
||||
|
||||
protected CompletableFuture<ISyncResult> applyDiscordIfDoesNotMatch(C config, long userId, S newState) {
|
||||
protected CompletableFuture<ISyncResult> applyDiscordIfDoesNotMatch(C config, long userId, @Nullable S newState) {
|
||||
return getDiscord(config, userId).thenCompose(currentState -> {
|
||||
ISyncResult result = doesStateMatch(newState, currentState);
|
||||
if (result != null) {
|
||||
@ -203,9 +220,9 @@ public abstract class AbstractSyncModule<
|
||||
* @param newState the newState to apply
|
||||
* @return a future with the result of the synchronization
|
||||
*/
|
||||
protected abstract CompletableFuture<ISyncResult> applyGame(C config, UUID playerUUID, S newState);
|
||||
protected abstract CompletableFuture<ISyncResult> applyGame(C config, UUID playerUUID, @Nullable S newState);
|
||||
|
||||
protected CompletableFuture<ISyncResult> applyGameIfDoesNotMatch(C config, UUID playerUUID, S newState) {
|
||||
protected CompletableFuture<ISyncResult> applyGameIfDoesNotMatch(C config, UUID playerUUID, @Nullable S newState) {
|
||||
return getGame(config, playerUUID).thenCompose(currentState -> {
|
||||
ISyncResult result = doesStateMatch(currentState, newState);
|
||||
if (result != null) {
|
||||
@ -216,7 +233,7 @@ public abstract class AbstractSyncModule<
|
||||
});
|
||||
}
|
||||
|
||||
protected CompletableFuture<SyncSummary<C>> discordChanged(ISyncCause cause, Someone someone, D discordId, S newState) {
|
||||
protected CompletableFuture<SyncSummary<C>> discordChanged(ISyncCause cause, Someone someone, D discordId, @Nullable S newState) {
|
||||
List<C> gameConfigs = configsForDiscord.get(discordId);
|
||||
if (gameConfigs == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
@ -264,7 +281,7 @@ public abstract class AbstractSyncModule<
|
||||
});
|
||||
}
|
||||
|
||||
protected CompletableFuture<SyncSummary<C>> gameChanged(ISyncCause cause, Someone someone, G gameId, S newState) {
|
||||
protected CompletableFuture<SyncSummary<C>> gameChanged(ISyncCause cause, Someone someone, @NotNull G gameId, @Nullable S newState) {
|
||||
List<C> discordConfigs = configsForGame.get(gameId);
|
||||
if (discordConfigs == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
|
Loading…
Reference in New Issue
Block a user