mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-11 11:44:32 +00:00
Compare commits
91 Commits
abstracto-
...
v1.5.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74c8cf7b6b | ||
|
|
c8739b90ec | ||
|
|
d39a303207 | ||
|
|
3e326fe47e | ||
|
|
a1d460973c | ||
|
|
d2475179e6 | ||
|
|
5adc304e77 | ||
|
|
4940577383 | ||
|
|
bba0a2ace6 | ||
|
|
b7c427026d | ||
|
|
cee10de915 | ||
|
|
1786231e11 | ||
|
|
2231fdf289 | ||
|
|
a46e22b5b2 | ||
|
|
1c9b9af833 | ||
|
|
3cafc95ceb | ||
|
|
6409bbaa1d | ||
|
|
346e462185 | ||
|
|
46baa79d3e | ||
|
|
650d062808 | ||
|
|
bac9832819 | ||
|
|
efbcb5c84b | ||
|
|
fd70e6ac90 | ||
|
|
29bde70796 | ||
|
|
ecd4feabb2 | ||
|
|
abf60409f1 | ||
|
|
080733957f | ||
|
|
8a41f366ae | ||
|
|
dbf478c44c | ||
|
|
3df688571f | ||
|
|
ca530949c6 | ||
|
|
724930e5a4 | ||
|
|
2875da117a | ||
|
|
f95ba6c28f | ||
|
|
1b2e7654f9 | ||
|
|
54976ed1d4 | ||
|
|
735816f5dd | ||
|
|
a984bdb84e | ||
|
|
21add6585d | ||
|
|
99e72245f3 | ||
|
|
9d184ff560 | ||
|
|
97895f5c56 | ||
|
|
f091559c49 | ||
|
|
fa7730975e | ||
|
|
03d7b9e2e2 | ||
|
|
a0bff12263 | ||
|
|
70e708601e | ||
|
|
f01418d0de | ||
|
|
ad539adb2a | ||
|
|
3c9fec989f | ||
|
|
21db3e3ee5 | ||
|
|
5b1ad2e075 | ||
|
|
63b3f68bdb | ||
|
|
7c1537c4a7 | ||
|
|
9836998087 | ||
|
|
8a1bb4cad8 | ||
|
|
a9dadec8ef | ||
|
|
3eaffaef87 | ||
|
|
b3a943e155 | ||
|
|
06dd4af131 | ||
|
|
0d51469975 | ||
|
|
aa10c88588 | ||
|
|
db27f64832 | ||
|
|
3903039aac | ||
|
|
41f42ee110 | ||
|
|
74f54e1257 | ||
|
|
a72e48f690 | ||
|
|
a813af8b1f | ||
|
|
abee7b2732 | ||
|
|
4c71ffbb7e | ||
|
|
18050e2a8a | ||
|
|
a0d83763d4 | ||
|
|
0461c8e4ec | ||
|
|
072f32975a | ||
|
|
6810d28c50 | ||
|
|
650a9099c4 | ||
|
|
1217e03725 | ||
|
|
2e837d8738 | ||
|
|
9ddd386c6f | ||
|
|
4e1db26df7 | ||
|
|
de335a1e2a | ||
|
|
9ba0ed711e | ||
|
|
b7376bf522 | ||
|
|
0d6182c5d5 | ||
|
|
96c38763b1 | ||
|
|
97b3099156 | ||
|
|
a0b2fc9c31 | ||
|
|
2db36ef96b | ||
|
|
08b3913b04 | ||
|
|
7a7ec5654f | ||
|
|
74679c2ccc |
24
.github/workflows/build.yml
vendored
24
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
||||
# This workflow will build a Java project with Maven
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
|
||||
name: Execute build and Sonar
|
||||
name: Execute Build
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -19,26 +19,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
distribution: 'corretto'
|
||||
java-version: 17
|
||||
- name: Build with Maven
|
||||
run: mvn -B install --file abstracto-application/pom.xml
|
||||
- name: Setup sonarqube
|
||||
uses: warchant/setup-sonar-scanner@v3
|
||||
- name: Run sonarqube
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: sonar-scanner
|
||||
-Dsonar.login=${{ secrets.SONAR_TOKEN }}
|
||||
-Dsonar.organization=sheldan
|
||||
-Dsonar.host.url=https://sonarcloud.io/
|
||||
-Dsonar.projectKey=abstracto-core
|
||||
-Dsonar.java.binaries=**/target/classes
|
||||
-Dsonar.coverage.jacoco.xmlReportPaths=abstracto-application/coverage/target/site/jacoco-aggregate/jacoco.xml
|
||||
-Dsonar.coverage.exclusions=**/*Test.java
|
||||
- uses: actions/setup-ruby@v1
|
||||
- name: Send Webhook Notification
|
||||
if: always()
|
||||
|
||||
33
.github/workflows/release.yml
vendored
33
.github/workflows/release.yml
vendored
@@ -6,13 +6,14 @@ jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Java for publishing to GitHub Packages
|
||||
uses: actions/setup-java@v1
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
distribution: 'corretto'
|
||||
java-version: 17
|
||||
- name: Load current version
|
||||
id: version
|
||||
run: echo "version=$(mvn --file abstracto-application/pom.xml -q -Dexec.executable="echo" -Dexec.args='${project.version}' --non-recursive exec:exec)" >> $GITHUB_ENV
|
||||
@@ -21,7 +22,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Deploy documentation to GitHub pages
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.0
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
repository-name: Sheldan/abstracto-docs
|
||||
target-folder: docs/${{ env.version }}
|
||||
@@ -29,22 +30,26 @@ jobs:
|
||||
ssh-key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
|
||||
folder: abstracto-application/documentation/target/generated-docs
|
||||
- name: Deploy documentation to GitHub pages latest
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.0
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
repository-name: Sheldan/abstracto-docs
|
||||
target-folder: docs/current
|
||||
branch: master
|
||||
ssh-key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
|
||||
folder: abstracto-application/documentation/target/generated-docs
|
||||
- name: Login to GitHub Packages Docker Registry
|
||||
uses: docker/login-action@v1
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: docker.pkg.github.com
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Push deployment container
|
||||
working-directory: ./abstracto-application/installer/src/main/docker/deployment
|
||||
registry: harbor.sheldan.dev
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_TOKEN }}
|
||||
- name: Load env files
|
||||
id: dotenv
|
||||
uses: falti/dotenv-action@v1.0.4
|
||||
with:
|
||||
path: ./deployment/installer/.env
|
||||
- name: Push container
|
||||
run: docker-compose build && docker-compose push
|
||||
env:
|
||||
REGISTRY_PREFIX: docker.pkg.github.com/sheldan/abstracto/
|
||||
VERSION: ${{ env.version }}
|
||||
REGISTRY_PREFIX: ${{ steps.dotenv.outputs.registry_prefix }}
|
||||
VERSION: ${{ steps.dotenv.outputs.version }}
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Sheldan
|
||||
Copyright (c) 2023 Sheldan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
14
README.md
14
README.md
@@ -1,8 +1,6 @@
|
||||
# Abstracto
|
||||
|
||||

|
||||
[](https://sonarcloud.io/dashboard?id=abstracto-core)
|
||||
[](https://sonarcloud.io/dashboard?id=abstracto-core)
|
||||

|
||||
[](https://github.com/Sheldan/abstracto/blob/master/LICENSE)
|
||||
|
||||
|
||||
@@ -14,22 +12,20 @@ An example implementation of this bot can be seen [here](https://github.com/Shel
|
||||
|
||||
|
||||
## Technologies
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 5.0.0-alpha.21
|
||||
* [Spring boot](https://github.com/spring-projects/spring-boot) is used as a framework to create standalone application in Java with Java EE methods. (including Dependency injection and more)
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 5.0.0-beta.5
|
||||
* [Spring boot](https://github.com/spring-projects/spring-boot) is used as a framework to create standalone application in Java with Java EE methods. (including dependency injection and more)
|
||||
* [Hibernate](https://github.com/hibernate/hibernate-orm) is used as a reference implementation of JPA.
|
||||
* [Freemarker](https://github.com/apache/freemarker) is used as a templating engine. This is used to provide internationalization for user facing text and enable dynamic embed configuration.
|
||||
* [Ehcache](https://github.com/ehcache/ehcache3) is used as a caching implementation.
|
||||
* [Lombok](https://github.com/rzwitserloot/lombok) is used as a framework in order to speed up creation of container classes and builders.
|
||||
* [Quartz](https://github.com/quartz-scheduler/quartz) is used as a scheduling framework in order to provide functionalities which either require a delayed or cronjob behaviour.
|
||||
* [Docker](https://github.com/docker) is used to package the application into a container and [Docker Compose](https://github.com/docker/compose) is used to connect the required containers together.
|
||||
* [Quartz](https://github.com/quartz-scheduler/quartz) is used as a scheduling framework in order to provide functionalities which either require a scheduled or cronjob behaviour.
|
||||
* [Docker](https://github.com/docker) is used to package the application into an image and [Docker Compose](https://github.com/docker/compose) is used to build the images
|
||||
* [Liquibase](https://github.com/liquibase/liquibase) is used to manage changes to the database
|
||||
|
||||
## Documentation
|
||||
A detailed documentation of the pure form of Abstracto including the terminology and commands in HTML form is available [here](https://sheldan.github.io/abstracto-docs/current). The PDF is available [here](https://sheldan.github.io/abstracto-docs/current/documentation.pdf)
|
||||
If you want to view the documentation to an earlier released version you need to append the desired version to the URL. The current version will be available aforementioned URL, but it is not right now, because Abstracto has not been released yet.
|
||||
|
||||
## Customization documentation
|
||||
TBD when Abstracto is released, as the current version is still being adapted, because of findings from the example customization in Crimson.
|
||||
|
||||
## Issues
|
||||
If you find any issue, feel free to create a GitHub issue.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>assignable-roles-int</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.ComponentPayload;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.assignableroles.model.database;
|
||||
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "assignable_role_condition")
|
||||
|
||||
@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.assignableroles.model.database;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.customcommand.model.database;
|
||||
import dev.sheldan.abstracto.core.models.database.*;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.sheldan.abstracto.activity.models;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -89,14 +89,14 @@ public class Slots extends AbstractConditionableCommand {
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
Parameter lowParameter = Parameter
|
||||
Parameter bidParameter = Parameter
|
||||
.builder()
|
||||
.name(BID_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.templated(true)
|
||||
.validators(Arrays.asList(MinIntegerValueValidator.min(0L)))
|
||||
.build();
|
||||
parameters.add(lowParameter);
|
||||
parameters.add(bidParameter);
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
package dev.sheldan.abstracto.entertainment.command.games;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureFlagService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.exception.NotEnoughCreditsException;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoard;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyUser;
|
||||
import dev.sheldan.abstracto.entertainment.service.GameService;
|
||||
import dev.sheldan.abstracto.entertainment.service.management.EconomyUserManagementService;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class Mines extends AbstractConditionableCommand {
|
||||
|
||||
private static final String MINES_COMMAND_NAME = "mines";
|
||||
private static final String WIDTH_PARAMETER = "width";
|
||||
private static final String HEIGHT_PARAMETER = "height";
|
||||
private static final String MINES_PARAMETER = "mines";
|
||||
private static final String CREDITS_PARAMETER = "credits";
|
||||
public static final String MINE_BOARD_TEMPLATE_KEY = "mines_board_response";
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private FeatureFlagService featureFlagService;
|
||||
|
||||
@Autowired
|
||||
private GameService gameService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private EconomyUserManagementService economyUserManagementService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
Integer width = 5;
|
||||
if(slashCommandParameterService.hasCommandOption(WIDTH_PARAMETER, event)) {
|
||||
width = slashCommandParameterService.getCommandOption(WIDTH_PARAMETER, event, Integer.class);
|
||||
}
|
||||
Integer height = 5;
|
||||
if(slashCommandParameterService.hasCommandOption(HEIGHT_PARAMETER, event)) {
|
||||
height = slashCommandParameterService.getCommandOption(HEIGHT_PARAMETER, event, Integer.class);
|
||||
}
|
||||
Integer mines = 5;
|
||||
if(slashCommandParameterService.hasCommandOption(MINES_PARAMETER, event)) {
|
||||
mines = slashCommandParameterService.getCommandOption(MINES_PARAMETER, event, Integer.class);
|
||||
}
|
||||
Integer credit = null;
|
||||
long serverId = event.getGuild().getIdLong();
|
||||
boolean economyEnabled = featureFlagService.getFeatureFlagValue(EntertainmentFeatureDefinition.ECONOMY, serverId);
|
||||
if(economyEnabled){
|
||||
credit = 50;
|
||||
if(slashCommandParameterService.hasCommandOption(CREDITS_PARAMETER, event)) {
|
||||
credit = slashCommandParameterService.getCommandOption(CREDITS_PARAMETER, event, Integer.class);
|
||||
}
|
||||
|
||||
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(ServerUser.fromMember(event.getMember()));
|
||||
if(!userOptional.isPresent()) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
EconomyUser user = userOptional.get();
|
||||
if(user.getCredits() < credit) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
}
|
||||
MineBoard board = gameService.createBoard(width, height, mines, serverId);
|
||||
board.setCreditsEnabled(economyEnabled);
|
||||
board.setUserId(event.getMember().getIdLong());
|
||||
board.setServerId(serverId);
|
||||
board.setCredits(credit);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MINE_BOARD_TEMPLATE_KEY, board);
|
||||
return interactionService.replyMessageToSend(messageToSend, event)
|
||||
.thenCompose(interactionHook -> interactionHook.retrieveOriginal().submit())
|
||||
.thenApply(message -> {
|
||||
gameService.persistMineBoardMessage(board, message);
|
||||
return CommandResult.fromSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
Integer width = 5;
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
if(!parameters.isEmpty()) {
|
||||
width = (Integer) parameters.get(0);
|
||||
}
|
||||
Integer height = 5;
|
||||
if(parameters.size() >= 2) {
|
||||
height = (Integer) parameters.get(1);
|
||||
}
|
||||
Integer mines = 5;
|
||||
if(parameters.size() >= 3) {
|
||||
mines = (Integer) parameters.get(2);
|
||||
}
|
||||
Integer credit = null;
|
||||
long serverId = commandContext.getGuild().getIdLong();
|
||||
boolean economyEnabled = featureFlagService.getFeatureFlagValue(EntertainmentFeatureDefinition.ECONOMY, serverId);
|
||||
if(economyEnabled){
|
||||
credit = 50;
|
||||
if(parameters.size() == 4) {
|
||||
credit = (Integer) parameters.get(3);
|
||||
}
|
||||
|
||||
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(ServerUser.fromMember(commandContext.getAuthor()));
|
||||
if(!userOptional.isPresent()) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
EconomyUser user = userOptional.get();
|
||||
if(user.getCredits() < credit) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
}
|
||||
MineBoard board = gameService.createBoard(width, height, mines, serverId);
|
||||
board.setCreditsEnabled(economyEnabled);
|
||||
board.setUserId(commandContext.getAuthor().getIdLong());
|
||||
board.setServerId(serverId);
|
||||
board.setCredits(credit);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MINE_BOARD_TEMPLATE_KEY, board);
|
||||
List<CompletableFuture<Message>> futures = channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
|
||||
return FutureUtils.toSingleFutureGeneric(futures)
|
||||
.thenAccept(unused -> gameService.persistMineBoardMessage(board, futures.get(0).join()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
Parameter widthParameter = Parameter
|
||||
.builder()
|
||||
.name(WIDTH_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.optional(true)
|
||||
.templated(true)
|
||||
.build();
|
||||
parameters.add(widthParameter);
|
||||
|
||||
Parameter heightParameter = Parameter
|
||||
.builder()
|
||||
.name(HEIGHT_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.optional(true)
|
||||
.templated(true)
|
||||
.build();
|
||||
parameters.add(heightParameter);
|
||||
|
||||
Parameter minesParameter = Parameter
|
||||
.builder()
|
||||
.name(MINES_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.optional(true)
|
||||
.templated(true)
|
||||
.build();
|
||||
parameters.add(minesParameter);
|
||||
|
||||
Parameter creditsParameter = Parameter
|
||||
.builder()
|
||||
.name(CREDITS_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.optional(true)
|
||||
.templated(true)
|
||||
.dependentFeatures(Arrays.asList(EntertainmentFeatureDefinition.ECONOMY.getKey()))
|
||||
.build();
|
||||
parameters.add(creditsParameter);
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.GAME)
|
||||
.commandName(MINES_COMMAND_NAME)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(MINES_COMMAND_NAME)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.async(true)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.GAMES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package dev.sheldan.abstracto.entertainment.listener.interaction;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListener;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerModel;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerResult;
|
||||
import dev.sheldan.abstracto.core.service.FeatureFlagService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.entertainment.command.games.Mines;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoard;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoardPayload;
|
||||
import dev.sheldan.abstracto.entertainment.service.GameService;
|
||||
import dev.sheldan.abstracto.entertainment.service.GameServiceBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MinesButtonClickedListener implements ButtonClickedListener {
|
||||
|
||||
@Autowired
|
||||
private GameService gameService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private FeatureFlagService featureFlagService;
|
||||
|
||||
@Override
|
||||
public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) {
|
||||
MineBoardPayload payload = (MineBoardPayload) model.getDeserializedPayload();
|
||||
if(model.getEvent().getUser().getIdLong() != payload.getMineBoard().getUserId()) {
|
||||
return ButtonClickedListenerResult.IGNORED;
|
||||
}
|
||||
MineBoard mineBoard = payload.getMineBoard();
|
||||
if(!mineBoard.getState().equals(GameService.MineResult.CONTINUE)) {
|
||||
return ButtonClickedListenerResult.IGNORED;
|
||||
}
|
||||
GameService.MineResult mineResult = gameService.uncoverField(mineBoard, payload.getX(), payload.getY());
|
||||
mineBoard.setState(mineResult);
|
||||
if(mineBoard.getState() != GameService.MineResult.CONTINUE) {
|
||||
if(featureFlagService.getFeatureFlagValue(EntertainmentFeatureDefinition.ECONOMY, model.getServerId())){
|
||||
gameService.evaluateCreditChanges(mineBoard);
|
||||
}
|
||||
gameService.uncoverBoard(mineBoard);
|
||||
}
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(Mines.MINE_BOARD_TEMPLATE_KEY, mineBoard);
|
||||
interactionService.editOriginal(messageToSend, model.getEvent().getHook()).thenAccept(message -> {
|
||||
gameService.updateMineBoard(mineBoard);
|
||||
log.info("Updated original mineboard for board {}.", mineBoard.getBoardId());
|
||||
});
|
||||
return ButtonClickedListenerResult.ACKNOWLEDGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.GAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPriority() {
|
||||
return ListenerPriority.MEDIUM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean handlesEvent(ButtonClickedListenerModel model) {
|
||||
return model.getOrigin().equals(GameServiceBean.MINES_BUTTON_ORIGIN);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import java.util.Optional;
|
||||
@Repository
|
||||
public interface EconomyUserRepository extends JpaRepository<EconomyUser, Long> {
|
||||
Optional<EconomyUser> findByUser(AUserInAServer aUserInAServer);
|
||||
Optional<EconomyUser> findByServer_IdAndUser_UserReference_Id(Long serverId, Long userId);
|
||||
|
||||
@Query(value = "WITH economy_user_ranked AS" +
|
||||
"( " +
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
package dev.sheldan.abstracto.entertainment.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentPayloadService;
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentService;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.entertainment.exception.InvalidGameBoardException;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoard;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoardField;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoardPayload;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoardRow;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyUser;
|
||||
import dev.sheldan.abstracto.entertainment.service.management.EconomyUserManagementService;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.sheldan.abstracto.entertainment.config.GamesFeatureConfig.MINES_CREDITS_FACTOR;
|
||||
import static dev.sheldan.abstracto.entertainment.config.GamesFeatureConfig.MINES_MINIMUM_MINES_RATIO;
|
||||
|
||||
@Component
|
||||
public class GameServiceBean implements GameService {
|
||||
|
||||
public static final String MINES_BUTTON_ORIGIN = "MINES_BUTTON";
|
||||
@Autowired
|
||||
private SecureRandom secureRandom;
|
||||
|
||||
@Autowired
|
||||
private ComponentService componentService;
|
||||
|
||||
@Autowired
|
||||
private ComponentPayloadService componentPayloadService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private EconomyService economyService;
|
||||
|
||||
@Autowired
|
||||
private EconomyUserManagementService economyUserManagementService;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Override
|
||||
public MineBoard createBoard(Integer width, Integer height, Integer mines, Long serverId) {
|
||||
double minMinesRatio = configService.getDoubleValueOrConfigDefault(MINES_MINIMUM_MINES_RATIO, serverId);
|
||||
if(mines >= width * height || width > 5 || height > 5 || mines <= 1 || height <= 1 || width <= 1) {
|
||||
throw new InvalidGameBoardException(minMinesRatio);
|
||||
}
|
||||
if((double) mines / (width * height) < minMinesRatio) {
|
||||
throw new InvalidGameBoardException(minMinesRatio);
|
||||
}
|
||||
MineBoard mineBoard = generateEmptyBoard(width, height);
|
||||
mineBoard.setMineCount(mines);
|
||||
fillWithMines(mineBoard);
|
||||
evaluateCounters(mineBoard);
|
||||
|
||||
return mineBoard;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void persistMineBoardMessage(MineBoard mineBoard, Message message) {
|
||||
mineBoard.setMessageId(message.getIdLong());
|
||||
mineBoard.setChannelId(message.getChannel().getIdLong());
|
||||
AServer server = serverManagementService.loadServer(message.getGuild());
|
||||
mineBoard.getFields().forEach(mineBoardField -> {
|
||||
MineBoardPayload payload = MineBoardPayload
|
||||
.builder()
|
||||
.x(mineBoardField.getX())
|
||||
.y(mineBoardField.getY())
|
||||
.mineBoard(mineBoard)
|
||||
.build();
|
||||
String componentId = mineBoard.getBoardId() + "_" + mineBoardField.getX() + "_" + mineBoardField.getY();
|
||||
componentPayloadService.createButtonPayload(componentId, payload, MINES_BUTTON_ORIGIN, server);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateMineBoard(MineBoard mineBoard) {
|
||||
mineBoard.getFields().forEach(mineBoardField -> {
|
||||
MineBoardPayload newPayload = MineBoardPayload
|
||||
.builder()
|
||||
.x(mineBoardField.getX())
|
||||
.y(mineBoardField.getY())
|
||||
.mineBoard(mineBoard)
|
||||
.build();
|
||||
String componentId = mineBoard.getBoardId() + "_" + mineBoardField.getX() + "_" + mineBoardField.getY();
|
||||
componentPayloadService.updateButtonPayload(componentId, newPayload);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncoverBoard(MineBoard mineBoard) {
|
||||
mineBoard.getFields().forEach(mineBoardField -> {
|
||||
if(mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.COVERED)) {
|
||||
mineBoardField.setType(MineBoardField.MineBoardFieldType.UNCOVERED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluateCreditChanges(MineBoard mineBoard) {
|
||||
Long credits = mineBoard.getCredits().longValue();
|
||||
Integer mineCount = mineBoard.getMineCount();
|
||||
List<MineBoardField> allFields = mineBoard.getFields();
|
||||
Integer leftFields = (int) allFields
|
||||
.stream()
|
||||
.filter(mineBoardField -> mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.COVERED)
|
||||
|| mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.MINE))
|
||||
.count();
|
||||
Integer fieldCount = allFields.size();
|
||||
Integer uncoveredFields = fieldCount - leftFields;
|
||||
Long creditChange = (long) (calculateCreditFactor(fieldCount, mineCount, uncoveredFields) * credits);
|
||||
if(mineBoard.getState().equals(MineResult.WON)) {
|
||||
Double factor = configService.getDoubleValueOrConfigDefault(MINES_CREDITS_FACTOR, mineBoard.getServerId());
|
||||
creditChange = (long) (creditChange * factor);
|
||||
}
|
||||
ServerUser serverUser = ServerUser
|
||||
.builder()
|
||||
.serverId(mineBoard.getServerId())
|
||||
.userId(mineBoard.getUserId())
|
||||
.build();
|
||||
Optional<EconomyUser> economyUserOptional = economyUserManagementService.getUser(serverUser);
|
||||
if(economyUserOptional.isPresent()) {
|
||||
economyService.addCredits(economyUserOptional.get(), -credits);
|
||||
economyService.addCredits(economyUserOptional.get(), creditChange);
|
||||
}
|
||||
mineBoard.setCreditChange(creditChange);
|
||||
}
|
||||
|
||||
private double calculateCreditFactor(int totalFields, int mines, int uncovered) {
|
||||
return ((double) uncovered / (totalFields - mines)) + totalFields / 25.0 - ((totalFields - mines) / 25.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MineResult uncoverField(MineBoard board, Integer x, Integer y) {
|
||||
return uncoverFieldOnBoard(board, x, y);
|
||||
}
|
||||
|
||||
public GameService.MineResult uncoverFieldOnBoard(MineBoard board, Integer x, Integer y) {
|
||||
MineBoardField field = board.getField(x, y);
|
||||
if(!MineBoardField.canInteract(field.getType())) {
|
||||
return GameService.MineResult.CONTINUE;
|
||||
}
|
||||
if(field.getType().equals(MineBoardField.MineBoardFieldType.MINE)) {
|
||||
field.setType(MineBoardField.MineBoardFieldType.EXPLODED);
|
||||
return GameService.MineResult.LOST;
|
||||
}
|
||||
if(field.getType().equals(MineBoardField.MineBoardFieldType.COVERED)) {
|
||||
if(field.getCounterValue() == 0) {
|
||||
Set<String> alreadyConsidered = new HashSet<>();
|
||||
Queue<MineBoardField> toUncover = new LinkedList<>();
|
||||
toUncover.add(field);
|
||||
while(!toUncover.isEmpty()) {
|
||||
MineBoardField fieldToHandle = toUncover.poll();
|
||||
fieldToHandle.setType(MineBoardField.MineBoardFieldType.UNCOVERED);
|
||||
alreadyConsidered.add(fieldToHandle.getX() + "_" + fieldToHandle.getY());
|
||||
// only when we actually got a free field, we should add its neighbors to the next one to uncover
|
||||
if(fieldToHandle.getCounterValue() == 0) {
|
||||
List<MineBoardField> neighbors = getNeighbors(board, fieldToHandle.getX(), fieldToHandle.getY(), false);
|
||||
List<MineBoardField> uncoverableNeighbors = neighbors
|
||||
.stream().filter(mineBoardField -> mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.COVERED))
|
||||
.collect(Collectors.toList());
|
||||
uncoverableNeighbors.forEach(mineBoardField -> {
|
||||
if(!alreadyConsidered.contains(mineBoardField.getX() + "_" + mineBoardField.getY())) {
|
||||
mineBoardField.setType(MineBoardField.MineBoardFieldType.UNCOVERED);
|
||||
// only if t he newly found neighbor is a free field, we should discover its neighbors
|
||||
if(mineBoardField.getCounterValue() == 0) {
|
||||
toUncover.addAll(uncoverableNeighbors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
field.setType(MineBoardField.MineBoardFieldType.UNCOVERED);
|
||||
}
|
||||
if(hasWon(board)) {
|
||||
return GameService.MineResult.WON;
|
||||
}
|
||||
return GameService.MineResult.CONTINUE;
|
||||
}
|
||||
throw new IllegalStateException("Did not find correct type of field.");
|
||||
}
|
||||
|
||||
private List<MineBoardField> getNeighbors(MineBoard mineBoard, int xPosition, int yPosition) {
|
||||
return getNeighbors(mineBoard, xPosition, yPosition, false);
|
||||
}
|
||||
|
||||
private List<MineBoardField> getNeighbors(MineBoard board, int xPosition, int yPosition, boolean directOnly) {
|
||||
List<MineBoardField> neighbors = new ArrayList<>();
|
||||
boolean isFirstRow = yPosition == 0;
|
||||
boolean isLastRow = yPosition == board.getRowCount() - 1;
|
||||
boolean isFirstColumn = xPosition == 0;
|
||||
boolean isLastColumn = xPosition == board.getColumnCount() - 1;
|
||||
if(!isFirstColumn) {
|
||||
if(!isFirstRow && !directOnly) {
|
||||
neighbors.add(board.getField(xPosition - 1, yPosition - 1));
|
||||
}
|
||||
neighbors.add(board.getField(xPosition - 1, yPosition));
|
||||
if(!isLastRow && !directOnly) {
|
||||
neighbors.add(board.getField(xPosition - 1, yPosition + 1));
|
||||
}
|
||||
}
|
||||
if(!isFirstRow && !directOnly) {
|
||||
neighbors.add(board.getField(xPosition, yPosition - 1));
|
||||
}
|
||||
if(!isLastRow && !directOnly) {
|
||||
neighbors.add(board.getField(xPosition, yPosition + 1));
|
||||
}
|
||||
if(!isLastColumn) {
|
||||
if(!isFirstRow && !directOnly) {
|
||||
neighbors.add(board.getField(xPosition + 1, yPosition - 1));
|
||||
}
|
||||
neighbors.add(board.getField(xPosition + 1, yPosition));
|
||||
if(!isLastRow && !directOnly) {
|
||||
neighbors.add(board.getField(xPosition + 1, yPosition + 1));
|
||||
}
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
|
||||
public MineBoard generateEmptyBoard(Integer width, Integer height) {
|
||||
List<MineBoardRow> rows = new ArrayList<>();
|
||||
for (int y = 0; y < height; y++) {
|
||||
List<MineBoardField> fields = new ArrayList<>();
|
||||
for (int x = 0; x < width; x++) {
|
||||
MineBoardField field = MineBoardField
|
||||
.builder()
|
||||
.y(y)
|
||||
.x(x)
|
||||
.counterValue(0)
|
||||
.type(MineBoardField.MineBoardFieldType.COVERED)
|
||||
.build();
|
||||
fields.add(field);
|
||||
}
|
||||
MineBoardRow row = MineBoardRow
|
||||
.builder()
|
||||
.fields(fields)
|
||||
.build();
|
||||
rows.add(row);
|
||||
}
|
||||
return MineBoard
|
||||
.builder()
|
||||
.rows(rows)
|
||||
.state(MineResult.CONTINUE)
|
||||
.columnCount(width)
|
||||
.creditChange(0L)
|
||||
.rowCount(height)
|
||||
.boardId(UUID.randomUUID().toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
public void fillWithMines(MineBoard board) {
|
||||
Set<String> usedKeys = new HashSet<>();
|
||||
int maxIterations = 1_0000_000;
|
||||
int iterations = 0;
|
||||
List<Pair<Integer, Integer>> foundPositions = new ArrayList<>();
|
||||
do {
|
||||
int x = secureRandom.nextInt(board.getColumnCount());
|
||||
int y = secureRandom.nextInt(board.getRowCount());
|
||||
String positionKey = x + "_" + y;
|
||||
if(!usedKeys.contains(positionKey)) {
|
||||
foundPositions.add(Pair.of(x, y));
|
||||
usedKeys.add(positionKey);
|
||||
iterations = 0;
|
||||
}
|
||||
iterations++;
|
||||
} while(foundPositions.size() < board.getMineCount() && iterations < maxIterations);
|
||||
foundPositions.forEach(xYPair -> board.getRows().get(xYPair.getRight()).getFields().get(xYPair.getLeft()).setType(MineBoardField.MineBoardFieldType.MINE));
|
||||
}
|
||||
|
||||
public void evaluateCounters(MineBoard board) {
|
||||
board.getRows().forEach(mineBoardRow -> mineBoardRow.getFields().forEach(mineBoardField -> {
|
||||
if(!mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.MINE)) {
|
||||
long mineCounts = getMineCounts(board, mineBoardField.getX(), mineBoardField.getY());
|
||||
mineBoardField.setCounterValue((int) mineCounts);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private long getMineCounts(MineBoard board, int xPosition, int yPosition) {
|
||||
List<MineBoardField> neighbors = getNeighbors(board, xPosition, yPosition);
|
||||
return neighbors
|
||||
.stream()
|
||||
.filter(mineBoardField -> mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.MINE))
|
||||
.count();
|
||||
}
|
||||
|
||||
private boolean hasWon(MineBoard board) {
|
||||
return board
|
||||
.getFields()
|
||||
.stream()
|
||||
.noneMatch(mineBoardField ->
|
||||
mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.COVERED)
|
||||
&& !mineBoardField.getType().equals(MineBoardField.MineBoardFieldType.MINE));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.entertainment.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyLeaderboardResult;
|
||||
@@ -39,6 +40,11 @@ public class EconomyUserManagementServiceBean implements EconomyUserManagementSe
|
||||
return repository.findByUser(aUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<EconomyUser> getUser(ServerUser serverUser) {
|
||||
return repository.findByServer_IdAndUser_UserReference_Id(serverUser.getServerId(), serverUser.getUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EconomyLeaderboardResult getRankOfUserInServer(AUserInAServer aUserInAServer) {
|
||||
return repository.getRankOfUserInServer(aUserInAServer.getUserInServerId(), aUserInAServer.getServerReference().getId());
|
||||
|
||||
@@ -20,6 +20,15 @@ abstracto.systemConfigs.slotsCooldown.longValue=30
|
||||
abstracto.featureFlags.economy.featureName=economy
|
||||
abstracto.featureFlags.economy.enabled=false
|
||||
|
||||
abstracto.featureFlags.games.featureName=games
|
||||
abstracto.featureFlags.games.enabled=false
|
||||
|
||||
abstracto.systemConfigs.minesCreditsFactor.name=minesCreditsFactor
|
||||
abstracto.systemConfigs.minesCreditsFactor.doubleValue=5
|
||||
|
||||
abstracto.systemConfigs.minesMinMineRatio.name=minesMinMineRatio
|
||||
abstracto.systemConfigs.minesMinMineRatio.doubleValue=0.2
|
||||
|
||||
# for now this is fine
|
||||
abstracto.systemConfigs.creditGambleJackpot.name=creditGambleJackpot
|
||||
abstracto.systemConfigs.creditGambleJackpot.longValue=1000
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<property name="entertainmentModule" value="(SELECT id FROM module WHERE name = 'entertainment')"/>
|
||||
<property name="gamesFeature" value="(SELECT id FROM feature WHERE key = 'games')"/>
|
||||
|
||||
<changeSet author="Sheldan" id="mines-commands">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="mines"/>
|
||||
<column name="module_id" valueComputed="${entertainmentModule}"/>
|
||||
<column name="feature_id" valueComputed="${gamesFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="feature.xml" relativeToChangelogFile="true"/>
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="games_feature-insertion">
|
||||
<insert tableName="feature">
|
||||
<column name="key" value="games"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -11,4 +11,5 @@
|
||||
<include file="1.2.9-entertainment/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.0/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.3/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.11/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum EntertainmentFeatureDefinition implements FeatureDefinition {
|
||||
ENTERTAINMENT("entertainment"), ECONOMY("economy");
|
||||
ENTERTAINMENT("entertainment"), ECONOMY("economy"), GAMES("games");
|
||||
|
||||
private String key;
|
||||
|
||||
|
||||
@@ -4,4 +4,5 @@ public class EntertainmentSlashCommandNames {
|
||||
public static final String ENTERTAINMENT = "entertainment";
|
||||
public static final String UTILITY = "utility";
|
||||
public static final String ECONOMY = "economy";
|
||||
public static final String GAME = "game";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.sheldan.abstracto.entertainment.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class GamesFeatureConfig implements FeatureConfig {
|
||||
|
||||
public static final String MINES_CREDITS_FACTOR = "minesCreditsFactor";
|
||||
public static final String MINES_MINIMUM_MINES_RATIO = "minesMinMineRatio";
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.GAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRequiredSystemConfigKeys() {
|
||||
return Arrays.asList(MINES_CREDITS_FACTOR, MINES_MINIMUM_MINES_RATIO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package dev.sheldan.abstracto.entertainment.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
|
||||
import dev.sheldan.abstracto.entertainment.model.exception.InvalidGameBoardExceptionModel;
|
||||
|
||||
public class InvalidGameBoardException extends AbstractoTemplatableException {
|
||||
|
||||
private final InvalidGameBoardExceptionModel model;
|
||||
|
||||
public InvalidGameBoardException(Double minRatio) {
|
||||
super();
|
||||
this.model = InvalidGameBoardExceptionModel
|
||||
.builder()
|
||||
.minMinesRatio(minRatio)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "invalid_mine_board_config_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package dev.sheldan.abstracto.entertainment.model.command.games;
|
||||
|
||||
import dev.sheldan.abstracto.entertainment.service.GameService;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class MineBoard {
|
||||
private String boardId;
|
||||
private Long userId;
|
||||
private Long serverId;
|
||||
private Long messageId;
|
||||
private Long channelId;
|
||||
private Integer rowCount;
|
||||
private Integer columnCount;
|
||||
private Integer credits;
|
||||
private Long creditChange;
|
||||
private boolean creditsEnabled;
|
||||
private Integer mineCount;
|
||||
private List<MineBoardRow> rows;
|
||||
private GameService.MineResult state;
|
||||
|
||||
public MineBoardField getField(int x, int y) {
|
||||
if(x > columnCount || y > rowCount) {
|
||||
throw new IllegalArgumentException("Out of bounds access to board.");
|
||||
}
|
||||
MineBoardRow mineBoardRow = rows.get(y);
|
||||
return mineBoardRow.getFields().get(x);
|
||||
}
|
||||
|
||||
public List<MineBoardField> getFields() {
|
||||
List<MineBoardField> fields = new ArrayList<>();
|
||||
rows.forEach(mineBoardRow -> fields.addAll(mineBoardRow.getFields()));
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package dev.sheldan.abstracto.entertainment.model.command.games;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@Setter
|
||||
public class MineBoardField {
|
||||
private MineBoardField.MineBoardFieldType type;
|
||||
private Integer x;
|
||||
private Integer y;
|
||||
private Integer counterValue;
|
||||
|
||||
public enum MineBoardFieldType {
|
||||
MINE, UNCOVERED, COVERED, EXPLODED
|
||||
}
|
||||
|
||||
public static boolean canInteract(MineBoardFieldType currentType) {
|
||||
return currentType != MineBoardFieldType.UNCOVERED && currentType != MineBoardFieldType.EXPLODED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.entertainment.model.command.games;
|
||||
|
||||
import dev.sheldan.abstracto.core.interaction.button.ButtonPayload;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@Setter
|
||||
public class MineBoardPayload implements ButtonPayload {
|
||||
private MineBoard mineBoard;
|
||||
private Integer x;
|
||||
private Integer y;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.entertainment.model.command.games;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class MineBoardRow {
|
||||
private List<MineBoardField> fields;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.entertainment.model.exception;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class InvalidGameBoardExceptionModel {
|
||||
private Double minMinesRatio;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package dev.sheldan.abstracto.entertainment.service;
|
||||
|
||||
import dev.sheldan.abstracto.entertainment.model.command.games.MineBoard;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
public interface GameService {
|
||||
MineBoard createBoard(Integer width, Integer height, Integer mines, Long serverId);
|
||||
void persistMineBoardMessage(MineBoard mineBoard, Message message);
|
||||
void updateMineBoard(MineBoard mineBoard);
|
||||
void uncoverBoard(MineBoard mineBoard);
|
||||
void evaluateCreditChanges(MineBoard mineBoard);
|
||||
MineResult uncoverField(MineBoard board, Integer x, Integer y);
|
||||
|
||||
|
||||
enum MineResult {
|
||||
WON, LOST, CONTINUE
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.entertainment.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyLeaderboardResult;
|
||||
@@ -11,6 +12,7 @@ import java.util.Optional;
|
||||
public interface EconomyUserManagementService {
|
||||
EconomyUser createUser(AUserInAServer aUserInAServer);
|
||||
Optional<EconomyUser> getUser(AUserInAServer aUserInAServer);
|
||||
Optional<EconomyUser> getUser(ServerUser serverUser);
|
||||
EconomyLeaderboardResult getRankOfUserInServer(AUserInAServer aUserInAServer);
|
||||
List<EconomyUser> getRanksInServer(AServer server, Integer page, Integer size);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package dev.sheldan.abstracto.experience.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
|
||||
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class ExpLevelUpNotification extends AbstractConditionableCommand {
|
||||
|
||||
private static final String FLAG_PARAMETER = "newValue";
|
||||
private static final String EXP_LEVEL_UP_NOTIFICATION_COMMAND = "expLevelUpNotification";
|
||||
private static final String EXP_LEVEL_UP_NOTIFICATION_RESPONSE = "expLevelUpNotification_response";
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private AUserExperienceService aUserExperienceService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Override
|
||||
public CommandResult execute(CommandContext commandContext) {
|
||||
Boolean newValue = (Boolean) commandContext.getParameters().getParameters().get(0);
|
||||
updateExpLevelNotification(commandContext.getAuthor(), newValue);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
Boolean newValue = slashCommandParameterService.getCommandOption(FLAG_PARAMETER, event, Boolean.class);
|
||||
updateExpLevelNotification(event.getMember(), newValue);
|
||||
return interactionService.replyEmbed(EXP_LEVEL_UP_NOTIFICATION_RESPONSE, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
private void updateExpLevelNotification(Member member, Boolean newValue) {
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
aUserExperienceService.setLevelUpNotification(aUserInAServer, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ExperienceFeatureDefinition.EXPERIENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
Parameter memberParameter = Parameter
|
||||
.builder()
|
||||
.name(FLAG_PARAMETER)
|
||||
.templated(true)
|
||||
.type(Boolean.class)
|
||||
.build();
|
||||
List<Parameter> parameters = Arrays.asList(memberParameter);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE)
|
||||
.commandName(EXP_LEVEL_UP_NOTIFICATION_COMMAND)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(EXP_LEVEL_UP_NOTIFICATION_COMMAND)
|
||||
.module(ExperienceModuleDefinition.EXPERIENCE)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.causesReaction(true)
|
||||
.supportsEmbedException(true)
|
||||
.templated(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,17 @@ public class Rank extends AbstractConditionableCommand {
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(toRender);
|
||||
AUserExperience experienceObj = userExperienceManagementService.findUserInServer(aUserInAServer);
|
||||
log.info("Rendering rank for user {} in server {}.", toRender.getId(), toRender.getGuild().getId());
|
||||
rankModel.setExperienceToNextLevel(experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience()));
|
||||
Long currentExpNeeded = experienceObj.getCurrentLevel().getExperienceNeeded();
|
||||
Long experienceNeededToNextLevel = experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience());
|
||||
Long nextLevelExperience = experienceLevelService.calculateNextLevel(experienceObj.getCurrentLevel().getLevel()).getExperienceNeeded();
|
||||
Long levelExperience = nextLevelExperience - currentExpNeeded;
|
||||
Long inLevelExperience = experienceObj.getExperience() - currentExpNeeded;
|
||||
rankModel.setExperienceForCurrentLevel(currentExpNeeded);
|
||||
rankModel.setCurrentLevelPercentage(((float) inLevelExperience / levelExperience) * 100);
|
||||
rankModel.setLevelExperience(levelExperience);
|
||||
rankModel.setExperienceToNextLevel(experienceNeededToNextLevel);
|
||||
rankModel.setInLevelExperience(inLevelExperience);
|
||||
rankModel.setNextLevelExperience(nextLevelExperience);
|
||||
return templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel, toRender.getGuild().getIdLong());
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +37,16 @@ public class JoiningUserRoleListener implements AsyncJoinListener {
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MemberJoinModel model) {
|
||||
if(model.getMember().isPending()) {
|
||||
log.info("Joining member {} in guild {} is still pending - ignoring for experience role assignment.", model.getJoiningUser().getUserId(), model.getJoiningUser().getServerId());
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
Optional<AUserInAServer> userInAServerOptional = userInServerManagementService.loadUserOptional(model.getServerId(), model.getJoiningUser().getUserId());
|
||||
userInAServerOptional.ifPresent(aUserInAServer -> {
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(aUserInAServer.getUserInServerId());
|
||||
if(userExperienceOptional.isPresent()) {
|
||||
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", model.getJoiningUser().getUserId(), model.getServerId());
|
||||
userExperienceService.syncForSingleUser(userExperienceOptional.get(), model.getMember()).thenAccept(result ->
|
||||
userExperienceService.syncForSingleUser(userExperienceOptional.get(), model.getMember(), true).thenAccept(result ->
|
||||
log.info("Finished re-assigning experience for re-joining user {} in server {}.", model.getJoiningUser().getUserId(), model.getServerId())
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
|
||||
import dev.sheldan.abstracto.core.listener.async.jda.AsyncUpdatePendingListener;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.listener.MemberUpdatePendingModel;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
|
||||
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* If a {@link Member member} updates the pending status, this {@link AsyncUpdatePendingListener listener} retrieves the previously stored {@link AUserExperience experience} and gives the
|
||||
* member the necessary {@link net.dv8tion.jda.api.entities.Role role} according to the current configuration, if any
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MemberPendingRoleListener implements AsyncUpdatePendingListener {
|
||||
|
||||
@Autowired
|
||||
private UserExperienceManagementService userExperienceManagementService;
|
||||
|
||||
@Autowired
|
||||
private AUserExperienceService userExperienceService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MemberUpdatePendingModel model) {
|
||||
Optional<AUserInAServer> userInAServerOptional = userInServerManagementService.loadUserOptional(model.getServerId(), model.getUser().getUserId());
|
||||
userInAServerOptional.ifPresent(aUserInAServer -> {
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(aUserInAServer.getUserInServerId());
|
||||
if(userExperienceOptional.isPresent()) {
|
||||
log.info("User {} updated pending status {} with previous experience. Setting up experience role again (if necessary).", model.getUser().getUserId(), model.getServerId());
|
||||
userExperienceService.syncForSingleUser(userExperienceOptional.get(), model.getMember(), true).thenAccept(result ->
|
||||
log.info("Finished re-assigning experience for update pending user {} in server {}.", model.getUser().getUserId(), model.getServerId())
|
||||
);
|
||||
} else {
|
||||
log.info("Member updating pending {} in server {} does not have any previous experience. Not setting up anything.", model.getUser().getUserId(), model.getServerId());
|
||||
}
|
||||
});
|
||||
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ExperienceFeatureDefinition.EXPERIENCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureConfig;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
@@ -28,6 +29,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
@@ -136,7 +138,10 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
// we store when the user is eligible for experience _again_
|
||||
Long maxSeconds = configService.getLongValueOrConfigDefault(EXP_COOLDOWN_SECONDS_KEY, serverId);
|
||||
serverExperience.put(userId, Instant.now().plus(maxSeconds, ChronoUnit.SECONDS));
|
||||
CompletableFuture.runAsync(() -> self.addExperienceToMember(member, message), experienceUpdateExecutor);
|
||||
CompletableFuture.runAsync(() -> self.addExperienceToMember(member, message), experienceUpdateExecutor).exceptionally(throwable -> {
|
||||
log.error("Failed to add experience to member {} in server {}.", message.getAuthor().getId(), message.getGuild().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
runTimeExperienceService.releaseLock();
|
||||
@@ -183,18 +188,37 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
CompletableFuture<Void> returnFuture = new CompletableFuture<>();
|
||||
Long serverId = server.getId();
|
||||
int supposedUserCount = userIds.size();
|
||||
memberService.getMembersInServerAsync(server.getId(), userIds).whenComplete((members, throwable) -> {
|
||||
if(throwable != null) {
|
||||
log.warn("Failed to load all members in server {} for syncing experience. We started with {} and got {}.",
|
||||
serverId, supposedUserCount, members.size(), throwable);
|
||||
|
||||
List<List<Long>> partitionedUserIds = ListUtils.partition(userIds, 100);
|
||||
List<CompletableFuture<List<Member>>> memberLoadingFutures = new ArrayList<>();
|
||||
for (List<Long> userIdsPart : partitionedUserIds) {
|
||||
memberLoadingFutures.add(memberService.getMembersInServerAsync(server.getId(), userIdsPart));
|
||||
try {
|
||||
Thread.sleep(500L);
|
||||
} catch (InterruptedException e) {
|
||||
log.error("Failed to sleep.", e);
|
||||
}
|
||||
self.syncUsers(members, serverId, messageChannel).thenAccept(unused -> {
|
||||
log.info("Finished syncing users for experience roles.");
|
||||
returnFuture.complete(null);
|
||||
}).exceptionally(throwable1 -> {
|
||||
}
|
||||
CompletableFutureList<List<Member>> listCompletableFutureList = new CompletableFutureList<>(memberLoadingFutures);
|
||||
listCompletableFutureList.getMainFuture().whenComplete((result, throwable) -> {
|
||||
List<Member> members = new ArrayList<>();
|
||||
listCompletableFutureList.getFutures().forEach(listCompletableFuture -> members.addAll(listCompletableFuture.join()));
|
||||
if(throwable != null) {
|
||||
log.warn("Failed to load all members in server {} for syncing experience. We started with {} and got {}.",
|
||||
serverId, supposedUserCount, members.size(), throwable);
|
||||
}
|
||||
self.syncUsers(members, serverId, messageChannel).thenAccept(unused -> {
|
||||
log.info("Finished syncing users for experience roles.");
|
||||
returnFuture.complete(null);
|
||||
}).exceptionally(throwable1 -> {
|
||||
log.error("Failed to sync members.", throwable);
|
||||
returnFuture.complete(null);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to load members.", throwable);
|
||||
returnFuture.complete(null);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
return returnFuture;
|
||||
}
|
||||
@@ -231,17 +255,17 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
public CompletableFuture<Void> syncUser(Member member, List<AExperienceRole> roles) {
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
AUserExperience userExperience = userExperienceManagementService.findByUserInServerId(aUserInAServer.getUserInServerId());
|
||||
return calculateAndApplyExperienceRole(userExperience, member, roles);
|
||||
return calculateAndApplyExperienceRole(userExperience, member, roles, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> syncForSingleUser(AUserExperience userExperience, Member member) {
|
||||
public CompletableFuture<Void> syncForSingleUser(AUserExperience userExperience, Member member, boolean forceRoles) {
|
||||
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(userExperience.getServer());
|
||||
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
|
||||
return calculateAndApplyExperienceRole(userExperience, member, roles);
|
||||
return calculateAndApplyExperienceRole(userExperience, member, roles, forceRoles);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> calculateAndApplyExperienceRole(AUserExperience userExperience, Member member, List<AExperienceRole> roles) {
|
||||
private CompletableFuture<Void> calculateAndApplyExperienceRole(AUserExperience userExperience, Member member, List<AExperienceRole> roles, boolean forceRoles) {
|
||||
AExperienceRole calculatedNewRole = experienceRoleService.calculateRole(roles, userExperience.getCurrentLevel().getLevel());
|
||||
Long oldRoleId = userExperience.getCurrentExperienceRole() != null && userExperience.getCurrentExperienceRole().getRole() != null ? userExperience.getCurrentExperienceRole().getRole().getId() : null;
|
||||
Long newRoleId = calculatedNewRole != null ? calculatedNewRole.getRole().getId() : null;
|
||||
@@ -249,7 +273,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
userExperience.setCurrentExperienceRole(calculatedNewRole);
|
||||
|
||||
CompletableFuture<Void> returningFuture;
|
||||
if(!Objects.equals(oldRoleId, newRoleId)) {
|
||||
if(!Objects.equals(oldRoleId, newRoleId) || forceRoles) {
|
||||
CompletableFuture<Void> addingFuture;
|
||||
if(oldRoleId != null) {
|
||||
addingFuture = roleService.removeRoleFromMemberAsync(member, oldRoleId);
|
||||
@@ -315,11 +339,13 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
oldLevel);
|
||||
aUserExperience.setCurrentLevel(newLevel);
|
||||
AExperienceRole calculatedNewRole = experienceRoleService.calculateRole(roles, newLevel.getLevel());
|
||||
Long oldRoleId = aUserExperience.getCurrentExperienceRole() != null ? aUserExperience.getCurrentExperienceRole().getRole().getId() : null;
|
||||
Long newRoleId = calculatedNewRole != null ? calculatedNewRole.getRole().getId() : null;
|
||||
Long oldRoleId = aUserExperience.getCurrentExperienceRole() != null && aUserExperience.getCurrentExperienceRole().getRole() != null ? aUserExperience.getCurrentExperienceRole().getRole().getId() : null;
|
||||
Long newRoleId = calculatedNewRole != null && calculatedNewRole.getRole() != null ? calculatedNewRole.getRole().getId() : null;
|
||||
result.setOldRoleId(oldRoleId);
|
||||
result.setNewRoleId(newRoleId);
|
||||
if(message != null && featureModeService.featureModeActive(ExperienceFeatureDefinition.EXPERIENCE, serverId, ExperienceFeatureMode.LEVEL_UP_NOTIFICATION)) {
|
||||
if(message != null
|
||||
&& aUserExperience.getLevelUpNotification()
|
||||
&& featureModeService.featureModeActive(ExperienceFeatureDefinition.EXPERIENCE, serverId, ExperienceFeatureMode.LEVEL_UP_NOTIFICATION)) {
|
||||
LevelUpNotificationModel model = LevelUpNotificationModel
|
||||
.builder()
|
||||
.memberDisplay(MemberDisplay.fromMember(member))
|
||||
@@ -408,6 +434,13 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
userExperience.setExperienceGainDisabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLevelUpNotification(AUserInAServer aUserInAServer, Boolean newValue) {
|
||||
Optional<AUserExperience> aUserExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(aUserInAServer.getUserInServerId());
|
||||
AUserExperience aUserExperience = aUserExperienceOptional.orElseGet(() -> userExperienceManagementService.createUserInServer(aUserInAServer));
|
||||
aUserExperience.setLevelUpNotification(newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a {@link MessageToSend messageToSend} to be used as a status message for the ongoing user synchronization
|
||||
* @param current The amount of users which have been synced
|
||||
|
||||
@@ -57,9 +57,14 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService {
|
||||
|
||||
@Override
|
||||
public Long calculateExperienceToNextLevel(Integer level, Long currentExperience) {
|
||||
AExperienceLevel nextLevel = experienceLevelManagementService.getLevelOptional(level + 1)
|
||||
.orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", level)));
|
||||
AExperienceLevel nextLevel = calculateNextLevel(level);
|
||||
return nextLevel.getExperienceNeeded() - currentExperience;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AExperienceLevel calculateNextLevel(Integer level) {
|
||||
return experienceLevelManagementService.getLevelOptional(level + 1)
|
||||
.orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", level)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
|
||||
.messageCount(0L)
|
||||
.server(aUserInAServer.getServerReference())
|
||||
.experienceGainDisabled(false)
|
||||
.levelUpNotification(true)
|
||||
.user(aUserInAServer)
|
||||
.id(aUserInAServer.getUserInServerId())
|
||||
.currentLevel(startingLevel)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<property name="experienceModule" value="(SELECT id FROM module WHERE name = 'experience')"/>
|
||||
<property name="experienceFeature" value="(SELECT id FROM feature WHERE key = 'experience')"/>
|
||||
<changeSet author="Sheldan" id="experience-expLevelUpNotification_command">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="expLevelUpNotification"/>
|
||||
<column name="module_id" valueComputed="${experienceModule}"/>
|
||||
<column name="feature_id" valueComputed="${experienceFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
|
||||
<include file="user_experience.xml" relativeToChangelogFile="true"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="user_experience-add_level_up_notification">
|
||||
<addColumn tableName="user_experience">
|
||||
<column name="level_up_notification" type="BOOLEAN" defaultValueBoolean="true"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -9,4 +9,5 @@
|
||||
<include file="1.0-experience/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.2.15/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.8/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.17/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -67,7 +67,7 @@ public class JoiningUserRoleListenerTest {
|
||||
public void testUserWithExperienceRejoining() {
|
||||
AUserExperience experience = Mockito.mock(AUserExperience.class);
|
||||
when(userExperienceManagementService.findByUserInServerIdOptional(USER_IN_SERVER_ID)).thenReturn(Optional.of(experience));
|
||||
when(userExperienceService.syncForSingleUser(experience, member)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(userExperienceService.syncForSingleUser(experience, member, true)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(model.getMember()).thenReturn(member);
|
||||
DefaultListenerResult result = testUnit.execute(model);
|
||||
Assert.assertEquals(DefaultListenerResult.PROCESSED, result);
|
||||
@@ -75,9 +75,18 @@ public class JoiningUserRoleListenerTest {
|
||||
|
||||
@Test
|
||||
public void testUserWithOutExperienceRejoining() {
|
||||
when(model.getMember()).thenReturn(member);
|
||||
when(userExperienceManagementService.findByUserInServerIdOptional(USER_IN_SERVER_ID)).thenReturn(Optional.empty());
|
||||
testUnit.execute(model);
|
||||
verify(userExperienceService, times(0)).syncForSingleUser(any(), any());
|
||||
verify(userExperienceService, times(0)).syncForSingleUser(any(), any(), eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPendingUserJoining() {
|
||||
when(member.isPending()).thenReturn(true);
|
||||
when(model.getMember()).thenReturn(member);
|
||||
testUnit.execute(model);
|
||||
verify(userExperienceService, times(0)).syncForSingleUser(any(), any(), eq(true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.experience.model.database;
|
||||
import dev.sheldan.abstracto.core.models.database.ARole;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.sheldan.abstracto.experience.model.database;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.ARole;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -60,6 +60,9 @@ public class AUserExperience implements Serializable {
|
||||
@Column(name = "experience_gain_disabled", nullable = false)
|
||||
private Boolean experienceGainDisabled = false;
|
||||
|
||||
@Column(name = "level_up_notification")
|
||||
private Boolean levelUpNotification;
|
||||
|
||||
/**
|
||||
* The {@link AExperienceLevel level} which the user currently has.
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,26 @@ public class RankModel {
|
||||
* The necessary experience to the next level up.
|
||||
*/
|
||||
private Long experienceToNextLevel;
|
||||
/**
|
||||
* Total experience needed for this level
|
||||
*/
|
||||
private Long experienceForCurrentLevel;
|
||||
/**
|
||||
* Percentage of progress within this level
|
||||
*/
|
||||
private Float currentLevelPercentage;
|
||||
/**
|
||||
* The total amount of experience needed for this level
|
||||
*/
|
||||
private Long levelExperience;
|
||||
/**
|
||||
* The experience which has been reached _within_ this level
|
||||
*/
|
||||
private Long inLevelExperience;
|
||||
/**
|
||||
* The experience needed to reach the next level
|
||||
*/
|
||||
private Long nextLevelExperience;
|
||||
/**
|
||||
* The member to show the rank for
|
||||
*/
|
||||
|
||||
@@ -44,7 +44,7 @@ public interface AUserExperienceService {
|
||||
|
||||
CompletableFuture<Void> syncUserRolesWithFeedback(AServer server, MessageChannel messageChannel);
|
||||
|
||||
CompletableFuture<Void> syncForSingleUser(AUserExperience userExperience, Member member);
|
||||
CompletableFuture<Void> syncForSingleUser(AUserExperience userExperience, Member member, boolean changeRoles);
|
||||
|
||||
/**
|
||||
* Loads the desired page of the ordered complete leaderboard from the {@link AServer} and returns the information as a {@link LeaderBoard}
|
||||
@@ -75,6 +75,7 @@ public interface AUserExperienceService {
|
||||
* @param userInAServer The {@link AUserInAServer} to enable experience for
|
||||
*/
|
||||
void enableExperienceForUser(AUserInAServer userInAServer);
|
||||
void setLevelUpNotification(AUserInAServer aUserInAServer, Boolean newValue);
|
||||
|
||||
boolean experienceGainEnabledInChannel(MessageChannel messageChannel);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package dev.sheldan.abstracto.experience.service;
|
||||
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
|
||||
/**
|
||||
* Service responsible for operations on {@link dev.sheldan.abstracto.experience.model.database.AExperienceLevel experienceLevel}
|
||||
* This includes creating and calculations.
|
||||
@@ -20,6 +22,7 @@ public interface ExperienceLevelService {
|
||||
* @return The amount of experience required necessary to reach the next level
|
||||
*/
|
||||
Long calculateExperienceToNextLevel(Integer level, Long currentExperience);
|
||||
AExperienceLevel calculateNextLevel(Integer level);
|
||||
|
||||
/**
|
||||
* Calculates the required experience to reach this level. This calculated experience is relative, in the sense that
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.invitefilter.model.database;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.invitefilter.model.database;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.invitefilter.model.database;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>logging</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>logging</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -33,33 +33,32 @@ public class ReportContextCommandListener implements MessageContextCommandListen
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MessageContextInteractionModel model) {
|
||||
Message targetMessage = model.getEvent().getTarget();
|
||||
if(targetMessage.getAuthor().getIdLong() == model.getEvent().getUser().getIdLong()) {
|
||||
interactionService.replyEmbed(ReactionReportServiceBean.REACTION_REPORT_OWN_MESSAGE_RESPONSE_TEMPLATE, new Object(), model.getEvent());
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
ServerUser userReporting = ServerUser
|
||||
.builder()
|
||||
.serverId(model.getServerId())
|
||||
.userId(model.getEvent().getUser().getIdLong())
|
||||
.isBot(model.getEvent().getUser().isBot())
|
||||
.build();
|
||||
|
||||
if(!reactionReportService.allowedToReport(userReporting)) {
|
||||
log.info("User {} was reported on message {} in server {} within the cooldown. Ignoring.",
|
||||
targetMessage.getAuthor().getIdLong(), targetMessage.getIdLong(), targetMessage.getGuild().getIdLong());
|
||||
interactionService.replyEmbed(ReactionReportServiceBean.REACTION_REPORT_COOLDOWN_RESPONSE_TEMPLATE, new Object(), model.getEvent());
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
|
||||
reactionReportService.createReactionReport(targetMessage, userReporting, null).exceptionally(throwable -> {
|
||||
log.error("Failed to create reaction report in server {} on message {} in channel {} with interaction.",
|
||||
model.getServerId(), targetMessage.getIdLong(), model.getEvent().getChannel().getIdLong(), throwable);
|
||||
return null;
|
||||
model.getEvent().deferReply(true).queue(interactionHook -> {
|
||||
Message targetMessage = model.getEvent().getTarget();
|
||||
if(targetMessage.getAuthor().getIdLong() == model.getEvent().getUser().getIdLong()) {
|
||||
interactionService.sendMessageToInteraction(ReactionReportServiceBean.REACTION_REPORT_OWN_MESSAGE_RESPONSE_TEMPLATE, new Object(), interactionHook);
|
||||
return;
|
||||
}
|
||||
ServerUser userReporting = ServerUser
|
||||
.builder()
|
||||
.serverId(model.getServerId())
|
||||
.userId(model.getEvent().getUser().getIdLong())
|
||||
.isBot(model.getEvent().getUser().isBot())
|
||||
.build();
|
||||
if(!reactionReportService.allowedToReport(userReporting)) {
|
||||
log.info("User {} was reported on message {} in server {} within the cooldown. Ignoring.",
|
||||
targetMessage.getAuthor().getIdLong(), targetMessage.getIdLong(), targetMessage.getGuild().getIdLong());
|
||||
interactionService.sendMessageToInteraction(ReactionReportServiceBean.REACTION_REPORT_COOLDOWN_RESPONSE_TEMPLATE, new Object(),interactionHook);
|
||||
return;
|
||||
}
|
||||
reactionReportService.createReactionReport(targetMessage, userReporting, null).exceptionally(throwable -> {
|
||||
log.error("Failed to create reaction report in server {} on message {} in channel {} with interaction.",
|
||||
model.getServerId(), targetMessage.getIdLong(), model.getEvent().getChannel().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
interactionService.sendMessageToInteraction(REACTION_REPORT_RESPONSE_TEMPLATE, new Object(), interactionHook);
|
||||
});
|
||||
|
||||
interactionService.replyEmbed(REACTION_REPORT_RESPONSE_TEMPLATE, new Object(), model.getEvent());
|
||||
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import net.dv8tion.jda.api.interactions.modals.ModalMapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static dev.sheldan.abstracto.moderation.service.ReactionReportServiceBean.REACTION_REPORT_FAILURE_RESPONSE_TEMPLATE;
|
||||
import static dev.sheldan.abstracto.moderation.service.ReactionReportServiceBean.REACTION_REPORT_RESPONSE_TEMPLATE;
|
||||
|
||||
@Component
|
||||
@@ -46,27 +47,35 @@ public class ReportContextModalListener implements ModalInteractionListener {
|
||||
.map(ModalMapping::getAsString)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
messageCache.getMessageFromCache(payload.getServerId(), payload.getChannelId(), payload.getMessageId()).thenAccept(cachedMessage -> {
|
||||
ServerUser userReporting = ServerUser
|
||||
.builder()
|
||||
.serverId(model.getServerId())
|
||||
.userId(cachedMessage.getAuthor().getAuthorId())
|
||||
.isBot(cachedMessage.getAuthor().getIsBot())
|
||||
.build();
|
||||
reactionReportService.createReactionReport(cachedMessage, userReporting, context)
|
||||
.thenAccept(unused -> {
|
||||
interactionService.replyEmbed(REACTION_REPORT_RESPONSE_TEMPLATE, new Object(), model.getEvent());
|
||||
log.info("Handled modal for message report with id {} in guild {} in channel {} on message {}",
|
||||
model.getEvent().getModalId(), payload.getServerId(), payload.getChannelId(), payload.getMessageId());
|
||||
componentPayloadManagementService.deletePayload(payload.getModalId());
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to create reaction report in server {} on message {} in channel {} with interaction.",
|
||||
model.getServerId(), cachedMessage.getMessageId(), model.getEvent().getChannel().getIdLong(), throwable);
|
||||
model.getEvent().deferReply(true).queue(interactionHook -> {
|
||||
messageCache.getMessageFromCache(payload.getServerId(), payload.getChannelId(), payload.getMessageId()).thenAccept(cachedMessage -> {
|
||||
ServerUser userReporting = ServerUser
|
||||
.builder()
|
||||
.serverId(model.getServerId())
|
||||
.userId(cachedMessage.getAuthor().getAuthorId())
|
||||
.isBot(cachedMessage.getAuthor().getIsBot())
|
||||
.build();
|
||||
reactionReportService.createReactionReport(cachedMessage, userReporting, context)
|
||||
.thenAccept(unused -> {
|
||||
interactionService.sendMessageToInteraction(REACTION_REPORT_RESPONSE_TEMPLATE, new Object(), interactionHook);
|
||||
log.info("Handled modal for message report with id {} in guild {} in channel {} on message {}",
|
||||
model.getEvent().getModalId(), payload.getServerId(), payload.getChannelId(), payload.getMessageId());
|
||||
componentPayloadManagementService.deletePayload(payload.getModalId());
|
||||
}).exceptionally(throwable -> {
|
||||
interactionService.sendMessageToInteraction(REACTION_REPORT_FAILURE_RESPONSE_TEMPLATE, new Object(), interactionHook);
|
||||
log.error("Failed to create reaction report in server {} on message {} in channel {} with interaction.",
|
||||
model.getServerId(), cachedMessage.getMessageId(), model.getEvent().getChannel().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
interactionService.sendMessageToInteraction(REACTION_REPORT_FAILURE_RESPONSE_TEMPLATE, new Object(), interactionHook);
|
||||
log.error("Failed to load reported message for reporting message {} in channel {} with context.",
|
||||
model.getEvent().getMessage().getIdLong(), model.getEvent().getChannel().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to load reported message.", throwable);
|
||||
return null;
|
||||
}, throwable -> {
|
||||
log.error("Failed to acknowledge modal interaction for report context modal listener in guild {} on message {}.", model.getServerId(),
|
||||
model.getEvent().getMessage() != null ? model.getEvent().getMessage().getIdLong() : 0, throwable);
|
||||
});
|
||||
|
||||
return ModalInteractionListenerResult.ACKNOWLEDGED;
|
||||
|
||||
@@ -71,6 +71,7 @@ public class ReactionReportServiceBean implements ReactionReportService {
|
||||
private static final String REACTION_REPORT_TEMPLATE_KEY = "reactionReport_notification";
|
||||
public static final String REACTION_REPORT_MODAL_ORIGIN = "reportMessageModal";
|
||||
public static final String REACTION_REPORT_RESPONSE_TEMPLATE = "reactionReport_response";
|
||||
public static final String REACTION_REPORT_FAILURE_RESPONSE_TEMPLATE = "reactionReport_failure_response";
|
||||
public static final String REACTION_REPORT_COOLDOWN_RESPONSE_TEMPLATE = "reactionReport_cooldown_response";
|
||||
public static final String REACTION_REPORT_OWN_MESSAGE_RESPONSE_TEMPLATE = "reactionReport_own_message_response";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation</artifactId>
|
||||
<version>1.4.8</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.moderation.model.database;
|
||||
import dev.sheldan.abstracto.moderation.model.database.embedded.InfractionParameterId;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
|
||||
@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
|
||||
@@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.ARole;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import jakarta.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ package dev.sheldan.abstracto.moderation.model.database.embedded;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Embeddable
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user