Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
851aceb
Feature/bot v1 (#1)
rainbowdashlabs Mar 27, 2022
29c5448
Add unregister command (#7)
rainbowdashlabs Apr 1, 2022
206b938
Fix disband boolean
rainbowdashlabs Apr 1, 2022
95a404c
Feature/voting (#8)
rainbowdashlabs Apr 3, 2022
d80cf37
Prevent team creation during vote
rainbowdashlabs Apr 3, 2022
c6e4c94
Allow all registered players to vote
rainbowdashlabs Apr 3, 2022
ac47b06
Bump db
rainbowdashlabs Apr 3, 2022
95c9e08
Fix unregister command registered with the wrong name
rainbowdashlabs Apr 4, 2022
36e67a2
Feature/user api (#17)
rainbowdashlabs Apr 16, 2022
11701f9
Feature/teams api (#18)
rainbowdashlabs Apr 18, 2022
0c8fe10
Automatically create a configuration if none is present initially. Us…
yannicklamprecht Apr 23, 2022
04c68d6
Bump cjda version
rainbowdashlabs Apr 28, 2022
42de7cf
Remove orga role and permission deployment
rainbowdashlabs Apr 28, 2022
caac557
Feature/bot docker image (#21)
yannicklamprecht Apr 28, 2022
d21c235
Add velocity server registration
rainbowdashlabs Oct 21, 2022
fc352c5
Add server service to bot
rainbowdashlabs Oct 22, 2022
190c687
Migrate to latest cjda and sadu
rainbowdashlabs Oct 22, 2022
d903795
Add server restart mechanism
rainbowdashlabs Oct 23, 2022
78303e0
Adjust localisation
rainbowdashlabs Oct 23, 2022
61ae043
Define server command
rainbowdashlabs Oct 23, 2022
a070496
Start implementing system commands
rainbowdashlabs Oct 25, 2022
aa60857
Rewrite DB acces. I hate myself for this.
rainbowdashlabs Oct 25, 2022
36355ca
Implement server setup and deletion
rainbowdashlabs Oct 26, 2022
e7edd5e
Add delete, start, stop and restart of servers
rainbowdashlabs Oct 26, 2022
b023122
Add log and console command
rainbowdashlabs Oct 26, 2022
1984746
Add command to upload world
rainbowdashlabs Oct 26, 2022
d3540b8
Add plugin upload command
rainbowdashlabs Oct 26, 2022
825f054
Add command to upload and replace plugin data
rainbowdashlabs Oct 27, 2022
5bff8b9
Refactor server commands to reduce duplication
rainbowdashlabs Oct 27, 2022
59e160f
Add command to install plugins
rainbowdashlabs Oct 27, 2022
ada3953
Add Uninstall command for plugins
rainbowdashlabs Oct 27, 2022
b5a4d6f
Add license
rainbowdashlabs Oct 27, 2022
54af6bf
Make this stuff at least a bit more secure
rainbowdashlabs Oct 27, 2022
832c767
Add command to download plugin data
rainbowdashlabs Oct 27, 2022
92545aa
Avoid memory leak on download
rainbowdashlabs Oct 27, 2022
550a306
Define server admin command
rainbowdashlabs Oct 27, 2022
73a5574
Add serveradmin commands
rainbowdashlabs Oct 29, 2022
3516de6
Fix broken velocity registration
rainbowdashlabs Oct 29, 2022
513fe1f
Add command to set message and fallback retrieval from velo instance
rainbowdashlabs Oct 29, 2022
bdc2ebd
Add config commands for server
rainbowdashlabs Oct 29, 2022
9a88d3e
Add license
rainbowdashlabs Oct 29, 2022
ee3835a
Add server restart request
rainbowdashlabs Oct 29, 2022
a3177f4
Add edit command
rainbowdashlabs Oct 30, 2022
48b31c4
Add license
rainbowdashlabs Oct 30, 2022
7e325c4
Fix failing test
rainbowdashlabs Oct 30, 2022
8656c2c
Start join service
rainbowdashlabs Oct 30, 2022
79247fc
Add locale to paper plugin
rainbowdashlabs Oct 30, 2022
136cde5
update config
rainbowdashlabs Oct 30, 2022
a55c33f
Add localization to new commands
Taucher2003 Oct 30, 2022
4549a6c
Add missing locale key UwU
rainbowdashlabs Oct 30, 2022
4ae9230
Merge branch 'feature/velocity-registration' into feature/velocity-re…
Taucher2003 Oct 30, 2022
22f5a93
Sort and add german locale
rainbowdashlabs Oct 30, 2022
9bd0200
Rename options
rainbowdashlabs Oct 30, 2022
b49aa3b
Add missing options to argument keys
Taucher2003 Oct 30, 2022
6e23aa4
Finally fix localisation
rainbowdashlabs Oct 30, 2022
c5f6cc4
Improve translations for German locale
Taucher2003 Oct 30, 2022
b3d6476
Fix some stuff
rainbowdashlabs Oct 30, 2022
100f935
Merge pull request #24 from devcordde/feature/velocity-registration-l…
Taucher2003 Oct 30, 2022
b4b0270
Merge pull request #23 from devcordde/feature/velocity-registration
rainbowdashlabs Oct 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
!src/**/build/
gradle.properties

/server/
/template/
/plugins/

# Ignore Gradle GUI configuration
gradle-app.setting

Expand Down Expand Up @@ -30,3 +34,11 @@ dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar

# Bot internal generated data
/config/
/logs/
/out/
*.db
*.sqlite
/wait.sh
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
Bot and spigot plugin used for the dev cord plugin jam
Bot and spigot plugin used for the dev cord plugin jamCreator

## Start Arguments for paper
`-Dpluginjam.port`

Port of the velocity server api

`-Dpluginjam.name`

Name of the server

`-Djavalin.port`

Port of the javalin api of the server

## Start Arguments for velocity
`-Djavalin.port`

Port of the javalin api of the server
19 changes: 0 additions & 19 deletions api/build.gradle.kts

This file was deleted.

57 changes: 52 additions & 5 deletions bot/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,19 +1,66 @@
plugins {
id("com.github.johnrengelman.shadow") version "7.1.2"
java
}

group = "de.chojo"
version = "1.0"

repositories {
maven("https://eldonexus.de/repository/maven-public")
maven("https://eldonexus.de/repository/maven-proxies")
maven("https://m2.dv8tion.net/releases")
mavenCentral()
}

dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
implementation(project(":plugin-api"))

// discord
implementation("de.chojo", "cjda-util", "2.7.8+alpha.22-DEV") {
exclude(module = "opus-java")
}
implementation("io.javalin", "javalin-bundle", "4.4.0")
implementation("net.lingala.zip4j", "zip4j", "2.11.2")

// database
implementation("de.chojo.sadu", "sadu-queries", "1.2.0")
implementation("de.chojo.sadu", "sadu-updater", "1.2.0")
implementation("de.chojo.sadu", "sadu-datasource", "1.2.0")
implementation("de.chojo.sadu", "sadu-postgresql", "1.2.0")
implementation("org.postgresql", "postgresql", "42.3.3")

// Logging
implementation("org.slf4j", "slf4j-api", "2.0.3")
implementation("org.apache.logging.log4j", "log4j-core", "2.19.0")
implementation("org.apache.logging.log4j", "log4j-slf4j2-impl", "2.19.0")
implementation("club.minnced", "discord-webhooks", "0.7.5")

// unit testing
testImplementation(platform("org.junit:junit-bom:5.9.0"))
testImplementation("org.junit.jupiter", "junit-jupiter")
}

tasks.getByName<Test>("test") {
useJUnitPlatform()
}
tasks {
processResources {
from(sourceSets.main.get().resources.srcDirs) {
filesMatching("version") {
expand(
"version" to project.version
)
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
}

build {
dependsOn(shadowJar)
}

shadowJar {
mergeServiceFiles()
manifest {
attributes(mapOf("Main-Class" to "de.chojo.gamejam.Bot"))
}
}
}
217 changes: 217 additions & 0 deletions bot/src/main/java/de/chojo/gamejam/Bot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
* SPDX-License-Identifier: AGPL-3.0-only
*
* Copyright (C) 2022 DevCord Team and Contributor
*/

package de.chojo.gamejam;

import de.chojo.gamejam.api.Api;
import de.chojo.gamejam.commands.jamadmin.JamAdmin;
import de.chojo.gamejam.commands.register.Register;
import de.chojo.gamejam.commands.server.Server;
import de.chojo.gamejam.commands.serveradmin.ServerAdmin;
import de.chojo.gamejam.commands.settings.Settings;
import de.chojo.gamejam.commands.team.Team;
import de.chojo.gamejam.commands.unregister.Unregister;
import de.chojo.gamejam.commands.vote.Votes;
import de.chojo.gamejam.configuration.Configuration;
import de.chojo.gamejam.data.access.Guilds;
import de.chojo.gamejam.data.access.Teams;
import de.chojo.gamejam.server.ServerService;
import de.chojo.gamejam.util.LogNotify;
import de.chojo.jdautil.interactions.dispatching.InteractionHub;
import de.chojo.jdautil.localization.ILocalizer;
import de.chojo.jdautil.localization.Localizer;
import de.chojo.sadu.databases.PostgreSql;
import de.chojo.sadu.datasource.DataSourceCreator;
import de.chojo.sadu.exceptions.ExceptionTransformer;
import de.chojo.sadu.mapper.PostgresqlMapper;
import de.chojo.sadu.mapper.RowMapperRegistry;
import de.chojo.sadu.updater.QueryReplacement;
import de.chojo.sadu.updater.SqlUpdater;
import de.chojo.sadu.wrapper.QueryBuilderConfig;
import net.dv8tion.jda.api.interactions.DiscordLocale;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder;
import net.dv8tion.jda.api.sharding.ShardManager;
import net.dv8tion.jda.api.utils.MemberCachePolicy;
import org.slf4j.Logger;

import javax.security.auth.login.LoginException;
import javax.sql.DataSource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.PosixFilePermission;
import java.sql.SQLException;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import static org.slf4j.LoggerFactory.getLogger;

public class Bot {
private static final Logger log = getLogger(Bot.class);
private static final Thread.UncaughtExceptionHandler EXCEPTION_HANDLER =
(t, e) -> log.error(LogNotify.NOTIFY_ADMIN, "An uncaught exception occured in " + t.getName() + "-" + t.getId() + ".", e);

private static final Bot instance;

static {
instance = new Bot();
}

private Configuration configuration;
private DataSource dataSource;
private ILocalizer localizer;
private ShardManager shardManager;
private Guilds guilds;
private ServerService serverService;

private static ThreadFactory createThreadFactory(String name) {
return createThreadFactory(new ThreadGroup(name));
}

private static ThreadFactory createThreadFactory(ThreadGroup group) {
return r -> {
var thread = new Thread(group, r, group.getName());
thread.setUncaughtExceptionHandler(EXCEPTION_HANDLER);
return thread;
};
}

public static void main(String[] args) {
try {
instance.start();
} catch (Exception e) {
log.error("Critical error occured during bot startup", e);
}
}

private ExecutorService createExecutor(String name) {
return Executors.newCachedThreadPool(createThreadFactory(name));
}

private ScheduledExecutorService createScheduledExecutor(String name, int size) {
return Executors.newScheduledThreadPool(10, createThreadFactory(name));
}

private ExecutorService createExecutor(int threads, String name) {
return Executors.newFixedThreadPool(threads, createThreadFactory(name));
}

public void start() throws IOException, SQLException, LoginException {
configuration = Configuration.create();

initDb();

initServer();

initBot();

buildLocale();

buildCommands();

Api.create(configuration, shardManager, guilds);

}

private void buildLocale() {
localizer = Localizer.builder(DiscordLocale.ENGLISH_US)
.addLanguage(DiscordLocale.GERMAN)
.withLanguageProvider(guild -> Optional.ofNullable(guilds.guild(guild).settings().locale())
.map(DiscordLocale::from))
.build();
}

private void buildCommands() {
InteractionHub.builder(shardManager)
.withLocalizer(localizer)
.withCommands(new JamAdmin(guilds),
new Register(guilds),
new Settings(guilds),
new Team(guilds),
new Unregister(guilds),
new Votes(guilds),
new Server(guilds, serverService, configuration),
new ServerAdmin(guilds, serverService))
.withPagination(builder -> builder.withLocalizer(localizer)
.withCache(cache -> cache.expireAfterAccess(30, TimeUnit.MINUTES)))
.withMenuService(builder -> builder.withLocalizer(localizer)
.withCache(cache -> cache.expireAfterAccess(30, TimeUnit.MINUTES)))
.withModalService(builder -> builder.withLocalizer(localizer))
.build();
}

private void initBot() {
shardManager = DefaultShardManagerBuilder.createDefault(configuration.baseSettings().token())
.enableIntents(
GatewayIntent.GUILD_MEMBERS,
GatewayIntent.DIRECT_MESSAGES,
GatewayIntent.GUILD_MESSAGES)
.setMemberCachePolicy(MemberCachePolicy.DEFAULT)
.setEventPool(Executors.newScheduledThreadPool(5, createThreadFactory("Event Worker")))
.build();
RestAction.setDefaultFailure(throwable -> log.error("Unhandled exception occured: ", throwable));
serverService.inject(new Teams(dataSource, guilds, shardManager));
serverService.syncVelocity();
}

private void initDb() throws IOException, SQLException {
var mapperRegistry = new RowMapperRegistry();
mapperRegistry.register(PostgresqlMapper.getDefaultMapper());
QueryBuilderConfig.setDefault(QueryBuilderConfig.builder()
.withExceptionHandler(err -> log.error(ExceptionTransformer.prettyException(err), err))
.withExecutor(createExecutor("DataWorker"))
.rowMappers(mapperRegistry)
.build());

dataSource = DataSourceCreator.create(PostgreSql.get())
.configure(config -> {
config.host(configuration.database().host())
.port(configuration.database().port())
.database(configuration.database().database())
.user(configuration.database().user())
.password(configuration.database().password());
})
.create()
.forSchema(configuration.database().schema())
.build();

SqlUpdater.builder(dataSource, PostgreSql.get())
.setReplacements(new QueryReplacement("gamejam", configuration.database().schema()))
.setSchemas(configuration.database().schema())
.execute();

guilds = new Guilds(dataSource);
}

private void initServer() throws IOException {
serverService = ServerService.create(createScheduledExecutor("Server ping", 1), configuration);

var templateDir = Path.of(configuration.serverTemplate().templateDir());
var serverDir = Path.of(configuration.serverManagement().serverDir());
var pluginDir = Path.of(configuration.plugins().pluginDir());

Files.createDirectories(templateDir);
Files.createDirectories(serverDir);
Files.createDirectories(pluginDir);

Path wait = Path.of("wait.sh");
Files.copy(getClass().getClassLoader().getResourceAsStream("wait.sh"),
wait, StandardCopyOption.REPLACE_EXISTING);
try {
Files.setPosixFilePermissions(wait, Set.of(PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE));
} catch (UnsupportedOperationException e) {
log.error("Use linux...");
}
}
}
Loading