mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-14 19:56:29 +00:00
[AB-25] refactoring experience collection to work instantly instead of delayed job
adding level up notification for experience
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.experience.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.service.ExecutorService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
|
||||
@Configuration
|
||||
public class ExperienceExecutorConfig {
|
||||
|
||||
@Autowired
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Bean(name = "experienceUpdateExecutor")
|
||||
public TaskExecutor experienceUpdateExecutor() {
|
||||
return executorService.setupExecutorFor("experienceUpdateExecutor");
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,14 @@ package dev.sheldan.abstracto.experience.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static dev.sheldan.abstracto.experience.config.ExperienceFeatureMode.LEVEL_UP_NOTIFICATION;
|
||||
|
||||
/**
|
||||
* {@link FeatureConfig} instance containing the required configuration concerning system config and post targets for
|
||||
* the {@link ExperienceFeatureDefinition} feature.
|
||||
@@ -26,6 +29,7 @@ public class ExperienceFeatureConfig implements FeatureConfig {
|
||||
* The multiplier which is applied to each calculated gained experience
|
||||
*/
|
||||
public static final String EXP_MULTIPLIER_KEY = "expMultiplier";
|
||||
public static final String EXP_COOLDOWN_SECONDS_KEY = "expCooldownSeconds";
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
@@ -37,6 +41,11 @@ public class ExperienceFeatureConfig implements FeatureConfig {
|
||||
*/
|
||||
@Override
|
||||
public List<String> getRequiredSystemConfigKeys() {
|
||||
return Arrays.asList(EXP_MULTIPLIER_KEY, MIN_EXP_KEY, MAX_EXP_KEY);
|
||||
return Arrays.asList(EXP_MULTIPLIER_KEY, MIN_EXP_KEY, MAX_EXP_KEY, EXP_COOLDOWN_SECONDS_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getAvailableModes() {
|
||||
return Arrays.asList(LEVEL_UP_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.experience.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ExperienceFeatureMode implements FeatureMode {
|
||||
LEVEL_UP_NOTIFICATION("levelUpNotification");
|
||||
|
||||
private final String key;
|
||||
|
||||
ExperienceFeatureMode(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
@Setter
|
||||
@Builder
|
||||
public class ExperienceGainResult {
|
||||
/**
|
||||
* The calculation result contained in a {@link CompletableFuture future}. The future is necessary, because the calculation both calculates the new role
|
||||
* and removes/adds {@link net.dv8tion.jda.api.entities.Role role} to the {@link net.dv8tion.jda.api.entities.Member member}
|
||||
*/
|
||||
private CompletableFuture<RoleCalculationResult> calculationResult;
|
||||
/**
|
||||
* The ID of the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} for which this is the result
|
||||
|
||||
@@ -4,20 +4,10 @@ import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* The result of calculating the appropriate {@link dev.sheldan.abstracto.experience.model.database.AExperienceRole role} for a {@link dev.sheldan.abstracto.experience.model.database.AUserExperience user}
|
||||
* in a server.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class RoleCalculationResult {
|
||||
/**
|
||||
* The ID of the {@link dev.sheldan.abstracto.experience.model.database.AExperienceRole role} which was given to the user. Can be null, in case no role is given.
|
||||
*/
|
||||
private Long experienceRoleId;
|
||||
/**
|
||||
* The ID of a {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} for who the role was calculated for.
|
||||
*/
|
||||
private Long userInServerId;
|
||||
private Long oldRoleId;
|
||||
private Long newRoleId;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Container object to store the experience in runtime and group it together. This basically is just a list of users who were tracked by experience.
|
||||
* The actual calculation of the appropriate experience amount is done later.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ServerExperience {
|
||||
/**
|
||||
* The ID of the {@link dev.sheldan.abstracto.core.models.database.AServer} for which this experience were collected
|
||||
*/
|
||||
private Long serverId;
|
||||
/**
|
||||
* A list of IDs of the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer} which should be given experience
|
||||
*/
|
||||
@Builder.Default
|
||||
private List<Long> userInServerIds = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.sheldan.abstracto.experience.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class LevelUpNotificationModel {
|
||||
private MemberDisplay memberDisplay;
|
||||
private Integer oldLevel;
|
||||
private Integer newLevel;
|
||||
private RoleDisplay oldRole;
|
||||
private RoleDisplay newRole;
|
||||
private Long oldExperience;
|
||||
private Long newExperience;
|
||||
}
|
||||
@@ -1,21 +1,17 @@
|
||||
package dev.sheldan.abstracto.experience.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import dev.sheldan.abstracto.experience.model.LeaderBoard;
|
||||
import dev.sheldan.abstracto.experience.model.LeaderBoardEntry;
|
||||
import dev.sheldan.abstracto.experience.model.RoleCalculationResult;
|
||||
import dev.sheldan.abstracto.experience.model.ServerExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Service providing the required mechanisms to provide experience tracking.
|
||||
@@ -24,12 +20,7 @@ import java.util.function.Function;
|
||||
*/
|
||||
public interface AUserExperienceService {
|
||||
String EXPERIENCE_GAIN_CHANNEL_GROUP_KEY = "experienceGain";
|
||||
/**
|
||||
* Adds the given {@link AUserInAServer userInAServer} to the list of user who gained experience in the current minute.
|
||||
* Does not add the user to the list of users, if it is already in there.
|
||||
* @param userInAServer The {@link AUserInAServer userInAServer} to be added to the list of users gaining experience
|
||||
*/
|
||||
void addExperience(AUserInAServer userInAServer);
|
||||
void addExperience(Member member, Message message);
|
||||
|
||||
/**
|
||||
* Calculates the appropriate level for the given experience amount according to the given {@link AExperienceLevel levels}
|
||||
@@ -51,58 +42,9 @@ public interface AUserExperienceService {
|
||||
*/
|
||||
boolean updateUserLevel(AUserExperience userExperience, List<AExperienceLevel> levels, Long experienceCount);
|
||||
|
||||
/**
|
||||
* Iterates through the given list of {@link AServer servers} and increases the experience of the users contained in the
|
||||
* {@link ServerExperience serverExperience} object, also increments the level and changes the role if necessary.
|
||||
* This uses the respective configurable max/minExp and multiplier for each {@link AServer server} and increases the message count
|
||||
* of each user by 1.
|
||||
* @param serverExp The list of {@link AServer servers} containing the users which get experience
|
||||
* @return A {@link CompletableFuture future} completing when the experience gain was calculated and roles were assigned
|
||||
*/
|
||||
CompletableFuture<Void> handleExperienceGain(List<ServerExperience> serverExp);
|
||||
CompletableFuture<Void> syncUserRolesWithFeedback(AServer server, MessageChannel messageChannel);
|
||||
|
||||
/**
|
||||
* Calculates the currently appropriate {@link AExperienceRole} for the given user and updates the role on the
|
||||
* {@link net.dv8tion.jda.api.entities.Member} and ond the {@link AUserExperience}. Effectively synchronizes the
|
||||
* state in the server and the database.
|
||||
* @param userExperience The {@link AUserExperience userExperience} object to recalculate the {@link AExperienceRole experienceRole} for
|
||||
* @param roles The list of {@link AExperienceRole roles} used as a role configuration
|
||||
* @param currentLevel The current level of the user
|
||||
* @return A {@link CompletableFuture future} containing the {@link RoleCalculationResult result} of the role calculation,
|
||||
* completing after the role of the {@link net.dv8tion.jda.api.entities.Member} has been updated, if any
|
||||
*/
|
||||
CompletableFuture<RoleCalculationResult> updateUserRole(AUserExperience userExperience, List<AExperienceRole> roles, Integer currentLevel);
|
||||
|
||||
/**
|
||||
* Synchronizes the state ({@link AExperienceRole}, {@link net.dv8tion.jda.api.entities.Role})
|
||||
* of all the users provided in the {@link AServer} object in the {@link AUserExperience}
|
||||
* and on the {@link net.dv8tion.jda.api.entities.Member} according
|
||||
* to how much experience the user has. Runs completely in the background.
|
||||
* @param server The {@link AServer} to update the users for
|
||||
* @return The list of {@link CompletableFuture futures} for each update of the users in the {@link AServer server}
|
||||
*/
|
||||
List<CompletableFuture<RoleCalculationResult>> syncUserRoles(AServer server);
|
||||
|
||||
/**
|
||||
* Synchronizes the state ({@link AExperienceRole}, {@link net.dv8tion.jda.api.entities.Role})
|
||||
* of all the users provided in the {@link AServer} object in the {@link AUserExperience}
|
||||
* and on the {@link net.dv8tion.jda.api.entities.Member} according
|
||||
* to how much experience the user has. This method provides feedback back to the user in the provided {@link AChannel channel}
|
||||
* while the process is going own.
|
||||
* @param server The {@link AServer} to update users for
|
||||
* @param channelId The ID of a {@link AChannel channel} in which the {@link dev.sheldan.abstracto.experience.model.template.UserSyncStatusModel statusUpdate}
|
||||
* should be posted to
|
||||
* @return A {@link CompletableFuture future} which completes after all the role changes have been completed
|
||||
*/
|
||||
CompletableFuture<Void> syncUserRolesWithFeedback(AServer server, Long channelId);
|
||||
|
||||
/**
|
||||
* Recalculates the role of a single user in a server and synchronize the {@link net.dv8tion.jda.api.entities.Role}
|
||||
* in the {@link net.dv8tion.jda.api.entities.Guild}
|
||||
* @param userExperience The {@link AUserExperience} to synchronize the role for
|
||||
* @return A {@link CompletableFuture future} which completes after the roles have been synced for the given {@link AUserInAServer user}
|
||||
*/
|
||||
CompletableFuture<RoleCalculationResult> syncForSingleUser(AUserExperience userExperience);
|
||||
CompletableFuture<Void> syncForSingleUser(AUserExperience userExperience, Member member);
|
||||
|
||||
/**
|
||||
* Loads the desired page of the ordered complete leaderboard from the {@link AServer} and returns the information as a {@link LeaderBoard}
|
||||
@@ -122,19 +64,6 @@ public interface AUserExperienceService {
|
||||
*/
|
||||
LeaderBoardEntry getRankOfUserInServer(AUserInAServer userInAServer);
|
||||
|
||||
/**
|
||||
* Provides a method to execute an action on a list of {@link AUserExperience} and provide feedback in the given {@link AChannel}
|
||||
* in the form of {@link dev.sheldan.abstracto.experience.model.template.UserSyncStatusModel} to be rendered with a certain
|
||||
* template
|
||||
* @param experiences The list of {@link AUserExperience} to be working on
|
||||
* @param channel The {@link AChannel} used to provide feedback to the user
|
||||
* @param toExecute The {@link Function} which should be executed on each element of the passed list,
|
||||
* this function needs to take a {@link AUserExperience userExperience} as parameter and returns a {@link CompletableFuture}
|
||||
* with a {@link RoleCalculationResult} for each of them. These futures are then returned.
|
||||
* @return A {@link CompletableFutureList completeFutureList} which represents the individual {@link RoleCalculationResult results} and a primary future, which is completed after all of the individual ones are
|
||||
*/
|
||||
CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute);
|
||||
|
||||
/**
|
||||
* Disables the experience gain for a user directly. This sets the `experienceGainDisabled` on the respective {@link AUserExperience} object to true
|
||||
* @param userInAServer The {@link AUserInAServer} to disable experience gain for
|
||||
@@ -147,12 +76,6 @@ public interface AUserExperienceService {
|
||||
*/
|
||||
void enableExperienceForUser(AUserInAServer userInAServer);
|
||||
|
||||
/**
|
||||
* Updates the actually stored experience roles in the database
|
||||
* @param results The list of {@link RoleCalculationResult} which should be updated in the database
|
||||
*/
|
||||
void syncRolesInStorage(List<RoleCalculationResult> results);
|
||||
|
||||
boolean experienceGainEnabledInChannel(MessageChannel messageChannel);
|
||||
|
||||
AUserExperience createUserExperienceForUser(AUserInAServer aUserInAServer, Long experience, Long messageCount);
|
||||
|
||||
@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.template.LevelRole;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -15,34 +16,12 @@ import java.util.concurrent.CompletableFuture;
|
||||
* Service providing several methods surrounding {@link dev.sheldan.abstracto.experience.model.database.AExperienceRole experienceRole}.
|
||||
*/
|
||||
public interface ExperienceRoleService {
|
||||
/**
|
||||
* Creates an {@link dev.sheldan.abstracto.experience.model.database.AExperienceRole experienceRole} according to the given
|
||||
* parameters. This actually updates the {@link net.dv8tion.jda.api.entities.Member members}
|
||||
* which currently possessed the given role before and provides a display to see how far the progress is
|
||||
* @param role The {@link ARole role} to set the level to
|
||||
* @param level The new level the {@link ARole role} should be awarded at
|
||||
* @param channelId The ID of the {@link dev.sheldan.abstracto.core.models.database.AChannel} in which the status updates
|
||||
* should be sent to
|
||||
* @return A {@link CompletableFuture future} which completes, after all the updates on the {@link net.dv8tion.jda.api.entities.Member}
|
||||
* have been completed
|
||||
*/
|
||||
CompletableFuture<Void> setRoleToLevel(Role role, Integer level, Long channelId);
|
||||
|
||||
/**
|
||||
* Removes the role from the {@link dev.sheldan.abstracto.experience.model.database.AExperienceRole} configuration,
|
||||
* this will also update all the {@link net.dv8tion.jda.api.entities.Member} which previously had this role and re-calculates
|
||||
* a new {@link AExperienceRole experienceRole} for them while also updating them in the guild
|
||||
* @param role The {@link ARole} to remove from the {@link dev.sheldan.abstracto.experience.model.database.AExperienceRole}
|
||||
* configuration
|
||||
* @param channelId The ID of the {@link dev.sheldan.abstracto.core.models.database.AChannel} in which the status updates
|
||||
* should be sent to
|
||||
* @return A {@link CompletableFuture future} which completes, after all the updates on the {@link net.dv8tion.jda.api.entities.Member}
|
||||
* have been completed
|
||||
*/
|
||||
CompletableFuture<Void> unsetRoles(ARole role, Long channelId);
|
||||
CompletableFuture<Void> setRoleToLevel(Role role, Integer level, GuildMessageChannel messageChannel);
|
||||
|
||||
CompletableFuture<Void> unsetRoles(ARole role, GuildMessageChannel messageChannel);
|
||||
List<AExperienceRole> getExperienceRolesAtLevel(Integer level, AServer server);
|
||||
CompletableFuture<Void> unsetRoles(List<ARole> roles, Long channelId);
|
||||
CompletableFuture<Void> unsetRoles(List<ARole> roles, Long channelId, AExperienceRole toAdd);
|
||||
CompletableFuture<Void> unsetRoles(List<ARole> roles, GuildMessageChannel messageChannel);
|
||||
|
||||
/**
|
||||
* Calculates the appropriate {@link AExperienceRole experienceRole} based on the provided list of {@link AExperienceRole experienceRole}
|
||||
|
||||
@@ -37,6 +37,7 @@ public interface ExperienceRoleManagementService {
|
||||
* @param role The {@link AExperienceRole experienceRole} to delete.
|
||||
*/
|
||||
void unsetRole(AExperienceRole role);
|
||||
void unsetRoles(List<AExperienceRole> role);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link AExperienceRole experienceRole} which uses the given {@link ARole role} in the {@link AServer server}
|
||||
@@ -44,6 +45,7 @@ public interface ExperienceRoleManagementService {
|
||||
* @return the {@link AExperienceRole experienceRole} which uses the given {@link ARole role}
|
||||
*/
|
||||
AExperienceRole getRoleInServer(ARole role);
|
||||
List<AExperienceRole> getRolesInServer(List<ARole> role);
|
||||
|
||||
/**
|
||||
* Retrieves a possible {@link AExperienceRole role}, if it exists, for the given {@link ARole}. Returns an empty Optional if it does not exist
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.experience.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LeaderBoardEntryResult;
|
||||
|
||||
@@ -19,6 +20,7 @@ public interface UserExperienceManagementService {
|
||||
* @return The {@link AUserExperience userExperience} object representing the {@link AUserInAServer userInAServer}
|
||||
*/
|
||||
AUserExperience findUserInServer(AUserInAServer aUserInAServer);
|
||||
void removeExperienceRoleFromUsers(AExperienceRole experienceRole);
|
||||
|
||||
/**
|
||||
* Retrieves a possible {@link AUserExperience userExperience} for the given ID of the {@link AUserInAServer}.
|
||||
|
||||
Reference in New Issue
Block a user