Compare commits

...

135 Commits

Author SHA1 Message Date
Sheldan
af5f9a8361 [maven-release-plugin] prepare release v1.5.13 2023-12-10 14:32:05 +01:00
Sheldan
e84b5ecbb5 [AB-30] adding giveaway feature 2023-12-10 14:25:08 +01:00
Sheldan
1ba8219d7b [AB-xxx] fixing using wrong parameter for unSuggest command 2023-11-15 01:06:30 +01:00
Sheldan
60d2c669a2 [maven-release-plugin] prepare for next development iteration 2023-10-29 18:23:09 +01:00
Sheldan
3a122a72e5 [maven-release-plugin] prepare release v1.5.12 2023-10-29 18:23:03 +01:00
Sheldan
d53126e5a5 [AB-xxx] actively limiting auto complete responses to the max allowed values
changing interface of slash command parameter service to be more applicable
adding utility functions to slash command auto complete service bean
2023-10-29 18:21:29 +01:00
Sheldan
208d9a28ed [maven-release-plugin] prepare for next development iteration 2023-10-23 01:27:29 +02:00
Sheldan
6643359953 [maven-release-plugin] prepare release v1.5.11 2023-10-23 01:27:22 +02:00
Sheldan
bd7149d159 [AB-xxx] prepare for release 2023-10-23 01:26:12 +02:00
Sheldan
c0b6a19bca [AB-82] adding instant for cooldown exception model
removing not needed models for payday and slots cooldown exceptions
2023-10-04 23:34:16 +02:00
Sheldan
58eece0814 [AB-xxx] setting duration to zero if it was not provided, for infraction storage 2023-10-04 22:45:51 +02:00
Sheldan
abfd2c9591 [AB-xxx] ignore slash command only commands for message commands 2023-09-26 23:37:04 +02:00
Sheldan
a71a448b4b [maven-release-plugin] prepare for next development iteration 2023-09-26 22:51:02 +02:00
Sheldan
4d1ce7158f [maven-release-plugin] prepare release v1.5.10 2023-09-26 22:50:58 +02:00
Sheldan
9bbb9430d9 [AB-xxx] preparing for release 2023-09-26 22:49:00 +02:00
Sheldan
a608fba082 [AB-106] renaming deletion days to deletion duration 2023-09-26 00:58:01 +02:00
Sheldan
f97fe42e65 [AB-106] adding ability to specify deletion duration on ban command
removing banDelete command
updating jda version
2023-09-26 00:56:15 +02:00
Sheldan
f12581f322 [AB-xxx] adding information whether a command is slash/message command only to help output
resizing template content column
2023-09-20 02:01:09 +02:00
Sheldan
e8f630c94c [AB-xxx] never using the interaction in echo when a channel is provided 2023-09-09 23:58:31 +02:00
Sheldan
14f35caede [AB-xxx] never using the interaction in echo when a channel is provided 2023-09-09 23:57:23 +02:00
Sheldan
915eb8ced9 [AB-xxx] fixing not limiting custom commands for auto complete 2023-09-08 00:17:43 +02:00
Sheldan
148c10f250 [maven-release-plugin] prepare for next development iteration 2023-09-07 23:30:10 +02:00
Sheldan
74e5154e29 [maven-release-plugin] prepare release v1.5.9 2023-09-07 23:30:05 +02:00
Sheldan
baad696a20 [AB-xxx] adding auto complete to custom command get 2023-09-07 22:57:51 +02:00
Sheldan
b7b5dc7b6a [AB-xxx] fixing installer version 2023-09-07 21:11:22 +02:00
Sheldan
f27f59c0b3 [maven-release-plugin] prepare for next development iteration 2023-09-07 21:10:31 +02:00
Sheldan
ccd7ace8d9 [maven-release-plugin] prepare release v1.5.8 2023-09-07 21:10:26 +02:00
Sheldan
73a73dc4f2 [AB-104] adding server wide member individual command cooldown and commands to set/reset this cooldown configuration on a command level
removing custom cooldown handling from payday and slots commands
2023-09-06 01:23:55 +02:00
Sheldan
156725afa6 [AB-97] adding wind speed to weather command
fixing command failing non gracefully in case the location for weather was not found
2023-09-05 01:44:01 +02:00
Sheldan
b369b56823 [AB-103] adding ability to create/delete/list/retrieve custom commands 2023-09-05 01:22:31 +02:00
Sheldan
7482bf545d [maven-release-plugin] prepare for next development iteration 2023-09-03 13:42:07 +02:00
Sheldan
9804d165ca [maven-release-plugin] prepare release v1.5.7 2023-09-03 13:42:03 +02:00
Sheldan
59ddb0b27d [AB-xxx] fixing random string not set when updating twitch notifications 2023-09-03 13:40:00 +02:00
Sheldan
9aea9d2b4f [AB-xxx] preparing for next release 2023-09-03 01:22:39 +02:00
Sheldan
b042e586a7 [maven-release-plugin] prepare for next development iteration 2023-09-03 00:51:48 +02:00
Sheldan
91e2bea2fc [maven-release-plugin] prepare release v1.5.6 2023-09-03 00:51:44 +02:00
Sheldan
f03bee8b1e [AB-94] adding command to show the state of a server poll 2023-09-03 00:19:35 +02:00
Sheldan
f3144eb094 [AB-99] changing the way roles are added/removed for experience system, as discord has a race condition in which quick additions/removals cause unexpected problems 2023-09-02 22:22:33 +02:00
Sheldan
2396bf300b [AB-101] adding random string to twitch stream preview image to invalidate cache 2023-09-02 21:42:28 +02:00
Sheldan
06ebf4c882 [AB-102] adding redirect to echo command 2023-09-02 21:20:36 +02:00
Sheldan
ff534c03ac [maven-release-plugin] prepare for next development iteration 2023-08-27 22:39:07 +02:00
Sheldan
67c76487e2 [maven-release-plugin] prepare release v1.5.5 2023-08-27 22:39:03 +02:00
Sheldan
9a2f47e244 [AB-xxx] increasing installer version to match abstracto version 2023-08-27 22:37:33 +02:00
Sheldan
2f33d19171 [maven-release-plugin] prepare for next development iteration 2023-08-27 21:46:27 +02:00
Sheldan
f6fc02e758 [maven-release-plugin] prepare release v1.5.4 2023-08-27 21:46:23 +02:00
Sheldan
007929cfa5 [AB-xxx] setting working dir for docker build 2023-08-27 21:45:09 +02:00
Sheldan
77e2eec3d1 [maven-release-plugin] prepare for next development iteration 2023-08-27 21:21:57 +02:00
Sheldan
74c8cf7b6b [maven-release-plugin] prepare release v1.5.3 2023-08-27 21:21:53 +02:00
Sheldan
c8739b90ec [AB-xxx] fixing .env file path 2023-08-27 21:18:57 +02:00
Sheldan
d39a303207 [maven-release-plugin] prepare for next development iteration 2023-08-27 20:58:00 +02:00
Sheldan
3e326fe47e [maven-release-plugin] prepare release v1.5.2 2023-08-27 20:57:55 +02:00
Sheldan
a1d460973c [AB-xxx] removing releaseProfiles 2023-08-27 20:56:02 +02:00
Sheldan
d2475179e6 [AB-xxx] removing duplicate release plugin declaration 2023-08-27 20:54:33 +02:00
Sheldan
5adc304e77 [AB-xxx] fixing release pipeline format 2023-08-27 20:28:39 +02:00
Sheldan
4940577383 [AB-xxx] changing tag format 2023-08-27 19:41:58 +02:00
Sheldan
bba0a2ace6 [AB-xxx] restructuring installer module to be outside of maven
split liquibase and template deployment
adding various features to the deployment images
2023-08-27 19:18:12 +02:00
Sheldan
b7c427026d [AB-xxx] adding serialization for instant and offset datetime for gson payload storage 2023-07-27 20:00:01 +02:00
Sheldan
cee10de915 [maven-release-plugin] prepare for next development iteration 2023-07-22 18:07:17 +02:00
Sheldan
1786231e11 [maven-release-plugin] prepare release abstracto-application-1.5.1 2023-07-22 18:07:13 +02:00
Sheldan
2231fdf289 [AB-xxx] changing class loader helper class, because sometimes the class is not found with the default one 2023-07-22 17:50:19 +02:00
Sheldan
a46e22b5b2 [AB-xxx] also stopping the triggers if a server poll is closed 2023-07-10 20:29:45 +02:00
Sheldan
1c9b9af833 [maven-release-plugin] prepare for next development iteration 2023-07-09 23:13:53 +02:00
Sheldan
3cafc95ceb [maven-release-plugin] prepare release abstracto-application-1.5.0 2023-07-09 23:13:48 +02:00
Sheldan
6409bbaa1d [AB-98] adding twitch support
upgrading to java 17
upgrade of dependencies
2023-07-09 23:06:52 +02:00
Sheldan
346e462185 [AB-xxx] fixing exact temperatures not leading to an appropriate color for weather service 2023-06-22 22:49:47 +02:00
Sheldan
46baa79d3e [maven-release-plugin] prepare for next development iteration 2023-06-04 21:17:29 +02:00
Sheldan
650d062808 [maven-release-plugin] prepare release abstracto-application-1.4.26 2023-06-04 21:17:25 +02:00
Sheldan
bac9832819 [AB-90] adding poll functionality
adding select menu functionality
not automatically acknowledging button interactions
adding ability to define positions for components
adding method to remove components to channel service
always replacing message contents with edit message in a channel
adding ability to reply a modal to a button interaction
moving post target specific methods from server management service to post target management
2023-06-04 21:12:46 +02:00
Sheldan
efbcb5c84b [maven-release-plugin] prepare for next development iteration 2023-05-19 00:27:06 +02:00
Sheldan
fd70e6ac90 [maven-release-plugin] prepare release abstracto-application-1.4.25 2023-05-19 00:27:02 +02:00
Sheldan
29bde70796 [AB-93] fixing setting attached files to null 2023-05-19 00:24:45 +02:00
Sheldan
ecd4feabb2 [maven-release-plugin] prepare for next development iteration 2023-05-18 23:45:59 +02:00
Sheldan
abf60409f1 [maven-release-plugin] prepare release abstracto-application-1.4.24 2023-05-18 23:45:55 +02:00
Sheldan
080733957f [AB-93] fixing not initializing the attached files 2023-05-18 23:43:34 +02:00
Sheldan
8a41f366ae [maven-release-plugin] prepare for next development iteration 2023-05-18 22:53:56 +02:00
Sheldan
dbf478c44c [maven-release-plugin] prepare release abstracto-application-1.4.23 2023-05-18 22:53:52 +02:00
Sheldan
3df688571f [AB-93] changing how MessageToSend handles attached plaintext files 2023-05-18 22:32:56 +02:00
Sheldan
ca530949c6 [AB-92] fixing not providing member display object for modmail thread already exists embed 2023-05-18 01:23:42 +02:00
Sheldan
724930e5a4 [AB-xxx] updating readme
upgrading JDA version to 5.0.0-beta.5
2023-03-20 23:16:52 +01:00
Sheldan
2875da117a [AB-91] adding location id to the available information for weather model 2023-03-19 10:54:54 +01:00
Sheldan
f95ba6c28f [maven-release-plugin] prepare for next development iteration 2023-03-19 00:14:21 +01:00
Sheldan
1b2e7654f9 [maven-release-plugin] prepare release abstracto-application-1.4.22 2023-03-19 00:14:16 +01:00
Sheldan
54976ed1d4 [AB-89] adding command to retrieve weather data 2023-03-19 00:09:43 +01:00
Sheldan
735816f5dd [AB-xxx] adding feature to split field value by configurable amount
using larger images for member avatar
2023-03-05 13:49:32 +01:00
Sheldan
a984bdb84e [AB-86] fixing exception in case of a re-joining user without experience role 2023-02-26 14:16:27 +01:00
Sheldan
21add6585d [maven-release-plugin] prepare for next development iteration 2023-02-26 10:58:01 +01:00
Sheldan
99e72245f3 [maven-release-plugin] prepare release abstracto-application-1.4.21 2023-02-26 10:57:57 +01:00
Sheldan
9d184ff560 [AB-85] adding feature mode to automatically create a thread for suggestions
reworking post target service to function with optionals
fixing trying to add reactions for suggestions if there was no message created
not showing votes in case the buttons feature mode is active
2023-02-26 10:50:36 +01:00
Sheldan
97895f5c56 [AB-84] fixing incorrect calculation for agreement percentage 2023-02-25 18:33:02 +01:00
Sheldan
f091559c49 [AB-84] adding necessary information to suggestion update message 2023-02-25 18:19:01 +01:00
Sheldan
fa7730975e [maven-release-plugin] prepare for next development iteration 2023-02-15 00:05:59 +01:00
Sheldan
03d7b9e2e2 [maven-release-plugin] prepare release abstracto-application-1.4.20 2023-02-15 00:05:51 +01:00
Sheldan
a0bff12263 [AB-xxx] adding default value for user experience object 2023-02-14 23:54:42 +01:00
Sheldan
70e708601e [AB-xxx] exception logging improvements for experience tracking 2023-02-14 21:14:18 +01:00
Sheldan
f01418d0de [AB-xxx] upgrading JDA version to version 5.0.0-beta.3 2023-02-04 20:57:02 +01:00
Sheldan
ad539adb2a [maven-release-plugin] prepare for next development iteration 2023-02-04 18:26:38 +01:00
Sheldan
3c9fec989f [maven-release-plugin] prepare release abstracto-application-1.4.19 2023-02-04 18:26:33 +01:00
Sheldan
21db3e3ee5 [AB-xxx] fixing compatible versions for installer 2023-02-04 18:22:06 +01:00
Sheldan
5b1ad2e075 [maven-release-plugin] prepare for next development iteration 2023-02-04 17:23:34 +01:00
Sheldan
63b3f68bdb [maven-release-plugin] prepare release abstracto-application-1.4.18 2023-02-04 17:23:29 +01:00
Sheldan
7c1537c4a7 Revert "[maven-release-plugin] prepare release abstracto-application-1.4.14"
This reverts commit 9836998087.
2023-02-04 17:21:15 +01:00
Sheldan
9836998087 [maven-release-plugin] prepare release abstracto-application-1.4.14 2023-02-04 17:13:57 +01:00
Sheldan
8a1bb4cad8 [AB-xxx] small installer logging improvement 2023-02-04 17:11:57 +01:00
Sheldan
a9dadec8ef [maven-release-plugin] prepare for next development iteration 2023-02-04 14:52:26 +01:00
Sheldan
3eaffaef87 [maven-release-plugin] prepare release abstracto-application-1.4.17 2023-02-04 14:52:20 +01:00
Sheldan
b3a943e155 [AB-20] adding level up notification configuration possibility 2023-01-28 13:13:38 +01:00
Sheldan
06dd4af131 [maven-release-plugin] prepare for next development iteration 2023-01-12 01:37:16 +01:00
Sheldan
0d51469975 [maven-release-plugin] prepare release abstracto-application-1.4.16 2023-01-12 01:37:12 +01:00
Sheldan
aa10c88588 [AB-81] adding support for choices in slash command parameters 2023-01-12 01:34:30 +01:00
Sheldan
db27f64832 [AB-80] fixing not cleaning up emote record when changing emote 2023-01-10 19:15:27 +01:00
Sheldan
3903039aac [AB-79] fixing test 2022-12-27 13:12:10 +01:00
Sheldan
41f42ee110 [AB-79] fix not applying role for re-joining users upon sync 2022-12-27 13:03:59 +01:00
Sheldan
74f54e1257 [maven-release-plugin] prepare for next development iteration 2022-12-21 13:27:21 +01:00
Sheldan
a72e48f690 [maven-release-plugin] prepare release abstracto-application-1.4.15 2022-12-21 13:27:16 +01:00
Sheldan
a813af8b1f [AB-xxx] fixing issue of not providing percentage to rank correctly 2022-12-21 01:34:32 +01:00
Sheldan
abee7b2732 [AB-xxx] providing more information in the rank model 2022-12-20 22:15:05 +01:00
Sheldan
4c71ffbb7e [maven-release-plugin] prepare for next development iteration 2022-12-10 16:54:36 +01:00
Sheldan
18050e2a8a [maven-release-plugin] prepare release abstracto-application-1.4.14 2022-12-10 16:54:32 +01:00
Sheldan
a0d83763d4 [AB-78] fixing users with previous experience not awarding the experience role if they join and are pending 2022-12-10 15:44:09 +01:00
Sheldan
0461c8e4ec [AB-77] deferring the reply for report with context interactions
do not defer the interaction all the time for modal interactions
2022-12-10 12:59:47 +01:00
Sheldan
072f32975a [maven-release-plugin] prepare for next development iteration 2022-12-03 20:17:11 +01:00
Sheldan
6810d28c50 [maven-release-plugin] prepare release abstracto-application-1.4.13 2022-12-03 20:16:57 +01:00
Sheldan
650a9099c4 [AB-66] fixing not reducing the bid on mines
fixing reaction report sometimes running into a timeout
2022-12-03 20:14:18 +01:00
Sheldan
1217e03725 [maven-release-plugin] prepare for next development iteration 2022-12-02 21:20:57 +01:00
Sheldan
2e837d8738 [maven-release-plugin] prepare release abstracto-application-1.4.12 2022-12-02 21:20:53 +01:00
Sheldan
9ddd386c6f [AB-66] adding min mines ratio and other input restrictions for mines game which should avoid some too easy setups 2022-12-02 21:16:32 +01:00
Sheldan
4e1db26df7 [AB-xxx] fixing java version in build file 2022-12-02 01:58:48 +01:00
Sheldan
de335a1e2a [AB-xxx] updating versions of GitHub actions in release/build job 2022-12-02 01:55:36 +01:00
Sheldan
9ba0ed711e [maven-release-plugin] prepare for next development iteration 2022-12-02 01:36:51 +01:00
Sheldan
b7376bf522 [maven-release-plugin] prepare release abstracto-application-1.4.11 2022-12-02 01:36:46 +01:00
Sheldan
0d6182c5d5 [AB-66] adding mines game
fixing suggestion evaluation job not getting the correct parameters
adding feature dependent parameters
2022-12-02 01:33:38 +01:00
Sheldan
96c38763b1 [maven-release-plugin] prepare for next development iteration 2022-11-20 23:22:21 +01:00
Sheldan
97b3099156 [maven-release-plugin] prepare release abstracto-application-1.4.10 2022-11-20 23:22:16 +01:00
Sheldan
a0b2fc9c31 [AB-25] artificial delay 2022-11-20 23:20:07 +01:00
Sheldan
2db36ef96b [maven-release-plugin] prepare for next development iteration 2022-11-20 22:39:40 +01:00
645 changed files with 15724 additions and 1712 deletions

View File

@@ -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()

View File

@@ -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,27 @@ 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
working-directory: ./deployment/installer/
env:
REGISTRY_PREFIX: docker.pkg.github.com/sheldan/abstracto/
VERSION: ${{ env.version }}
REGISTRY_PREFIX: ${{ steps.dotenv.outputs.registry_prefix }}
VERSION: ${{ steps.dotenv.outputs.version }}

View File

@@ -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

View File

@@ -1,8 +1,6 @@
# Abstracto
![Build](https://github.com/Sheldan/abstracto/workflows/Execute%20build%20and%20Sonar/badge.svg)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=abstracto-core&metric=coverage)](https://sonarcloud.io/dashboard?id=abstracto-core)
[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-white.svg)](https://sonarcloud.io/dashboard?id=abstracto-core)
![Build](https://github.com/Sheldan/abstracto/workflows/Execute%20Build/badge.svg)
[![GitHub license](https://img.shields.io/github/license/Sheldan/abstracto)](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.13
* [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.

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -41,13 +41,19 @@ public class ActivateAssignableRolePlace extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter placeName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(placeName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("activateAssignableRolePlace")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.messageCommandOnly(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)

View File

@@ -36,16 +36,40 @@ public class AddAssignableRoleCondition extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(Role.class).templated(true).build();
Parameter conditionKey = Parameter.builder().name("conditionKey").type(AssignableRoleConditionType.class).templated(true).build();
Parameter conditionValue = Parameter.builder().name("conditionParameter").type(String.class).templated(true).build();
Parameter placeName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
Parameter role = Parameter
.builder()
.name("role")
.type(Role.class)
.templated(true)
.build();
Parameter conditionKey = Parameter
.builder()
.name("conditionKey")
.type(AssignableRoleConditionType.class)
.templated(true)
.build();
Parameter conditionValue = Parameter
.builder()
.name("conditionParameter")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(placeName, role, conditionKey, conditionValue);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("addAssignableRoleCondition")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.messageCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -62,17 +62,42 @@ public class AddRoleToAssignableRolePost extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(Role.class).templated(true).build();
Parameter rolePostName = Parameter.builder().name("displayText").type(String.class).templated(true).build();
Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).optional(true).templated(true).build();
Parameter placeName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
Parameter role = Parameter
.builder()
.name("role")
.type(Role.class)
.templated(true)
.build();
Parameter rolePostName = Parameter
.builder()
.name("displayText")
.type(String.class)
.templated(true)
.build();
Parameter emote = Parameter
.builder()
.name("emote")
.type(FullEmote.class)
.optional(true)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(placeName, role, rolePostName, emote);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("addRoleToAssignableRolePlace")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.causesReaction(true)
.messageCommandOnly(true)
.async(true)
.supportsEmbedException(true)
.parameters(parameters)

View File

@@ -47,9 +47,24 @@ public class ChangeAssignableRolePlaceConfig extends AbstractConditionableComman
@Override
public CommandConfiguration getConfiguration() {
Parameter assignableRolePlaceName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter parameterKey = Parameter.builder().name("key").type(AssignableRolePlaceParameterKey.class).templated(true).build();
Parameter parameterValue = Parameter.builder().name("value").type(String.class).templated(true).build();
Parameter assignableRolePlaceName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
Parameter parameterKey = Parameter
.builder()
.name("key")
.type(AssignableRolePlaceParameterKey.class)
.templated(true)
.build();
Parameter parameterValue = Parameter
.builder()
.name("value")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(assignableRolePlaceName, parameterKey, parameterValue);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
@@ -57,6 +72,7 @@ public class ChangeAssignableRolePlaceConfig extends AbstractConditionableComman
.name("changeAssignableRolePlaceConfig")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.messageCommandOnly(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)

View File

@@ -33,9 +33,6 @@ public class CreateAssignableRolePost extends AbstractConditionableCommand {
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private ServerManagementService serverManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
@@ -57,20 +54,47 @@ public class CreateAssignableRolePost extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
List<ParameterValidator> rolePlaceNameValidator = Arrays.asList(MaxStringLengthValidator.max(AssignableRolePlace.ASSIGNABLE_PLACE_NAME_LIMIT));
Parameter rolePostName = Parameter.builder().name("name").validators(rolePlaceNameValidator).type(String.class).templated(true).build();
Parameter channel = Parameter.builder().name("channel").type(TextChannel.class).templated(true).build();
Parameter type = Parameter.builder().name("type").type(AssignableRolePlaceType.class).templated(true).optional(true).build();
Parameter rolePostName = Parameter
.builder()
.name("name")
.validators(rolePlaceNameValidator)
.type(String.class)
.templated(true)
.build();
Parameter channel = Parameter
.builder()
.name("channel")
.type(TextChannel.class)
.templated(true)
.build();
Parameter type = Parameter
.builder()
.name("type")
.type(AssignableRolePlaceType.class)
.templated(true)
.optional(true)
.build();
List<ParameterValidator> rolePlaceDescriptionValidator = Arrays.asList(MaxStringLengthValidator.max(AssignableRolePlace.ASSIGNABLE_PLACE_NAME_LIMIT));
Parameter text = Parameter.builder().name("text").validators(rolePlaceDescriptionValidator).type(String.class).templated(true).build();
Parameter text = Parameter
.builder()
.name("text")
.validators(rolePlaceDescriptionValidator)
.type(String.class)
.templated(true)
.build();
List<String> aliases = Arrays.asList("crRPl", "crAssRoPl");
List<Parameter> parameters = Arrays.asList(rolePostName, channel, text, type);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("createAssignableRolePlace")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.messageCommandOnly(true)
.parameters(parameters)
.aliases(aliases)
.help(helpInfo)

View File

@@ -41,7 +41,12 @@ public class DeactivateAssignableRolePlace extends AbstractConditionableCommand
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter rolePostName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(rolePostName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
@@ -49,6 +54,7 @@ public class DeactivateAssignableRolePlace extends AbstractConditionableCommand
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.async(true)
.messageCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -41,7 +41,12 @@ public class DeleteAssignableRolePlace extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter rolePostName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(rolePostName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
@@ -50,6 +55,7 @@ public class DeleteAssignableRolePlace extends AbstractConditionableCommand {
.templated(true)
.causesReaction(true)
.async(true)
.messageCommandOnly(true)
.requiresConfirmation(true)
.supportsEmbedException(true)
.parameters(parameters)

View File

@@ -46,15 +46,29 @@ public class EditAssignableRolePlaceText extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
List<ParameterValidator> rolePlaceNameValidator = Arrays.asList(MaxStringLengthValidator.max(AssignableRolePlace.ASSIGNABLE_PLACE_NAME_LIMIT));
Parameter rolePostName = Parameter.builder().name("name").validators(rolePlaceNameValidator).type(String.class).templated(true).build();
Parameter newText = Parameter.builder().name("newText").type(String.class).templated(true).build();
Parameter rolePostName = Parameter
.builder().name("name")
.validators(rolePlaceNameValidator)
.type(String.class)
.templated(true)
.build();
Parameter newText = Parameter
.builder()
.name("newText")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(rolePostName, newText);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("editAssignableRolePlaceText")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.async(true)
.messageCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -67,6 +67,7 @@ public class MoveAssignableRolePlace extends AbstractConditionableCommand {
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.causesReaction(true)
.messageCommandOnly(true)
.async(true)
.supportsEmbedException(true)
.parameters(parameters)

View File

@@ -35,15 +35,31 @@ public class RemoveAssignableRoleCondition extends AbstractConditionableCommand
@Override
public CommandConfiguration getConfiguration() {
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(Role.class).templated(true).build();
Parameter conditionKey = Parameter.builder().name("conditionKey").type(AssignableRoleConditionType.class).templated(true).build();
Parameter placeName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
Parameter role = Parameter
.builder()
.name("role")
.type(Role.class)
.templated(true)
.build();
Parameter conditionKey = Parameter
.builder()
.name("conditionKey")
.type(AssignableRoleConditionType.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(placeName, role, conditionKey);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("removeAssignableRoleCondition")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.messageCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -44,16 +44,30 @@ public class RemoveRoleFromAssignableRolePlace extends AbstractConditionableComm
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(ARole.class).templated(true).build();
Parameter rolePostName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
Parameter role = Parameter
.builder()
.name("role")
.type(ARole.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(rolePostName, role);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("removeRoleFromAssignableRolePlace")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.causesReaction(true)
.async(true)
.messageCommandOnly(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -48,14 +48,23 @@ public class SetupAssignableRolePlace extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter rolePostName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(rolePostName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("setupAssignableRolePlace")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.async(true)
.messageCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -48,15 +48,24 @@ public class ShowAssignableRolePlaceConfig extends AbstractConditionableCommand
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter rolePostName = Parameter
.builder()
.name("name")
.type(String.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(rolePostName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("showAssignableRolePlaceConfig")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.async(true)
.causesReaction(false)
.messageCommandOnly(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -45,11 +45,15 @@ public class ShowAssignableRolePlaces extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("showAssignableRolePlaces")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.messageCommandOnly(true)
.async(true)
.supportsEmbedException(true)
.help(helpInfo)

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>assignable-roles-int</artifactId>

View File

@@ -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;

View File

@@ -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")

View File

@@ -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;

View File

@@ -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;

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,100 @@
package dev.sheldan.abstracto.customcommand.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
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.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.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
import lombok.extern.slf4j.Slf4j;
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
@Slf4j
public class CreateCustomCommand extends AbstractConditionableCommand {
private static final String CREATE_CUSTOM_COMMAND_COMMAND = "createCustomCommand";
private static final String CUSTOM_COMMAND_NAME_PARAMETER = "commandName";
private static final String CUSTOM_COMMAND_CONTENT_PARAMETER = "response";
private static final String CREATE_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY = "createCustomCommand_response";
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private CustomCommandService customCommandService;
@Autowired
private InteractionService interactionService;
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String name = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_NAME_PARAMETER, event, String.class);
String content = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_CONTENT_PARAMETER, event, String.class);
customCommandService.createCustomCommand(name, content, event.getMember());
return interactionService.replyEmbed(CREATE_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override
public FeatureDefinition getFeature() {
return CustomCommandFeatureDefinition.CUSTOM_COMMAND;
}
@Override
public CommandConfiguration getConfiguration() {
Parameter commandNameParameter = Parameter
.builder()
.name(CUSTOM_COMMAND_NAME_PARAMETER)
.templated(true)
.type(String.class)
.build();
Parameter commandContentParameter = Parameter
.builder()
.name(CUSTOM_COMMAND_CONTENT_PARAMETER)
.templated(true)
.type(String.class)
.build();
List<Parameter> parameters = Arrays.asList(commandNameParameter, commandContentParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND)
.commandName("create")
.build();
return CommandConfiguration.builder()
.name(CREATE_CUSTOM_COMMAND_COMMAND)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.async(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.causesReaction(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
}

View File

@@ -0,0 +1,91 @@
package dev.sheldan.abstracto.customcommand.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
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.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.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
import lombok.extern.slf4j.Slf4j;
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
@Slf4j
public class DeleteCustomCommand extends AbstractConditionableCommand {
private static final String DELETE_CUSTOM_COMMAND_COMMAND = "deleteCustomCommand";
private static final String DELETE_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY = "deleteCustomCommand_response";
private static final String CUSTOM_COMMAND_NAME_PARAMETER = "commandName";
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private CustomCommandService customCommandService;
@Autowired
private InteractionService interactionService;
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String name = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_NAME_PARAMETER, event, String.class);
customCommandService.deleteCustomCommand(name, event.getGuild());
return interactionService.replyEmbed(DELETE_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter commandNameParameter = Parameter
.builder()
.name(CUSTOM_COMMAND_NAME_PARAMETER)
.templated(true)
.type(String.class)
.build();
List<Parameter> parameters = Arrays.asList(commandNameParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND)
.commandName("delete")
.build();
return CommandConfiguration.builder()
.name(DELETE_CUSTOM_COMMAND_COMMAND)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.async(true)
.slashCommandConfig(slashCommandConfig)
.causesReaction(true)
.slashCommandOnly(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CustomCommandFeatureDefinition.CUSTOM_COMMAND;
}
}

View File

@@ -0,0 +1,115 @@
package dev.sheldan.abstracto.customcommand.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
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.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.SlashCommandAutoCompleteService;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.model.command.CustomCommandResponseModel;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
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.concurrent.CompletableFuture;
@Component
public class GetCustomCommand extends AbstractConditionableCommand {
private static final String GET_CUSTOM_COMMAND_COMMAND = "getCustomCommand";
private static final String CUSTOM_COMMAND_NAME_PARAMETER = "commandName";
private static final String GET_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY = "getCustomCommand_response";
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Autowired
private CustomCommandService customCommandService;
@Autowired
private SlashCommandAutoCompleteService slashCommandAutoCompleteService;
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String name = slashCommandParameterService.getCommandOption(CUSTOM_COMMAND_NAME_PARAMETER, event, String.class);
CustomCommand customCommand = customCommandService.getCustomCommand(name, event.getGuild());
CustomCommandResponseModel model = CustomCommandResponseModel
.builder()
.additionalText(customCommand.getAdditionalMessage())
.build();
return interactionService.replyEmbed(GET_CUSTOM_COMMAND_RESPONSE_TEMPLATE_KEY, model, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override
public List<String> performAutoComplete(CommandAutoCompleteInteractionEvent event) {
if(slashCommandAutoCompleteService.matchesParameter(event.getFocusedOption(), CUSTOM_COMMAND_NAME_PARAMETER)) {
String input = event.getFocusedOption().getValue();
return customCommandService.getCustomCommandsStartingWith(input, event.getGuild())
.stream()
.map(CustomCommand::getName)
.limit(25)
.toList();
} else {
return new ArrayList<>();
}
}
@Override
public FeatureDefinition getFeature() {
return CustomCommandFeatureDefinition.CUSTOM_COMMAND;
}
@Override
public CommandConfiguration getConfiguration() {
Parameter commandNameParameter = Parameter
.builder()
.name(CUSTOM_COMMAND_NAME_PARAMETER)
.templated(true)
.supportsAutoComplete(true)
.type(String.class)
.build();
List<Parameter> parameters = Arrays.asList(commandNameParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND_PUBLIC)
.commandName("get")
.build();
return CommandConfiguration.builder()
.name(GET_CUSTOM_COMMAND_COMMAND)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.async(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.causesReaction(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
}

View File

@@ -0,0 +1,86 @@
package dev.sheldan.abstracto.customcommand.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
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.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.service.PaginatorService;
import dev.sheldan.abstracto.customcommand.config.CustomCommandFeatureDefinition;
import dev.sheldan.abstracto.customcommand.config.CustomCommandSlashCommandNames;
import dev.sheldan.abstracto.customcommand.model.command.ListCustomCommandsResponseModel;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ListCustomCommands extends AbstractConditionableCommand {
private static final String CREATE_CUSTOM_COMMAND_COMMAND = "listCustomCommands";
private static final String LIST_CUSTOM_COMMANDS_TEMPLATE_KEY = "listCustomCommands_response";
private static final String NO_CUSTOM_COMMANDS_TEMPLATE_KEY = "listCustomCommands_no_commands_response";
@Autowired
private CustomCommandService customCommandService;
@Autowired
private InteractionService interactionService;
@Autowired
private PaginatorService paginatorService;
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
List<CustomCommand> customCommands = customCommandService.getCustomCommands(event.getGuild());
if(customCommands.isEmpty()) {
return interactionService.replyEmbed(NO_CUSTOM_COMMANDS_TEMPLATE_KEY, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
ListCustomCommandsResponseModel model = ListCustomCommandsResponseModel.fromCommands(customCommands);
return paginatorService.createPaginatorFromTemplate(LIST_CUSTOM_COMMANDS_TEMPLATE_KEY, model, event)
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public FeatureDefinition getFeature() {
return CustomCommandFeatureDefinition.CUSTOM_COMMAND;
}
@Override
public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(CustomCommandSlashCommandNames.CUSTOM_COMMAND_PUBLIC)
.commandName("list")
.build();
return CommandConfiguration.builder()
.name(CREATE_CUSTOM_COMMAND_COMMAND)
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.async(true)
.slashCommandOnly(true)
.slashCommandConfig(slashCommandConfig)
.causesReaction(true)
.supportsEmbedException(true)
.help(helpInfo)
.build();
}
}

View File

@@ -5,9 +5,13 @@ import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface CustomCommandRepository extends JpaRepository<CustomCommand, Long> {
Optional<CustomCommand> getByNameIgnoreCaseAndServer(String name, AServer server);
void deleteByNameAndServer(String name, AServer server);
List<CustomCommand> findByServer(AServer server);
List<CustomCommand> findByNameStartsWithIgnoreCaseAndServer(String prefix, AServer server);
}

View File

@@ -0,0 +1,66 @@
package dev.sheldan.abstracto.customcommand.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.customcommand.exception.CustomCommandExistsException;
import dev.sheldan.abstracto.customcommand.exception.CustomCommandNotFoundException;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandManagementService;
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class CustomCommandServiceBean implements CustomCommandService {
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private CustomCommandManagementService customCommandManagementService;
@Autowired
private ServerManagementService serverManagementService;
@Override
public CustomCommand createCustomCommand(String name, String content, Member creator) {
if(customCommandManagementService.getCustomCommandByName(name, creator.getGuild().getIdLong()).isPresent()) {
throw new CustomCommandExistsException();
}
AUserInAServer creatorUser = userInServerManagementService.loadOrCreateUser(creator);
return customCommandManagementService.createCustomCommand(name, content, creatorUser);
}
@Override
public void deleteCustomCommand(String name, Guild guild) {
if(customCommandManagementService.getCustomCommandByName(name, guild.getIdLong()).isEmpty()) {
throw new CustomCommandNotFoundException();
}
AServer server = serverManagementService.loadServer(guild);
customCommandManagementService.deleteCustomCommand(name, server);
}
@Override
public List<CustomCommand> getCustomCommands(Guild guild) {
AServer server = serverManagementService.loadServer(guild);
return customCommandManagementService.getCustomCommands(server);
}
@Override
public CustomCommand getCustomCommand(String name, Guild guild) {
return customCommandManagementService.getCustomCommandByName(name, guild.getIdLong())
.orElseThrow(CustomCommandNotFoundException::new);
}
@Override
public List<CustomCommand> getCustomCommandsStartingWith(String prefix, Guild guild) {
AServer server = serverManagementService.loadServer(guild);
return customCommandManagementService.getCustomCommandsStartingWith(prefix, server);
}
}

View File

@@ -1,12 +1,14 @@
package dev.sheldan.abstracto.customcommand.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import dev.sheldan.abstracto.customcommand.repository.CustomCommandRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
@@ -23,4 +25,32 @@ public class CustomCommandManagementServiceBean implements CustomCommandManageme
AServer server = serverManagementService.loadServer(serverId);
return repository.getByNameIgnoreCaseAndServer(name, server);
}
@Override
public CustomCommand createCustomCommand(String name, String content, AUserInAServer creator) {
CustomCommand customCommand = CustomCommand
.builder()
.name(name)
.additionalMessage(content)
.server(creator.getServerReference())
.creator(creator)
.build();
return repository.save(customCommand);
}
@Override
public void deleteCustomCommand(String name, AServer server) {
repository.deleteByNameAndServer(name, server);
}
@Override
public List<CustomCommand> getCustomCommands(AServer server) {
return repository.findByServer(server);
}
@Override
public List<CustomCommand> getCustomCommandsStartingWith(String prefix, AServer server) {
return repository.findByNameStartsWithIgnoreCaseAndServer(prefix, server);
}
}

View File

@@ -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="seedData/data.xml" relativeToChangelogFile="true"/>
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,35 @@
<?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="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
<property name="customCommandFeature" value="(SELECT id FROM feature WHERE key = 'customCommand')"/>
<changeSet author="Sheldan" id="customCommand-commands">
<insert tableName="command">
<column name="name" value="createCustomCommand"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${customCommandFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="deleteCustomCommand"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${customCommandFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="getCustomCommand"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${customCommandFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="listCustomCommands"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${customCommandFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -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>

View File

@@ -0,0 +1,16 @@
<?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="custom_command-add_auto_increment">
<sql>
create sequence custom_command_id_seq;
alter table custom_command alter id set default nextval('custom_command_id_seq');
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -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="custom_command.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -7,4 +7,5 @@
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="1.4.0/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.8/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.customcommand.config;
public class CustomCommandSlashCommandNames {
public static final String CUSTOM_COMMAND = "cc";
public static final String CUSTOM_COMMAND_PUBLIC = "customCommands";
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.customcommand.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class CustomCommandExistsException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "custom_command_exists_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.customcommand.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class CustomCommandNotFoundException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "custom_command_not_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.customcommand.model.command;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class ListCustomCommandModel {
private String name;
private String content;
private MemberDisplay creator;
public static ListCustomCommandModel fromCustomCommand(CustomCommand customCommand) {
return ListCustomCommandModel
.builder()
.name(customCommand.getName())
.content(customCommand.getAdditionalMessage())
.creator(MemberDisplay.fromAUserInAServer(customCommand.getCreator()))
.build();
}
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.customcommand.model.command;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import lombok.Builder;
import lombok.Getter;
import java.util.List;
import java.util.stream.Collectors;
@Builder
@Getter
public class ListCustomCommandsResponseModel {
private List<ListCustomCommandModel> customCommands;
public static ListCustomCommandsResponseModel fromCommands(List<CustomCommand> customCommands) {
return ListCustomCommandsResponseModel
.builder()
.customCommands(customCommands
.stream()
.map(ListCustomCommandModel::fromCustomCommand)
.collect(Collectors.toList()))
.build();
}
}

View File

@@ -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;

View File

@@ -1,9 +1,16 @@
package dev.sheldan.abstracto.customcommand.service.management;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import java.util.List;
import java.util.Optional;
public interface CustomCommandManagementService {
Optional<CustomCommand> getCustomCommandByName(String name, Long serverId);
CustomCommand createCustomCommand(String name, String content, AUserInAServer creator);
void deleteCustomCommand(String name, AServer server);
List<CustomCommand> getCustomCommands(AServer server);
List<CustomCommand> getCustomCommandsStartingWith(String prefix, AServer server);
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.customcommand.service.management;
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import java.util.List;
public interface CustomCommandService {
CustomCommand createCustomCommand(String name, String content, Member creator);
void deleteCustomCommand(String name, Guild guild);
List<CustomCommand> getCustomCommands(Guild guild);
CustomCommand getCustomCommand(String name, Guild guild);
List<CustomCommand> getCustomCommandsStartingWith(String prefix, Guild guild);
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>dynamic-activity</artifactId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>dynamic-activity</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -2,7 +2,7 @@ package dev.sheldan.abstracto.activity.models;
import lombok.*;
import javax.persistence.*;
import jakarta.persistence.*;
import java.time.Instant;
@Builder

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -52,14 +52,28 @@ public class React extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("message").type(Message.class).templated(true).build());
parameters.add(Parameter.builder().name("text").type(String.class).remainder(true).templated(true).build());
Parameter messageParameter = Parameter
.builder()
.name("message")
.type(Message.class)
.templated(true)
.build();
parameters.add(messageParameter);
Parameter textParameter = Parameter
.builder()
.name("text")
.type(String.class)
.remainder(true)
.templated(true)
.build();
parameters.add(textParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("react")
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true)
.causesReaction(true)
.messageCommandOnly(true)
.async(true)
.supportsEmbedException(true)
.parameters(parameters)

View File

@@ -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()

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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" +
"( " +

View File

@@ -9,8 +9,6 @@ import dev.sheldan.abstracto.entertainment.dto.CreditGambleResult;
import dev.sheldan.abstracto.entertainment.dto.PayDayResult;
import dev.sheldan.abstracto.entertainment.dto.SlotsResult;
import dev.sheldan.abstracto.entertainment.exception.NotEnoughCreditsException;
import dev.sheldan.abstracto.entertainment.exception.PayDayCooldownException;
import dev.sheldan.abstracto.entertainment.exception.SlotsCooldownException;
import dev.sheldan.abstracto.entertainment.model.command.CreditsLeaderboardEntry;
import dev.sheldan.abstracto.entertainment.model.database.EconomyLeaderboardResult;
import dev.sheldan.abstracto.entertainment.model.database.EconomyUser;
@@ -19,14 +17,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.security.SecureRandom;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import static dev.sheldan.abstracto.entertainment.config.EconomyFeatureConfig.PAYDAY_COOLDOWN_CONFIG_KEY;
import static dev.sheldan.abstracto.entertainment.config.EconomyFeatureConfig.SLOTS_COOLDOWN_CONFIG_KEY;
@Component
public class EconomyServiceBean implements EconomyService {
@@ -70,42 +62,6 @@ public class EconomyServiceBean implements EconomyService {
private static final Integer TRIPLE_FACTOR = 10;
private static final Integer DOUBLE_FACTOR = 2;
@Override
public boolean canTriggerPayDay(AUserInAServer aUserInAServer) {
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(aUserInAServer);
return userOptional.map(this::canTriggerPayDay).orElse(true);
}
@Override
public boolean canTriggerSlots(AUserInAServer aUserInAServer) {
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(aUserInAServer);
return userOptional.map(this::canTriggerSlots).orElse(true);
}
@Override
public boolean canTriggerPayDay(EconomyUser economyUser) {
return slotsTriggerIn(economyUser).isNegative();
}
@Override
public boolean canTriggerSlots(EconomyUser economyUser) {
return payDayTriggerIn(economyUser).isNegative();
}
@Override
public Duration payDayTriggerIn(EconomyUser economyUser) {
Long cooldownSeconds = configService.getLongValueOrConfigDefault(PAYDAY_COOLDOWN_CONFIG_KEY, economyUser.getServer().getId());
Instant minTimeStamp = Instant.now().minus(cooldownSeconds, ChronoUnit.SECONDS);
return Duration.between(economyUser.getLastPayDay(), minTimeStamp);
}
@Override
public Duration slotsTriggerIn(EconomyUser economyUser) {
Long cooldownSeconds = configService.getLongValueOrConfigDefault(SLOTS_COOLDOWN_CONFIG_KEY, economyUser.getServer().getId());
Instant minTimeStamp = Instant.now().minus(cooldownSeconds, ChronoUnit.SECONDS);
return Duration.between(economyUser.getLastSlots(), minTimeStamp);
}
@Override
public EconomyUser addCredits(AUserInAServer aUserInAServer, Long credits) {
Optional<EconomyUser> existingUserOptional = economyUserManagementService.getUser(aUserInAServer);
@@ -137,11 +93,6 @@ public class EconomyServiceBean implements EconomyService {
Long creditsToAdd = configService.getLongValueOrConfigDefault(EconomyFeatureConfig.PAYDAY_CREDITS_CONFIG_KEY,
aUserInAServer.getServerReference().getId());
EconomyUser economyUser = addCredits(aUserInAServer, creditsToAdd);
Duration durationForPayday = payDayTriggerIn(economyUser);
if (durationForPayday.isNegative()) {
throw new PayDayCooldownException(durationForPayday.abs());
}
economyUser.setLastPayDay(Instant.now());
return PayDayResult
.builder()
.currentCredits(economyUser.getCredits())
@@ -160,17 +111,12 @@ public class EconomyServiceBean implements EconomyService {
if(user.getCredits() < bid) {
throw new NotEnoughCreditsException();
}
Duration durationForSlots = slotsTriggerIn(user);
if (durationForSlots.isNegative()) {
throw new SlotsCooldownException(durationForSlots.abs());
}
SlotGame slotGame = playSlots();
Integer factor = slotGame.getResultFactor();
Long creditChange = bid * factor;
addCredits(user, -bid);
addCredits(user, creditChange);
user.setLastSlots(Instant.now());
return SlotsResult
.builder()
.bid(bid)

View File

@@ -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));
}
}

View File

@@ -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;
@@ -26,8 +27,6 @@ public class EconomyUserManagementServiceBean implements EconomyUserManagementSe
.builder()
.id(aUserInAServer.getUserInServerId())
.server(aUserInAServer.getServerReference())
.lastPayDay(Instant.now().minus(1, ChronoUnit.DAYS))
.lastSlots(Instant.now().minus(1, ChronoUnit.DAYS))
.credits(0L)
.user(aUserInAServer)
.build();
@@ -39,6 +38,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());

View File

@@ -10,16 +10,18 @@ abstracto.featureFlags.entertainment.enabled=false
abstracto.systemConfigs.paydayCredits.name=paydayCredits
abstracto.systemConfigs.paydayCredits.longValue=120
# maybe replace this by command cooldowns which are globally on the server, instead of only channel group based
abstracto.systemConfigs.paydayCooldown.name=paydayCooldown
abstracto.systemConfigs.paydayCooldown.longValue=300
abstracto.systemConfigs.slotsCooldown.name=slotsCooldown
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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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="system_config.xml" relativeToChangelogFile="true"/>
<include file="economy_user.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -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="economy_user-delete-cooldown-columns">
<dropColumn tableName="economy_user">
<column name="last_pay_day" />
<column name="last_slots" />
</dropColumn>
</changeSet>
</databaseChangeLog>

View File

@@ -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" >
<changeSet author="Sheldan" id="economy_cooldown-system-config-deletions">
<delete tableName="system_config">
<where>name='paydayCooldown'</where>
</delete>
<delete tableName="system_config">
<where>name='slotsCooldown'</where>
</delete>
</changeSet>
</databaseChangeLog>

View File

@@ -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="cleanup/deletions.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -11,4 +11,6 @@
<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"/>
<include file="1.5.8/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -11,8 +11,6 @@ import java.util.List;
public class EconomyFeatureConfig implements FeatureConfig {
public static final String PAYDAY_CREDITS_CONFIG_KEY = "paydayCredits";
public static final String PAYDAY_COOLDOWN_CONFIG_KEY = "paydayCooldown";
public static final String SLOTS_COOLDOWN_CONFIG_KEY = "slotsCooldown";
@Override
public FeatureDefinition getFeature() {
@@ -21,6 +19,6 @@ public class EconomyFeatureConfig implements FeatureConfig {
@Override
public List<String> getRequiredSystemConfigKeys() {
return Arrays.asList(PAYDAY_CREDITS_CONFIG_KEY, PAYDAY_COOLDOWN_CONFIG_KEY, SLOTS_COOLDOWN_CONFIG_KEY);
return Arrays.asList(PAYDAY_CREDITS_CONFIG_KEY);
}
}

View File

@@ -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;

View File

@@ -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";
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -1,28 +0,0 @@
package dev.sheldan.abstracto.entertainment.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
import dev.sheldan.abstracto.entertainment.model.exception.PayDayCooldownExceptionModel;
import java.time.Duration;
public class PayDayCooldownException extends AbstractoTemplatableException {
private final PayDayCooldownExceptionModel model;
public PayDayCooldownException(Duration duration) {
this.model = PayDayCooldownExceptionModel
.builder()
.tryAgainDuration(duration)
.build();
}
@Override
public String getTemplateName() {
return "payday_cooldown_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -1,28 +0,0 @@
package dev.sheldan.abstracto.entertainment.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
import dev.sheldan.abstracto.entertainment.model.exception.SlotsCooldownExceptionModel;
import java.time.Duration;
public class SlotsCooldownException extends AbstractoTemplatableException {
private final SlotsCooldownExceptionModel model;
public SlotsCooldownException(Duration duration) {
this.model = SlotsCooldownExceptionModel
.builder()
.tryAgainDuration(duration)
.build();
}
@Override
public String getTemplateName() {
return "slots_cooldown_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
@@ -33,12 +33,6 @@ public class EconomyUser implements Serializable {
@Column(name = "credits", nullable = false)
private Long credits;
@Column(name = "last_slots", nullable = false)
private Instant lastSlots;
@Column(name = "last_pay_day", nullable = false)
private Instant lastPayDay;
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;

View File

@@ -3,10 +3,8 @@ package dev.sheldan.abstracto.entertainment.model.exception;
import lombok.Builder;
import lombok.Getter;
import java.time.Duration;
@Builder
@Getter
public class SlotsCooldownExceptionModel {
private Duration tryAgainDuration;
@Builder
public class InvalidGameBoardExceptionModel {
private Double minMinesRatio;
}

View File

@@ -1,12 +0,0 @@
package dev.sheldan.abstracto.entertainment.model.exception;
import lombok.Builder;
import lombok.Getter;
import java.time.Duration;
@Builder
@Getter
public class PayDayCooldownExceptionModel {
private Duration tryAgainDuration;
}

View File

@@ -10,16 +10,9 @@ import dev.sheldan.abstracto.entertainment.model.database.EconomyUser;
import lombok.Builder;
import lombok.Getter;
import java.time.Duration;
import java.util.List;
public interface EconomyService {
boolean canTriggerPayDay(AUserInAServer aUserInAServer);
boolean canTriggerSlots(AUserInAServer aUserInAServer);
boolean canTriggerPayDay(EconomyUser economyUser);
boolean canTriggerSlots(EconomyUser economyUser);
Duration payDayTriggerIn(EconomyUser economyUser);
Duration slotsTriggerIn(EconomyUser economyUser);
EconomyUser addCredits(AUserInAServer aUserInAServer, Long credits);
void addCredits(EconomyUser economyUser, Long credits);
void addPayDayCredits(AUserInAServer aUserInAServer);

View File

@@ -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
}
}

View File

@@ -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);
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.4.9</version>
<version>1.5.13</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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();
}
}

View File

@@ -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());
}

View File

@@ -69,6 +69,7 @@ public class SetExpRole extends AbstractConditionableCommand {
.module(ExperienceModuleDefinition.EXPERIENCE)
.templated(true)
.async(true)
.messageCommandOnly(true)
.supportsEmbedException(true)
.causesReaction(true)
.requiresConfirmation(true)

View File

@@ -46,7 +46,10 @@ public class SyncRoles extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder()
.name("syncExpRoles")
.module(ExperienceModuleDefinition.EXPERIENCE)
@@ -54,6 +57,7 @@ public class SyncRoles extends AbstractConditionableCommand {
.async(true)
.requiresConfirmation(true)
.supportsEmbedException(true)
.messageCommandOnly(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -59,13 +59,20 @@ public class UnSetExpRole extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("role").templated(true).type(ARole.class).build());
Parameter roleParameter = Parameter
.builder()
.name("role")
.templated(true)
.type(ARole.class)
.build();
parameters.add(roleParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("unSetExpRole")
.module(ExperienceModuleDefinition.EXPERIENCE)
.templated(true)
.async(true)
.messageCommandOnly(true)
.causesReaction(true)
.requiresConfirmation(true)
.supportsEmbedException(true)

Some files were not shown because too many files have changed in this diff Show More