mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-11-01 08:39:31 +01:00
Fix group sync not finding members that are not cached, enable chunking by default. Add GroupSyncResult for being able to interact with role
This commit is contained in:
parent
67c609aa4f
commit
37476fd8f9
@ -54,6 +54,13 @@ public interface DiscordGuild extends JDAEntity<Guild>, Snowflake {
|
|||||||
@Placeholder("server_member_count")
|
@Placeholder("server_member_count")
|
||||||
int getMemberCount();
|
int getMemberCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bot's membership in the server.
|
||||||
|
* @return the connected bot's member
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
DiscordGuildMember getSelfMember();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a Discord guild member from Discord by id.
|
* Retrieves a Discord guild member from Discord by id.
|
||||||
* @param id the id for the Discord guild member
|
* @param id the id for the Discord guild member
|
||||||
|
@ -76,6 +76,13 @@ public interface DiscordGuildMember extends JDAEntity<Member>, Mentionable {
|
|||||||
*/
|
*/
|
||||||
boolean hasRole(@NotNull DiscordRole role);
|
boolean hasRole(@NotNull DiscordRole role);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this member can interact (edit, add/take from members) with the specified role.
|
||||||
|
* @param role the role
|
||||||
|
* @return {@code true} if the member has a role above the specified role or is the server owner
|
||||||
|
*/
|
||||||
|
boolean canInteract(@NotNull DiscordRole role);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives the given role to this member.
|
* Gives the given role to this member.
|
||||||
* @param role the role to give
|
* @param role the role to give
|
||||||
|
@ -34,7 +34,7 @@ public class MemberCachingConfig {
|
|||||||
public boolean all = false;
|
public boolean all = false;
|
||||||
|
|
||||||
@Comment("If members should be cached at startup, this requires the \"Server Members Intent\"")
|
@Comment("If members should be cached at startup, this requires the \"Server Members Intent\"")
|
||||||
public boolean chunk = false;
|
public boolean chunk = true;
|
||||||
|
|
||||||
@Comment("Filter for which servers should be cached at startup")
|
@Comment("Filter for which servers should be cached at startup")
|
||||||
public GuildFilter chunkingServerFilter = new GuildFilter();
|
public GuildFilter chunkingServerFilter = new GuildFilter();
|
||||||
|
@ -56,6 +56,11 @@ public class DiscordGuildImpl implements DiscordGuild {
|
|||||||
return guild.getMemberCount();
|
return guild.getMemberCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull DiscordGuildMember getSelfMember() {
|
||||||
|
return discordSRV.discordAPI().getGuildMember(guild.getSelfMember());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull CompletableFuture<DiscordGuildMember> retrieveMemberById(long id) {
|
public @NotNull CompletableFuture<DiscordGuildMember> retrieveMemberById(long id) {
|
||||||
return discordSRV.discordAPI().mapExceptions(() -> guild.retrieveMemberById(id)
|
return discordSRV.discordAPI().mapExceptions(() -> guild.retrieveMemberById(id)
|
||||||
|
@ -87,6 +87,11 @@ public class DiscordGuildMemberImpl implements DiscordGuildMember {
|
|||||||
return roles.stream().anyMatch(role::equals);
|
return roles.stream().anyMatch(role::equals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canInteract(@NotNull DiscordRole role) {
|
||||||
|
return member.canInteract(role.asJDA());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> addRole(@NotNull DiscordRole role) {
|
public CompletableFuture<Void> addRole(@NotNull DiscordRole role) {
|
||||||
return discordSRV.discordAPI().mapExceptions(() ->
|
return discordSRV.discordAPI().mapExceptions(() ->
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
package com.discordsrv.common.groupsync;
|
package com.discordsrv.common.groupsync;
|
||||||
|
|
||||||
import com.discordsrv.api.discord.entity.guild.DiscordGuildMember;
|
|
||||||
import com.discordsrv.api.discord.entity.guild.DiscordRole;
|
import com.discordsrv.api.discord.entity.guild.DiscordRole;
|
||||||
import com.discordsrv.api.discord.events.member.role.DiscordMemberRoleAddEvent;
|
import com.discordsrv.api.discord.events.member.role.DiscordMemberRoleAddEvent;
|
||||||
import com.discordsrv.api.discord.events.member.role.DiscordMemberRoleRemoveEvent;
|
import com.discordsrv.api.discord.events.member.role.DiscordMemberRoleRemoveEvent;
|
||||||
@ -316,85 +315,90 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
|
|||||||
return CompletableFuture.completedFuture(GroupSyncResult.ROLE_DOESNT_EXIST);
|
return CompletableFuture.completedFuture(GroupSyncResult.ROLE_DOESNT_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscordGuildMember member = role.getGuild().getMemberById(userId);
|
if (!role.getGuild().getSelfMember().canInteract(role)) {
|
||||||
if (member == null) {
|
return CompletableFuture.completedFuture(GroupSyncResult.ROLE_CANNOT_INTERACT);
|
||||||
return CompletableFuture.completedFuture(GroupSyncResult.NOT_A_GUILD_MEMBER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasRole = member.hasRole(role);
|
return role.getGuild().retrieveMemberById(userId).thenCompose(member -> {
|
||||||
String groupName = pair.groupName;
|
if (member == null) {
|
||||||
CompletableFuture<GroupSyncResult> resultFuture = new CompletableFuture<>();
|
return CompletableFuture.completedFuture(GroupSyncResult.NOT_A_GUILD_MEMBER);
|
||||||
|
|
||||||
hasGroup(player, groupName, pair.serverContext).whenComplete((hasGroup, t) -> {
|
|
||||||
if (t != null) {
|
|
||||||
discordSRV.logger().error("Failed to check if player " + player + " has group " + groupName, t);
|
|
||||||
resultFuture.complete(GroupSyncResult.PERMISSION_BACKEND_FAIL_CHECK);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasRole == hasGroup) {
|
boolean hasRole = member.hasRole(role);
|
||||||
resultFuture.complete(hasRole ? GroupSyncResult.BOTH_TRUE : GroupSyncResult.BOTH_FALSE);
|
String groupName = pair.groupName;
|
||||||
// We're all good
|
CompletableFuture<GroupSyncResult> resultFuture = new CompletableFuture<>();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupSyncSide side = pair.tieBreaker();
|
hasGroup(player, groupName, pair.serverContext).whenComplete((hasGroup, t) -> {
|
||||||
GroupSyncDirection direction = pair.direction();
|
if (t != null) {
|
||||||
CompletableFuture<Void> future;
|
discordSRV.logger().error("Failed to check if player " + player + " has group " + groupName, t);
|
||||||
GroupSyncResult result;
|
resultFuture.complete(GroupSyncResult.PERMISSION_BACKEND_FAIL_CHECK);
|
||||||
if (hasRole) {
|
|
||||||
if (side == GroupSyncSide.DISCORD) {
|
|
||||||
// Has role, add group
|
|
||||||
if (direction == GroupSyncDirection.MINECRAFT_TO_DISCORD) {
|
|
||||||
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GroupSyncResult.ADD_GROUP;
|
|
||||||
future = addGroup(player, groupName, pair.serverContext);
|
|
||||||
} else {
|
|
||||||
// Doesn't have group, remove role
|
|
||||||
if (direction == GroupSyncDirection.DISCORD_TO_MINECRAFT) {
|
|
||||||
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GroupSyncResult.REMOVE_ROLE;
|
|
||||||
future = member.removeRole(role);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (side == GroupSyncSide.DISCORD) {
|
|
||||||
// Doesn't have role, remove group
|
|
||||||
if (direction == GroupSyncDirection.MINECRAFT_TO_DISCORD) {
|
|
||||||
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GroupSyncResult.REMOVE_GROUP;
|
|
||||||
future = removeGroup(player, groupName, pair.serverContext);
|
|
||||||
} else {
|
|
||||||
// Has group, add role
|
|
||||||
if (direction == GroupSyncDirection.DISCORD_TO_MINECRAFT) {
|
|
||||||
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GroupSyncResult.ADD_ROLE;
|
|
||||||
future = member.addRole(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
future.whenComplete((v, t2) -> {
|
|
||||||
if (t2 != null) {
|
|
||||||
discordSRV.logger().error("Failed to " + result + " to " + player + "/" + Long.toUnsignedString(userId), t2);
|
|
||||||
resultFuture.complete(GroupSyncResult.UPDATE_FAILED);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resultFuture.complete(result);
|
if (hasRole == hasGroup) {
|
||||||
});
|
resultFuture.complete(hasRole ? GroupSyncResult.BOTH_TRUE : GroupSyncResult.BOTH_FALSE);
|
||||||
});
|
// We're all good
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return resultFuture;
|
GroupSyncSide side = pair.tieBreaker();
|
||||||
|
GroupSyncDirection direction = pair.direction();
|
||||||
|
CompletableFuture<Void> future;
|
||||||
|
GroupSyncResult result;
|
||||||
|
if (hasRole) {
|
||||||
|
if (side == GroupSyncSide.DISCORD) {
|
||||||
|
// Has role, add group
|
||||||
|
if (direction == GroupSyncDirection.MINECRAFT_TO_DISCORD) {
|
||||||
|
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GroupSyncResult.ADD_GROUP;
|
||||||
|
future = addGroup(player, groupName, pair.serverContext);
|
||||||
|
} else {
|
||||||
|
// Doesn't have group, remove role
|
||||||
|
if (direction == GroupSyncDirection.DISCORD_TO_MINECRAFT) {
|
||||||
|
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GroupSyncResult.REMOVE_ROLE;
|
||||||
|
future = member.removeRole(role);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (side == GroupSyncSide.DISCORD) {
|
||||||
|
// Doesn't have role, remove group
|
||||||
|
if (direction == GroupSyncDirection.MINECRAFT_TO_DISCORD) {
|
||||||
|
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GroupSyncResult.REMOVE_GROUP;
|
||||||
|
future = removeGroup(player, groupName, pair.serverContext);
|
||||||
|
} else {
|
||||||
|
// Has group, add role
|
||||||
|
if (direction == GroupSyncDirection.DISCORD_TO_MINECRAFT) {
|
||||||
|
resultFuture.complete(GroupSyncResult.WRONG_DIRECTION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GroupSyncResult.ADD_ROLE;
|
||||||
|
future = member.addRole(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
future.whenComplete((v, t2) -> {
|
||||||
|
if (t2 != null) {
|
||||||
|
discordSRV.logger().error("Failed to " + result + " to " + player + "/" + Long.toUnsignedString(userId), t2);
|
||||||
|
resultFuture.complete(GroupSyncResult.UPDATE_FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultFuture.complete(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return resultFuture;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listeners & methods to indicate something changed
|
// Listeners & methods to indicate something changed
|
||||||
@ -636,44 +640,49 @@ public class GroupSyncModule extends AbstractModule<DiscordSRV> {
|
|||||||
return CompletableFuture.completedFuture(GroupSyncResult.ROLE_DOESNT_EXIST);
|
return CompletableFuture.completedFuture(GroupSyncResult.ROLE_DOESNT_EXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscordGuildMember member = role.getGuild().getMemberById(userId);
|
if (!role.getGuild().getSelfMember().canInteract(role)) {
|
||||||
if (member == null) {
|
return CompletableFuture.completedFuture(GroupSyncResult.ROLE_CANNOT_INTERACT);
|
||||||
return CompletableFuture.completedFuture(GroupSyncResult.NOT_A_GUILD_MEMBER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Long, Boolean> expected = expectedDiscordChanges.get(userId, key -> new ConcurrentHashMap<>());
|
return role.getGuild().retrieveMemberById(userId).thenCompose(member -> {
|
||||||
if (expected != null) {
|
if (member == null) {
|
||||||
expected.put(roleId, remove);
|
return CompletableFuture.completedFuture(GroupSyncResult.NOT_A_GUILD_MEMBER);
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasRole = member.hasRole(role);
|
|
||||||
CompletableFuture<GroupSyncResult> future;
|
|
||||||
if (remove && hasRole) {
|
|
||||||
future = member.removeRole(role).thenApply(v -> GroupSyncResult.REMOVE_ROLE);
|
|
||||||
} else if (!remove && !hasRole) {
|
|
||||||
future = member.addRole(role).thenApply(v -> GroupSyncResult.ADD_ROLE);
|
|
||||||
} else {
|
|
||||||
if (expected != null) {
|
|
||||||
// Nothing needed to be changed, remove expectation
|
|
||||||
expected.remove(roleId);
|
|
||||||
}
|
}
|
||||||
return CompletableFuture.completedFuture(GroupSyncResult.ALREADY_IN_SYNC);
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletableFuture<GroupSyncResult> resultFuture = new CompletableFuture<>();
|
Map<Long, Boolean> expected = expectedDiscordChanges.get(userId, key -> new ConcurrentHashMap<>());
|
||||||
future.whenComplete((result, t) -> {
|
if (expected != null) {
|
||||||
if (t != null) {
|
expected.put(roleId, remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasRole = member.hasRole(role);
|
||||||
|
CompletableFuture<GroupSyncResult> future;
|
||||||
|
if (remove && hasRole) {
|
||||||
|
future = member.removeRole(role).thenApply(v -> GroupSyncResult.REMOVE_ROLE);
|
||||||
|
} else if (!remove && !hasRole) {
|
||||||
|
future = member.addRole(role).thenApply(v -> GroupSyncResult.ADD_ROLE);
|
||||||
|
} else {
|
||||||
if (expected != null) {
|
if (expected != null) {
|
||||||
// Failed, remove expectation
|
// Nothing needed to be changed, remove expectation
|
||||||
expected.remove(roleId);
|
expected.remove(roleId);
|
||||||
}
|
}
|
||||||
|
return CompletableFuture.completedFuture(GroupSyncResult.ALREADY_IN_SYNC);
|
||||||
resultFuture.complete(GroupSyncResult.UPDATE_FAILED);
|
|
||||||
discordSRV.logger().error("Failed to give/take role " + role + " to/from " + member, t);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
resultFuture.complete(result);
|
|
||||||
|
CompletableFuture<GroupSyncResult> resultFuture = new CompletableFuture<>();
|
||||||
|
future.whenComplete((result, t) -> {
|
||||||
|
if (t != null) {
|
||||||
|
if (expected != null) {
|
||||||
|
// Failed, remove expectation
|
||||||
|
expected.remove(roleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultFuture.complete(GroupSyncResult.UPDATE_FAILED);
|
||||||
|
discordSRV.logger().error("Failed to give/take role " + role + " to/from " + member, t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resultFuture.complete(result);
|
||||||
|
});
|
||||||
|
return resultFuture;
|
||||||
});
|
});
|
||||||
return resultFuture;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ public enum GroupSyncResult {
|
|||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
ROLE_DOESNT_EXIST("Role doesn't exist"),
|
ROLE_DOESNT_EXIST("Role doesn't exist"),
|
||||||
|
ROLE_CANNOT_INTERACT("Bot doesn't have a role above the synced role (cannot interact)"),
|
||||||
NOT_A_GUILD_MEMBER("User is not part of the server the role is in"),
|
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"),
|
PERMISSION_BACKEND_FAIL_CHECK("Failed to check group status, error printed"),
|
||||||
UPDATE_FAILED("Failed to modify role/group, error printed"),
|
UPDATE_FAILED("Failed to modify role/group, error printed"),
|
||||||
|
Loading…
Reference in New Issue
Block a user