Compare commits
159 Commits
cb45047f71
...
master-ant
Author | SHA1 | Date | |
---|---|---|---|
092d33beb3 | |||
71d5d8303d | |||
49eeb646ea | |||
ceca038b27 | |||
76ceb9ef79 | |||
219879974c | |||
bd630ebb7a | |||
c56f318f1c | |||
4d98d7aa75 | |||
619190d0ae | |||
06641c5d84 | |||
2a52177043 | |||
fc067a2ae0 | |||
116a9c11a2 | |||
3f29ceb08f | |||
a33ee357e8 | |||
e36256d5be | |||
0e3a54a1b9 | |||
2e67b41b44 | |||
e4ac8f7a63 | |||
e89e9d2181 | |||
8faf0efd60 | |||
2f1aeb71ee | |||
6475a7b825 | |||
193d8d778f | |||
38da5b1d34 | |||
04e3ddb09f | |||
47db27a86e | |||
f13534da3f | |||
e45698c88a | |||
9197840873 | |||
63d8335b3a | |||
184617e9c3 | |||
696c4bc260 | |||
9004609c1b | |||
ddedcea8ea | |||
318a30fe54 | |||
4808d22f6a | |||
6b2a323a9c | |||
694ca0efba | |||
0276763a8d | |||
8811328571 | |||
b3c43f1763 | |||
86677c942f | |||
31581fc643 | |||
a412f5c24c | |||
eae979ee65 | |||
28b9b84e07 | |||
a5cdb93f1b | |||
1572096020 | |||
0ff9512a7f | |||
f0ffb3ad21 | |||
3c82939120 | |||
c9935637b9 | |||
b35c5b9240 | |||
39814dae05 | |||
7e3b043c98 | |||
5324749a64 | |||
b9f88bc4b2 | |||
8470115a74 | |||
0f976d2316 | |||
c52207298e | |||
fd902f4ec6 | |||
0a7052b6f5 | |||
0ea2d4958b | |||
e8534b42ac | |||
3abf5a95e8 | |||
fc5b76290e | |||
01d1926104 | |||
e7075140e3 | |||
125b604393 | |||
c468696537 | |||
bc84b06f0d | |||
b1427ac90e | |||
918ee5ed00 | |||
77fbc12873 | |||
14a33cae39 | |||
8462e43e89 | |||
985b36ddc8 | |||
d69089a0eb | |||
346847d2b2 | |||
e3b07aa62f | |||
497c5ad749 | |||
471cd8e610 | |||
f96356b620 | |||
d8259b79ae | |||
26b9fd5e0f | |||
9390d8c67b | |||
da33e6e592 | |||
1aebae6cd5 | |||
bf94e152c8 | |||
3c1dea3451 | |||
36fc89e915 | |||
7a15984f19 | |||
87870c96f7 | |||
70a1740644 | |||
24fbd50c62 | |||
05e88845be | |||
e5ff3d36fa | |||
d66996bc73 | |||
247dae0155 | |||
d7bc440620 | |||
b2021d5815 | |||
f4da7e7674 | |||
da8e421532 | |||
7a97b1595e | |||
aaad9fe7d8 | |||
f89a935c05 | |||
f49cca7f33 | |||
e11b3fd7bc | |||
d6a3fe358d | |||
0959eb4aa5 | |||
50e4192e32 | |||
d21f009f7d | |||
825fed639c | |||
077c40f29d | |||
2d696dcdbd | |||
577e99fcfc | |||
ebab4cbd34 | |||
4c4975b0a4 | |||
1ef4f86a14 | |||
f187a867af | |||
62703ffd12 | |||
772687b15d | |||
a60b6265a8 | |||
3dc25d63fd | |||
78ba105291 | |||
35b40262a4 | |||
70058c552d | |||
c01ae32f1f | |||
eb2c0505f5 | |||
7678fe11a3 | |||
b5bab4e4b6 | |||
10918e284e | |||
c1cfb0c856 | |||
71c413673d | |||
a3fe1bf737 | |||
53b94c99a9 | |||
de559df98c | |||
4bfcc5a2ff | |||
2be1865263 | |||
9278af6071 | |||
e16cf54712 | |||
f1e917ab7c | |||
41152d7864 | |||
933ea496c8 | |||
c059880ece | |||
0ea9738867 | |||
b72a5947b4 | |||
848c3f02fe | |||
bbaf4f394b | |||
33e9e749a0 | |||
40d0950d22 | |||
e651b8c799 | |||
7c76177cfb | |||
efd228edfc | |||
5786b2409e | |||
281a2109e6 | |||
9d79e8dc07 |
37
build.gradle
37
build.gradle
@ -16,14 +16,20 @@ repositories {
|
|||||||
name = "sonatype"
|
name = "sonatype"
|
||||||
url = "https://oss.sonatype.org/content/groups/public/"
|
url = "https://oss.sonatype.org/content/groups/public/"
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url = uri("https://repo.opencollab.dev/main/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly "io.papermc.paper:paper-api:1.19.4-R0.1-SNAPSHOT"
|
compileOnly 'io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
|
compileOnly 'org.geysermc.floodgate:api:2.2.2-SNAPSHOT'
|
||||||
|
implementation 'org.apache.httpcomponents:httpclient:4.5.14'
|
||||||
|
implementation 'com.sparkjava:spark-core:2.9.4'
|
||||||
|
implementation 'org.reflections:reflections:0.10.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
def targetJavaVersion = 17
|
def targetJavaVersion = 21
|
||||||
java {
|
java {
|
||||||
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
sourceCompatibility = javaVersion
|
sourceCompatibility = javaVersion
|
||||||
@ -39,9 +45,24 @@ tasks.withType(JavaCompile).configureEach {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('copyJarToServer', Exec) {
|
configurations {
|
||||||
dependsOn jar
|
shadowImplementation.extendsFrom implementation
|
||||||
mustRunAfter jar
|
}
|
||||||
|
|
||||||
commandLine 'scp', 'build/libs/spawn-1.0.jar', 'root@10.20.6.1:/root/server/plugins'
|
shadowJar {
|
||||||
|
configurations = [project.configurations.shadowImplementation]
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyJarToServer', Exec) {
|
||||||
|
dependsOn shadowJar
|
||||||
|
mustRunAfter shadowJar
|
||||||
|
|
||||||
|
commandLine 'scp', 'build/libs/spawn-1.0-all.jar', 'root@10.20.6.1:/home/minecraft/server/plugins'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyJarToTestServer', Exec) {
|
||||||
|
dependsOn shadowJar
|
||||||
|
mustRunAfter shadowJar
|
||||||
|
|
||||||
|
commandLine 'cp', 'build/libs/spawn-1.0-all.jar', '/home/elias/Dokumente/mcTestServer/plugins/spawn-1.0-all.jar'
|
||||||
}
|
}
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
19
gradlew
vendored
19
gradlew
vendored
@ -55,7 +55,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@ -83,7 +83,8 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@ -201,11 +202,11 @@ fi
|
|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
# Collect all arguments for the java command:
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
# and any embedded shellness will be escaped.
|
||||||
# double quotes to make sure that they get re-expanded; and
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
@ -1,72 +1,98 @@
|
|||||||
package eu.mhsl.craftattack.spawn;
|
package eu.mhsl.craftattack.spawn;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.RepositoryLoader;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.server.HttpServer;
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.adminMarker.AdminMarker;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.chatMessages.ChatMessages;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.countdown.Countdown;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.debug.Debug;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.Event;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.Help;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.report.Report;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.tablist.Tablist;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.titleClear.TitleClear;
|
|
||||||
import eu.mhsl.craftattack.spawn.config.Configuration;
|
import eu.mhsl.craftattack.spawn.config.Configuration;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.worldmuseum.WorldMuseum;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public final class Main extends JavaPlugin {
|
public final class Main extends JavaPlugin {
|
||||||
private static Main instance;
|
private static Main instance;
|
||||||
|
private static Logger logger;
|
||||||
|
|
||||||
private List<Appliance> appliances;
|
private List<Appliance> appliances;
|
||||||
|
private RepositoryLoader repositoryLoader;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
saveDefaultConfig();
|
logger = instance().getLogger();
|
||||||
Configuration.readConfig();
|
this.saveDefaultConfig();
|
||||||
|
try {
|
||||||
|
this.wrappedEnable();
|
||||||
|
} catch(Exception e) {
|
||||||
|
Main.logger().log(Level.SEVERE, "Error while initializing Spawn plugin, shutting down!", e);
|
||||||
|
Bukkit.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
appliances = List.of(
|
private void wrappedEnable() {
|
||||||
new AdminMarker(),
|
Configuration.readConfig();
|
||||||
new WorldMuseum(),
|
List<String> disabledAppliances = Configuration.pluginConfig.getStringList("disabledAppliances");
|
||||||
new TitleClear(),
|
|
||||||
new Countdown(),
|
Main.logger().info("Loading Repositories...");
|
||||||
new Tablist(),
|
this.repositoryLoader = new RepositoryLoader();
|
||||||
new ChatMessages(),
|
Main.logger().info(String.format("Loaded %d repositories!", this.repositoryLoader.getRepositories().size()));
|
||||||
new Report(),
|
|
||||||
new Event(),
|
Main.logger().info("Loading appliances...");
|
||||||
new Help(),
|
Reflections reflections = new Reflections(this.getClass().getPackageName());
|
||||||
new Debug()
|
Set<Class<? extends Appliance>> applianceClasses = reflections.getSubTypesOf(Appliance.class);
|
||||||
);
|
|
||||||
Bukkit.getLogger().info("Loading appliances...");
|
this.appliances = applianceClasses.stream()
|
||||||
appliances.forEach(appliance -> {
|
.filter(applianceClass -> !disabledAppliances.contains(applianceClass.getSimpleName()))
|
||||||
Bukkit.getLogger().info("Enabling " + appliance.getClass().getSimpleName());
|
.map(applianceClass -> {
|
||||||
|
try {
|
||||||
|
return (Appliance) applianceClass.getDeclaredConstructor().newInstance();
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new RuntimeException(String.format("Failed to create instance of '%s'", applianceClass.getName()), e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
Main.logger().info(String.format("Loaded %d appliances!", this.appliances.size()));
|
||||||
|
|
||||||
|
Main.logger().info("Initializing appliances...");
|
||||||
|
this.appliances.forEach(appliance -> {
|
||||||
appliance.onEnable();
|
appliance.onEnable();
|
||||||
appliance.initialize(this);
|
appliance.initialize(this);
|
||||||
});
|
});
|
||||||
Bukkit.getLogger().info("Loaded " + appliances.size() + " appliances!");
|
Main.logger().info(String.format("Initialized %d appliances!", this.appliances.size()));
|
||||||
|
|
||||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
Main.logger().info("Starting HTTP API...");
|
||||||
|
new HttpServer();
|
||||||
|
|
||||||
|
this.getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
||||||
|
Main.logger().info("Startup complete!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
Bukkit.getLogger().info("Disabling appliances...");
|
Main.logger().info("Disabling appliances...");
|
||||||
appliances.forEach(appliance -> {
|
this.appliances.forEach(appliance -> {
|
||||||
Bukkit.getLogger().info("Disabling " + appliance.getClass().getSimpleName());
|
Main.logger().info("Disabling " + appliance.getClass().getSimpleName());
|
||||||
appliance.onDisable();
|
appliance.onDisable();
|
||||||
appliance.destruct(this);
|
appliance.destruct(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
HandlerList.unregisterAll(this);
|
HandlerList.unregisterAll(this);
|
||||||
Bukkit.getScheduler().cancelTasks(this);
|
Bukkit.getScheduler().cancelTasks(this);
|
||||||
Bukkit.getLogger().info("Disabled " + appliances.size() + " appliances!");
|
Main.logger().info("Disabled " + this.appliances.size() + " appliances!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Appliance> T getAppliance(Class<T> clazz) {
|
public <T extends Appliance> T getAppliance(Class<T> clazz) {
|
||||||
return this.appliances.stream().filter(clazz::isInstance).map(clazz::cast).findFirst().orElseThrow();
|
return this.appliances.stream()
|
||||||
|
.filter(clazz::isInstance)
|
||||||
|
.map(clazz::cast)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new RuntimeException(String.format("Appliance %s not loaded or instantiated!", clazz)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -75,10 +101,18 @@ public final class Main extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<Appliance> getAppliances() {
|
public List<Appliance> getAppliances() {
|
||||||
return appliances;
|
return this.appliances;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepositoryLoader getRepositoryLoader() {
|
||||||
|
return this.repositoryLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Main instance() {
|
public static Main instance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Logger logger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import org.apache.http.client.utils.URIBuilder;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@RepositoryLoader.IgnoreRepository
|
||||||
|
public abstract class HttpRepository extends Repository {
|
||||||
|
private final Consumer<URIBuilder> baseUriBuilder;
|
||||||
|
|
||||||
|
public HttpRepository(URI basePath) {
|
||||||
|
this(basePath, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRepository(URI basePath, @Nullable Consumer<URIBuilder> baseUriBuilder) {
|
||||||
|
super(basePath);
|
||||||
|
|
||||||
|
this.baseUriBuilder = baseUriBuilder == null
|
||||||
|
? uriBuilder -> {
|
||||||
|
}
|
||||||
|
: baseUriBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <TInput, TOutput> ReqResp<TOutput> post(String command, TInput data, Class<TOutput> outputType) {
|
||||||
|
return this.post(command, parameters -> {
|
||||||
|
}, data, outputType);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <TInput, TOutput> ReqResp<TOutput> post(String command, Consumer<URIBuilder> parameters, TInput data, Class<TOutput> outputType) {
|
||||||
|
HttpRequest request = this.getRequestBuilder(this.getUri(command, parameters))
|
||||||
|
.POST(HttpRequest.BodyPublishers.ofString(this.gson.toJson(data)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return this.execute(request, outputType);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <TOutput> ReqResp<TOutput> get(String command, Class<TOutput> outputType) {
|
||||||
|
return this.get(command, parameters -> {
|
||||||
|
}, outputType);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <TOutput> ReqResp<TOutput> get(String command, Consumer<URIBuilder> parameters, Class<TOutput> outputType) {
|
||||||
|
HttpRequest request = this.getRequestBuilder(this.getUri(command, parameters))
|
||||||
|
.GET()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return this.execute(request, outputType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private URI getUri(String command, Consumer<URIBuilder> parameters) {
|
||||||
|
try {
|
||||||
|
URIBuilder builder = new URIBuilder(this.basePath + "/" + command);
|
||||||
|
this.baseUriBuilder.accept(builder);
|
||||||
|
parameters.accept(builder);
|
||||||
|
return builder.build();
|
||||||
|
} catch(URISyntaxException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpRequest.Builder getRequestBuilder(URI endpoint) {
|
||||||
|
return HttpRequest.newBuilder()
|
||||||
|
.uri(endpoint)
|
||||||
|
.header("User-Agent", Main.instance().getServer().getBukkitVersion())
|
||||||
|
.header("Content-Type", "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
private <TResponse> ReqResp<TResponse> execute(HttpRequest request, Class<TResponse> clazz) {
|
||||||
|
ReqResp<String> rawResponse = this.sendHttp(request);
|
||||||
|
return new ReqResp<>(rawResponse.status(), this.gson.fromJson(rawResponse.data(), clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReqResp<String> sendHttp(HttpRequest request) {
|
||||||
|
try(HttpClient client = HttpClient.newHttpClient()) {
|
||||||
|
this.validateThread(request.uri().getPath());
|
||||||
|
HttpResponse<String> httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
|
return new ReqResp<>(httpResponse.statusCode(), httpResponse.body());
|
||||||
|
} catch(IOException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public abstract class Repository {
|
||||||
|
protected URI basePath;
|
||||||
|
protected Gson gson;
|
||||||
|
|
||||||
|
public Repository(URI basePath) {
|
||||||
|
this.basePath = basePath;
|
||||||
|
this.gson = new Gson();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void validateThread(String commandName) {
|
||||||
|
if(!Bukkit.isPrimaryThread()) return;
|
||||||
|
|
||||||
|
Main.logger().warning(String.format(
|
||||||
|
"Repository '%s' was called synchronously with command '%s'!",
|
||||||
|
this.getClass().getSimpleName(),
|
||||||
|
commandName
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class RepositoryLoader {
|
||||||
|
private final List<Repository> repositories;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface IgnoreRepository {
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepositoryLoader() {
|
||||||
|
Reflections reflections = new Reflections(this.getClass().getPackageName());
|
||||||
|
Set<Class<? extends Repository>> repositories = reflections.getSubTypesOf(Repository.class);
|
||||||
|
|
||||||
|
this.repositories = repositories.stream()
|
||||||
|
.filter(repository -> !repository.isAnnotationPresent(IgnoreRepository.class))
|
||||||
|
.map(repository -> {
|
||||||
|
try {
|
||||||
|
return (Repository) repository.getDeclaredConstructor().newInstance();
|
||||||
|
} catch(InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||||
|
NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getRepository(Class<T> clazz) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return this.repositories.stream()
|
||||||
|
.filter(clazz::isInstance)
|
||||||
|
.map(repository -> (T) repository)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new NotImplementedException(String.format("Repository '%s' not found!", clazz.getSimpleName())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Repository> getRepositories() {
|
||||||
|
return this.repositories;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client;
|
||||||
|
|
||||||
|
public record ReqResp<TData>(int status, TData data) {
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client.repositories;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.HttpRepository;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.api.EventApiUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class EventRepository extends HttpRepository {
|
||||||
|
public EventRepository() {
|
||||||
|
super(EventApiUtil.getBaseUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
public record CreatedRoom(UUID uuid) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record QueueRoom(UUID player, UUID room) {
|
||||||
|
public record Response(String error) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReqResp<CreatedRoom> createSession() {
|
||||||
|
return this.post("room", null, CreatedRoom.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReqResp<QueueRoom.Response> queueRoom(QueueRoom request) {
|
||||||
|
return this.post("queueRoom", request, QueueRoom.Response.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client.repositories;
|
||||||
|
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.HttpRepository;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.api.WebsiteApiUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class FeedbackRepository extends HttpRepository {
|
||||||
|
public FeedbackRepository() {
|
||||||
|
super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Request(String event, List<UUID> users) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReqResp<Map<UUID, String>> createFeedbackUrls(Request data) {
|
||||||
|
final Type responseType = new TypeToken<Map<UUID, String>>() {
|
||||||
|
}.getType();
|
||||||
|
ReqResp<Object> rawData = this.post("feedback", data, Object.class);
|
||||||
|
return new ReqResp<>(rawData.status(), this.gson.fromJson(this.gson.toJson(rawData.data()), responseType));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client.repositories;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.HttpRepository;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.api.WebsiteApiUtil;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ReportRepository extends HttpRepository {
|
||||||
|
public ReportRepository() {
|
||||||
|
super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ReportCreationInfo(@NotNull UUID reporter, @Nullable UUID reported, String reason) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ReportUrl(@NotNull String url) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PlayerReports(
|
||||||
|
List<Report> from_self,
|
||||||
|
Object to_self
|
||||||
|
) {
|
||||||
|
public record Report(
|
||||||
|
@Nullable Reporter reported,
|
||||||
|
@NotNull String subject,
|
||||||
|
boolean draft,
|
||||||
|
@NotNull String status,
|
||||||
|
@NotNull String url
|
||||||
|
) {
|
||||||
|
public record Reporter(
|
||||||
|
@NotNull String username,
|
||||||
|
@NotNull String uuid
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReqResp<PlayerReports> queryReports(UUID player) {
|
||||||
|
return this.get(
|
||||||
|
"report",
|
||||||
|
(parameters) -> parameters.addParameter("uuid", player.toString()),
|
||||||
|
PlayerReports.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReqResp<ReportUrl> createReport(ReportCreationInfo data) {
|
||||||
|
return this.post(
|
||||||
|
"report",
|
||||||
|
data,
|
||||||
|
ReportUrl.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.client.repositories;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.HttpRepository;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.api.WebsiteApiUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class WhitelistRepository extends HttpRepository {
|
||||||
|
public WhitelistRepository() {
|
||||||
|
super(WebsiteApiUtil.getBaseUri(), WebsiteApiUtil::withAuthorizationSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record UserData(
|
||||||
|
UUID uuid,
|
||||||
|
String username,
|
||||||
|
String firstname,
|
||||||
|
String lastname,
|
||||||
|
Long banned_until,
|
||||||
|
Long outlawed_until
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReqResp<UserData> getUserData(UUID userId) {
|
||||||
|
return this.get(
|
||||||
|
"user",
|
||||||
|
parameters -> parameters.addParameter("uuid", userId.toString()),
|
||||||
|
UserData.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.api.server;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import spark.Request;
|
||||||
|
import spark.Spark;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class HttpServer {
|
||||||
|
private final ConfigurationSection apiConf = Main.instance().getConfig().getConfigurationSection("api");
|
||||||
|
protected final Gson gson = new Gson();
|
||||||
|
|
||||||
|
public static Object nothing = null;
|
||||||
|
|
||||||
|
public HttpServer() {
|
||||||
|
Spark.port(8080);
|
||||||
|
|
||||||
|
Spark.get("/ping", (request, response) -> System.currentTimeMillis());
|
||||||
|
|
||||||
|
Main.instance().getAppliances().forEach(appliance -> appliance.httpApi(new ApiBuilder(appliance)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Response(Status status, Object error, Object response) {
|
||||||
|
public enum Status {
|
||||||
|
FAILURE,
|
||||||
|
SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiBuilder {
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface RequestProvider<TParsed, TOriginal, TResponse> {
|
||||||
|
TResponse apply(TParsed parsed, TOriginal original);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String applianceName;
|
||||||
|
|
||||||
|
private ApiBuilder(Appliance appliance) {
|
||||||
|
this.applianceName = appliance.getClass().getSimpleName().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void get(String path, Function<Request, Object> onCall) {
|
||||||
|
Spark.get(this.buildRoute(path), (req, resp) -> this.process(() -> onCall.apply(req)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rawPost(String path, Function<Request, Object> onCall) {
|
||||||
|
Spark.post(this.buildRoute(path), (req, resp) -> this.process(() -> onCall.apply(req)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <TRequest> void post(String path, Class<TRequest> clazz, RequestProvider<TRequest, Request, Object> onCall) {
|
||||||
|
Spark.post(this.buildRoute(path), (req, resp) -> {
|
||||||
|
Main.instance().getLogger().info(req.body());
|
||||||
|
TRequest parsed = HttpServer.this.gson.fromJson(req.body(), clazz);
|
||||||
|
return this.process(() -> onCall.apply(parsed, req));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildRoute(String path) {
|
||||||
|
return String.format("/api/%s/%s", this.applianceName, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String process(Supplier<Object> exec) {
|
||||||
|
HttpServer.Response response;
|
||||||
|
try {
|
||||||
|
response = new Response(Response.Status.SUCCESS, null, exec.get());
|
||||||
|
} catch(Exception e) {
|
||||||
|
response = new Response(Response.Status.FAILURE, e, null);
|
||||||
|
}
|
||||||
|
return HttpServer.this.gson.toJson(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliance;
|
package eu.mhsl.craftattack.spawn.appliance;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.Repository;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.server.HttpServer;
|
||||||
import eu.mhsl.craftattack.spawn.config.Configuration;
|
import eu.mhsl.craftattack.spawn.config.Configuration;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
@ -19,12 +22,15 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public abstract class Appliance {
|
public abstract class Appliance {
|
||||||
private String localConfigPath;
|
private String localConfigPath;
|
||||||
|
private List<Listener> listeners;
|
||||||
|
private List<ApplianceCommand<?>> commands;
|
||||||
|
|
||||||
public Appliance() {
|
public Appliance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this constructor to specify a config sub-path for use with the localConfig() method.
|
* Use this constructor to specify a config sub-path for use with the localConfig() method.
|
||||||
|
*
|
||||||
* @param localConfigPath sub path, if not found, the whole config will be used
|
* @param localConfigPath sub path, if not found, the whole config will be used
|
||||||
*/
|
*/
|
||||||
public Appliance(String localConfigPath) {
|
public Appliance(String localConfigPath) {
|
||||||
@ -33,15 +39,17 @@ public abstract class Appliance {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a list of listeners for the appliance. All listeners will be automatically registered.
|
* Provides a list of listeners for the appliance. All listeners will be automatically registered.
|
||||||
|
*
|
||||||
* @return List of listeners
|
* @return List of listeners
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
protected List<Listener> eventHandlers() {
|
protected List<Listener> listeners() {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a list of commands for the appliance. All commands will be automatically registered.
|
* Provides a list of commands for the appliance. All commands will be automatically registered.
|
||||||
|
*
|
||||||
* @return List of commands
|
* @return List of commands
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
@ -49,35 +57,68 @@ public abstract class Appliance {
|
|||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on initialization to add all needed API Routes.
|
||||||
|
* The routeBuilder can be used to get the correct Path prefixes
|
||||||
|
*
|
||||||
|
* @param apiBuilder holds data for needed route prefixes.
|
||||||
|
*/
|
||||||
|
public void httpApi(HttpServer.ApiBuilder apiBuilder) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a localized config section. Path can be set in appliance constructor.
|
* Provides a localized config section. Path can be set in appliance constructor.
|
||||||
|
*
|
||||||
* @return Section of configuration for your appliance
|
* @return Section of configuration for your appliance
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public ConfigurationSection localConfig() {
|
public ConfigurationSection localConfig() {
|
||||||
return Optional.ofNullable(Configuration.cfg.getConfigurationSection(localConfigPath)).orElse(Configuration.cfg);
|
return Optional.ofNullable(Configuration.cfg.getConfigurationSection(this.localConfigPath))
|
||||||
|
.orElseGet(() -> Configuration.cfg.createSection(this.localConfigPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEnable() {}
|
public void onEnable() {
|
||||||
public void onDisable() {}
|
}
|
||||||
|
|
||||||
|
public void onDisable() {
|
||||||
|
}
|
||||||
|
|
||||||
public void initialize(@NotNull JavaPlugin plugin) {
|
public void initialize(@NotNull JavaPlugin plugin) {
|
||||||
eventHandlers().forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, plugin));
|
this.listeners = this.listeners();
|
||||||
commands().forEach(command -> setCommandExecutor(plugin, command.commandName, command));
|
this.commands = this.commands();
|
||||||
|
|
||||||
|
this.listeners.forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, plugin));
|
||||||
|
this.commands.forEach(command -> this.setCommandExecutor(plugin, command.commandName, command));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destruct(@NotNull JavaPlugin plugin) {
|
public void destruct(@NotNull JavaPlugin plugin) {
|
||||||
eventHandlers().forEach(HandlerList::unregisterAll);
|
this.listeners.forEach(HandlerList::unregisterAll);
|
||||||
commands().forEach(command -> setCommandExecutor(plugin, command.commandName, null));
|
}
|
||||||
|
|
||||||
|
protected <T extends Appliance> T queryAppliance(Class<T> clazz) {
|
||||||
|
return Main.instance().getAppliance(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T extends Repository> T queryRepository(Class<T> clazz) {
|
||||||
|
return Main.instance().getRepositoryLoader().getRepository(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCommandExecutor(JavaPlugin plugin, String name, ApplianceCommand<?> executor) {
|
private void setCommandExecutor(JavaPlugin plugin, String name, ApplianceCommand<?> executor) {
|
||||||
PluginCommand command = plugin.getCommand(name);
|
PluginCommand command = plugin.getCommand(name);
|
||||||
if(command != null) {
|
if(command != null && executor != null) {
|
||||||
command.setExecutor(executor);
|
command.setExecutor(executor);
|
||||||
command.setTabCompleter(executor);
|
command.setTabCompleter(executor);
|
||||||
} else {
|
} else {
|
||||||
Bukkit.getLogger().warning("Command " + name + " is not specified in plugin.yml!");
|
Main.logger().warning("Command " + name + " is not specified in plugin.yml!");
|
||||||
|
throw new RuntimeException("All commands must be registered in plugin.yml. Missing command: " + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Listener> getListeners() {
|
||||||
|
return this.listeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ApplianceCommand<?>> getCommands() {
|
||||||
|
return this.commands;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliance;
|
package eu.mhsl.craftattack.spawn.appliance;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -17,9 +17,10 @@ import java.util.Optional;
|
|||||||
/**
|
/**
|
||||||
* Utility class which enables command name definition over a constructor.
|
* Utility class which enables command name definition over a constructor.
|
||||||
*/
|
*/
|
||||||
public abstract class ApplianceCommand<T extends Appliance> extends ApplianceSupplier<T> implements TabCompleter, CommandExecutor {
|
public abstract class ApplianceCommand<T extends Appliance> extends CachedApplianceSupplier<T> implements TabCompleter, CommandExecutor {
|
||||||
public String commandName;
|
public String commandName;
|
||||||
protected Component errorMessage = Component.text("Fehler: ").color(NamedTextColor.RED);
|
protected Component errorMessage = Component.text("Fehler: ").color(NamedTextColor.RED);
|
||||||
|
|
||||||
public ApplianceCommand(String command) {
|
public ApplianceCommand(String command) {
|
||||||
this.commandName = command;
|
this.commandName = command;
|
||||||
}
|
}
|
||||||
@ -32,12 +33,12 @@ public abstract class ApplianceCommand<T extends Appliance> extends ApplianceSup
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
try {
|
try {
|
||||||
execute(sender, command, label, args);
|
this.execute(sender, command, label, args);
|
||||||
} catch (Error e) {
|
} catch(Error e) {
|
||||||
sender.sendMessage(errorMessage.append(Component.text(e.getMessage())));
|
sender.sendMessage(this.errorMessage.append(Component.text(e.getMessage())));
|
||||||
} catch (Exception e) {
|
} catch(Exception e) {
|
||||||
sender.sendMessage(errorMessage.append(Component.text("Interner Fehler")));
|
sender.sendMessage(this.errorMessage.append(Component.text("Interner Fehler")));
|
||||||
Bukkit.getLogger().warning("Error executing appliance command " + commandName + ": " + e.getMessage());
|
Main.logger().warning("Error executing appliance command " + this.commandName + ": " + e.getMessage());
|
||||||
e.printStackTrace(System.err);
|
e.printStackTrace(System.err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -50,10 +51,10 @@ public abstract class ApplianceCommand<T extends Appliance> extends ApplianceSup
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> tabCompleteReducer(List<String> response, String[] args) {
|
protected List<String> tabCompleteReducer(List<String> response, String[] args) {
|
||||||
return response.stream().filter(s -> s.startsWith(args[args.length-1])).toList();
|
return response.stream().filter(s -> s.startsWith(args[args.length - 1])).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args);
|
protected abstract void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for command which can only be used as a Player. You can access the executing player with the getPlayer() method.
|
* Utility class for command which can only be used as a Player. You can access the executing player with the getPlayer() method.
|
||||||
@ -61,6 +62,7 @@ public abstract class ApplianceCommand<T extends Appliance> extends ApplianceSup
|
|||||||
public static abstract class PlayerChecked<T extends Appliance> extends ApplianceCommand<T> {
|
public static abstract class PlayerChecked<T extends Appliance> extends ApplianceCommand<T> {
|
||||||
private Player player;
|
private Player player;
|
||||||
private Component notPlayerMessage = Component.text("Dieser Command kann nur von Spielern ausgeführt werden!").color(NamedTextColor.RED);
|
private Component notPlayerMessage = Component.text("Dieser Command kann nur von Spielern ausgeführt werden!").color(NamedTextColor.RED);
|
||||||
|
|
||||||
public PlayerChecked(String command) {
|
public PlayerChecked(String command) {
|
||||||
super(command);
|
super(command);
|
||||||
}
|
}
|
||||||
@ -78,7 +80,7 @@ public abstract class ApplianceCommand<T extends Appliance> extends ApplianceSup
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
if(!(sender instanceof Player)) {
|
if(!(sender instanceof Player)) {
|
||||||
sender.sendMessage(notPlayerMessage);
|
sender.sendMessage(this.notPlayerMessage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.player = (Player) sender;
|
this.player = (Player) sender;
|
||||||
|
@ -5,8 +5,9 @@ import org.bukkit.event.Listener;
|
|||||||
/**
|
/**
|
||||||
* Utility class which provides a specific, type save appliance.
|
* Utility class which provides a specific, type save appliance.
|
||||||
* You can access the appliance with the protected 'appliance' field.
|
* You can access the appliance with the protected 'appliance' field.
|
||||||
|
*
|
||||||
* @param <T> the type of your appliance
|
* @param <T> the type of your appliance
|
||||||
*/
|
*/
|
||||||
public abstract class ApplianceListener<T extends Appliance> extends ApplianceSupplier<T> implements Listener {
|
public abstract class ApplianceListener<T extends Appliance> extends CachedApplianceSupplier<T> implements Listener {
|
||||||
|
|
||||||
}
|
}
|
@ -2,11 +2,11 @@ package eu.mhsl.craftattack.spawn.appliance;
|
|||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.Main;
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
|
||||||
public class ApplianceSupplier<T extends Appliance> implements IApplianceSupplier<T> {
|
public class CachedApplianceSupplier<T extends Appliance> implements IApplianceSupplier<T> {
|
||||||
private final T appliance;
|
private final T appliance;
|
||||||
|
|
||||||
public ApplianceSupplier() {
|
public CachedApplianceSupplier() {
|
||||||
this.appliance = Main.instance().getAppliance(Main.getApplianceType(getClass()));
|
this.appliance = Main.instance().getAppliance(Main.getApplianceType(this.getClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -1,15 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.adminMarker;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AdminMarker extends Appliance {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<Listener> eventHandlers() {
|
|
||||||
return List.of(new AdminMarkerListener());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.adminMarker;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import org.bukkit.Color;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
|
|
||||||
|
|
||||||
public class AdminMarkerListener extends ApplianceListener<AdminMarker> {
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
Player p = event.getPlayer();
|
|
||||||
|
|
||||||
p.displayName(p.displayName().color(getPlayerColor(p)));
|
|
||||||
p.playerListName(p.playerListName().color(getPlayerColor(p)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private TextColor getPlayerColor(Player player) {
|
|
||||||
if (player.hasPermission("chatcolor")) return TextColor.color(Color.AQUA.asRGB()); // TODO read permission from config
|
|
||||||
return TextColor.color(Color.WHITE.asRGB());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.chatMessages;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ChatMessages extends Appliance {
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<Listener> eventHandlers() {
|
|
||||||
return List.of(new ChatMessagesListener());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.chatMessages;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
|
||||||
import io.papermc.paper.event.player.AsyncChatEvent;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.event.ClickEvent;
|
|
||||||
import net.kyori.adventure.text.event.HoverEvent;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import org.bukkit.Color;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class ChatMessagesListener extends ApplianceListener<ChatMessages> {
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerChatEvent(AsyncChatEvent event) {
|
|
||||||
event.renderer(
|
|
||||||
(source, sourceDisplayName, message, viewer) ->
|
|
||||||
Component.text("")
|
|
||||||
.append(getReportablePlayerName(source))
|
|
||||||
.append(Component.text(" > ").color(TextColor.color(Color.GRAY.asRGB())))
|
|
||||||
.append(message).color(TextColor.color(Color.SILVER.asRGB()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
event.joinMessage(
|
|
||||||
Component
|
|
||||||
.text(">>> ").color(NamedTextColor.GREEN)
|
|
||||||
.append(getReportablePlayerName(event.getPlayer()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerLeave(PlayerQuitEvent event) {
|
|
||||||
event.quitMessage(
|
|
||||||
Component
|
|
||||||
.text("<<< ").color(NamedTextColor.RED)
|
|
||||||
.append(getReportablePlayerName(event.getPlayer()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onDeath(PlayerDeathEvent event) {
|
|
||||||
event.deathMessage(
|
|
||||||
Component
|
|
||||||
.text("☠ ")
|
|
||||||
.append(
|
|
||||||
Optional
|
|
||||||
.ofNullable(event.deathMessage())
|
|
||||||
.orElse(Component.text(event.getPlayer().getName()))
|
|
||||||
)
|
|
||||||
.color(TextColor.color(Color.SILVER.asRGB()))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component getReportablePlayerName(Player player) {
|
|
||||||
return Component
|
|
||||||
.text("")
|
|
||||||
.append(player.displayName())
|
|
||||||
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um diesen Spieler zu reporten").color(NamedTextColor.GOLD)))
|
|
||||||
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/report " + player.getName() + " "));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.countdown;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.Main;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.countdown.command.ProjectStartCancelCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.countdown.command.ProjectStartCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.countdown.command.ProjectStartResetCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.countdown.listener.PlayerInvincibleListener;
|
|
||||||
import eu.mhsl.craftattack.spawn.config.Configuration;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.WorldBorder;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class Countdown extends Appliance {
|
|
||||||
public Countdown() {
|
|
||||||
super("countdown");
|
|
||||||
}
|
|
||||||
|
|
||||||
private int taskId = -1;
|
|
||||||
private boolean isRunning = false;
|
|
||||||
private int countDown;
|
|
||||||
public void startCountdown() {
|
|
||||||
if(!isEnabled()) return;
|
|
||||||
if(isRunning) return;
|
|
||||||
|
|
||||||
this.countDown = localConfig().getInt("countdown");
|
|
||||||
this.isRunning = true;
|
|
||||||
this.taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.instance(), () -> {
|
|
||||||
if(this.countDown <= 0) {
|
|
||||||
this.cancelCountdown();
|
|
||||||
this.projectStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage("Sekunden:" + this.countDown));
|
|
||||||
this.countDown--;
|
|
||||||
}, 20, 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelCountdown() {
|
|
||||||
if(taskId == -1) return;
|
|
||||||
Bukkit.getScheduler().cancelTask(this.taskId);
|
|
||||||
this.isRunning = false;
|
|
||||||
this.restoreBeforeStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return localConfig().getBoolean("enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
localConfig().set("enabled", enabled);
|
|
||||||
Configuration.saveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void projectStart() {
|
|
||||||
setEnabled(false);
|
|
||||||
|
|
||||||
worldBorderModifier(worldBorder -> worldBorder.setSize(worldBorder.getMaxSize()));
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
|
||||||
player.setFoodLevel(20);
|
|
||||||
player.setHealth(20);
|
|
||||||
player.playerListName(player.playerListName().color(NamedTextColor.AQUA));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void restoreBeforeStart() {
|
|
||||||
setEnabled(true);
|
|
||||||
|
|
||||||
worldBorderModifier(worldBorder -> {
|
|
||||||
worldBorder.setSize(localConfig().getLong("worldborder-before"));
|
|
||||||
worldBorder.setWarningDistance(0);
|
|
||||||
worldBorder.setDamageAmount(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void worldBorderModifier(Consumer<WorldBorder> worldBorder) {
|
|
||||||
Bukkit.getWorlds().forEach(world -> worldBorder.accept(world.getWorldBorder()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRunning() {
|
|
||||||
return isRunning;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<Listener> eventHandlers() {
|
|
||||||
return List.of(new PlayerInvincibleListener());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
|
||||||
return List.of(
|
|
||||||
new ProjectStartCommand(),
|
|
||||||
new ProjectStartCancelCommand(),
|
|
||||||
new ProjectStartResetCommand()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.debug;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.debug.command.AppliancesCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.debug.command.UserInfoCommand;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
public class Debug extends Appliance {
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
|
||||||
return List.of(
|
|
||||||
new UserInfoCommand(),
|
|
||||||
new AppliancesCommand()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.debug.command;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.Main;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.debug.Debug;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.ComponentBuilder;
|
|
||||||
import net.kyori.adventure.text.TextComponent;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class AppliancesCommand extends ApplianceCommand<Debug> {
|
|
||||||
public AppliancesCommand() {
|
|
||||||
super("appliances");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
ComponentBuilder<TextComponent, TextComponent.Builder> componentBuilder = Component.text()
|
|
||||||
.append(Component.text(Main.instance().getAppliances().size()))
|
|
||||||
.append(Component.text(" appliances loaded:"))
|
|
||||||
.appendNewline()
|
|
||||||
.append(Component.text(Main.instance().getAppliances().stream().map(appliance -> appliance.getClass().getSimpleName()).collect(Collectors.joining(", "))));
|
|
||||||
|
|
||||||
sender.sendMessage(componentBuilder.build());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.debug.command;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.debug.Debug;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.event.ClickEvent;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class UserInfoCommand extends ApplianceCommand<Debug> {
|
|
||||||
public UserInfoCommand() {
|
|
||||||
super("userInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
if(args.length != 1) {
|
|
||||||
sender.sendMessage(Component.text("Bitte gib einen Nutzernamen an.", NamedTextColor.RED));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]);
|
|
||||||
|
|
||||||
sender.sendMessage(
|
|
||||||
Component.text()
|
|
||||||
.appendNewline()
|
|
||||||
.append(Component.text("Informationen zu: ", NamedTextColor.GOLD))
|
|
||||||
.append(
|
|
||||||
Component
|
|
||||||
.text(Objects.requireNonNull(player.getName()), NamedTextColor.YELLOW)
|
|
||||||
.clickEvent(ClickEvent.copyToClipboard(Objects.requireNonNull(player.getName())))
|
|
||||||
)
|
|
||||||
.appendNewline()
|
|
||||||
.append(
|
|
||||||
Component
|
|
||||||
.text("UUID: " + player.getUniqueId(), NamedTextColor.GRAY)
|
|
||||||
.clickEvent(ClickEvent.copyToClipboard(player.getUniqueId().toString()))
|
|
||||||
)
|
|
||||||
.appendNewline()
|
|
||||||
.append(
|
|
||||||
Component
|
|
||||||
.text("Erster Besuch: " + formatUnixTimestamp(player.getFirstPlayed()), NamedTextColor.GRAY)
|
|
||||||
.clickEvent(ClickEvent.copyToClipboard(String.valueOf(player.getFirstPlayed())))
|
|
||||||
)
|
|
||||||
.appendNewline()
|
|
||||||
.append(
|
|
||||||
Component
|
|
||||||
.text("Letzter Besuch: " + formatUnixTimestamp(player.getLastSeen()), NamedTextColor.GRAY)
|
|
||||||
.clickEvent(ClickEvent.copyToClipboard(String.valueOf(player.getLastSeen())))
|
|
||||||
)
|
|
||||||
.appendNewline()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
if(args.length < 2) {
|
|
||||||
return Stream.concat(
|
|
||||||
Bukkit.getOnlinePlayers().stream().map(Player::getName),
|
|
||||||
Arrays.stream(Bukkit.getOfflinePlayers()).map(OfflinePlayer::getName)
|
|
||||||
).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String formatUnixTimestamp(long timestamp) {
|
|
||||||
DateFormat format = new SimpleDateFormat("E dd.MM.yyyy H:m:s");
|
|
||||||
return format.format(new Date(timestamp));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.event;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.command.EventCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.command.EventEndSessionCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.command.EventOpenSessionCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.command.MoveEventVillagerCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.util.DisplayVillager;
|
|
||||||
import eu.mhsl.craftattack.spawn.util.PluginMessage;
|
|
||||||
import eu.mhsl.craftattack.spawn.util.commonListeners.DismissInventoryOpenFromHolder;
|
|
||||||
import eu.mhsl.craftattack.spawn.util.commonListeners.PlayerInteractAtEntityEventListener;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.Villager;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Event extends Appliance {
|
|
||||||
public DisplayVillager.ConfigBound villager;
|
|
||||||
private boolean isOpen = false;
|
|
||||||
|
|
||||||
public Event() {
|
|
||||||
super("event");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
this.villager = new DisplayVillager.ConfigBound(
|
|
||||||
localConfig(),
|
|
||||||
villager -> {
|
|
||||||
villager.customName(Component.text("Events", NamedTextColor.GOLD));
|
|
||||||
villager.setProfession(Villager.Profession.LIBRARIAN);
|
|
||||||
villager.setVillagerType(Villager.Type.SNOW);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openEvent() {
|
|
||||||
if(isOpen) throw new ApplianceCommand.Error("Es läuft derzeit bereits ein Event!");
|
|
||||||
isOpen = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void joinEvent(Player p) {
|
|
||||||
if(!isOpen) {
|
|
||||||
p.sendMessage(Component.text("Zurzeit ist kein Event geöffnet.", NamedTextColor.RED));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginMessage.connect(p, localConfig().getString("connect-server-name"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void endEvent() {
|
|
||||||
if(!isOpen) throw new ApplianceCommand.Error("Es läuft derzeit kein Event!");
|
|
||||||
isOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
|
||||||
return List.of(
|
|
||||||
new EventCommand(),
|
|
||||||
new MoveEventVillagerCommand(),
|
|
||||||
new EventOpenSessionCommand(),
|
|
||||||
new EventEndSessionCommand()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<Listener> eventHandlers() {
|
|
||||||
return List.of(
|
|
||||||
new PlayerInteractAtEntityEventListener(this.villager.getUniqueId(), playerInteractAtEntityEvent -> joinEvent(playerInteractAtEntityEvent.getPlayer())),
|
|
||||||
new DismissInventoryOpenFromHolder(this.villager.getUniqueId())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,47 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.antiSignEdit;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.SelectSetting;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import org.bukkit.block.sign.SignSide;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AntiSignEdit extends Appliance {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(SignEditSetting.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean preventSignEdit(Player p, SignSide sign) {
|
||||||
|
SelectSetting.Options.Option setting = Settings.instance().getSetting(p, Settings.Key.SignEdit, SelectSetting.Options.Option.class);
|
||||||
|
if(setting.is(SignEditSetting.editable)) return false;
|
||||||
|
if(setting.is(SignEditSetting.readOnly)) {
|
||||||
|
p.sendActionBar(Component.text("Das Bearbeiten von Schildern ist in deinen Einstellungen deaktiviert.", NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(setting.is(SignEditSetting.editableWhenEmpty)) {
|
||||||
|
boolean hasText = sign.lines().stream()
|
||||||
|
.anyMatch(line -> !PlainTextComponentSerializer.plainText().serialize(line).isBlank());
|
||||||
|
|
||||||
|
if(hasText) {
|
||||||
|
p.sendActionBar(Component.text("Das Bearbeiten von Schildern, welch bereits beschrieben sind, ist bei dir deaktiviert.", NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new OnSignEditListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.antiSignEdit;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import io.papermc.paper.event.player.PlayerOpenSignEvent;
|
||||||
|
import org.bukkit.block.sign.SignSide;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
|
||||||
|
class OnSignEditListener extends ApplianceListener<AntiSignEdit> {
|
||||||
|
@EventHandler
|
||||||
|
public void onEdit(PlayerOpenSignEvent event) {
|
||||||
|
if(event.getCause().equals(PlayerOpenSignEvent.Cause.PLACE)) return;
|
||||||
|
SignSide signSide = event.getSign().getSide(event.getSide());
|
||||||
|
event.setCancelled(this.getAppliance().preventSignEdit(event.getPlayer(), signSide));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.antiSignEdit;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.SelectSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class SignEditSetting extends SelectSetting implements CategorizedSetting {
|
||||||
|
private static final String namespace = SignEditSetting.class.getSimpleName().toLowerCase(Locale.ROOT);
|
||||||
|
public static Options.Option editable = new Options.Option("Bearbeitbar", new NamespacedKey(namespace, "editable"));
|
||||||
|
public static Options.Option editableWhenEmpty = new Options.Option("Bearbeitbar wenn leer", new NamespacedKey(namespace, "emptyeditable"));
|
||||||
|
public static Options.Option readOnly = new Options.Option("Nicht bearbeitbar", new NamespacedKey(namespace, "readonly"));
|
||||||
|
|
||||||
|
public SignEditSetting() {
|
||||||
|
super(
|
||||||
|
Settings.Key.SignEdit,
|
||||||
|
new Options(List.of(editable, editableWhenEmpty, readOnly))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Bearbeiten von Schildern";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Bei einem Klick auf ein Schild, kann dieses Bearbeitet werden";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.OAK_SIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Options.Option defaultValue() {
|
||||||
|
return editableWhenEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Gameplay;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.autoShulker;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.ShulkerBox;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AutoShulker extends Appliance {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(AutoShulkerSetting.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tryAutoShulker(Player p, Item item) {
|
||||||
|
ItemStack itemStack = item.getItemStack();
|
||||||
|
ItemStack offhandStack = p.getInventory().getItemInOffHand();
|
||||||
|
if(itemStack.getType().equals(Material.SHULKER_BOX)) return false;
|
||||||
|
if(!offhandStack.getType().equals(Material.SHULKER_BOX)) return false;
|
||||||
|
BlockStateMeta blockStateMeta = (BlockStateMeta) offhandStack.getItemMeta();
|
||||||
|
ShulkerBox shulkerBox = (ShulkerBox) blockStateMeta.getBlockState();
|
||||||
|
|
||||||
|
HashMap<Integer, ItemStack> leftOver = shulkerBox.getInventory().addItem(itemStack);
|
||||||
|
if(leftOver.size() > 1)
|
||||||
|
throw new IllegalStateException("Multiple ItemStacks cannot be processed by AutoShulker!");
|
||||||
|
if(itemStack.equals(leftOver.get(0))) {
|
||||||
|
p.sendActionBar(Component.text("Die Shulkerbox ist voll!", NamedTextColor.RED));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(leftOver.isEmpty()) {
|
||||||
|
item.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
blockStateMeta.setBlockState(shulkerBox);
|
||||||
|
offhandStack.setItemMeta(blockStateMeta);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new ItemPickupListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.autoShulker;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.SelectSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class AutoShulkerSetting extends SelectSetting implements CategorizedSetting {
|
||||||
|
private static final String namespace = AutoShulkerSetting.class.getSimpleName().toLowerCase(Locale.ROOT);
|
||||||
|
public static Options.Option disabled = new Options.Option("Deaktiviert", new NamespacedKey(namespace, "disabled"));
|
||||||
|
public static Options.Option notFromPlayers = new Options.Option("Keine manuell gedroppten Items", new NamespacedKey(namespace, "noplayerdrops"));
|
||||||
|
public static Options.Option enabled = new Options.Option("Alle", new NamespacedKey(namespace, "enabled"));
|
||||||
|
|
||||||
|
public AutoShulkerSetting() {
|
||||||
|
super(
|
||||||
|
Settings.Key.AutoShulker,
|
||||||
|
new Options(List.of(disabled, notFromPlayers, enabled))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Shulker in offhand automatisch befüllen";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Wenn eine Shulker in der zweiten Hand gehalten wird, werden alle aufgesammelten Items in dieser abgelegt";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.SHULKER_BOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Options.Option defaultValue() {
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Gameplay;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.autoShulker;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.SelectSetting;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||||
|
|
||||||
|
class ItemPickupListener extends ApplianceListener<AutoShulker> {
|
||||||
|
@EventHandler
|
||||||
|
public void onPickup(EntityPickupItemEvent event) {
|
||||||
|
if(event.getEntity() instanceof Player p) {
|
||||||
|
SelectSetting.Options.Option setting = Settings.instance().getSetting(p, Settings.Key.AutoShulker, SelectSetting.Options.Option.class);
|
||||||
|
if(setting.is(AutoShulkerSetting.disabled)) return;
|
||||||
|
if(setting.is(AutoShulkerSetting.notFromPlayers) && event.getItem().getThrower() != null) return;
|
||||||
|
event.setCancelled(this.getAppliance().tryAutoShulker(p, event.getItem()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.customAdvancements;
|
||||||
|
|
||||||
|
public class Advancements {
|
||||||
|
public static String searchTrouble = "search_trouble";
|
||||||
|
public static String fleischerchest = "fleischerchest";
|
||||||
|
public static String craftPixelblock = "craft_pixelblock";
|
||||||
|
public static String usePixelblock = "use_pixelblock";
|
||||||
|
public static String start = "start";
|
||||||
|
public static String winner = "winner";
|
||||||
|
public static String participateEvent = "participate_event";
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.customAdvancements;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
class ApplyPendingAdvancementsListener extends ApplianceListener<CustomAdvancements> {
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
this.getAppliance().applyPendingAdvancements(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.customAdvancements;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.advancement.Advancement;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class CustomAdvancements extends Appliance {
|
||||||
|
record PendingAdvancement(UUID receiver, String advancement) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<PendingAdvancement> pendingAdvancements = new ArrayList<>();
|
||||||
|
|
||||||
|
public void grantAdvancement(String advancementName, UUID playerUUID) {
|
||||||
|
Player player = Bukkit.getPlayer(playerUUID);
|
||||||
|
if(player == null) {
|
||||||
|
this.addPendingAdvancement(playerUUID, advancementName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
NamespacedKey namespacedKey = Objects.requireNonNull(
|
||||||
|
NamespacedKey.fromString("craftattack_advancements:craftattack/" + advancementName),
|
||||||
|
String.format("NamespacedKey with '%s' is invalid!", advancementName)
|
||||||
|
);
|
||||||
|
Advancement advancement = Objects.requireNonNull(
|
||||||
|
Bukkit.getAdvancement(namespacedKey),
|
||||||
|
String.format("The advancement '%s' does not exist!", namespacedKey.asString())
|
||||||
|
);
|
||||||
|
player.getAdvancementProgress(advancement).awardCriteria("criteria");
|
||||||
|
} catch(Exception e) {
|
||||||
|
Main.logger().info("Advancement " + advancementName + " not found! (is Custom Advancements data pack loaded?)");
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyPendingAdvancements(Player player) {
|
||||||
|
if(this.pendingAdvancements.isEmpty()) return;
|
||||||
|
List<PendingAdvancement> grantedAdvancements = this.pendingAdvancements.stream()
|
||||||
|
.filter(pendingAdvancement -> pendingAdvancement.receiver.equals(player.getUniqueId())).toList();
|
||||||
|
this.pendingAdvancements.removeAll(grantedAdvancements);
|
||||||
|
grantedAdvancements.forEach(pendingAdvancement -> this.grantAdvancement(pendingAdvancement.advancement(), player.getUniqueId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPendingAdvancement(UUID receiver, String advancement) {
|
||||||
|
this.pendingAdvancements.add(new PendingAdvancement(receiver, advancement));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<Listener> listeners() {
|
||||||
|
return List.of(
|
||||||
|
new CustomAdvancementsListener(),
|
||||||
|
new ApplyPendingAdvancementsListener()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.customAdvancements;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
|
import org.bukkit.event.inventory.CraftItemEvent;
|
||||||
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
class CustomAdvancementsListener extends ApplianceListener<CustomAdvancements> {
|
||||||
|
@EventHandler
|
||||||
|
public void onEntityDamageEntity(EntityDamageByEntityEvent event) {
|
||||||
|
if(!(event.getEntity() instanceof Player damaged)) return;
|
||||||
|
if(!(event.getDamager() instanceof Player damager)) return;
|
||||||
|
if(!damager.getInventory().getItemInMainHand().getType().equals(Material.AIR)) return;
|
||||||
|
if(!damaged.hasPermission("admin")) return;
|
||||||
|
|
||||||
|
this.getAppliance().grantAdvancement(Advancements.searchTrouble, damager.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onCraftItem(CraftItemEvent event) {
|
||||||
|
ItemStack result = event.getInventory().getResult();
|
||||||
|
if(result == null) return;
|
||||||
|
if(!(event.getView().getPlayer() instanceof Player player)) return;
|
||||||
|
|
||||||
|
if(result.getType() == Material.RED_SHULKER_BOX) {
|
||||||
|
this.getAppliance().grantAdvancement(Advancements.fleischerchest, player.getUniqueId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result.getItemMeta().itemName().equals(Component.text("98fdf0ae-c3ab-4ef7-ae25-efd518d600de"))) {
|
||||||
|
this.getAppliance().grantAdvancement(Advancements.craftPixelblock, player.getUniqueId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onChangeWorld(PlayerChangedWorldEvent event) {
|
||||||
|
if(!event.getPlayer().getWorld().getName().startsWith("plugins/PixelBlocks/worlds")) return;
|
||||||
|
|
||||||
|
this.getAppliance().grantAdvancement(Advancements.usePixelblock, event.getPlayer().getUniqueId());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.doubleDoor;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.block.data.type.Door;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DoubleDoor extends Appliance {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(DoubleDoorSetting.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openNextDoor(Block block) {
|
||||||
|
BlockData clickedData = block.getBlockData();
|
||||||
|
if(!(clickedData instanceof Door clickedDoor)) return;
|
||||||
|
|
||||||
|
BlockFace neighborFace = this.getNeighborFace(clickedDoor.getFacing(), clickedDoor.getHinge());
|
||||||
|
Block neighbourBlock = block.getRelative(neighborFace);
|
||||||
|
BlockData neighbourData = neighbourBlock.getBlockData();
|
||||||
|
|
||||||
|
if(!(neighbourData instanceof Door neighbourDoor)) return;
|
||||||
|
if(!(neighbourDoor.getFacing() == clickedDoor.getFacing())) return;
|
||||||
|
if(neighbourDoor.getHinge() == clickedDoor.getHinge()) return;
|
||||||
|
|
||||||
|
neighbourDoor.setOpen(!clickedDoor.isOpen());
|
||||||
|
neighbourBlock.setBlockData(neighbourDoor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull BlockFace getNeighborFace(BlockFace face, Door.Hinge hinge) {
|
||||||
|
return switch(face) {
|
||||||
|
case EAST -> (hinge == Door.Hinge.RIGHT) ? BlockFace.NORTH : BlockFace.SOUTH;
|
||||||
|
case WEST -> (hinge == Door.Hinge.RIGHT) ? BlockFace.SOUTH : BlockFace.NORTH;
|
||||||
|
case SOUTH -> (hinge == Door.Hinge.RIGHT) ? BlockFace.EAST : BlockFace.WEST;
|
||||||
|
case NORTH -> (hinge == Door.Hinge.RIGHT) ? BlockFace.WEST : BlockFace.EAST;
|
||||||
|
default ->
|
||||||
|
throw new IllegalStateException(String.format("BlockFace '%s' of clicked door is not valid!", face));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new OnDoorInteractListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.doubleDoor;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.BoolSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public class DoubleDoorSetting extends BoolSetting implements CategorizedSetting {
|
||||||
|
public DoubleDoorSetting() {
|
||||||
|
super(Settings.Key.DoubleDoors);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Automatische Doppeltüren";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Öffnet und schließt die zweite Hälfte einer Doppeltür automatisch";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.OAK_DOOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean defaultValue() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Gameplay;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.doubleDoor;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
class OnDoorInteractListener extends ApplianceListener<DoubleDoor> {
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
|
if(!event.hasBlock()) return;
|
||||||
|
if(!Objects.equals(event.getHand(), EquipmentSlot.HAND)) return;
|
||||||
|
if(!event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) return;
|
||||||
|
if(event.getPlayer().isSneaking()) return;
|
||||||
|
Block clickedBlock = event.getClickedBlock();
|
||||||
|
if(clickedBlock == null) return;
|
||||||
|
if(clickedBlock.getType().equals(Material.IRON_DOOR)) return;
|
||||||
|
if(!Settings.instance().getSetting(event.getPlayer(), Settings.Key.DoubleDoors, Boolean.class)) return;
|
||||||
|
this.getAppliance().openNextDoor(clickedBlock);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.fleischerchest;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Fleischerchest extends Appliance {
|
||||||
|
public void renameItem(ItemStack item) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
meta.displayName(Component.text("Fleischerchest").color(TextColor.color(235, 20, 28)));
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<Listener> listeners() {
|
||||||
|
return List.of(new FleischerchestCraftItemListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.fleischerchest;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.inventory.PrepareItemCraftEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
class FleischerchestCraftItemListener extends ApplianceListener<Fleischerchest> {
|
||||||
|
@EventHandler
|
||||||
|
public void onPrepareItemCraft(PrepareItemCraftEvent event) {
|
||||||
|
ItemStack result = event.getInventory().getResult();
|
||||||
|
if(result == null) return;
|
||||||
|
if(result.getType() != Material.RED_SHULKER_BOX) return;
|
||||||
|
|
||||||
|
this.getAppliance().renameItem(event.getInventory().getResult());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.glowingBerries;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import net.kyori.adventure.sound.Sound;
|
||||||
|
import net.kyori.adventure.util.Ticks;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GlowingBerries extends Appliance {
|
||||||
|
private static final PotionEffect glowEffect = new PotionEffect(
|
||||||
|
PotionEffectType.GLOWING,
|
||||||
|
Ticks.TICKS_PER_SECOND * 15,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
public void letPlayerGlow(Player player) {
|
||||||
|
player.addPotionEffect(glowEffect);
|
||||||
|
Sound sound = Sound.sound(org.bukkit.Sound.BLOCK_AMETHYST_BLOCK_CHIME.key(), Sound.Source.PLAYER, 1f, 1f);
|
||||||
|
player.stopSound(sound);
|
||||||
|
player.playSound(sound, Sound.Emitter.self());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new OnBerryEaten());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.glowingBerries;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||||
|
|
||||||
|
class OnBerryEaten extends ApplianceListener<GlowingBerries> {
|
||||||
|
@EventHandler
|
||||||
|
public void onEat(PlayerItemConsumeEvent event) {
|
||||||
|
if(event.getItem().getType().equals(Material.GLOW_BERRIES))
|
||||||
|
this.getAppliance().letPlayerGlow(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.hotbarRefill;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
public class HotbarRefill extends Appliance {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(HotbarRefillSetting.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleHotbarChange(Player player, ItemStack item) {
|
||||||
|
if(player.getGameMode().equals(GameMode.CREATIVE)) return;
|
||||||
|
if(item.getAmount() != 1) return;
|
||||||
|
Inventory inventory = player.getInventory();
|
||||||
|
|
||||||
|
int itemSlot = inventory.first(item);
|
||||||
|
if(itemSlot > 8) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
int replacementSlot = inventory.all(item.getType()).entrySet().stream()
|
||||||
|
.filter(entry -> entry.getKey() > 8)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow()
|
||||||
|
.getKey();
|
||||||
|
|
||||||
|
Bukkit.getScheduler().scheduleSyncDelayedTask(Main.instance(), () -> {
|
||||||
|
ItemStack firstItem = inventory.getItem(itemSlot);
|
||||||
|
ItemStack secondItem = inventory.getItem(replacementSlot);
|
||||||
|
|
||||||
|
inventory.setItem(itemSlot, secondItem);
|
||||||
|
inventory.setItem(replacementSlot, firstItem);
|
||||||
|
|
||||||
|
player.sendActionBar(Component.text("Die Hotbar wurde aufgefüllt", NamedTextColor.GREEN));
|
||||||
|
}, 1);
|
||||||
|
} catch(NoSuchElementException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new HotbarRefillListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.hotbarRefill;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
import org.bukkit.event.player.PlayerItemBreakEvent;
|
||||||
|
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class HotbarRefillListener extends ApplianceListener<HotbarRefill> {
|
||||||
|
private HotbarRefillSetting.HotbarReplaceConfig getPlayerSetting(Player player) {
|
||||||
|
return Settings.instance().getSetting(
|
||||||
|
player,
|
||||||
|
Settings.Key.HotbarReplacer,
|
||||||
|
HotbarRefillSetting.HotbarReplaceConfig.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void blockPlace(BlockPlaceEvent event) {
|
||||||
|
ItemStack stackInHand = event.getItemInHand();
|
||||||
|
if(stackInHand.getAmount() != 1) return;
|
||||||
|
if(stackInHand.getType().getMaxDurability() > 0) return;
|
||||||
|
if(stackInHand.getType().getMaxStackSize() > 0) return;
|
||||||
|
|
||||||
|
if(!this.getPlayerSetting(event.getPlayer()).onBlocks()) return;
|
||||||
|
this.getAppliance().handleHotbarChange(event.getPlayer(), stackInHand);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerItemBreak(PlayerItemBreakEvent event) {
|
||||||
|
if(!this.getPlayerSetting(event.getPlayer()).onTools()) return;
|
||||||
|
|
||||||
|
this.getAppliance().handleHotbarChange(event.getPlayer(), event.getBrokenItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerItemConsume(PlayerItemConsumeEvent event) {
|
||||||
|
if(List.of(Material.POTION, Material.HONEY_BOTTLE).contains(event.getItem().getType())) return;
|
||||||
|
if(!this.getPlayerSetting(event.getPlayer()).onConsumable()) return;
|
||||||
|
|
||||||
|
this.getAppliance().handleHotbarChange(event.getPlayer(), event.getItem());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.hotbarRefill;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.MultiBoolSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public class HotbarRefillSetting extends MultiBoolSetting<HotbarRefillSetting.HotbarReplaceConfig> implements CategorizedSetting {
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Gameplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record HotbarReplaceConfig(
|
||||||
|
@DisplayName("Blöcke") boolean onBlocks,
|
||||||
|
@DisplayName("Werkzeuge") boolean onTools,
|
||||||
|
@DisplayName("Essen") boolean onConsumable
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotbarRefillSetting() {
|
||||||
|
super(Settings.Key.HotbarReplacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Automatische Hotbar";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Verschiebe Items automatisch von deinem Inventar in die Hotbar, wenn diese verbraucht werden";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.CHEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HotbarReplaceConfig defaultValue() {
|
||||||
|
return new HotbarReplaceConfig(false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> dataType() {
|
||||||
|
return HotbarReplaceConfig.class;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.knockDoor;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.SelectSetting;
|
||||||
|
import org.bukkit.*;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.metadata.FixedMetadataValue;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KnockDoor extends Appliance {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(KnockDoorSetting.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void knockAtDoor(Player knockingPlayer, Block knockedBlock) {
|
||||||
|
SelectSetting.Options.Option setting = Settings.instance().getSetting(knockingPlayer, Settings.Key.KnockDoors, SelectSetting.Options.Option.class);
|
||||||
|
if(setting.is(KnockDoorSetting.disabled)) return;
|
||||||
|
|
||||||
|
if(setting.is(KnockDoorSetting.knockSingleTime)) {
|
||||||
|
this.playSound(knockedBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(setting.is(KnockDoorSetting.knockThreeTimes)) {
|
||||||
|
String metadataKey = new NamespacedKey(Main.instance(), KnockDoor.class.getName()).getNamespace();
|
||||||
|
if(knockingPlayer.hasMetadata(metadataKey)) return;
|
||||||
|
knockingPlayer.setMetadata(metadataKey, new FixedMetadataValue(Main.instance(), 0));
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int timesKnocked = knockingPlayer.getMetadata(metadataKey).getFirst().asInt();
|
||||||
|
if(timesKnocked >= 3) {
|
||||||
|
knockingPlayer.removeMetadata(metadataKey, Main.instance());
|
||||||
|
this.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KnockDoor.this.playSound(knockedBlock);
|
||||||
|
knockingPlayer.setMetadata(metadataKey, new FixedMetadataValue(Main.instance(), timesKnocked + 1));
|
||||||
|
}
|
||||||
|
}.runTaskTimer(Main.instance(), 0, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playSound(Block knockedBlock) {
|
||||||
|
Location knockLocation = knockedBlock.getLocation();
|
||||||
|
Sound sound = knockedBlock.getType() == Material.IRON_DOOR
|
||||||
|
? Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR
|
||||||
|
: Sound.ITEM_SHIELD_BLOCK;
|
||||||
|
|
||||||
|
knockLocation.getWorld().playSound(knockLocation, sound, SoundCategory.PLAYERS, 1f, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new KnockDoorListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.knockDoor;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.data.type.Door;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.block.BlockDamageAbortEvent;
|
||||||
|
|
||||||
|
class KnockDoorListener extends ApplianceListener<KnockDoor> {
|
||||||
|
@EventHandler
|
||||||
|
public void onKnock(BlockDamageAbortEvent event) {
|
||||||
|
if(event.getPlayer().getGameMode() != GameMode.SURVIVAL) return;
|
||||||
|
Block block = event.getBlock();
|
||||||
|
if(!(block.getBlockData() instanceof Door)) return;
|
||||||
|
this.getAppliance().knockAtDoor(event.getPlayer(), block);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.knockDoor;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.SelectSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class KnockDoorSetting extends SelectSetting implements CategorizedSetting {
|
||||||
|
private static final String namespace = KnockDoorSetting.class.getSimpleName().toLowerCase(Locale.ROOT);
|
||||||
|
public static Options.Option disabled = new Options.Option("Deaktiviert", new NamespacedKey(namespace, "disabled"));
|
||||||
|
public static Options.Option knockSingleTime = new Options.Option("Einmal an der Tür anklopfen", new NamespacedKey(namespace, "single"));
|
||||||
|
public static Options.Option knockThreeTimes = new Options.Option("Dreimal an der Tür anklopfen", new NamespacedKey(namespace, "three"));
|
||||||
|
|
||||||
|
public KnockDoorSetting() {
|
||||||
|
super(
|
||||||
|
Settings.Key.KnockDoors,
|
||||||
|
new Options(List.of(disabled, knockSingleTime, knockThreeTimes))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Gameplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Klopfen an Türen";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Klopft durch das schlagen an eine Tür an.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.BELL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Options.Option defaultValue() {
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.outlawed;
|
||||||
|
|
||||||
|
class OutlawChangeNotPermitted extends Exception {
|
||||||
|
public OutlawChangeNotPermitted(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.outlawed;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.displayName.DisplayName;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.tooling.whitelist.Whitelist;
|
||||||
|
import eu.mhsl.craftattack.spawn.config.Configuration;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.DisconnectInfo;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Outlawed extends Appliance implements DisplayName.Prefixed {
|
||||||
|
public final int timeoutInMs = 1000 * 60 * 60 * 6;
|
||||||
|
private final Map<UUID, Long> timeouts = new HashMap<>();
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
DISABLED,
|
||||||
|
VOLUNTARILY,
|
||||||
|
FORCED
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<Player, Status> playerStatusMap = new WeakHashMap<>();
|
||||||
|
private final String voluntarilyEntry = "voluntarily";
|
||||||
|
|
||||||
|
public Outlawed() {
|
||||||
|
super("outlawed");
|
||||||
|
Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||||
|
Main.instance(),
|
||||||
|
() -> this.playerStatusMap.forEach((player, status) -> {
|
||||||
|
if(!player.isOnline()) return;
|
||||||
|
if(status != Status.FORCED) return;
|
||||||
|
try {
|
||||||
|
this.queryAppliance(Whitelist.class).fullIntegrityCheck(player);
|
||||||
|
} catch(DisconnectInfo.Throwable e) {
|
||||||
|
e.getDisconnectScreen().applyKick(player);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
20 * 60,
|
||||||
|
20 * 60 * 5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void switchLawStatus(Player player) throws OutlawChangeNotPermitted {
|
||||||
|
if(this.getLawStatus(player).equals(Status.FORCED)) {
|
||||||
|
throw new OutlawChangeNotPermitted("Dein Vogelfreistatus wurde als Strafe auferlegt und kann daher nicht verändert werden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.isTimeout(player)) {
|
||||||
|
throw new OutlawChangeNotPermitted("Du kannst deinen Vogelfreistatus nicht so schnell wechseln. Bitte warte einige Stunden bevor du umschaltest!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setLawStatus(player, this.isOutlawed(player) ? Status.DISABLED : Status.VOLUNTARILY);
|
||||||
|
this.setTimeout(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateForcedStatus(Player player, boolean forced) {
|
||||||
|
this.setLawStatus(player, forced ? Status.FORCED : this.getLawStatus(player) == Status.FORCED ? Status.DISABLED : this.getLawStatus(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status getLawStatus(Player player) {
|
||||||
|
return this.playerStatusMap.computeIfAbsent(player, p -> {
|
||||||
|
if(this.localConfig().getStringList(this.voluntarilyEntry).contains(p.getUniqueId().toString()))
|
||||||
|
return Status.VOLUNTARILY;
|
||||||
|
return Status.DISABLED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLawStatus(Player player, Status status) {
|
||||||
|
this.playerStatusMap.put(player, status);
|
||||||
|
this.queryAppliance(DisplayName.class).update(player);
|
||||||
|
|
||||||
|
List<String> newList = this.localConfig().getStringList(this.voluntarilyEntry);
|
||||||
|
if(status.equals(Status.VOLUNTARILY)) {
|
||||||
|
newList.add(player.getUniqueId().toString());
|
||||||
|
} else {
|
||||||
|
newList.remove(player.getUniqueId().toString());
|
||||||
|
}
|
||||||
|
this.localConfig().set(this.voluntarilyEntry, newList.stream().distinct().toList());
|
||||||
|
Configuration.saveChanges();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOutlawed(Player player) {
|
||||||
|
return this.getLawStatus(player) != Status.DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTimeout(Player player) {
|
||||||
|
return this.timeouts.getOrDefault(player.getUniqueId(), 0L) > System.currentTimeMillis() - this.timeoutInMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTimeout(Player player) {
|
||||||
|
this.timeouts.put(player.getUniqueId(), System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getStatusDescription(Status status) {
|
||||||
|
return switch(status) {
|
||||||
|
case DISABLED -> Component.text("Vogelfreistatus inaktiv: ", NamedTextColor.GREEN)
|
||||||
|
.append(Component.text("Es gelten die Standard Regeln!", NamedTextColor.GOLD));
|
||||||
|
|
||||||
|
case VOLUNTARILY, FORCED -> Component.text("Vogelfreistatus aktiv: ", NamedTextColor.RED)
|
||||||
|
.append(Component.text("Du darfst von jedem angegriffen und getötet werden!", NamedTextColor.GOLD));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getNamePrefix(Player player) {
|
||||||
|
if(this.isOutlawed(player)) {
|
||||||
|
return Component.text("[☠]", NamedTextColor.RED)
|
||||||
|
.hoverEvent(HoverEvent.showText(Component.text("Vogelfreie Spieler dürfen ohne Grund angegriffen werden!")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<ApplianceCommand<?>> commands() {
|
||||||
|
return List.of(new OutlawedCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<Listener> listeners() {
|
||||||
|
return List.of(new OutlawedReminderListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.outlawed;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
class OutlawedCommand extends ApplianceCommand.PlayerChecked<Outlawed> {
|
||||||
|
public OutlawedCommand() {
|
||||||
|
super("vogelfrei");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
|
try {
|
||||||
|
this.getAppliance().switchLawStatus(this.getPlayer());
|
||||||
|
sender.sendMessage(
|
||||||
|
this.getAppliance()
|
||||||
|
.getStatusDescription(this.getAppliance().getLawStatus(this.getPlayer()))
|
||||||
|
);
|
||||||
|
} catch(OutlawChangeNotPermitted e) {
|
||||||
|
sender.sendMessage(Component.text(e.getMessage(), NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.outlawed;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
class OutlawedReminderListener extends ApplianceListener<Outlawed> {
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent e) {
|
||||||
|
if(this.getAppliance().isOutlawed(e.getPlayer())) {
|
||||||
|
e.getPlayer().sendMessage(this.getAppliance().getStatusDescription(this.getAppliance().getLawStatus(e.getPlayer())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.portableCrafting;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
|
||||||
|
class OnCraftingTableUseListener extends ApplianceListener<PortableCrafting> {
|
||||||
|
@EventHandler
|
||||||
|
public void inInteract(PlayerInteractEvent event) {
|
||||||
|
if(!event.getAction().equals(Action.RIGHT_CLICK_AIR)) return;
|
||||||
|
if(!event.getMaterial().equals(Material.CRAFTING_TABLE)) return;
|
||||||
|
this.getAppliance().openFor(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.portableCrafting;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PortableCrafting extends Appliance {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(PortableCraftingSetting.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openFor(Player player) {
|
||||||
|
if(!Settings.instance().getSetting(player, Settings.Key.EnablePortableCrafting, Boolean.class)) return;
|
||||||
|
player.openWorkbench(null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new OnCraftingTableUseListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.portableCrafting;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.BoolSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public class PortableCraftingSetting extends BoolSetting implements CategorizedSetting {
|
||||||
|
public PortableCraftingSetting() {
|
||||||
|
super(Settings.Key.EnablePortableCrafting);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Portables Crafting";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Erlaubt das öffnen einer Werkbank in der Hand, ohne sie plazieren zu müssen";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.CRAFTING_TABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean defaultValue() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Gameplay;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.snowballKnockback;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SnowballKnockback extends Appliance {
|
||||||
|
public void dealSnowballKnockback(LivingEntity entity, Entity snowball) {
|
||||||
|
entity.damage(0.1);
|
||||||
|
entity.knockback(0.4, -snowball.getVelocity().getX(), -snowball.getVelocity().getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<Listener> listeners() {
|
||||||
|
return List.of(new SnowballKnockbackListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.gameplay.snowballKnockback;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.entity.ProjectileHitEvent;
|
||||||
|
|
||||||
|
class SnowballKnockbackListener extends ApplianceListener<SnowballKnockback> {
|
||||||
|
@EventHandler
|
||||||
|
public void onSnowballHit(ProjectileHitEvent event) {
|
||||||
|
if(event.getHitEntity() == null) return;
|
||||||
|
if(!event.getEntityType().equals(EntityType.SNOWBALL)) return;
|
||||||
|
if(!(event.getHitEntity() instanceof LivingEntity hitEntity)) return;
|
||||||
|
|
||||||
|
Entity snowball = event.getEntity();
|
||||||
|
this.getAppliance().dealSnowballKnockback(hitEntity, snowball);
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.help;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.command.DiscordCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.command.HelpCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.command.SpawnCommand;
|
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.command.TeamspeakCommand;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Help extends Appliance {
|
|
||||||
public Help() {
|
|
||||||
super("help");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
|
||||||
return List.of(
|
|
||||||
new HelpCommand(),
|
|
||||||
new SpawnCommand(),
|
|
||||||
new TeamspeakCommand(),
|
|
||||||
new DiscordCommand()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,20 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.internal.debug;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.internal.debug.command.AppliancesCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.internal.debug.command.UserInfoCommand;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Debug extends Appliance {
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<ApplianceCommand<?>> commands() {
|
||||||
|
return List.of(
|
||||||
|
new UserInfoCommand(),
|
||||||
|
new AppliancesCommand()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.internal.debug.command;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.internal.debug.Debug;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.ComponentBuilder;
|
||||||
|
import net.kyori.adventure.text.TextComponent;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AppliancesCommand extends ApplianceCommand<Debug> {
|
||||||
|
public AppliancesCommand() {
|
||||||
|
super("appliances");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
ComponentBuilder<TextComponent, TextComponent.Builder> componentBuilder = Component.text()
|
||||||
|
.append(Component.text(Main.instance().getAppliances().size()))
|
||||||
|
.append(Component.text(" appliances running:"))
|
||||||
|
.appendNewline();
|
||||||
|
|
||||||
|
Main.instance().getAppliances().forEach(appliance -> {
|
||||||
|
List<ApplianceCommand<?>> commands = appliance.getCommands();
|
||||||
|
List<Listener> listener = appliance.getListeners();
|
||||||
|
|
||||||
|
componentBuilder
|
||||||
|
.append(Component.text(appliance.getClass().getSimpleName(), NamedTextColor.GREEN)
|
||||||
|
.hoverEvent(HoverEvent.showText(Component.text(appliance.getClass().getName()))))
|
||||||
|
.append(Component.text(": ", NamedTextColor.DARK_GRAY))
|
||||||
|
.append(Component.text(commands.size() + " Commands", NamedTextColor.GRAY)
|
||||||
|
.hoverEvent(HoverEvent.showText(commands.stream()
|
||||||
|
.map(applianceCommand -> Component.text()
|
||||||
|
.append(Component.text(applianceCommand.commandName, NamedTextColor.DARK_GREEN))
|
||||||
|
.append(Component.text(": "))
|
||||||
|
.append(Component.text(applianceCommand.getClass().getName()))
|
||||||
|
.build())
|
||||||
|
.reduce(ComponentUtil::appendWithNewline)
|
||||||
|
.orElse(Component.text("No commands available")))))
|
||||||
|
.append(Component.text(", ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text(listener.size() + " Listener", NamedTextColor.GRAY)
|
||||||
|
.hoverEvent(HoverEvent.showText(listener.stream()
|
||||||
|
.map(eventHandler -> Component.text()
|
||||||
|
.append(Component.text(eventHandler.getClass().getSimpleName(), NamedTextColor.DARK_GREEN))
|
||||||
|
.append(Component.text(": "))
|
||||||
|
.append(Component.text(eventHandler.getClass().getName()))
|
||||||
|
.build())
|
||||||
|
.reduce(ComponentUtil::appendWithNewline)
|
||||||
|
.orElse(Component.text("No listeners available")))))
|
||||||
|
.appendNewline();
|
||||||
|
});
|
||||||
|
|
||||||
|
componentBuilder.append(Component.text(Main.instance().getClass().getName(), NamedTextColor.GRAY));
|
||||||
|
|
||||||
|
sender.sendMessage(componentBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.internal.debug.command;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.internal.debug.Debug;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class UserInfoCommand extends ApplianceCommand<Debug> {
|
||||||
|
public UserInfoCommand() {
|
||||||
|
super("userInfo");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if(args.length != 1) {
|
||||||
|
sender.sendMessage(Component.text("Bitte gib einen Nutzernamen an.", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]);
|
||||||
|
|
||||||
|
sender.sendMessage(
|
||||||
|
Component.text()
|
||||||
|
.appendNewline()
|
||||||
|
.append(Component.text("Informationen zu: ", NamedTextColor.GOLD))
|
||||||
|
.append(
|
||||||
|
Component
|
||||||
|
.text(Objects.requireNonNull(player.getName()), NamedTextColor.YELLOW)
|
||||||
|
.clickEvent(ClickEvent.copyToClipboard(Objects.requireNonNull(player.getName())))
|
||||||
|
)
|
||||||
|
.appendNewline()
|
||||||
|
.append(
|
||||||
|
Component
|
||||||
|
.text("UUID: " + player.getUniqueId(), NamedTextColor.GRAY)
|
||||||
|
.clickEvent(ClickEvent.copyToClipboard(player.getUniqueId().toString()))
|
||||||
|
)
|
||||||
|
.appendNewline()
|
||||||
|
.append(
|
||||||
|
Component
|
||||||
|
.text("Erster Besuch: " + this.formatUnixTimestamp(player.getFirstPlayed()), NamedTextColor.GRAY)
|
||||||
|
.clickEvent(ClickEvent.copyToClipboard(String.valueOf(player.getFirstPlayed())))
|
||||||
|
)
|
||||||
|
.appendNewline()
|
||||||
|
.append(
|
||||||
|
Component
|
||||||
|
.text("Letzter Besuch: " + this.formatUnixTimestamp(player.getLastSeen()), NamedTextColor.GRAY)
|
||||||
|
.clickEvent(ClickEvent.copyToClipboard(String.valueOf(player.getLastSeen())))
|
||||||
|
)
|
||||||
|
.appendNewline()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if(args.length < 2) {
|
||||||
|
return Stream.concat(
|
||||||
|
Bukkit.getOnlinePlayers().stream().map(Player::getName),
|
||||||
|
Arrays.stream(Bukkit.getOfflinePlayers()).map(OfflinePlayer::getName)
|
||||||
|
).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatUnixTimestamp(long timestamp) {
|
||||||
|
DateFormat format = new SimpleDateFormat("E dd.MM.yyyy H:m:s");
|
||||||
|
return format.format(new Date(timestamp));
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,20 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.titleClear;
|
package eu.mhsl.craftattack.spawn.appliances.internal.titleClear;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TitleClear extends Appliance {
|
public class TitleClear extends Appliance {
|
||||||
|
public void clearTitle(Player player) {
|
||||||
|
player.clearTitle();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @NotNull List<Listener> eventHandlers() {
|
@NotNull
|
||||||
|
protected List<Listener> listeners() {
|
||||||
return List.of(
|
return List.of(
|
||||||
new TitleClearListener()
|
new TitleClearListener()
|
||||||
);
|
);
|
@ -1,12 +1,12 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.titleClear;
|
package eu.mhsl.craftattack.spawn.appliances.internal.titleClear;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
public class TitleClearListener extends ApplianceListener<TitleClear> {
|
class TitleClearListener extends ApplianceListener<TitleClear> {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
event.getPlayer().resetTitle();
|
this.getAppliance().clearTitle(event.getPlayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.adminMarker;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public class AdminMarker extends Appliance {
|
||||||
|
public TextColor getPlayerColor(Player player) {
|
||||||
|
if(player.hasPermission("chatcolor"))
|
||||||
|
return TextColor.color(Color.AQUA.asRGB()); // TODO read permission from config
|
||||||
|
return TextColor.color(Color.WHITE.asRGB());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.afkTag;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
|
||||||
|
class AfkResetListener extends ApplianceListener<AfkTag> {
|
||||||
|
@EventHandler
|
||||||
|
public void onMove(PlayerMoveEvent event) {
|
||||||
|
this.getAppliance().resetTiming(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInteract(PlayerInteractEvent event) {
|
||||||
|
this.getAppliance().resetTiming(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onChat(AsyncChatEvent event) {
|
||||||
|
this.getAppliance().resetTiming(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
this.getAppliance().resetTiming(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.afkTag;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.displayName.DisplayName;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.util.Ticks;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class AfkTag extends Appliance implements DisplayName.Prefixed {
|
||||||
|
private final HashMap<UUID, Long> afkTimings = new HashMap<>();
|
||||||
|
private static final int updateIntervalSeconds = 30;
|
||||||
|
private static final int afkWhenMillis = 3 * 60 * 1000;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||||
|
Main.instance(),
|
||||||
|
this::checkAfkPlayers,
|
||||||
|
Ticks.TICKS_PER_SECOND,
|
||||||
|
Ticks.TICKS_PER_SECOND * updateIntervalSeconds
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetTiming(Player player) {
|
||||||
|
boolean wasAfk = this.isAfk(player);
|
||||||
|
this.afkTimings.put(player.getUniqueId(), System.currentTimeMillis());
|
||||||
|
if(wasAfk) this.updateAfkPrefix(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAfkPlayers() {
|
||||||
|
this.afkTimings.keySet().stream()
|
||||||
|
.map(Bukkit::getPlayer)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(this::isAfk)
|
||||||
|
.forEach(this::updateAfkPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAfk(Player player) {
|
||||||
|
if(player.isSleeping()) return false;
|
||||||
|
|
||||||
|
long lastTimeActive = this.afkTimings.getOrDefault(player.getUniqueId(), 0L);
|
||||||
|
long timeSinceLastActive = System.currentTimeMillis() - lastTimeActive;
|
||||||
|
return timeSinceLastActive >= afkWhenMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAfkPrefix(Player player) {
|
||||||
|
Main.instance().getAppliance(DisplayName.class).update(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Component getNamePrefix(Player player) {
|
||||||
|
if(this.isAfk(player)) return Component.text("[ᵃᶠᵏ]", NamedTextColor.GRAY)
|
||||||
|
.hoverEvent(HoverEvent.showText(Component.text("Der Spieler ist AFK")));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new AfkResetListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.chatMention;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import net.kyori.adventure.sound.Sound;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class ChatMention extends Appliance {
|
||||||
|
private static List<String> playerNames;
|
||||||
|
|
||||||
|
public String formatPlayer(String name) {
|
||||||
|
return "@" + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPlayerNames() {
|
||||||
|
return playerNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshPlayers() {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(
|
||||||
|
Main.instance(),
|
||||||
|
() -> playerNames = Arrays.stream(Bukkit.getOfflinePlayers())
|
||||||
|
.map(OfflinePlayer::getName)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyPlayers(List<String> playerNames) {
|
||||||
|
playerNames.stream()
|
||||||
|
.distinct()
|
||||||
|
.map(Bukkit::getPlayer)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(player -> Settings.instance()
|
||||||
|
.getSetting(player, Settings.Key.ChatMentions, ChatMentionSetting.ChatMentionConfig.class)
|
||||||
|
.notifyOnMention()
|
||||||
|
)
|
||||||
|
.forEach(player -> player.playSound(
|
||||||
|
Sound.sound(
|
||||||
|
org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP,
|
||||||
|
Sound.Source.PLAYER,
|
||||||
|
1.0f,
|
||||||
|
1.0f
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(ChatMentionSetting.class);
|
||||||
|
this.refreshPlayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new ChatMentionListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.chatMention;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.chatMessages.ChatMessages;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||||
|
import io.papermc.paper.event.player.AsyncChatDecorateEvent;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class ChatMentionListener extends ApplianceListener<ChatMention> {
|
||||||
|
@SuppressWarnings("UnstableApiUsage")
|
||||||
|
@EventHandler
|
||||||
|
public void coloringEvent(AsyncChatDecorateEvent event) {
|
||||||
|
String message = PlainTextComponentSerializer.plainText().serialize(event.result());
|
||||||
|
List<String> words = List.of(message.split(" "));
|
||||||
|
List<String> mentioned = new ArrayList<>();
|
||||||
|
|
||||||
|
ChatMentionSetting.ChatMentionConfig config = Settings.instance()
|
||||||
|
.getSetting(event.player(), Settings.Key.ChatMentions, ChatMentionSetting.ChatMentionConfig.class);
|
||||||
|
ChatMessages chatMessages = Main.instance().getAppliance(ChatMessages.class);
|
||||||
|
|
||||||
|
Component result = words.stream()
|
||||||
|
.map(word -> {
|
||||||
|
String wordWithoutAnnotation = word.replace("@", "");
|
||||||
|
boolean isPlayer = this.getAppliance().getPlayerNames().contains(wordWithoutAnnotation);
|
||||||
|
if(isPlayer && config.applyMentions()) {
|
||||||
|
mentioned.add(wordWithoutAnnotation);
|
||||||
|
Component mention = Component.text(
|
||||||
|
this.getAppliance().formatPlayer(wordWithoutAnnotation),
|
||||||
|
NamedTextColor.GOLD
|
||||||
|
);
|
||||||
|
return chatMessages.addReportActions(mention, wordWithoutAnnotation);
|
||||||
|
} else {
|
||||||
|
return Component.text(word);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.reduce(ComponentUtil::appendWithSpace)
|
||||||
|
.orElseThrow();
|
||||||
|
|
||||||
|
this.getAppliance().notifyPlayers(mentioned);
|
||||||
|
event.result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
this.getAppliance().refreshPlayers();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.chatMention;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.MultiBoolSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public class ChatMentionSetting extends MultiBoolSetting<ChatMentionSetting.ChatMentionConfig> implements CategorizedSetting {
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Visuals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ChatMentionConfig(
|
||||||
|
@DisplayName("Spielernamen hervorheben") boolean applyMentions,
|
||||||
|
@DisplayName("Benachrichtigungston") boolean notifyOnMention
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChatMentionSetting() {
|
||||||
|
super(Settings.Key.ChatMentions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Erwähnungen im Chat";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Erwähnungen werden automatisch im Chat angewandt und der Empfänger erhält einen Signalton";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.FEATHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ChatMentionConfig defaultValue() {
|
||||||
|
return new ChatMentionConfig(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> dataType() {
|
||||||
|
return ChatMentionConfig.class;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.chatMessages;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ChatMessages extends Appliance {
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Settings.instance().declareSetting(ShowJoinAndLeaveMessagesSetting.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getReportablePlayerName(Player player) {
|
||||||
|
return this.addReportActions(player.displayName(), player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component addReportActions(Component message, String username) {
|
||||||
|
return message
|
||||||
|
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um diesen Spieler zu reporten").color(NamedTextColor.GOLD)))
|
||||||
|
.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.format("/report %s ", username)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<Listener> listeners() {
|
||||||
|
return List.of(new ChatMessagesListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.chatMessages;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.IteratorUtil;
|
||||||
|
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
class ChatMessagesListener extends ApplianceListener<ChatMessages> {
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerChatEvent(AsyncChatEvent event) {
|
||||||
|
event.renderer(
|
||||||
|
(source, sourceDisplayName, message, viewer) ->
|
||||||
|
Component.text("")
|
||||||
|
.append(this.getAppliance().getReportablePlayerName(source))
|
||||||
|
.append(Component.text(" > ").color(TextColor.color(Color.GRAY.asRGB())))
|
||||||
|
.append(message).color(TextColor.color(Color.SILVER.asRGB()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGH)
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
event.joinMessage(null);
|
||||||
|
IteratorUtil.onlinePlayers(player -> {
|
||||||
|
if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return;
|
||||||
|
player.sendMessage(
|
||||||
|
Component
|
||||||
|
.text(">>> ").color(NamedTextColor.GREEN)
|
||||||
|
.append(this.getAppliance().getReportablePlayerName(event.getPlayer()))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerLeave(PlayerQuitEvent event) {
|
||||||
|
event.quitMessage(null);
|
||||||
|
IteratorUtil.onlinePlayers(player -> {
|
||||||
|
if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return;
|
||||||
|
player.sendMessage(
|
||||||
|
Component
|
||||||
|
.text("<<< ").color(NamedTextColor.RED)
|
||||||
|
.append(this.getAppliance().getReportablePlayerName(event.getPlayer()))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onDeath(PlayerDeathEvent event) {
|
||||||
|
event.deathMessage(
|
||||||
|
Component
|
||||||
|
.text("☠ ")
|
||||||
|
.append(
|
||||||
|
Optional
|
||||||
|
.ofNullable(event.deathMessage())
|
||||||
|
.orElse(Component.text(event.getPlayer().getName()))
|
||||||
|
)
|
||||||
|
.color(TextColor.color(Color.SILVER.asRGB()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.chatMessages;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.CategorizedSetting;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.SettingCategory;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.Settings;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.settings.datatypes.BoolSetting;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public class ShowJoinAndLeaveMessagesSetting extends BoolSetting implements CategorizedSetting {
|
||||||
|
public ShowJoinAndLeaveMessagesSetting() {
|
||||||
|
super(Settings.Key.ShowJoinAndLeaveMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String title() {
|
||||||
|
return "Join & Leave Nachrichten anzeigen";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String description() {
|
||||||
|
return "Zeige allgemeine Beitritts und Verlassensmeldungen im Chat";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material icon() {
|
||||||
|
return Material.PLAYER_HEAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean defaultValue() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SettingCategory category() {
|
||||||
|
return SettingCategory.Visuals;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.displayName;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.gameplay.outlawed.Outlawed;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.adminMarker.AdminMarker;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.afkTag.AfkTag;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.sleepTag.SleepTag;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.yearRank.YearRank;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.server.Floodgate;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.ComponentBuilder;
|
||||||
|
import net.kyori.adventure.text.TextComponent;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class DisplayName extends Appliance {
|
||||||
|
public interface Prefixed {
|
||||||
|
@Nullable
|
||||||
|
Component getNamePrefix(Player player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(Player player) {
|
||||||
|
TextColor playerColor = this.queryAppliance(AdminMarker.class).getPlayerColor(player);
|
||||||
|
List<Supplier<Prefixed>> prefixes = List.of(
|
||||||
|
() -> this.queryAppliance(Outlawed.class),
|
||||||
|
() -> this.queryAppliance(YearRank.class),
|
||||||
|
() -> this.queryAppliance(AfkTag.class),
|
||||||
|
() -> this.queryAppliance(SleepTag.class)
|
||||||
|
);
|
||||||
|
|
||||||
|
ComponentBuilder<TextComponent, TextComponent.Builder> playerName = Component.text();
|
||||||
|
prefixes.stream()
|
||||||
|
.map(prefixed -> prefixed.get().getNamePrefix(player))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.forEach(prefix -> playerName
|
||||||
|
.append(prefix)
|
||||||
|
.append(ComponentUtil.clearedSpace())
|
||||||
|
);
|
||||||
|
|
||||||
|
if(Floodgate.isBedrock(player)) {
|
||||||
|
playerName
|
||||||
|
.append(
|
||||||
|
Component.text("\uD83C\uDFAE", NamedTextColor.GRAY)
|
||||||
|
.hoverEvent(HoverEvent.showText(Component.text(
|
||||||
|
String.format("%s spielt die Minecraft: Bedrock Edition", player.getName())
|
||||||
|
)))
|
||||||
|
)
|
||||||
|
.append(ComponentUtil.clearedSpace());
|
||||||
|
}
|
||||||
|
|
||||||
|
playerName.append(Component.text(player.getName(), playerColor));
|
||||||
|
|
||||||
|
this.setGlobal(player, playerName.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setGlobal(Player player, Component component) {
|
||||||
|
try {
|
||||||
|
player.customName(component);
|
||||||
|
player.displayName(component);
|
||||||
|
player.playerListName(component);
|
||||||
|
} catch(Exception e) {
|
||||||
|
Main.instance().getLogger().log(Level.SEVERE, e, e::getMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.displayName;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
class DisplayNameUpdateListener extends ApplianceListener<DisplayName> {
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
this.getAppliance().update(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.event;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
class ApplyPendingRewardsListener extends ApplianceListener<Event> {
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
this.getAppliance().applyPendingRewards(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,230 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.event;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.repositories.EventRepository;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.server.HttpServer;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.gameplay.customAdvancements.Advancements;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.gameplay.customAdvancements.CustomAdvancements;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.command.*;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.IteratorUtil;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.api.HttpStatus;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.entity.DisplayVillager;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.listener.DismissInventoryOpenFromHolder;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.listener.PlayerInteractAtEntityEventListener;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.server.PluginMessage;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.Countdown;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.entity.Villager;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Event extends Appliance {
|
||||||
|
enum AdvertisementStatus {
|
||||||
|
BEFORE,
|
||||||
|
ADVERTISED,
|
||||||
|
DONE
|
||||||
|
}
|
||||||
|
|
||||||
|
Countdown advertiseCountdown = new Countdown(
|
||||||
|
120,
|
||||||
|
announcementData -> Component.text()
|
||||||
|
.append(ComponentUtil.createRainbowText("Event", 30))
|
||||||
|
.append(Component.text(" Start in ", NamedTextColor.GOLD))
|
||||||
|
.append(Component.text(announcementData.count(), NamedTextColor.AQUA))
|
||||||
|
.append(Component.text(" " + announcementData.unit() + "!", NamedTextColor.GOLD))
|
||||||
|
.build(),
|
||||||
|
component -> IteratorUtil.onlinePlayers(player -> player.sendMessage(component)),
|
||||||
|
() -> this.advertiseStatus = AdvertisementStatus.DONE
|
||||||
|
);
|
||||||
|
public DisplayVillager.ConfigBound villager;
|
||||||
|
private boolean isOpen = false;
|
||||||
|
private AdvertisementStatus advertiseStatus = AdvertisementStatus.BEFORE;
|
||||||
|
private UUID roomId;
|
||||||
|
private final List<Reward> pendingRewards = new ArrayList<>();
|
||||||
|
|
||||||
|
record RewardConfiguration(String memorialMaterial, String memorialTitle, String memorialLore, List<UUID> memorials,
|
||||||
|
String material, Map<UUID, Integer> rewards) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record Reward(UUID playerUuid, ItemStack itemStack) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Event() {
|
||||||
|
super("event");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
this.villager = new DisplayVillager.ConfigBound(
|
||||||
|
this.localConfig(),
|
||||||
|
villager -> {
|
||||||
|
villager.customName(Component.text("Events", NamedTextColor.GOLD));
|
||||||
|
villager.setProfession(Villager.Profession.LIBRARIAN);
|
||||||
|
villager.setVillagerType(Villager.Type.SNOW);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.isOpen = this.localConfig().getBoolean("enabled", false);
|
||||||
|
if(this.isOpen) this.roomId = UUID.fromString(this.localConfig().getString("roomId", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openEvent() {
|
||||||
|
if(this.isOpen) throw new ApplianceCommand.Error("Es läuft derzeit bereits ein Event!");
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||||
|
ReqResp<EventRepository.CreatedRoom> sessionResponse = this.queryRepository(EventRepository.class).createSession();
|
||||||
|
|
||||||
|
if(sessionResponse.status() != HttpStatus.OK)
|
||||||
|
throw new ApplianceCommand.Error("Event-Server meldet Fehler: " + sessionResponse.status());
|
||||||
|
|
||||||
|
this.isOpen = true;
|
||||||
|
this.roomId = sessionResponse.data().uuid();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void joinEvent(Player p) {
|
||||||
|
if(!this.isOpen) {
|
||||||
|
p.sendMessage(Component.text("Zurzeit ist kein Event geöffnet.", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!p.hasPermission("admin") && this.advertiseStatus == AdvertisementStatus.BEFORE) {
|
||||||
|
p.sendMessage(Component.text("Die Event befinden sich noch in der Vorbereitung.", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!p.hasPermission("admin") && this.advertiseStatus == AdvertisementStatus.DONE) {
|
||||||
|
p.sendMessage(Component.text("Die Events laufen bereits. Ein nachträgliches Beitreten ist nicht möglich.", NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Main.instance().getLogger().info("Verbinde mit eventserver: " + p.getName());
|
||||||
|
p.sendMessage(Component.text("Authentifiziere...", NamedTextColor.GREEN));
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||||
|
ReqResp<EventRepository.QueueRoom.Response> queueResponse = this.queryRepository(EventRepository.class)
|
||||||
|
.queueRoom(new EventRepository.QueueRoom(p.getUniqueId(), this.roomId));
|
||||||
|
|
||||||
|
if(queueResponse.status() != HttpStatus.OK || queueResponse.data().error() != null) {
|
||||||
|
p.sendMessage(Component.text("Fehler beim Betreten: " + queueResponse.data().error(), NamedTextColor.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.sendMessage(Component.text("Betrete...", NamedTextColor.GREEN));
|
||||||
|
PluginMessage.connect(p, this.localConfig().getString("connect-server-name"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endEvent() {
|
||||||
|
if(!this.isOpen) throw new ApplianceCommand.Error("Es läuft derzeit kein Event!");
|
||||||
|
this.isOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rewardPlayers(RewardConfiguration rewardConfiguration) {
|
||||||
|
rewardConfiguration.rewards.forEach((uuid, amount) -> {
|
||||||
|
Reward reward = new Reward(uuid, new ItemStack(Objects.requireNonNull(Material.matchMaterial(rewardConfiguration.material)), amount));
|
||||||
|
|
||||||
|
if(Bukkit.getPlayer(uuid) == null) {
|
||||||
|
this.pendingRewards.add(reward);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.giveReward(reward);
|
||||||
|
});
|
||||||
|
|
||||||
|
rewardConfiguration.memorials.forEach(uuid -> {
|
||||||
|
ItemStack memorialItem = new ItemStack(Objects.requireNonNull(Material.matchMaterial(rewardConfiguration.memorialMaterial)));
|
||||||
|
ItemMeta meta = memorialItem.getItemMeta();
|
||||||
|
meta.displayName(Component.text(rewardConfiguration.memorialTitle, NamedTextColor.GOLD));
|
||||||
|
meta.lore(List.of(Component.text(rewardConfiguration.memorialLore, NamedTextColor.AQUA)));
|
||||||
|
memorialItem.setItemMeta(meta);
|
||||||
|
Reward memorial = new Reward(uuid, memorialItem);
|
||||||
|
|
||||||
|
Main.instance().getAppliance(CustomAdvancements.class).grantAdvancement(Advancements.participateEvent, uuid);
|
||||||
|
|
||||||
|
if(Bukkit.getPlayer(uuid) == null) {
|
||||||
|
this.pendingRewards.add(memorial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.giveReward(memorial);
|
||||||
|
});
|
||||||
|
|
||||||
|
rewardConfiguration.rewards.keySet().stream()
|
||||||
|
.max(Comparator.comparing(rewardConfiguration.rewards::get))
|
||||||
|
.ifPresent(uuid -> Main.instance().getAppliance(CustomAdvancements.class)
|
||||||
|
.grantAdvancement(Advancements.winner, uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void giveReward(Reward reward) {
|
||||||
|
Player player = Bukkit.getPlayer(reward.playerUuid);
|
||||||
|
if(player == null) throw new RuntimeException("Cannot reward offline playerUuid!");
|
||||||
|
|
||||||
|
Map<Integer, ItemStack> remaining = player.getInventory().addItem(reward.itemStack);
|
||||||
|
Bukkit.getScheduler().runTask(
|
||||||
|
Main.instance(),
|
||||||
|
() -> remaining.values().forEach(remainingStack -> player.getWorld().dropItem(player.getLocation(), remainingStack))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyPendingRewards(Player player) {
|
||||||
|
if(this.pendingRewards.isEmpty()) return;
|
||||||
|
List<Reward> givenRewards = this.pendingRewards.stream().filter(reward -> reward.playerUuid.equals(player.getUniqueId())).toList();
|
||||||
|
this.pendingRewards.removeAll(givenRewards);
|
||||||
|
givenRewards.forEach(this::giveReward);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void advertise() {
|
||||||
|
this.advertiseCountdown.cancelIfRunning();
|
||||||
|
this.advertiseStatus = AdvertisementStatus.ADVERTISED;
|
||||||
|
IteratorUtil.onlinePlayers(player -> player.sendMessage(
|
||||||
|
Component.text()
|
||||||
|
.append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
|
||||||
|
.append(Component.text("Ein Event wurde gestartet!", NamedTextColor.GOLD)).appendNewline()
|
||||||
|
.append(Component.text("Nutze "))
|
||||||
|
.append(Component.text("/event", NamedTextColor.AQUA))
|
||||||
|
.append(Component.text(", um dem Event beizutreten!")).appendNewline()
|
||||||
|
.append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
|
||||||
|
));
|
||||||
|
this.advertiseCountdown.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void httpApi(HttpServer.ApiBuilder apiBuilder) {
|
||||||
|
apiBuilder.post("reward", RewardConfiguration.class, (rewardConfiguration, request) -> {
|
||||||
|
this.rewardPlayers(rewardConfiguration);
|
||||||
|
return HttpServer.nothing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<ApplianceCommand<?>> commands() {
|
||||||
|
return List.of(
|
||||||
|
new EventCommand(),
|
||||||
|
new MoveEventVillagerCommand(),
|
||||||
|
new EventOpenSessionCommand(),
|
||||||
|
new EventEndSessionCommand(),
|
||||||
|
new EventAdvertiseCommand()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<Listener> listeners() {
|
||||||
|
return List.of(
|
||||||
|
new ApplyPendingRewardsListener(),
|
||||||
|
new PlayerInteractAtEntityEventListener(this.villager.getUniqueId(), playerInteractAtEntityEvent -> this.joinEvent(playerInteractAtEntityEvent.getPlayer())),
|
||||||
|
new DismissInventoryOpenFromHolder(this.villager.getUniqueId())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.command;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.Event;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class EventAdvertiseCommand extends ApplianceCommand<Event> {
|
||||||
|
public EventAdvertiseCommand() {
|
||||||
|
super("eventAdvertise");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
|
this.getAppliance().advertise();
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.event.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.Event;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.Event;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -12,7 +12,7 @@ public class EventCommand extends ApplianceCommand.PlayerChecked<Event> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
getAppliance().joinEvent(getPlayer());
|
this.getAppliance().joinEvent(this.getPlayer());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.event.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.Event;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.Event;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -13,6 +13,6 @@ public class EventEndSessionCommand extends ApplianceCommand<Event> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
getAppliance().endEvent();
|
this.getAppliance().endEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,9 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.event.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.Event;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.Event;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -12,7 +14,8 @@ public class EventOpenSessionCommand extends ApplianceCommand<Event> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
getAppliance().openEvent();
|
this.getAppliance().openEvent();
|
||||||
|
sender.sendMessage(Component.text("Event-Server gestartet!", NamedTextColor.GREEN));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.event.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.event.Event;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.event.Event;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@ -13,6 +13,6 @@ public class MoveEventVillagerCommand extends ApplianceCommand.PlayerChecked<Eve
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
getAppliance().villager.updateLocation(getPlayer().getLocation());
|
this.getAppliance().villager.updateLocation(this.getPlayer().getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.feedback;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.ReqResp;
|
||||||
|
import eu.mhsl.craftattack.spawn.api.client.repositories.FeedbackRepository;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.api.HttpStatus;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.ComponentBuilder;
|
||||||
|
import net.kyori.adventure.text.TextComponent;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Feedback extends Appliance {
|
||||||
|
public Feedback() {
|
||||||
|
super("feedback");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void requestFeedback(String eventName, List<Player> receivers, @Nullable String question) {
|
||||||
|
ReqResp<Map<UUID, String>> response = this.queryRepository(FeedbackRepository.class).createFeedbackUrls(
|
||||||
|
new FeedbackRepository.Request(eventName, receivers.stream().map(Entity::getUniqueId).toList())
|
||||||
|
);
|
||||||
|
|
||||||
|
System.out.println(response.toString());
|
||||||
|
System.out.println(response.status());
|
||||||
|
|
||||||
|
if(response.status() != HttpStatus.CREATED) throw new RuntimeException();
|
||||||
|
|
||||||
|
Component border = Component.text("-".repeat(40), NamedTextColor.GRAY);
|
||||||
|
|
||||||
|
receivers.forEach(player -> {
|
||||||
|
String feedbackUrl = response.data().get(player.getUniqueId());
|
||||||
|
if(feedbackUrl == null) {
|
||||||
|
Main.logger().warning(String.format("FeedbackUrl not found for player '%s' from backend!", player.getUniqueId()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentBuilder<TextComponent, TextComponent.Builder> message = Component.text()
|
||||||
|
.append(border)
|
||||||
|
.appendNewline();
|
||||||
|
|
||||||
|
if(question != null) {
|
||||||
|
message
|
||||||
|
.append(Component.text(question, NamedTextColor.GREEN))
|
||||||
|
.appendNewline()
|
||||||
|
.appendNewline();
|
||||||
|
}
|
||||||
|
|
||||||
|
message
|
||||||
|
.append(Component.text("Klicke hier und gib uns Feedback, damit wir dein Spielerlebnis verbessern können!", NamedTextColor.DARK_GREEN)
|
||||||
|
.clickEvent(ClickEvent.openUrl(feedbackUrl)))
|
||||||
|
.hoverEvent(HoverEvent.showText(Component.text("Klicke, um Feedback zu geben.")))
|
||||||
|
.appendNewline()
|
||||||
|
.append(border);
|
||||||
|
|
||||||
|
player.sendMessage(message.build());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||||
|
return List.of(
|
||||||
|
new FeedbackCommand(),
|
||||||
|
new RequestFeedbackCommand()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.feedback;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class FeedbackCommand extends ApplianceCommand.PlayerChecked<Feedback> {
|
||||||
|
public FeedbackCommand() {
|
||||||
|
super("feedback");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
|
sender.sendMessage(ComponentUtil.pleaseWait());
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(
|
||||||
|
Main.instance(),
|
||||||
|
() -> this.getAppliance().requestFeedback(
|
||||||
|
"self-issued-ingame",
|
||||||
|
List.of(this.getPlayer()),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.feedback;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
class RequestFeedbackCommand extends ApplianceCommand<Feedback> {
|
||||||
|
public RequestFeedbackCommand() {
|
||||||
|
super("requestFeedback");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(
|
||||||
|
Main.instance(),
|
||||||
|
() -> this.getAppliance().requestFeedback(
|
||||||
|
"admin-issued-ingame",
|
||||||
|
new ArrayList<>(Bukkit.getOnlinePlayers()), String.join(" ", args)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.help;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command.DiscordCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command.HelpCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command.SpawnCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command.TeamspeakCommand;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Help extends Appliance {
|
||||||
|
public Help() {
|
||||||
|
super("help");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
protected List<ApplianceCommand<?>> commands() {
|
||||||
|
return List.of(
|
||||||
|
new HelpCommand(),
|
||||||
|
new SpawnCommand(),
|
||||||
|
new TeamspeakCommand(),
|
||||||
|
new DiscordCommand()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.help.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.Help;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.Help;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
@ -13,11 +14,14 @@ public class DiscordCommand extends ApplianceCommand<Help> {
|
|||||||
super("discord");
|
super("discord");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final static String discordLink = "https://discord.gg/TXxspGVanq";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
sender.sendMessage(
|
sender.sendMessage(
|
||||||
Component.text("Einen offiziellen Discord Server gibt es nicht, aber Du kannst gerne unserem Teamspeak joinen: ", NamedTextColor.GOLD)
|
Component.text("Offizieller Discord Server: ", NamedTextColor.GOLD)
|
||||||
.append(Component.text("mhsl.eu", NamedTextColor.AQUA))
|
.append(Component.text(discordLink, NamedTextColor.AQUA))
|
||||||
|
.clickEvent(ClickEvent.openUrl(discordLink))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.help.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.Help;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.Help;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
@ -18,7 +18,8 @@ public class HelpCommand extends ApplianceCommand<Help> {
|
|||||||
sender.sendMessage(
|
sender.sendMessage(
|
||||||
Component.text("Willkommen auf Craftattack!", NamedTextColor.GOLD)
|
Component.text("Willkommen auf Craftattack!", NamedTextColor.GOLD)
|
||||||
.appendNewline()
|
.appendNewline()
|
||||||
.append(Component.text("Hier ist ein Hilfetext!", NamedTextColor.GRAY))
|
.append(Component.text("Wenn du hilfe benötigst kannst du dich jederzeit an einen Admin wenden." +
|
||||||
|
" Weitere Informationen zu Funktionen und Befehlen erhältst du zudem im Turm am Spawn.", NamedTextColor.GRAY))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.help.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.Help;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.Help;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
@ -12,13 +12,15 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public class SpawnCommand extends ApplianceCommand<Help> {
|
public class SpawnCommand extends ApplianceCommand<Help> {
|
||||||
private static final String spawnKey = "spawn";
|
private static final String spawnKey = "spawn";
|
||||||
|
|
||||||
public SpawnCommand() {
|
public SpawnCommand() {
|
||||||
super("spawn");
|
super("spawn");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
if(!getAppliance().localConfig().isString(spawnKey)) throw new ApplianceCommand.Error("Es wurde kein Spawnbereich hinterlegt!");
|
if(!this.getAppliance().localConfig().isString(spawnKey))
|
||||||
sender.sendMessage(Component.text(Objects.requireNonNull(getAppliance().localConfig().getString(spawnKey)), NamedTextColor.GOLD));
|
throw new ApplianceCommand.Error("Es wurde kein Spawnbereich hinterlegt!");
|
||||||
|
sender.sendMessage(Component.text(Objects.requireNonNull(this.getAppliance().localConfig().getString(spawnKey)), NamedTextColor.GOLD));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package eu.mhsl.craftattack.spawn.appliances.help.command;
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.command;
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
import eu.mhsl.craftattack.spawn.appliances.help.Help;
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.help.Help;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
@ -10,17 +10,19 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
public class TeamspeakCommand extends ApplianceCommand<Help> {
|
public class TeamspeakCommand extends ApplianceCommand<Help> {
|
||||||
private static final String teamspeakKey = "teamspeak";
|
private static final String teamspeakKey = "teamspeak";
|
||||||
|
|
||||||
public TeamspeakCommand() {
|
public TeamspeakCommand() {
|
||||||
super("teamspeak");
|
super("teamspeak");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
if(!getAppliance().localConfig().isString(teamspeakKey)) throw new ApplianceCommand.Error("Es wurde kein Teamspeak hinterlegt!");
|
if(!this.getAppliance().localConfig().isString(teamspeakKey))
|
||||||
|
throw new ApplianceCommand.Error("Es wurde kein Teamspeak hinterlegt!");
|
||||||
sender.sendMessage(
|
sender.sendMessage(
|
||||||
Component.text()
|
Component.text()
|
||||||
.append(Component.text("Joine unserem Teamspeak: ", NamedTextColor.GOLD))
|
.append(Component.text("Joine unserem Teamspeak: ", NamedTextColor.GOLD))
|
||||||
.append(getTeamspeakIp(getAppliance().localConfig().getString(teamspeakKey)))
|
.append(this.getTeamspeakIp(this.getAppliance().localConfig().getString(teamspeakKey)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import net.kyori.adventure.bossbar.BossBar;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.util.Ticks;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
|
public abstract class Bar {
|
||||||
|
private BossBar bossBar;
|
||||||
|
private final BukkitTask updateTask;
|
||||||
|
|
||||||
|
public Bar() {
|
||||||
|
long refreshRateInTicks = this.refresh().get(ChronoUnit.SECONDS) * Ticks.TICKS_PER_SECOND;
|
||||||
|
this.updateTask = Bukkit.getScheduler().runTaskTimerAsynchronously(
|
||||||
|
Main.instance(),
|
||||||
|
this::update,
|
||||||
|
refreshRateInTicks,
|
||||||
|
refreshRateInTicks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BossBar getBossBar() {
|
||||||
|
if(this.bossBar == null) this.bossBar = this.createBar();
|
||||||
|
return this.bossBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BossBar createBar() {
|
||||||
|
return BossBar.bossBar(
|
||||||
|
this.title(),
|
||||||
|
this.correctedProgress(),
|
||||||
|
this.color(),
|
||||||
|
this.overlay()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update() {
|
||||||
|
if(this.bossBar == null) return;
|
||||||
|
|
||||||
|
this.beforeRefresh();
|
||||||
|
this.bossBar.name(this.title());
|
||||||
|
this.bossBar.progress(this.correctedProgress());
|
||||||
|
this.bossBar.color(this.color());
|
||||||
|
this.bossBar.overlay(this.overlay());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopUpdate() {
|
||||||
|
this.updateTask.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float correctedProgress() {
|
||||||
|
return Math.clamp(this.progress(), 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void beforeRefresh() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Duration refresh();
|
||||||
|
protected abstract String name();
|
||||||
|
|
||||||
|
protected abstract Component title();
|
||||||
|
protected abstract float progress();
|
||||||
|
protected abstract BossBar.Color color();
|
||||||
|
protected abstract BossBar.Overlay overlay();
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class InfoBarCommand extends ApplianceCommand.PlayerChecked<InfoBars> {
|
||||||
|
public InfoBarCommand() {
|
||||||
|
super("infobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
|
||||||
|
if(args.length == 0) throw new Error("<show|hide|hideall> [bar name]");
|
||||||
|
switch(args[0]) {
|
||||||
|
case "hideAll" -> this.getAppliance().hideAll(this.getPlayer());
|
||||||
|
case "show" -> this.getAppliance().show(this.getPlayer(), args[1]);
|
||||||
|
case "hide" -> this.getAppliance().hide(this.getPlayer(), args[1]);
|
||||||
|
default -> throw new Error("Erlaubte Optionen sind 'show', 'hide', 'hideAll'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if(args.length == 1) return List.of("show", "hide", "hideAll");
|
||||||
|
return this.getAppliance().getInfoBars().stream().map(Bar::name).toList();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.bars.MsptBar;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.bars.PlayerCounterBar;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.bars.TpsBar;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class InfoBars extends Appliance {
|
||||||
|
private final NamespacedKey infoBarKey = new NamespacedKey(Main.instance(), "infobars");
|
||||||
|
private final List<Bar> infoBars = List.of(
|
||||||
|
new TpsBar(),
|
||||||
|
new MsptBar(),
|
||||||
|
new PlayerCounterBar()
|
||||||
|
);
|
||||||
|
|
||||||
|
public void showAll(Player player) {
|
||||||
|
this.getStoredBars(player).forEach(bar -> this.show(player, bar));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideAll(Player player) {
|
||||||
|
this.getStoredBars(player).forEach(bar -> this.hide(player, bar));
|
||||||
|
this.setStoredBars(player, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show(Player player, String bar) {
|
||||||
|
this.validateBarName(bar);
|
||||||
|
List<String> existingBars = new ArrayList<>(this.getStoredBars(player));
|
||||||
|
existingBars.add(bar);
|
||||||
|
player.showBossBar(this.getBarByName(bar).getBossBar());
|
||||||
|
this.setStoredBars(player, existingBars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide(Player player, String bar) {
|
||||||
|
this.validateBarName(bar);
|
||||||
|
List<String> existingBars = new ArrayList<>(this.getStoredBars(player));
|
||||||
|
existingBars.remove(bar);
|
||||||
|
player.hideBossBar(this.getBarByName(bar).getBossBar());
|
||||||
|
this.setStoredBars(player, existingBars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getStoredBars(Player player) {
|
||||||
|
PersistentDataContainer container = player.getPersistentDataContainer();
|
||||||
|
if(!container.has(this.infoBarKey)) return List.of();
|
||||||
|
return container.get(this.infoBarKey, PersistentDataType.LIST.strings());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setStoredBars(Player player, List<String> bars) {
|
||||||
|
player.getPersistentDataContainer().set(this.infoBarKey, PersistentDataType.LIST.strings(), bars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bar getBarByName(String name) {
|
||||||
|
return this.infoBars.stream()
|
||||||
|
.filter(bar -> bar.name().equalsIgnoreCase(name))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateBarName(String name) {
|
||||||
|
if(this.getBarByName(name) == null)
|
||||||
|
throw new ApplianceCommand.Error(String.format("Ungültiger infobar name '%s'", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Bar> getInfoBars() {
|
||||||
|
return this.infoBars;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
this.infoBars.forEach(Bar::stopUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new ShowPreviousBarsListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<ApplianceCommand<?>> commands() {
|
||||||
|
return List.of(new InfoBarCommand());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
class ShowPreviousBarsListener extends ApplianceListener<InfoBars> {
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
// this.getAppliance().showAll(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.bars;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.Bar;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.statistics.ServerMonitor;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ColorUtil;
|
||||||
|
import net.kyori.adventure.bossbar.BossBar;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
public class MsptBar extends Bar {
|
||||||
|
@Override
|
||||||
|
protected Duration refresh() {
|
||||||
|
return Duration.ofSeconds(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String name() {
|
||||||
|
return "mspt";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Component title() {
|
||||||
|
return Component.text()
|
||||||
|
.append(Component.text("M"))
|
||||||
|
.append(Component.text("illi", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("S"))
|
||||||
|
.append(Component.text("econds ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("P"))
|
||||||
|
.append(Component.text("er ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("T"))
|
||||||
|
.append(Component.text("ick", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text(": "))
|
||||||
|
.append(Component.text(String.format("%.2f", this.currentMSPT()), ColorUtil.msptColor(this.currentMSPT())))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float progress() {
|
||||||
|
return this.currentMSPT() / 50f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossBar.Color color() {
|
||||||
|
return BossBar.Color.BLUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossBar.Overlay overlay() {
|
||||||
|
return BossBar.Overlay.PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float currentMSPT() {
|
||||||
|
return ServerMonitor.getServerMSPT();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.bars;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.Bar;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.tooling.playerlimit.PlayerLimit;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ColorUtil;
|
||||||
|
import net.kyori.adventure.bossbar.BossBar;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
public class PlayerCounterBar extends Bar {
|
||||||
|
@Override
|
||||||
|
protected Duration refresh() {
|
||||||
|
return Duration.ofSeconds(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String name() {
|
||||||
|
return "playerCounter";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Component title() {
|
||||||
|
TextColor color = ColorUtil.mapGreenToRed(this.getCurrentPlayerCount(), 0, this.getMaxPlayerCount(), true);
|
||||||
|
return Component.text()
|
||||||
|
.append(Component.text("Spieler online: "))
|
||||||
|
.append(Component.text(this.getCurrentPlayerCount(), color))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float progress() {
|
||||||
|
return (float) this.getCurrentPlayerCount() / this.getMaxPlayerCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossBar.Color color() {
|
||||||
|
return BossBar.Color.BLUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossBar.Overlay overlay() {
|
||||||
|
return BossBar.Overlay.PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCurrentPlayerCount() {
|
||||||
|
return Bukkit.getOnlinePlayers().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMaxPlayerCount() {
|
||||||
|
return Main.instance().getAppliance(PlayerLimit.class).getLimit();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.bars;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliances.metaGameplay.infoBars.Bar;
|
||||||
|
import eu.mhsl.craftattack.spawn.util.text.ColorUtil;
|
||||||
|
import net.kyori.adventure.bossbar.BossBar;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
public class TpsBar extends Bar {
|
||||||
|
@Override
|
||||||
|
protected Duration refresh() {
|
||||||
|
return Duration.ofSeconds(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String name() {
|
||||||
|
return "tps";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Component title() {
|
||||||
|
return Component.text()
|
||||||
|
.append(Component.text("T"))
|
||||||
|
.append(Component.text("icks ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("P"))
|
||||||
|
.append(Component.text("er ", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text("S"))
|
||||||
|
.append(Component.text("econds", NamedTextColor.GRAY))
|
||||||
|
.append(Component.text(": "))
|
||||||
|
.append(Component.text(String.format("%.2f", this.currentTps()), ColorUtil.tpsColor(this.currentTps())))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float progress() {
|
||||||
|
return this.currentTps() / 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossBar.Color color() {
|
||||||
|
return BossBar.Color.BLUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossBar.Overlay overlay() {
|
||||||
|
return BossBar.Overlay.NOTCHED_20;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float currentTps() {
|
||||||
|
return (float) Bukkit.getTPS()[0];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.optionLinks;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.Main;
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.Appliance;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ServerLinks;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@SuppressWarnings("UnstableApiUsage")
|
||||||
|
public class OptionLinks extends Appliance {
|
||||||
|
record ComponentSupplier() {
|
||||||
|
}
|
||||||
|
|
||||||
|
record UriSupplier(Player player) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record UriConsumer(String uri) {
|
||||||
|
}
|
||||||
|
|
||||||
|
record SuppliedLink(Function<ComponentSupplier, Component> component, Function<UriSupplier, UriConsumer> uri) {
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SuppliedLink> links = List.of(
|
||||||
|
new SuppliedLink(
|
||||||
|
componentSupplier -> Component.text("CraftAttack Homepage", NamedTextColor.GOLD),
|
||||||
|
uriSupplier -> new UriConsumer("https://mhsl.eu/craftattack")
|
||||||
|
),
|
||||||
|
new SuppliedLink(
|
||||||
|
componentSupplier -> Component.text("Regeln", NamedTextColor.GOLD),
|
||||||
|
uriSupplier -> new UriConsumer("https://mhsl.eu/craftattack/rules")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Bukkit.getServer().getServerLinks().getLinks()
|
||||||
|
.forEach(serverLink -> Bukkit.getServer().getServerLinks().removeLink(serverLink));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerLinks(Player player) {
|
||||||
|
ServerLinks playerLinks = Bukkit.getServerLinks().copy();
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> {
|
||||||
|
this.links.forEach(suppliedLink -> {
|
||||||
|
Component component = suppliedLink.component.apply(new ComponentSupplier());
|
||||||
|
String uri = suppliedLink.uri.apply(new UriSupplier(player)).uri;
|
||||||
|
|
||||||
|
try {
|
||||||
|
playerLinks.addLink(component, URI.create(uri));
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
Main.logger().log(Level.INFO, String.format("Failed to create OptionLink '%s' for player '%s'", uri, player.getName()), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
player.sendLinks(playerLinks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull List<Listener> listeners() {
|
||||||
|
return List.of(new UpdateLinksListener());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package eu.mhsl.craftattack.spawn.appliances.metaGameplay.optionLinks;
|
||||||
|
|
||||||
|
import eu.mhsl.craftattack.spawn.appliance.ApplianceListener;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
class UpdateLinksListener extends ApplianceListener<OptionLinks> {
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
this.getAppliance().setServerLinks(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user