init commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
.gradle
|
||||
.idea
|
||||
build
|
||||
gradle
|
||||
run
|
||||
@@ -0,0 +1,57 @@
|
||||
# Pierredufaulersack - Boss Hunt Plugin
|
||||
|
||||
Paper plugin for a configurable Boss Hunt mode (1 boss vs hunters).
|
||||
|
||||
## Features
|
||||
|
||||
- Lobby flow with `/bosshunt join` and `/bosshunt leave`
|
||||
- Colored, prefixed chat messages for game + kit commands
|
||||
- Configurable start countdown with per-second and final beep sounds
|
||||
- Admin controls:
|
||||
- `/bosshunt setlobby`
|
||||
- `/bosshunt setarena`
|
||||
- `/bosshunt start`
|
||||
- `/bosshunt stop`
|
||||
- Kit management for 3 boss kits and 3 hunter kits:
|
||||
- `/bosskit add|set|del|list <1-3>`
|
||||
- `/hunterkit add|set|del|list <1-3>`
|
||||
- Saved kits preserve item metadata from inventory, including enchantments
|
||||
- Weighted random kit selection from `config.yml` (default `40/40/20`)
|
||||
- Hunter kit duplication limit per round (`hunter-kit-max-duplicates`, default `2`)
|
||||
- Friendly fire protection for hunter vs hunter
|
||||
|
||||
## Setup
|
||||
|
||||
1. Build plugin jar.
|
||||
2. Put jar into your Paper server `plugins/` folder.
|
||||
3. Start server once to generate `config.yml`.
|
||||
4. In game as OP/admin:
|
||||
- set lobby and arena
|
||||
- save kits in slots 1-3 for boss and hunter
|
||||
- players join lobby
|
||||
- start round
|
||||
|
||||
## Permissions
|
||||
|
||||
- `pierredufaulersack.admin` (default: op)
|
||||
|
||||
## Build
|
||||
|
||||
```powershell
|
||||
.\gradlew.bat build
|
||||
```
|
||||
|
||||
## Quick test commands (in game)
|
||||
|
||||
```text
|
||||
/bosshunt setlobby
|
||||
/bosshunt setarena
|
||||
/bosskit set 1
|
||||
/bosskit set 2
|
||||
/bosskit set 3
|
||||
/hunterkit set 1
|
||||
/hunterkit set 2
|
||||
/hunterkit set 3
|
||||
/bosshunt join
|
||||
/bosshunt start
|
||||
```
|
||||
@@ -0,0 +1,57 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||
}
|
||||
|
||||
group = 'de.winniepat'
|
||||
version = '1.17-MeinKraft'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = "papermc-repo"
|
||||
url = "https://repo.papermc.io/repository/maven-public/"
|
||||
}
|
||||
maven {
|
||||
name = "luckperms-repo"
|
||||
url = "https://repo.lucko.me/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
|
||||
compileOnly("net.luckperms:api:5.4")
|
||||
}
|
||||
|
||||
tasks {
|
||||
runServer {
|
||||
minecraftVersion("1.21.10")
|
||||
}
|
||||
}
|
||||
|
||||
def targetJavaVersion = 21
|
||||
java {
|
||||
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||
sourceCompatibility = javaVersion
|
||||
targetCompatibility = javaVersion
|
||||
if (JavaVersion.current() < javaVersion) {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = 'UTF-8'
|
||||
|
||||
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||
options.release.set(targetJavaVersion)
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
def props = [version: version]
|
||||
inputs.properties props
|
||||
filteringCharset 'UTF-8'
|
||||
filesMatching('plugin.yml') {
|
||||
expand props
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# 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.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# 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.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1 @@
|
||||
rootProject.name = 'Pierredufaulersack'
|
||||
@@ -0,0 +1,73 @@
|
||||
package de.winniepat.pierredufaulersack;
|
||||
|
||||
import de.winniepat.pierredufaulersack.commands.*;
|
||||
import de.winniepat.pierredufaulersack.game.*;
|
||||
import de.winniepat.pierredufaulersack.kits.*;
|
||||
import de.winniepat.pierredufaulersack.listeners.*;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class Pierredufaulersack extends JavaPlugin {
|
||||
|
||||
private KitService kitService;
|
||||
private GameManager gameManager;
|
||||
private SidebarService sidebarService;
|
||||
private LuckPermsService luckPermsService;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
saveDefaultConfig();
|
||||
|
||||
this.kitService = new KitService(this);
|
||||
this.luckPermsService = new LuckPermsService(this);
|
||||
this.gameManager = new GameManager(this, kitService, luckPermsService);
|
||||
this.sidebarService = new SidebarService(this, gameManager);
|
||||
|
||||
registerCommands();
|
||||
getServer().getPluginManager().registerEvents(new FriendlyFireListener(gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerConnectionListener(gameManager, sidebarService), this);
|
||||
getServer().getPluginManager().registerEvents(new RoundOutcomeListener(gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new RoundWaterCleanupListener(gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this, gameManager, kitService), this);
|
||||
getServer().getPluginManager().registerEvents(new CobwebDecayListener(this, gameManager), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerDeathListener(), this);
|
||||
|
||||
sidebarService.start();
|
||||
getLogger().info("Pierredufaulersack enabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (sidebarService != null) {
|
||||
sidebarService.shutdown();
|
||||
}
|
||||
if (gameManager != null) {
|
||||
gameManager.shutdown();
|
||||
gameManager.stopRound(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
PluginCommand bossHunt = getCommand("bosshunt");
|
||||
PluginCommand bossKit = getCommand("bosskit");
|
||||
PluginCommand hunterKit = getCommand("hunterkit");
|
||||
|
||||
if (bossHunt != null) {
|
||||
BossHuntCommand bossHuntCommand = new BossHuntCommand(gameManager);
|
||||
bossHunt.setExecutor(bossHuntCommand);
|
||||
bossHunt.setTabCompleter(bossHuntCommand);
|
||||
}
|
||||
|
||||
if (bossKit != null) {
|
||||
KitCommand cmd = new KitCommand(kitService, KitType.BOSS);
|
||||
bossKit.setExecutor(cmd);
|
||||
bossKit.setTabCompleter(cmd);
|
||||
}
|
||||
|
||||
if (hunterKit != null) {
|
||||
KitCommand cmd = new KitCommand(kitService, KitType.HUNTER);
|
||||
hunterKit.setExecutor(cmd);
|
||||
hunterKit.setTabCompleter(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package de.winniepat.pierredufaulersack.commands;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import de.winniepat.pierredufaulersack.game.GameState;
|
||||
import java.util.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BossHuntCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final GameManager gameManager;
|
||||
private static final String PREFIX = "&8[&6BossHunt&8] &r";
|
||||
|
||||
public BossHuntCommand(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length < 1) {
|
||||
send(sender, "&cNutzung: &f/" + label + " <queues|select|join|leave|start|stop|setlobby|setarena|status>");
|
||||
return true;
|
||||
}
|
||||
|
||||
String sub = args[0].toLowerCase();
|
||||
|
||||
switch (sub) {
|
||||
case "queues" -> sendQueues(sender);
|
||||
case "select" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können eine Warteschlange auswählen.");
|
||||
return true;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
send(sender, "&cNutzung: &f/" + label + " select <queue>");
|
||||
return true;
|
||||
}
|
||||
gameManager.selectQueue(player, args[1]);
|
||||
}
|
||||
case "join" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können einer Warteschlange beitreten.");
|
||||
return true;
|
||||
}
|
||||
gameManager.join(player, args.length >= 2 ? args[1] : null);
|
||||
}
|
||||
case "leave" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können die Warteschlange verlassen.");
|
||||
return true;
|
||||
}
|
||||
gameManager.leave(player);
|
||||
}
|
||||
case "setlobby" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können die Lobby setzen.");
|
||||
return true;
|
||||
}
|
||||
gameManager.setLobby(player);
|
||||
}
|
||||
case "setarena" -> {
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können Arenen setzen.");
|
||||
return true;
|
||||
}
|
||||
if (args.length < 2) {
|
||||
send(sender, "&cNutzung: &f/" + label + " setarena <queue>");
|
||||
return true;
|
||||
}
|
||||
gameManager.setArena(player, args[1]);
|
||||
}
|
||||
case "start" -> gameManager.startRound(sender, args.length >= 2 ? args[1] : null);
|
||||
case "stop" -> gameManager.stopRoundByCommand(sender, args.length >= 2 ? args[1] : null);
|
||||
case "status" -> sendStatus(sender, args.length >= 2 ? args[1] : null);
|
||||
default -> send(sender, "&cUnbekannter Unterbefehl.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return List.of("queues", "select", "join", "leave", "start", "stop", "setlobby", "setarena", "status").stream()
|
||||
.filter(option -> option.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
if (args.length == 2) {
|
||||
String sub = args[0].toLowerCase();
|
||||
if (sub.equals("select") || sub.equals("join") || sub.equals("setarena") || sub.equals("start") || sub.equals("status")) {
|
||||
return gameManager.queueIds().stream()
|
||||
.filter(id -> id.toLowerCase().startsWith(args[1].toLowerCase()))
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
if (sub.equals("stop")) {
|
||||
List<String> options = new ArrayList<>(gameManager.queueIds());
|
||||
options.add("all");
|
||||
return options.stream()
|
||||
.filter(id -> id.toLowerCase().startsWith(args[1].toLowerCase()))
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private void sendQueues(CommandSender sender) {
|
||||
send(sender, "&fWarteschlangen:");
|
||||
for (String queueId : new TreeSet<>(gameManager.queueIds())) {
|
||||
GameState state = gameManager.getState(queueId);
|
||||
send(sender, "&e- " + queueId + " &7(" + stateText(state) + "&7) &f"
|
||||
+ gameManager.lobbySize(queueId) + "&7/&f" + gameManager.maxPlayers());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendStatus(CommandSender sender, String queueIdArg) {
|
||||
String queueId = queueIdArg;
|
||||
if ((queueId == null || queueId.isBlank()) && sender instanceof Player player) {
|
||||
queueId = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
}
|
||||
if (queueId == null || queueId.isBlank()) {
|
||||
sendQueues(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gameManager.queueIds().contains(queueId)) {
|
||||
send(sender, "&cUnbekannte Warteschlange. Benutze &f/bosshunt queues&c.");
|
||||
return;
|
||||
}
|
||||
|
||||
GameState state = gameManager.getState(queueId);
|
||||
send(sender, "&fWarteschlange: &e" + queueId);
|
||||
send(sender, "&fStatus: " + stateText(state));
|
||||
send(sender, "&fSpieler: &b" + gameManager.lobbySize(queueId) + "&7/&b" + gameManager.maxPlayers());
|
||||
|
||||
List<String> onlineLobbyPlayers = new ArrayList<>();
|
||||
for (UUID uuid : gameManager.lobbyPlayers(queueId)) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
onlineLobbyPlayers.add(player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineLobbyPlayers.isEmpty()) {
|
||||
send(sender, "&7Warteschlange ist leer.");
|
||||
} else {
|
||||
send(sender, "&fIn der Warteschlange: &e" + String.join("&7, &e", onlineLobbyPlayers));
|
||||
}
|
||||
}
|
||||
|
||||
private String stateText(GameState state) {
|
||||
return switch (state) {
|
||||
case WAITING -> "&7WAITING";
|
||||
case COUNTDOWN -> "&eCOUNTDOWN";
|
||||
case RUNNING -> "&aRUNNING";
|
||||
};
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String message) {
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', PREFIX + message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package de.winniepat.pierredufaulersack.commands;
|
||||
|
||||
import de.winniepat.pierredufaulersack.kits.*;
|
||||
import java.util.*;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class KitCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private static final String ADMIN_PERMISSION = "pierredufaulersack.admin";
|
||||
private static final String PREFIX = "&8[&6BossHunt&8] &r";
|
||||
|
||||
private final KitService kitService;
|
||||
private final KitType type;
|
||||
|
||||
public KitCommand(KitService kitService, KitType type) {
|
||||
this.kitService = kitService;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!sender.hasPermission(ADMIN_PERMISSION)) {
|
||||
send(sender, "&cKeine Berechtigung.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
send(sender, "&cNutzung: &f/" + label + " <add|set|del|list> [1-3]");
|
||||
return true;
|
||||
}
|
||||
|
||||
String action = args[0].toLowerCase();
|
||||
switch (action) {
|
||||
case "list" -> handleList(sender, label);
|
||||
case "add", "set", "del" -> handleKitMutation(sender, label, action, args);
|
||||
default -> send(sender, "&cUnbekannter Unterbefehl. &7Nutzung: &f/" + label + " <add|set|del|list> [1-3]");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return List.of("add", "set", "del", "list").stream()
|
||||
.filter(opt -> opt.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
if (args.length == 2 && !"list".equalsIgnoreCase(args[0])) {
|
||||
List<String> slots = List.of("1", "2", "3");
|
||||
List<String> filtered = new ArrayList<>();
|
||||
for (String slot : slots) {
|
||||
if (slot.startsWith(args[1])) {
|
||||
filtered.add(slot);
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private void handleList(CommandSender sender, String label) {
|
||||
List<Integer> slots = kitService.listKitSlots(type);
|
||||
if (slots.isEmpty()) {
|
||||
send(sender, "&eKeine Kits für &f/" + label + " &egespeichert.");
|
||||
return;
|
||||
}
|
||||
|
||||
send(sender, "&aVerfügbare Kits fuer &f/" + label + "&a: &e" + slots);
|
||||
}
|
||||
|
||||
private void handleKitMutation(CommandSender sender, String label, String action, String[] args) {
|
||||
if (args.length != 2) {
|
||||
send(sender, "&cNutzung: &f/" + label + " " + action + " <1-3>");
|
||||
return;
|
||||
}
|
||||
|
||||
Integer slot = parseSlot(args[1]);
|
||||
if (slot == null) {
|
||||
send(sender, "&cSlot muss 1, 2 oder 3 sein.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ("del".equals(action)) {
|
||||
boolean deleted = kitService.deleteKit(type, slot);
|
||||
send(sender, deleted ? "&aKit &e" + slot + " &agelöscht." : "&eKit &f" + slot + " &eexistiert nicht.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(sender instanceof Player player)) {
|
||||
send(sender, "&cNur Spieler können Inventar-Kits speichern.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ("add".equals(action)) {
|
||||
boolean added = kitService.addKit(type, slot, player);
|
||||
send(sender, added
|
||||
? "&aKit &e" + slot + " &agespeichert."
|
||||
: "&eKit &f" + slot + " &eexistiert bereits. Nutze &fset &ezum Ueberschreiben.");
|
||||
return;
|
||||
}
|
||||
|
||||
kitService.setKit(type, slot, player);
|
||||
send(sender, "&aKit &e" + slot + " &agesetzt.");
|
||||
}
|
||||
|
||||
private Integer parseSlot(String value) {
|
||||
try {
|
||||
int parsed = Integer.parseInt(value);
|
||||
if (parsed < 1 || parsed > 3) {
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
} catch (NumberFormatException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String message) {
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', PREFIX + message));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
public enum GameState {
|
||||
WAITING,
|
||||
COUNTDOWN,
|
||||
RUNNING
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class LuckPermsService {
|
||||
|
||||
private static final String BOSS_PREFIX = "&c[ʙᴏꜱꜱ] &r";
|
||||
private static final String HUNTER_PREFIX = "&9[ʜᴜɴᴛᴇʀ] &r";
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final Map<UUID, PrefixNode> appliedPrefixes = new ConcurrentHashMap<>();
|
||||
private LuckPerms luckPerms;
|
||||
|
||||
public LuckPermsService(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
initialize();
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
return luckPerms != null;
|
||||
}
|
||||
|
||||
public void applyBossPrefix(Player player) {
|
||||
applyPrefix(player.getUniqueId(), BOSS_PREFIX, 100);
|
||||
}
|
||||
|
||||
public void applyHunterPrefix(Player player) {
|
||||
applyPrefix(player.getUniqueId(), HUNTER_PREFIX, 90);
|
||||
}
|
||||
|
||||
public void clearPrefix(Player player) {
|
||||
clearPrefix(player.getUniqueId());
|
||||
}
|
||||
|
||||
public void clearPrefix(UUID playerId) {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrefixNode previous = appliedPrefixes.remove(playerId);
|
||||
if (previous == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
luckPerms.getUserManager().modifyUser(playerId, user -> user.transientData().remove(previous));
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
Set<UUID> tracked = Set.copyOf(appliedPrefixes.keySet());
|
||||
for (UUID playerId : tracked) {
|
||||
clearPrefix(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPrefix(UUID playerId, String prefix, int priority) {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrefixNode next = PrefixNode.builder(prefix, priority).build();
|
||||
PrefixNode previous = appliedPrefixes.put(playerId, next);
|
||||
luckPerms.getUserManager().modifyUser(playerId, user -> {
|
||||
if (previous != null) {
|
||||
user.transientData().remove(previous);
|
||||
}
|
||||
user.transientData().add(next);
|
||||
});
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
if (Bukkit.getPluginManager().getPlugin("LuckPerms") == null) {
|
||||
plugin.getLogger().info("LuckPerms not found. Prefix integration disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
luckPerms = LuckPermsProvider.get();
|
||||
plugin.getLogger().info("LuckPerms detected. Prefix integration enabled.");
|
||||
} catch (IllegalStateException ex) {
|
||||
plugin.getLogger().warning("LuckPerms detected but API is not ready. Prefix integration disabled.");
|
||||
luckPerms = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
public enum Role {
|
||||
BOSS,
|
||||
HUNTER
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package de.winniepat.pierredufaulersack.game;
|
||||
|
||||
import java.util.TreeSet;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.bukkit.scoreboard.*;
|
||||
|
||||
public class SidebarService {
|
||||
|
||||
private static final String OBJECTIVE_ID = "bosshunt";
|
||||
private static final String TEAM_BOSS = "0_boss";
|
||||
private static final String TEAM_HUNTER_SAME_QUEUE = "1_hunter_same";
|
||||
private static final String TEAM_HUNTER_OTHER_QUEUE = "1_hunter_other";
|
||||
private static final String TEAM_NORMAL = "2_normal";
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final GameManager gameManager;
|
||||
private BukkitTask refreshTask;
|
||||
|
||||
public SidebarService(JavaPlugin plugin, GameManager gameManager) {
|
||||
this.plugin = plugin;
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
refreshTask = Bukkit.getScheduler().runTaskTimer(plugin, this::refreshAll, 0L, 20L);
|
||||
}
|
||||
|
||||
public void refreshAll() {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
showFor(player);
|
||||
}
|
||||
}
|
||||
|
||||
public void showFor(Player player) {
|
||||
ScoreboardManager manager = Bukkit.getScoreboardManager();
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scoreboard board = manager.getNewScoreboard();
|
||||
Objective objective = board.registerNewObjective(OBJECTIVE_ID, "dummy", color("&6&lʙᴏꜱꜱʜᴜɴᴛ"));
|
||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||
|
||||
applyTablistOrderingTeams(board, player);
|
||||
|
||||
Role role = gameManager.getRole(player.getUniqueId());
|
||||
if (role != null) {
|
||||
String queueId = gameManager.queueOfPlayer(player.getUniqueId());
|
||||
showRunningSession(objective, player, role, queueId);
|
||||
} else {
|
||||
showLobbyView(objective, player);
|
||||
}
|
||||
|
||||
player.setScoreboard(board);
|
||||
}
|
||||
|
||||
public void clearFor(Player player) {
|
||||
ScoreboardManager manager = Bukkit.getScoreboardManager();
|
||||
if (manager != null) {
|
||||
player.setScoreboard(manager.getMainScoreboard());
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (refreshTask != null) {
|
||||
refreshTask.cancel();
|
||||
refreshTask = null;
|
||||
}
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
clearFor(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void showRunningSession(Objective objective, Player player, Role role, String queueId) {
|
||||
int line = 9;
|
||||
|
||||
objective.getScore(" ").setScore(line--);
|
||||
objective.getScore(color("&7Status: &aLÄUFT")).setScore(line--);
|
||||
objective.getScore(" ").setScore(line--);
|
||||
objective.getScore(color("&fQueue: &e" + queueId)).setScore(line--);
|
||||
objective.getScore(color("&fRolle: " + roleText(role))).setScore(line--);
|
||||
objective.getScore(color("&fHunter Verbleibend: &b" + gameManager.huntersLeft(player.getUniqueId()))).setScore(line--);
|
||||
objective.getScore(" ").setScore(line--);
|
||||
objective.getScore(color("&eKämpft!")).setScore(line);
|
||||
}
|
||||
|
||||
private void applyTablistOrderingTeams(Scoreboard board, Player viewer) {
|
||||
Team bosses = board.registerNewTeam(TEAM_BOSS);
|
||||
Team huntersSameQueue = board.registerNewTeam(TEAM_HUNTER_SAME_QUEUE);
|
||||
Team huntersOtherQueue = board.registerNewTeam(TEAM_HUNTER_OTHER_QUEUE);
|
||||
Team normals = board.registerNewTeam(TEAM_NORMAL);
|
||||
|
||||
huntersSameQueue.setColor(ChatColor.RED);
|
||||
|
||||
String viewerQueue = gameManager.queueOfPlayer(viewer.getUniqueId());
|
||||
for (Player online : Bukkit.getOnlinePlayers()) {
|
||||
Role onlineRole = gameManager.getRole(online.getUniqueId());
|
||||
if (onlineRole == Role.BOSS) {
|
||||
bosses.addEntry(online.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (onlineRole == Role.HUNTER) {
|
||||
String onlineQueue = gameManager.queueOfPlayer(online.getUniqueId());
|
||||
if (viewerQueue != null && viewerQueue.equals(onlineQueue)) {
|
||||
huntersSameQueue.addEntry(online.getName());
|
||||
} else {
|
||||
huntersOtherQueue.addEntry(online.getName());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
normals.addEntry(online.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void showLobbyView(Objective objective, Player player) {
|
||||
int line = 12;
|
||||
|
||||
String selected = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
String currentQueue = gameManager.queueOfPlayer(player.getUniqueId());
|
||||
String selectedText = (selected == null || selected.isBlank()) ? "-" : selected;
|
||||
|
||||
objective.getScore(color("&7Status: &7LOBBY")).setScore(line--);
|
||||
if (currentQueue != null) {
|
||||
objective.getScore(color("&fQueued: &aJa (&e" + currentQueue + "&a)")).setScore(line--);
|
||||
}
|
||||
objective.getScore(" ").setScore(line--);
|
||||
|
||||
for (String queueId : new TreeSet<>(gameManager.queueIds())) {
|
||||
objective.getScore(color("&e" + queueId + ": &f" + gameManager.lobbySize(queueId) + "&7/&f" + gameManager.maxPlayers())).setScore(line--);
|
||||
}
|
||||
}
|
||||
|
||||
private String roleText(Role role) {
|
||||
if (role == Role.BOSS) {
|
||||
return "&6BOSS";
|
||||
}
|
||||
return "&bHUNTER";
|
||||
}
|
||||
|
||||
private String color(String text) {
|
||||
return ChatColor.translateAlternateColorCodes('&', text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
package de.winniepat.pierredufaulersack.kits;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class KitService {
|
||||
|
||||
private static final int MIN_SLOT = 1;
|
||||
private static final int MAX_SLOT = 3;
|
||||
private static final int KIT_CONTENT_SIZE = 41;
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
public KitService(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public boolean addKit(KitType type, int slot, Player player) {
|
||||
validateSlot(slot);
|
||||
String path = path(type, slot);
|
||||
if (plugin.getConfig().contains(path)) {
|
||||
return false;
|
||||
}
|
||||
setKit(type, slot, player);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setKit(KitType type, int slot, Player player) {
|
||||
setKit(type, slot, player.getInventory().getContents());
|
||||
}
|
||||
|
||||
public void setKit(KitType type, int slot, ItemStack[] contents) {
|
||||
validateSlot(slot);
|
||||
|
||||
ItemStack[] normalizedContents = normalizeContents(contents);
|
||||
List<Map<String, Object>> serialized = new ArrayList<>(normalizedContents.length);
|
||||
for (ItemStack item : normalizedContents) {
|
||||
serialized.add(item == null ? null : item.clone().serialize());
|
||||
}
|
||||
|
||||
plugin.getConfig().set(path(type, slot), serialized);
|
||||
plugin.saveConfig();
|
||||
}
|
||||
|
||||
public boolean deleteKit(KitType type, int slot) {
|
||||
validateSlot(slot);
|
||||
String path = path(type, slot);
|
||||
if (!plugin.getConfig().contains(path)) {
|
||||
return false;
|
||||
}
|
||||
plugin.getConfig().set(path, null);
|
||||
plugin.saveConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<Integer> listKitSlots(KitType type) {
|
||||
List<Integer> slots = new ArrayList<>();
|
||||
for (int slot = MIN_SLOT; slot <= MAX_SLOT; slot++) {
|
||||
if (hasKit(type, slot)) {
|
||||
slots.add(slot);
|
||||
}
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
||||
public boolean hasKit(KitType type, int slot) {
|
||||
validateSlot(slot);
|
||||
return plugin.getConfig().contains(path(type, slot));
|
||||
}
|
||||
|
||||
public Optional<List<ItemStack>> getKit(KitType type, int slot) {
|
||||
validateSlot(slot);
|
||||
|
||||
List<?> raw = plugin.getConfig().getList(path(type, slot));
|
||||
if (raw == null || raw.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<ItemStack> saved = new ArrayList<>(KIT_CONTENT_SIZE);
|
||||
boolean hasItem = false;
|
||||
|
||||
for (int index = 0; index < KIT_CONTENT_SIZE; index++) {
|
||||
Object element = index < raw.size() ? raw.get(index) : null;
|
||||
ItemStack item = deserializeItem(element);
|
||||
if (item != null) {
|
||||
hasItem = true;
|
||||
}
|
||||
saved.add(item);
|
||||
}
|
||||
|
||||
if (!hasItem) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(cloneInventory(saved));
|
||||
}
|
||||
|
||||
public Optional<List<ItemStack>> getKitForPlayer(UUID playerId, KitType type, int slot) {
|
||||
Optional<List<ItemStack>> maybeBase = getKit(type, slot);
|
||||
if (maybeBase.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
List<ItemStack> base = maybeBase.get();
|
||||
Optional<int[]> maybeLayout = getPlayerLayout(playerId, type, slot);
|
||||
if (maybeLayout.isEmpty()) {
|
||||
return Optional.of(cloneInventory(base));
|
||||
}
|
||||
|
||||
return Optional.of(applyLayout(base, maybeLayout.get()));
|
||||
}
|
||||
|
||||
public boolean setPlayerLayout(UUID playerId, KitType type, int slot, ItemStack[] arrangedContents) {
|
||||
validateSlot(slot);
|
||||
|
||||
Optional<List<ItemStack>> maybeBase = getKit(type, slot);
|
||||
if (maybeBase.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ItemStack> base = maybeBase.get();
|
||||
ItemStack[] arranged = normalizeContents(arrangedContents);
|
||||
int[] layout = deriveLayout(base, arranged);
|
||||
|
||||
List<Integer> serialized = new ArrayList<>(layout.length);
|
||||
for (int value : layout) {
|
||||
serialized.add(value);
|
||||
}
|
||||
|
||||
plugin.getConfig().set(playerLayoutPath(playerId, type, slot), serialized);
|
||||
plugin.saveConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
private Optional<int[]> getPlayerLayout(UUID playerId, KitType type, int slot) {
|
||||
String path = playerLayoutPath(playerId, type, slot);
|
||||
List<?> raw = plugin.getConfig().getList(path);
|
||||
if (raw == null || raw.size() != KIT_CONTENT_SIZE) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
int[] layout = new int[KIT_CONTENT_SIZE];
|
||||
for (int i = 0; i < KIT_CONTENT_SIZE; i++) {
|
||||
Object element = raw.get(i);
|
||||
if (!(element instanceof Number number)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
int value = number.intValue();
|
||||
if (value < 0 || value >= KIT_CONTENT_SIZE) {
|
||||
return Optional.empty();
|
||||
}
|
||||
layout[i] = value;
|
||||
}
|
||||
|
||||
return Optional.of(layout);
|
||||
}
|
||||
|
||||
private static List<ItemStack> applyLayout(List<ItemStack> base, int[] layout) {
|
||||
List<ItemStack> arranged = new ArrayList<>(KIT_CONTENT_SIZE);
|
||||
boolean[] consumed = new boolean[KIT_CONTENT_SIZE];
|
||||
|
||||
for (int target = 0; target < KIT_CONTENT_SIZE; target++) {
|
||||
int source = target < layout.length ? layout[target] : target;
|
||||
if (source < 0 || source >= KIT_CONTENT_SIZE || consumed[source]) {
|
||||
source = firstUnused(consumed, target);
|
||||
}
|
||||
consumed[source] = true;
|
||||
|
||||
ItemStack item = source < base.size() ? base.get(source) : null;
|
||||
arranged.add(item == null ? null : item.clone());
|
||||
}
|
||||
|
||||
return arranged;
|
||||
}
|
||||
|
||||
private static int[] deriveLayout(List<ItemStack> base, ItemStack[] arranged) {
|
||||
int[] layout = new int[KIT_CONTENT_SIZE];
|
||||
boolean[] used = new boolean[KIT_CONTENT_SIZE];
|
||||
|
||||
for (int target = 0; target < KIT_CONTENT_SIZE; target++) {
|
||||
ItemStack desired = arranged[target];
|
||||
int matched = -1;
|
||||
|
||||
for (int source = 0; source < KIT_CONTENT_SIZE; source++) {
|
||||
if (used[source]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemStack sourceItem = source < base.size() ? base.get(source) : null;
|
||||
if (isSameStack(sourceItem, desired)) {
|
||||
matched = source;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched == -1) {
|
||||
matched = firstUnused(used, target);
|
||||
}
|
||||
|
||||
used[matched] = true;
|
||||
layout[target] = matched;
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
private static int firstUnused(boolean[] used, int fallback) {
|
||||
if (fallback >= 0 && fallback < used.length && !used[fallback]) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
for (int i = 0; i < used.length; i++) {
|
||||
if (!used[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean isSameStack(ItemStack a, ItemStack b) {
|
||||
if (a == null || a.getType().isAir()) {
|
||||
return b == null || b.getType().isAir();
|
||||
}
|
||||
if (b == null || b.getType().isAir()) {
|
||||
return false;
|
||||
}
|
||||
return a.getAmount() == b.getAmount() && a.isSimilar(b);
|
||||
}
|
||||
|
||||
private static ItemStack deserializeItem(Object element) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (element instanceof ItemStack itemStack) {
|
||||
return itemStack.clone();
|
||||
}
|
||||
|
||||
if (element instanceof Map<?, ?> map) {
|
||||
Map<String, Object> serialized = new LinkedHashMap<>();
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
if (entry.getKey() instanceof String key) {
|
||||
serialized.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (!serialized.isEmpty()) {
|
||||
try {
|
||||
return ItemStack.deserialize(serialized);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public OptionalInt rollKitSlot(KitType type, IntPredicate allowedSlot) {
|
||||
List<Integer> slots = new ArrayList<>();
|
||||
List<Integer> weights = new ArrayList<>();
|
||||
int total = 0;
|
||||
|
||||
for (int slot = MIN_SLOT; slot <= MAX_SLOT; slot++) {
|
||||
if (!allowedSlot.test(slot) || !hasKit(type, slot)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int weight = getChance(type, slot);
|
||||
if (weight <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
slots.add(slot);
|
||||
weights.add(weight);
|
||||
total += weight;
|
||||
}
|
||||
|
||||
if (total <= 0) {
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
int roll = ThreadLocalRandom.current().nextInt(total);
|
||||
int cursor = 0;
|
||||
for (int i = 0; i < slots.size(); i++) {
|
||||
cursor += weights.get(i);
|
||||
if (roll < cursor) {
|
||||
return OptionalInt.of(slots.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
public OptionalInt rollKitSlot(KitType type) {
|
||||
return rollKitSlot(type, slot -> true);
|
||||
}
|
||||
|
||||
private int getChance(KitType type, int slot) {
|
||||
String chancePath = "kit-chances." + type.key() + "." + slot;
|
||||
return plugin.getConfig().getInt(chancePath, 0);
|
||||
}
|
||||
|
||||
private static ItemStack[] normalizeContents(ItemStack[] contents) {
|
||||
ItemStack[] normalized = new ItemStack[KIT_CONTENT_SIZE];
|
||||
if (contents == null) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
int copyLength = Math.min(KIT_CONTENT_SIZE, contents.length);
|
||||
for (int index = 0; index < copyLength; index++) {
|
||||
ItemStack item = contents[index];
|
||||
normalized[index] = item == null ? null : item.clone();
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static List<ItemStack> cloneInventory(List<ItemStack> contents) {
|
||||
List<ItemStack> cloned = new ArrayList<>(contents.size());
|
||||
for (ItemStack item : contents) {
|
||||
cloned.add(item == null ? null : item.clone());
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
private static String path(KitType type, int slot) {
|
||||
return "kits." + type.key() + "." + slot;
|
||||
}
|
||||
|
||||
private static String playerLayoutPath(UUID playerId, KitType type, int slot) {
|
||||
return "player-kit-layouts." + playerId + "." + type.key() + "." + slot;
|
||||
}
|
||||
|
||||
private static void validateSlot(int slot) {
|
||||
if (slot < MIN_SLOT || slot > MAX_SLOT) {
|
||||
throw new IllegalArgumentException("Slot must be between 1 and 3");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.winniepat.pierredufaulersack.kits;
|
||||
|
||||
public enum KitType {
|
||||
BOSS("boss"),
|
||||
HUNTER("hunter");
|
||||
|
||||
private final String key;
|
||||
|
||||
KitType(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class CobwebDecayListener implements Listener {
|
||||
|
||||
private static final long COBWEB_LIFETIME_TICKS = 20L * 10L;
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final GameManager gameManager;
|
||||
|
||||
public CobwebDecayListener(JavaPlugin plugin, GameManager gameManager) {
|
||||
this.plugin = plugin;
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlace(BlockPlaceEvent event) {
|
||||
if (event.getBlockPlaced().getType() != Material.COBWEB) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gameManager.getRole(player.getUniqueId()) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = event.getBlockPlaced().getLocation();
|
||||
UUID worldId = location.getWorld() == null ? null : location.getWorld().getUID();
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
if (worldId == null) {
|
||||
return;
|
||||
}
|
||||
World world = plugin.getServer().getWorld(worldId);
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (world.getBlockAt(x, y, z).getType() == Material.COBWEB) {
|
||||
world.getBlockAt(x, y, z).setType(Material.AIR, false);
|
||||
}
|
||||
}, COBWEB_LIFETIME_TICKS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
|
||||
public class FriendlyFireListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
|
||||
public FriendlyFireListener(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onDamage(EntityDamageByEntityEvent event) {
|
||||
if (!gameManager.isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player attacker = asPlayerDamager(event.getDamager());
|
||||
if (attacker == null || !(event.getEntity() instanceof Player victim)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameManager.areBothHunters(attacker.getUniqueId(), victim.getUniqueId())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private Player asPlayerDamager(Entity entity) {
|
||||
if (entity instanceof Player player) {
|
||||
return player;
|
||||
}
|
||||
|
||||
if (entity instanceof Projectile projectile && projectile.getShooter() instanceof Player shooter) {
|
||||
return shooter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.player.*;
|
||||
|
||||
public class PlayerConnectionListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
private final SidebarService sidebarService;
|
||||
|
||||
public PlayerConnectionListener(GameManager gameManager, SidebarService sidebarService) {
|
||||
this.gameManager = gameManager;
|
||||
this.sidebarService = sidebarService;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
sidebarService.showFor(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
gameManager.handlePlayerQuit(event.getPlayer());
|
||||
sidebarService.clearFor(event.getPlayer());
|
||||
|
||||
event.setQuitMessage(null);
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
p.sendMessage(Component.text("§4- §r" + event.getPlayer().getDisplayName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class PlayerDeathListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||
event.setDeathMessage(null);
|
||||
|
||||
Player victim = event.getEntity();
|
||||
victim.getInventory().clear();
|
||||
victim.getInventory().setArmorContents(new ItemStack[0]);
|
||||
victim.getInventory().setItemInOffHand(new ItemStack(Material.AIR));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,757 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.Pierredufaulersack;
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import de.winniepat.pierredufaulersack.kits.KitService;
|
||||
import de.winniepat.pierredufaulersack.kits.KitType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryAction;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
|
||||
public class PlayerJoinListener implements Listener {
|
||||
|
||||
private static final String SELECTOR_KEY = "queue_selector";
|
||||
private static final String QUEUE_ITEM_KEY = "queue_item";
|
||||
private static final String LEAVE_ITEM_KEY = "leave_item";
|
||||
private static final String KIT_EDITOR_KEY = "kit_editor";
|
||||
private static final String KIT_TYPE_ITEM_KEY = "kit_editor_type";
|
||||
private static final String KIT_SLOT_ITEM_KEY = "kit_editor_slot";
|
||||
private static final String LEAVE_ACTION = "leave";
|
||||
private static final String QUEUE_MENU_TITLE = "&8Queue Auswahl";
|
||||
private static final String KIT_TYPE_MENU_TITLE = "&8Kit Editor - Rolle";
|
||||
private static final int KIT_STORAGE_SIZE = 36;
|
||||
private static final int KIT_TOTAL_SIZE = 41;
|
||||
private static final int EDITOR_SIZE = 54;
|
||||
private static final int EDITOR_BOOTS_SLOT = 45;
|
||||
private static final int EDITOR_LEGGINGS_SLOT = 46;
|
||||
private static final int EDITOR_CHESTPLATE_SLOT = 47;
|
||||
private static final int EDITOR_HELMET_SLOT = 48;
|
||||
private static final int EDITOR_OFFHAND_SLOT = 50;
|
||||
|
||||
private final Pierredufaulersack plugin;
|
||||
private final GameManager gameManager;
|
||||
private final KitService kitService;
|
||||
private final NamespacedKey selectorItemKey;
|
||||
private final NamespacedKey queueItemKey;
|
||||
private final NamespacedKey leaveItemKey;
|
||||
private final NamespacedKey kitEditorItemKey;
|
||||
private final NamespacedKey kitTypeItemKey;
|
||||
private final NamespacedKey kitSlotItemKey;
|
||||
|
||||
public PlayerJoinListener(Pierredufaulersack plugin, GameManager gameManager, KitService kitService) {
|
||||
this.plugin = plugin;
|
||||
this.gameManager = gameManager;
|
||||
this.kitService = kitService;
|
||||
this.selectorItemKey = new NamespacedKey(plugin, SELECTOR_KEY);
|
||||
this.queueItemKey = new NamespacedKey(plugin, QUEUE_ITEM_KEY);
|
||||
this.leaveItemKey = new NamespacedKey(plugin, LEAVE_ITEM_KEY);
|
||||
this.kitEditorItemKey = new NamespacedKey(plugin, KIT_EDITOR_KEY);
|
||||
this.kitTypeItemKey = new NamespacedKey(plugin, KIT_TYPE_ITEM_KEY);
|
||||
this.kitSlotItemKey = new NamespacedKey(plugin, KIT_SLOT_ITEM_KEY);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
gameManager.handlePlayerQuit(player);
|
||||
|
||||
event.setJoinMessage(null);
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
p.sendMessage(Component.text("§a+ §r" + player.getDisplayName()));
|
||||
}
|
||||
|
||||
Location lobby = loadLocation("locations.lobby");
|
||||
if (lobby != null) {
|
||||
player.teleport(lobby);
|
||||
}
|
||||
|
||||
player.getInventory().clear();
|
||||
player.getInventory().setArmorContents(new ItemStack[4]);
|
||||
player.getInventory().setItemInOffHand(null);
|
||||
for (PotionEffect effect : player.getActivePotionEffects()) {
|
||||
player.removePotionEffect(effect.getType());
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> giveLobbyItems(player));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRespawn(PlayerRespawnEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
if (gameManager.getRole(player.getUniqueId()) != null) {
|
||||
return;
|
||||
}
|
||||
if (isLobbyLocation(player.getLocation()) || isLobbyLocation(event.getRespawnLocation())) {
|
||||
giveLobbyItems(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onTeleport(PlayerTeleportEvent event) {
|
||||
if (isLobbyLocation(event.getTo())) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> giveLobbyItems(event.getPlayer()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onSelectorUse(PlayerInteractEvent event) {
|
||||
if (event.getHand() != EquipmentSlot.HAND) {
|
||||
return;
|
||||
}
|
||||
|
||||
Action action = event.getAction();
|
||||
if (action != Action.RIGHT_CLICK_AIR && action != Action.RIGHT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack used = event.getItem();
|
||||
if (used == null) {
|
||||
used = event.getPlayer().getInventory().getItemInMainHand();
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gameManager.getRole(player.getUniqueId()) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isQueueSelector(used)) {
|
||||
event.setCancelled(true);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> openQueueSelectorMenu(player));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isKitEditorOpener(used)) {
|
||||
event.setCancelled(true);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> openKitTypeMenu(player));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
Inventory topInventory = event.getView().getTopInventory();
|
||||
|
||||
if (isQueueMenu(topInventory)) {
|
||||
event.setCancelled(true);
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory() != topInventory) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemMeta meta = clicked.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String queueId = meta.getPersistentDataContainer().get(queueItemKey, PersistentDataType.STRING);
|
||||
String leaveAction = meta.getPersistentDataContainer().get(leaveItemKey, PersistentDataType.STRING);
|
||||
|
||||
if (LEAVE_ACTION.equals(leaveAction)) {
|
||||
gameManager.leave(player);
|
||||
gameManager.clearSelectedQueue(player);
|
||||
giveLobbyItems(player);
|
||||
player.closeInventory();
|
||||
return;
|
||||
}
|
||||
|
||||
if (queueId == null || queueId.isBlank()) {
|
||||
return;
|
||||
}
|
||||
|
||||
gameManager.selectQueue(player, queueId);
|
||||
gameManager.join(player, queueId);
|
||||
giveLobbyItems(player);
|
||||
player.closeInventory();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isKitTypeMenu(topInventory)) {
|
||||
event.setCancelled(true);
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory() != topInventory) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = clicked.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String rawType = meta.getPersistentDataContainer().get(kitTypeItemKey, PersistentDataType.STRING);
|
||||
KitType type = parseKitType(rawType);
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
openKitSlotMenu(player, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topInventory != null && topInventory.getHolder() instanceof KitSlotMenuHolder slotHolder) {
|
||||
event.setCancelled(true);
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory() != topInventory) {
|
||||
return;
|
||||
}
|
||||
if (!(event.getWhoClicked() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
ItemMeta meta = clicked.getItemMeta();
|
||||
if (meta == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer slot = meta.getPersistentDataContainer().get(kitSlotItemKey, PersistentDataType.INTEGER);
|
||||
if (slot == null || slot < 1 || slot > 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
openKitEditor(player, slotHolder.type(), slot);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topInventory.getHolder() instanceof KitEditorMenuHolder) {
|
||||
if (event.getClickedInventory() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getClickedInventory() != topInventory) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isShiftClick()
|
||||
|| event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY
|
||||
|| event.getAction() == InventoryAction.DROP_ALL_SLOT
|
||||
|| event.getAction() == InventoryAction.DROP_ONE_SLOT
|
||||
|| event.getAction() == InventoryAction.DROP_ALL_CURSOR
|
||||
|| event.getAction() == InventoryAction.DROP_ONE_CURSOR
|
||||
|| event.getClick() == ClickType.NUMBER_KEY
|
||||
|| event.getClick() == ClickType.SWAP_OFFHAND
|
||||
|| event.getClick() == ClickType.DOUBLE_CLICK
|
||||
|| event.getClick() == ClickType.DROP
|
||||
|| event.getClick() == ClickType.CONTROL_DROP) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
Inventory topInventory = event.getView().getTopInventory();
|
||||
if (isQueueMenu(topInventory)
|
||||
|| isKitTypeMenu(topInventory)
|
||||
|| topInventory.getHolder() instanceof KitSlotMenuHolder) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (topInventory.getHolder() instanceof KitEditorMenuHolder) {
|
||||
int topSize = topInventory.getSize();
|
||||
for (int rawSlot : event.getRawSlots()) {
|
||||
if (rawSlot >= topSize) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onKitEditorClose(InventoryCloseEvent event) {
|
||||
Inventory inventory = event.getInventory();
|
||||
if (!(inventory.getHolder() instanceof KitEditorMenuHolder editorHolder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPlayer() instanceof Player player) {
|
||||
ItemStack cursor = player.getItemOnCursor();
|
||||
if (hasItem(cursor)) {
|
||||
ItemStack leftover = placeIntoEditableSlots(inventory, cursor.clone());
|
||||
if (hasItem(leftover)) {
|
||||
player.getWorld().dropItemNaturally(player.getLocation(), leftover);
|
||||
}
|
||||
player.setItemOnCursor(null);
|
||||
}
|
||||
|
||||
boolean saved = kitService.setPlayerLayout(
|
||||
player.getUniqueId(),
|
||||
editorHolder.type(),
|
||||
editorHolder.slot(),
|
||||
extractKitFromEditor(inventory));
|
||||
|
||||
if (!saved) {
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &cKein Basis-Kit vorhanden. Layout nicht gespeichert."));
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &aKit &e" + editorHolder.slot() + " &afür &e"
|
||||
+ typeDisplayName(editorHolder.type()) + " &aAnordnung gespeichert."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Non-player close is rare, but keep layout persistence consistent.
|
||||
kitService.setPlayerLayout(
|
||||
event.getPlayer().getUniqueId(),
|
||||
editorHolder.type(),
|
||||
editorHolder.slot(),
|
||||
extractKitFromEditor(inventory));
|
||||
}
|
||||
|
||||
private void giveLobbyItems(Player player) {
|
||||
if (gameManager.getRole(player.getUniqueId()) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack selector = new ItemStack(Material.COMPASS);
|
||||
ItemMeta selectorMeta = selector.getItemMeta();
|
||||
if (selectorMeta != null) {
|
||||
String selected = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
String selectedText = selected == null || selected.isBlank() ? "None" : selected;
|
||||
selectorMeta.setDisplayName(color("&6Queue Auswahl"));
|
||||
selectorMeta.setLore(List.of(
|
||||
color("&7Gerade: &e" + selectedText),
|
||||
color("&7Clicke um das Menü zu öffnen")));
|
||||
selectorMeta.getPersistentDataContainer().set(selectorItemKey, PersistentDataType.BYTE, (byte) 1);
|
||||
selector.setItemMeta(selectorMeta);
|
||||
}
|
||||
|
||||
ItemStack kitEditor = new ItemStack(Material.CHEST);
|
||||
ItemMeta editorMeta = kitEditor.getItemMeta();
|
||||
if (editorMeta != null) {
|
||||
editorMeta.setDisplayName(color("&dKit Editor"));
|
||||
editorMeta.setLore(List.of(
|
||||
color("&7Clicke um Boss/Hunter Kits"),
|
||||
color("&7für Slot 1-3 zu bearbeiten")));
|
||||
editorMeta.getPersistentDataContainer().set(kitEditorItemKey, PersistentDataType.BYTE, (byte) 1);
|
||||
kitEditor.setItemMeta(editorMeta);
|
||||
}
|
||||
|
||||
player.getInventory().setItem(4, selector);
|
||||
player.getInventory().setItem(6, kitEditor);
|
||||
}
|
||||
|
||||
private boolean isQueueSelector(ItemStack item) {
|
||||
if (item == null || item.getType() != Material.COMPASS || !item.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Byte marker = meta.getPersistentDataContainer().get(selectorItemKey, PersistentDataType.BYTE);
|
||||
if (marker != null && marker == (byte) 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String displayName = meta.getDisplayName();
|
||||
return displayName != null && displayName.equals(color("&6Queue Selector"));
|
||||
}
|
||||
|
||||
private boolean isKitEditorOpener(ItemStack item) {
|
||||
if (item == null || item.getType() != Material.CHEST || !item.hasItemMeta()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Byte marker = meta.getPersistentDataContainer().get(kitEditorItemKey, PersistentDataType.BYTE);
|
||||
return marker != null && marker == (byte) 1;
|
||||
}
|
||||
|
||||
private boolean isLobbyLocation(Location location) {
|
||||
Location lobby = loadLocation("locations.lobby");
|
||||
if (location == null || lobby == null) {
|
||||
return false;
|
||||
}
|
||||
if (location.getWorld() == null || lobby.getWorld() == null) {
|
||||
return false;
|
||||
}
|
||||
if (!location.getWorld().getUID().equals(lobby.getWorld().getUID())) {
|
||||
return false;
|
||||
}
|
||||
return location.distanceSquared(lobby) <= 4.0;
|
||||
}
|
||||
|
||||
private void openQueueSelectorMenu(Player player) {
|
||||
List<String> queueIds = new ArrayList<>(gameManager.queueIds());
|
||||
if (queueIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Collections.sort(queueIds);
|
||||
|
||||
int requiredSlots = queueIds.size() + 1;
|
||||
int size = 9;
|
||||
while (size < requiredSlots) {
|
||||
size += 9;
|
||||
}
|
||||
|
||||
Inventory menu = Bukkit.createInventory(new QueueMenuHolder(), size, color(QUEUE_MENU_TITLE));
|
||||
String selectedQueue = gameManager.getSelectedQueue(player.getUniqueId());
|
||||
|
||||
int slot = 0;
|
||||
for (String queueId : queueIds) {
|
||||
if (slot == 8) {
|
||||
slot++;
|
||||
}
|
||||
if (slot >= size) {
|
||||
break;
|
||||
}
|
||||
boolean selected = queueId.equals(selectedQueue);
|
||||
menu.setItem(slot, createQueueMenuItem(queueId, selected));
|
||||
slot++;
|
||||
}
|
||||
|
||||
if (size > 8) {
|
||||
menu.setItem(8, createLeaveMenuItem());
|
||||
}
|
||||
|
||||
player.openInventory(menu);
|
||||
}
|
||||
|
||||
private void openKitTypeMenu(Player player) {
|
||||
Inventory menu = Bukkit.createInventory(new KitTypeMenuHolder(), 9, color(KIT_TYPE_MENU_TITLE));
|
||||
menu.setItem(3, createKitTypeMenuItem(KitType.BOSS));
|
||||
menu.setItem(5, createKitTypeMenuItem(KitType.HUNTER));
|
||||
player.openInventory(menu);
|
||||
}
|
||||
|
||||
private void openKitSlotMenu(Player player, KitType type) {
|
||||
Inventory menu = Bukkit.createInventory(new KitSlotMenuHolder(type), 9,
|
||||
color("&8Kit Editor - " + typeDisplayName(type)));
|
||||
menu.setItem(2, createKitSlotMenuItem(type, 1));
|
||||
menu.setItem(4, createKitSlotMenuItem(type, 2));
|
||||
menu.setItem(6, createKitSlotMenuItem(type, 3));
|
||||
player.openInventory(menu);
|
||||
}
|
||||
|
||||
private void openKitEditor(Player player, KitType type, int slot) {
|
||||
Inventory editor = Bukkit.createInventory(new KitEditorMenuHolder(type, slot), EDITOR_SIZE,
|
||||
color("&8Edit " + typeDisplayName(type) + " Kit " + slot));
|
||||
|
||||
kitService.getKitForPlayer(player.getUniqueId(), type, slot)
|
||||
.ifPresent(kit -> editor.setContents(buildEditorContents(kit)));
|
||||
|
||||
player.openInventory(editor);
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &7Bearbeite das Kit und schließe das Inventar zum Speichern."));
|
||||
player.sendMessage(color("&8[&6BossHunt&8] &7Armor: Slots 46-49, Offhand: Slot 51."));
|
||||
}
|
||||
|
||||
private ItemStack createQueueMenuItem(String queueId, boolean selected) {
|
||||
Material material = selected ? Material.LIME_WOOL : Material.GRAY_WOOL;
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
meta.setDisplayName(color((selected ? "&a" : "&e") + queueId));
|
||||
meta.setLore(List.of(
|
||||
color("&7Spieler: &f" + gameManager.lobbySize(queueId) + "&7/&f" + gameManager.maxPlayers()),
|
||||
color("&7Status: &f" + gameManager.getState(queueId).name()),
|
||||
color(selected ? "&aGerade ausgewählt" : "&eClicke zum auswählen")));
|
||||
meta.getPersistentDataContainer().set(queueItemKey, PersistentDataType.STRING, queueId);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createLeaveMenuItem() {
|
||||
ItemStack item = new ItemStack(Material.BARRIER);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
meta.setDisplayName(color("&cLeave Queue/Lobby"));
|
||||
meta.setLore(List.of(
|
||||
color("&7Click um die queue zu verlassen")));
|
||||
meta.getPersistentDataContainer().set(leaveItemKey, PersistentDataType.STRING, LEAVE_ACTION);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createKitTypeMenuItem(KitType type) {
|
||||
Material material = type == KitType.BOSS ? Material.NETHERITE_CHESTPLATE : Material.IRON_CHESTPLATE;
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
String display = typeDisplayName(type);
|
||||
meta.setDisplayName(color("&e" + display));
|
||||
meta.setLore(List.of(color("&7Clicke um " + display + " Kits zu bearbeiten")));
|
||||
meta.getPersistentDataContainer().set(kitTypeItemKey, PersistentDataType.STRING, type.key());
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createKitSlotMenuItem(KitType type, int slot) {
|
||||
boolean hasKit = kitService.hasKit(type, slot);
|
||||
ItemStack item = new ItemStack(hasKit ? Material.LIME_SHULKER_BOX : Material.GRAY_SHULKER_BOX);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta == null) {
|
||||
return item;
|
||||
}
|
||||
|
||||
meta.setDisplayName(color("&eKit " + slot));
|
||||
meta.setLore(List.of(
|
||||
color(hasKit ? "&aBereits gespeichert" : "&7Noch leer"),
|
||||
color("&7Clicke zum Bearbeiten")));
|
||||
meta.getPersistentDataContainer().set(kitSlotItemKey, PersistentDataType.INTEGER, slot);
|
||||
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private KitType parseKitType(String raw) {
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (KitType type : KitType.values()) {
|
||||
if (type.key().equalsIgnoreCase(raw)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String typeDisplayName(KitType type) {
|
||||
return type == KitType.BOSS ? "Boss" : "Hunter";
|
||||
}
|
||||
|
||||
private ItemStack[] buildEditorContents(List<ItemStack> kit) {
|
||||
ItemStack[] editor = new ItemStack[EDITOR_SIZE];
|
||||
for (int i = 0; i < Math.min(KIT_STORAGE_SIZE, kit.size()); i++) {
|
||||
ItemStack item = kit.get(i);
|
||||
editor[i] = item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
editor[EDITOR_BOOTS_SLOT] = cloneAt(kit, 36);
|
||||
editor[EDITOR_LEGGINGS_SLOT] = cloneAt(kit, 37);
|
||||
editor[EDITOR_CHESTPLATE_SLOT] = cloneAt(kit, 38);
|
||||
editor[EDITOR_HELMET_SLOT] = cloneAt(kit, 39);
|
||||
editor[EDITOR_OFFHAND_SLOT] = cloneAt(kit, 40);
|
||||
return editor;
|
||||
}
|
||||
|
||||
private ItemStack[] extractKitFromEditor(Inventory inventory) {
|
||||
ItemStack[] editorContents = inventory.getContents();
|
||||
ItemStack[] kit = new ItemStack[KIT_TOTAL_SIZE];
|
||||
for (int i = 0; i < KIT_STORAGE_SIZE; i++) {
|
||||
ItemStack item = editorContents[i];
|
||||
kit[i] = item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
kit[36] = cloneAt(editorContents, EDITOR_BOOTS_SLOT);
|
||||
kit[37] = cloneAt(editorContents, EDITOR_LEGGINGS_SLOT);
|
||||
kit[38] = cloneAt(editorContents, EDITOR_CHESTPLATE_SLOT);
|
||||
kit[39] = cloneAt(editorContents, EDITOR_HELMET_SLOT);
|
||||
kit[40] = cloneAt(editorContents, EDITOR_OFFHAND_SLOT);
|
||||
return kit;
|
||||
}
|
||||
|
||||
private ItemStack cloneAt(List<ItemStack> items, int index) {
|
||||
if (index < 0 || index >= items.size()) {
|
||||
return null;
|
||||
}
|
||||
ItemStack item = items.get(index);
|
||||
return item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
private ItemStack cloneAt(ItemStack[] items, int index) {
|
||||
if (index < 0 || index >= items.length) {
|
||||
return null;
|
||||
}
|
||||
ItemStack item = items[index];
|
||||
return item == null ? null : item.clone();
|
||||
}
|
||||
|
||||
private boolean hasItem(ItemStack item) {
|
||||
return item != null && item.getType() != Material.AIR;
|
||||
}
|
||||
|
||||
private ItemStack placeIntoEditableSlots(Inventory inventory, ItemStack stack) {
|
||||
ItemStack remaining = stack;
|
||||
|
||||
for (int slot = 0; slot < KIT_STORAGE_SIZE; slot++) {
|
||||
if (remaining == null || remaining.getType() == Material.AIR) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ItemStack existing = inventory.getItem(slot);
|
||||
if (existing == null || existing.getType() == Material.AIR) {
|
||||
inventory.setItem(slot, remaining);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (existing.isSimilar(remaining) && existing.getAmount() < existing.getMaxStackSize()) {
|
||||
int free = existing.getMaxStackSize() - existing.getAmount();
|
||||
int move = Math.min(free, remaining.getAmount());
|
||||
existing.setAmount(existing.getAmount() + move);
|
||||
remaining.setAmount(remaining.getAmount() - move);
|
||||
}
|
||||
}
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
private boolean isQueueMenu(Inventory inventory) {
|
||||
if (inventory == null) {
|
||||
return false;
|
||||
}
|
||||
return inventory.getHolder() instanceof QueueMenuHolder;
|
||||
}
|
||||
|
||||
private boolean isKitTypeMenu(Inventory inventory) {
|
||||
if (inventory == null) {
|
||||
return false;
|
||||
}
|
||||
return inventory.getHolder() instanceof KitTypeMenuHolder;
|
||||
}
|
||||
|
||||
private static final class QueueMenuHolder implements InventoryHolder {
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class KitTypeMenuHolder implements InventoryHolder {
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class KitSlotMenuHolder implements InventoryHolder {
|
||||
private final KitType type;
|
||||
|
||||
private KitSlotMenuHolder(KitType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private KitType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class KitEditorMenuHolder implements InventoryHolder {
|
||||
private final KitType type;
|
||||
private final int slot;
|
||||
|
||||
private KitEditorMenuHolder(KitType type, int slot) {
|
||||
this.type = type;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
private KitType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private int slot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory getInventory() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String color(String text) {
|
||||
return ChatColor.translateAlternateColorCodes('&', text);
|
||||
}
|
||||
|
||||
private Location loadLocation(String path) {
|
||||
FileConfiguration config = plugin.getConfig();
|
||||
ConfigurationSection section = config.getConfigurationSection(path);
|
||||
if (section == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String worldName = section.getString("world");
|
||||
if (worldName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Location(
|
||||
world,
|
||||
section.getDouble("x"),
|
||||
section.getDouble("y"),
|
||||
section.getDouble("z"),
|
||||
(float) section.getDouble("yaw"),
|
||||
(float) section.getDouble("pitch"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
|
||||
public class RoundOutcomeListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
|
||||
public RoundOutcomeListener(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onDeath(PlayerDeathEvent event) {
|
||||
|
||||
Player victim = event.getEntity();
|
||||
Player killer = victim.getKiller();
|
||||
if (killer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
gameManager.handleKill(killer, victim);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onRespawn(PlayerRespawnEvent event) {
|
||||
Location lobby = gameManager.consumePendingLobbyRespawn(event.getPlayer().getUniqueId());
|
||||
if (lobby != null) {
|
||||
event.setRespawnLocation(lobby);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package de.winniepat.pierredufaulersack.listeners;
|
||||
|
||||
import de.winniepat.pierredufaulersack.game.GameManager;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerBucketEmptyEvent;
|
||||
|
||||
public class RoundWaterCleanupListener implements Listener {
|
||||
|
||||
private final GameManager gameManager;
|
||||
|
||||
public RoundWaterCleanupListener(GameManager gameManager) {
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onWaterBucketEmpty(PlayerBucketEmptyEvent event) {
|
||||
if (event.getBucket() != Material.WATER_BUCKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gameManager.getRole(player.getUniqueId()) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Block placedAt = event.getBlockClicked().getRelative(event.getBlockFace());
|
||||
gameManager.trackRoundWaterPlacement(player, placedAt.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
max-players: 5
|
||||
max-concurrent-games: 3
|
||||
hunter-kit-max-duplicates: 2
|
||||
|
||||
countdown:
|
||||
seconds: 10
|
||||
full-seconds: 10
|
||||
not-full-seconds: 20
|
||||
min-players: 2
|
||||
announce-every-second: true
|
||||
|
||||
sounds:
|
||||
countdown:
|
||||
sound: BLOCK_NOTE_BLOCK_HAT
|
||||
volume: 1.0
|
||||
pitch: 1.4
|
||||
countdown-final:
|
||||
sound: BLOCK_NOTE_BLOCK_PLING
|
||||
volume: 1.0
|
||||
pitch: 1.8
|
||||
start:
|
||||
sound: ENTITY_PLAYER_LEVELUP
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
stop:
|
||||
sound: ENTITY_ITEM_BREAK
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
killed:
|
||||
sound: ENTITY_PLAYER_HURT
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
hunter-win:
|
||||
sound: ENTITY_PLAYER_LEVELUP
|
||||
volume: 1.0
|
||||
pitch: 1.2
|
||||
boss-lose:
|
||||
sound: ENTITY_VILLAGER_NO
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
boss-win:
|
||||
sound: ENTITY_ENDER_DRAGON_GROWL
|
||||
volume: 1.0
|
||||
pitch: 1.0
|
||||
|
||||
kit-chances:
|
||||
boss:
|
||||
1: 40
|
||||
2: 40
|
||||
3: 20
|
||||
hunter:
|
||||
1: 40
|
||||
2: 40
|
||||
3: 20
|
||||
|
||||
locations:
|
||||
lobby: {}
|
||||
|
||||
arenas:
|
||||
game1: {}
|
||||
game2: {}
|
||||
game3: {}
|
||||
|
||||
kits:
|
||||
boss: {}
|
||||
hunter: {}
|
||||
@@ -0,0 +1,26 @@
|
||||
name: Pierredufaulersack
|
||||
version: '${version}'
|
||||
main: de.winniepat.pierredufaulersack.Pierredufaulersack
|
||||
api-version: '1.21'
|
||||
authors: [ WinniePatGG ]
|
||||
website: https://winniepat.de
|
||||
description: Plugin für Boss Hunt Minigame by WinniePatGG
|
||||
depend: [ LuckPerms ]
|
||||
|
||||
commands:
|
||||
bosshunt:
|
||||
description: Hauptbefehl für Boss Hunt
|
||||
usage: /bosshunt <queues|select|join|leave|start|stop|setlobby|setarena|status>
|
||||
bosskit:
|
||||
description: Verwalte Boss Kits
|
||||
usage: /bosskit <add|set|del|list> [1-3]
|
||||
permission: pierredufaulersack.admin
|
||||
hunterkit:
|
||||
description: Verwalte Hunter Kits
|
||||
usage: /hunterkit <add|set|del|list> [1-3]
|
||||
permission: pierredufaulersack.admin
|
||||
|
||||
permissions:
|
||||
pierredufaulersack.admin:
|
||||
description: Admin Rechte für Boss Hunt
|
||||
default: op
|
||||
Reference in New Issue
Block a user