mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-12-28 17:37:52 +01:00
Convert resync to a combined command
This commit is contained in:
parent
3e3438f0d2
commit
4613e821e2
@ -2,6 +2,7 @@ package com.discordsrv.common.command.combined.abstraction;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public interface CommandExecution {
|
||||
|
||||
@ -12,7 +13,12 @@ public interface CommandExecution {
|
||||
default void send(Text... texts) {
|
||||
send(Arrays.asList(texts));
|
||||
}
|
||||
void send(Collection<Text> texts);
|
||||
|
||||
default void send(Collection<Text> texts) {
|
||||
send(texts, Collections.emptyList());
|
||||
}
|
||||
|
||||
void send(Collection<Text> texts, Collection<Text> extra);
|
||||
|
||||
void runAsync(Runnable runnable);
|
||||
}
|
||||
|
@ -35,19 +35,23 @@ public class DiscordCommandExecution implements CommandExecution {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Collection<Text> texts) {
|
||||
public void send(Collection<Text> texts, Collection<Text> extra) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
EnumMap<Text.Formatting, Boolean> formats = new EnumMap<>(Text.Formatting.class);
|
||||
|
||||
for (Text text : texts) {
|
||||
if (StringUtils.isEmpty(text.content())) continue;
|
||||
|
||||
verifyStyle(builder, formats, text);
|
||||
builder.append(text.content());
|
||||
render(text, builder, formats);
|
||||
}
|
||||
|
||||
verifyStyle(builder, formats, null);
|
||||
|
||||
if (!extra.isEmpty()) {
|
||||
builder.append("\n\n");
|
||||
for (Text text : extra) {
|
||||
render(text, builder, formats);
|
||||
}
|
||||
verifyStyle(builder, formats, null);
|
||||
}
|
||||
|
||||
InteractionHook interactionHook = hook.get();
|
||||
boolean ephemeral = isEphemeral.get();
|
||||
if (interactionHook != null) {
|
||||
@ -57,6 +61,13 @@ public class DiscordCommandExecution implements CommandExecution {
|
||||
}
|
||||
}
|
||||
|
||||
private void render(Text text, StringBuilder builder, EnumMap<Text.Formatting, Boolean> formats) {
|
||||
if (StringUtils.isEmpty(text.content())) return;
|
||||
|
||||
verifyStyle(builder, formats, text);
|
||||
builder.append(text.content());
|
||||
}
|
||||
|
||||
private void verifyStyle(StringBuilder builder, EnumMap<Text.Formatting, Boolean> formats, Text text) {
|
||||
for (Text.Formatting format : Text.Formatting.values()) {
|
||||
boolean is = formats.computeIfAbsent(format, key -> false);
|
||||
|
@ -5,6 +5,7 @@ import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -31,7 +32,15 @@ public class GameCommandExecution implements CommandExecution {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Collection<Text> texts) {
|
||||
public void send(Collection<Text> texts, Collection<Text> extra) {
|
||||
TextComponent.Builder builder = render(texts);
|
||||
if (!extra.isEmpty()) {
|
||||
builder.hoverEvent(HoverEvent.showText(render(extra)));
|
||||
}
|
||||
sender.sendMessage(builder);
|
||||
}
|
||||
|
||||
private TextComponent.Builder render(Collection<Text> texts) {
|
||||
TextComponent.Builder builder = Component.text();
|
||||
for (Text text : texts) {
|
||||
builder.append(
|
||||
@ -40,7 +49,7 @@ public class GameCommandExecution implements CommandExecution {
|
||||
.decorations(text.gameFormatting(), true)
|
||||
);
|
||||
}
|
||||
sender.sendMessage(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,118 @@
|
||||
package com.discordsrv.common.command.combined.commands;
|
||||
|
||||
import com.discordsrv.api.discord.entity.interaction.command.Command;
|
||||
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.abstraction.CombinedCommand;
|
||||
import com.discordsrv.common.command.combined.abstraction.CommandExecution;
|
||||
import com.discordsrv.common.command.combined.abstraction.GameCommandExecution;
|
||||
import com.discordsrv.common.command.combined.abstraction.Text;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.future.util.CompletableFutureUtil;
|
||||
import com.discordsrv.common.groupsync.GroupSyncModule;
|
||||
import com.discordsrv.common.groupsync.enums.GroupSyncCause;
|
||||
import com.discordsrv.common.groupsync.enums.GroupSyncResult;
|
||||
import com.discordsrv.common.player.IPlayer;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ResyncCommand extends CombinedCommand {
|
||||
|
||||
private static ResyncCommand INSTANCE;
|
||||
private static GameCommand GAME;
|
||||
private static Command DISCORD;
|
||||
|
||||
private static ResyncCommand getInstance(DiscordSRV discordSRV) {
|
||||
return INSTANCE != null ? INSTANCE : (INSTANCE = new ResyncCommand(discordSRV));
|
||||
}
|
||||
|
||||
public static GameCommand getGame(DiscordSRV discordSRV) {
|
||||
if (GAME == null) {
|
||||
ResyncCommand command = getInstance(discordSRV);
|
||||
GAME = GameCommand.literal("resync")
|
||||
.requiredPermission("discordsrv.admin.resync")
|
||||
.executor(command);
|
||||
}
|
||||
|
||||
return GAME;
|
||||
}
|
||||
|
||||
public static Command getDiscord(DiscordSRV discordSRV) {
|
||||
if (DISCORD == null) {
|
||||
ResyncCommand command = getInstance(discordSRV);
|
||||
DISCORD = Command.chatInput(ComponentIdentifier.of("DiscordSRV", "resync"), "resync", "Perform group resync for online players")
|
||||
.setEventHandler(command)
|
||||
.build();
|
||||
}
|
||||
|
||||
return DISCORD;
|
||||
}
|
||||
|
||||
public ResyncCommand(DiscordSRV discordSRV) {
|
||||
super(discordSRV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandExecution execution) {
|
||||
GroupSyncModule module = discordSRV.getModule(GroupSyncModule.class);
|
||||
if (module == null) {
|
||||
execution.send(new Text("GroupSync module has not initialized correctly.").withGameColor(NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
if (module.noPermissionProvider()) {
|
||||
execution.send(new Text("No permission provider available.").withGameColor(NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
if (execution instanceof GameCommandExecution) {
|
||||
// Acknowledge for in-game runs
|
||||
execution.send(new Text("Synchronizing online players").withGameColor(NamedTextColor.GRAY));
|
||||
}
|
||||
|
||||
execution.runAsync(() -> {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
CompletableFutureUtil.combine(resyncOnlinePlayers(module))
|
||||
.whenComplete((results, t) -> {
|
||||
EnumMap<GroupSyncResult, AtomicInteger> resultCounts = new EnumMap<>(GroupSyncResult.class);
|
||||
int total = 0;
|
||||
for (List<GroupSyncResult> result : results) {
|
||||
for (GroupSyncResult singleResult : result) {
|
||||
total++;
|
||||
resultCounts.computeIfAbsent(singleResult, key -> new AtomicInteger(0)).getAndIncrement();
|
||||
}
|
||||
}
|
||||
String resultHover = resultCounts.entrySet().stream()
|
||||
.map(entry -> entry.getKey().toString() + ": " + entry.getValue().get())
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
long time = System.currentTimeMillis() - startTime;
|
||||
execution.send(
|
||||
Arrays.asList(
|
||||
new Text("Synchronization completed in ").withGameColor(NamedTextColor.GRAY),
|
||||
new Text(time + "ms").withGameColor(NamedTextColor.GREEN).withFormatting(Text.Formatting.BOLD),
|
||||
new Text(" (").withGameColor(NamedTextColor.GRAY),
|
||||
new Text(total + " result" + (total == 1 ? "" : "s"))
|
||||
.withGameColor(NamedTextColor.GREEN)
|
||||
.withDiscordFormatting(Text.Formatting.BOLD),
|
||||
new Text(")").withGameColor(NamedTextColor.GRAY)
|
||||
),
|
||||
total > 0 ? Collections.singletonList(new Text(resultHover)) : Collections.emptyList()
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private List<CompletableFuture<List<GroupSyncResult>>> resyncOnlinePlayers(GroupSyncModule module) {
|
||||
List<CompletableFuture<List<GroupSyncResult>>> futures = new ArrayList<>();
|
||||
for (IPlayer player : discordSRV.playerProvider().allPlayers()) {
|
||||
futures.add(module.resync(player.uniqueId(), GroupSyncCause.COMMAND));
|
||||
}
|
||||
return futures;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import com.discordsrv.api.discord.entity.interaction.command.Command;
|
||||
import com.discordsrv.api.discord.entity.interaction.component.ComponentIdentifier;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.commands.DebugCommand;
|
||||
import com.discordsrv.common.command.combined.commands.ResyncCommand;
|
||||
import com.discordsrv.common.command.combined.commands.VersionCommand;
|
||||
|
||||
public class DiscordSRVDiscordCommand {
|
||||
@ -17,6 +18,7 @@ public class DiscordSRVDiscordCommand {
|
||||
INSTANCE = Command.chatInput(IDENTIFIER, "discordsrv", "DiscordSRV related commands")
|
||||
.addSubCommand(DebugCommand.getDiscord(discordSRV))
|
||||
.addSubCommand(VersionCommand.getDiscord(discordSRV))
|
||||
.addSubCommand(ResyncCommand.getDiscord(discordSRV))
|
||||
.setGuildOnly(false)
|
||||
.setDefaultPermission(Command.DefaultPermission.ADMINISTRATOR)
|
||||
.build();
|
||||
|
@ -21,11 +21,13 @@ package com.discordsrv.common.command.game.commands;
|
||||
import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.combined.commands.DebugCommand;
|
||||
import com.discordsrv.common.command.combined.commands.ResyncCommand;
|
||||
import com.discordsrv.common.command.combined.commands.VersionCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandExecutor;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.*;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.BroadcastCommand;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.LinkCommand;
|
||||
import com.discordsrv.common.command.game.commands.subcommand.reload.ReloadCommand;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
import com.discordsrv.common.component.util.ComponentUtil;
|
||||
@ -52,7 +54,7 @@ public class DiscordSRVGameCommand implements GameCommandExecutor {
|
||||
.then(DebugCommand.getGame(discordSRV))
|
||||
.then(LinkCommand.get(discordSRV))
|
||||
.then(ReloadCommand.get(discordSRV))
|
||||
.then(ResyncCommand.get(discordSRV))
|
||||
.then(ResyncCommand.getGame(discordSRV))
|
||||
.then(VersionCommand.getGame(discordSRV))
|
||||
);
|
||||
}
|
||||
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2023 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.command.game.commands.subcommand;
|
||||
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommand;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandArguments;
|
||||
import com.discordsrv.common.command.game.abstraction.GameCommandExecutor;
|
||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||
import com.discordsrv.common.future.util.CompletableFutureUtil;
|
||||
import com.discordsrv.common.groupsync.GroupSyncModule;
|
||||
import com.discordsrv.common.groupsync.enums.GroupSyncCause;
|
||||
import com.discordsrv.common.groupsync.enums.GroupSyncResult;
|
||||
import com.discordsrv.common.player.IPlayer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ResyncCommand implements GameCommandExecutor {
|
||||
|
||||
private static GameCommand INSTANCE;
|
||||
|
||||
public static GameCommand get(DiscordSRV discordSRV) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = GameCommand.literal("resync")
|
||||
.requiredPermission("discordsrv.admin.resync")
|
||||
.executor(new ResyncCommand(discordSRV));
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
|
||||
public ResyncCommand(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ICommandSender sender, GameCommandArguments arguments) {
|
||||
GroupSyncModule module = discordSRV.getModule(GroupSyncModule.class);
|
||||
if (module == null) {
|
||||
sender.sendMessage(Component.text("GroupSync module has not initialized correctly.", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(Component.text("Synchronizing online players", NamedTextColor.GRAY));
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
CompletableFutureUtil.combine(resyncOnlinePlayers(module))
|
||||
.whenComplete((results, t) -> {
|
||||
EnumMap<GroupSyncResult, AtomicInteger> resultCounts = new EnumMap<>(GroupSyncResult.class);
|
||||
int total = 0;
|
||||
for (List<GroupSyncResult> result : results) {
|
||||
for (GroupSyncResult singleResult : result) {
|
||||
total++;
|
||||
resultCounts.computeIfAbsent(singleResult, key -> new AtomicInteger(0)).getAndIncrement();
|
||||
}
|
||||
}
|
||||
String resultHover;
|
||||
if (total == 0) {
|
||||
resultHover = "Nothing done";
|
||||
} else {
|
||||
resultHover = total + " result" + (total == 1 ? "" : "s") + ":\n\n" +
|
||||
resultCounts.entrySet().stream()
|
||||
.map(entry -> entry.getKey().toString() + ": " + entry.getValue().get())
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
long time = System.currentTimeMillis() - startTime;
|
||||
sender.sendMessage(
|
||||
Component.text("Synchronization completed in ", NamedTextColor.GRAY)
|
||||
.append(Component.text(time + "ms", NamedTextColor.GREEN))
|
||||
.append(Component.text(" (", NamedTextColor.GRAY))
|
||||
.append(Component.text(total, NamedTextColor.GREEN))
|
||||
.append(Component.text(" result" + (total == 1 ? "" : "s") + ")", NamedTextColor.GRAY))
|
||||
.hoverEvent(HoverEvent.showText(Component.text(resultHover)))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private List<CompletableFuture<List<GroupSyncResult>>> resyncOnlinePlayers(GroupSyncModule module) {
|
||||
List<CompletableFuture<List<GroupSyncResult>>> futures = new ArrayList<>();
|
||||
for (IPlayer player : discordSRV.playerProvider().allPlayers()) {
|
||||
futures.add(module.resync(player.uniqueId(), GroupSyncCause.COMMAND));
|
||||
}
|
||||
return futures;
|
||||
}
|
||||
}
|
@ -202,7 +202,7 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
|
||||
return groupsContext == null ? discordSRV.getModule(PermissionDataProvider.Groups.class) : groupsContext;
|
||||
}
|
||||
|
||||
private boolean noPermissionProvider() {
|
||||
public boolean noPermissionProvider() {
|
||||
PermissionDataProvider.Groups groups = getPermissionProvider();
|
||||
return groups == null || !groups.isEnabled();
|
||||
}
|
||||
@ -276,8 +276,10 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
|
||||
}
|
||||
|
||||
public Collection<CompletableFuture<GroupSyncResult>> resync(UUID player, long userId, GroupSyncCause cause) {
|
||||
if (noPermissionProvider() || (discordSRV.playerProvider().player(player) == null && !supportsOffline())) {
|
||||
return Collections.emptyList();
|
||||
if (noPermissionProvider()) {
|
||||
return Collections.singletonList(CompletableFuture.completedFuture(GroupSyncResult.NO_PERMISSION_PROVIDER));
|
||||
} else if (discordSRV.playerProvider().player(player) == null && !supportsOffline()) {
|
||||
return Collections.singletonList(CompletableFuture.completedFuture(GroupSyncResult.PERMISSION_PROVIDER_NO_OFFLINE_SUPPORT));
|
||||
}
|
||||
|
||||
Map<GroupSyncConfig.PairConfig, CompletableFuture<GroupSyncResult>> futures = new LinkedHashMap<>();
|
||||
|
@ -37,6 +37,8 @@ public enum GroupSyncResult {
|
||||
NOT_A_GUILD_MEMBER("User is not part of the server the role is in"),
|
||||
PERMISSION_BACKEND_FAIL_CHECK("Failed to check group status, error printed"),
|
||||
UPDATE_FAILED("Failed to modify role/group, error printed"),
|
||||
NO_PERMISSION_PROVIDER("No permission provider"),
|
||||
PERMISSION_PROVIDER_NO_OFFLINE_SUPPORT("Permission provider doesn't support offline players"),
|
||||
|
||||
;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user