first commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
.idea/
|
||||
*.iml
|
||||
out/
|
||||
srv/
|
||||
build/
|
||||
*.log
|
||||
.gradle/
|
||||
.DS_Store
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 WinniePatGG
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,39 @@
|
||||
# SMPPlugin
|
||||
|
||||
1.21.4 Plugin for my SMP Server. This plugin is hardcoded for my Server. If you want to use it, go ahead. You'll need to change some stuff in the code
|
||||
|
||||
## 💡 Features
|
||||
|
||||
- Black Market
|
||||
- Block Elevators (Currently broken)
|
||||
- Bloodmoon (Stronger, Faster mobs)
|
||||
- Polls
|
||||
- Player reports (With db and gui)
|
||||
- Starter (To start the Event)
|
||||
- Suggestions (With db and gui)
|
||||
- waypoints (Commands)
|
||||
- trash (Delete Items)
|
||||
- Coding Tag (/coding on) Requires a Resourcepack (Maybe I'll provide it)
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Java 21
|
||||
- Gradle
|
||||
- Paper 1.21.4 Server
|
||||
- (Not needed but recommended) Resourcepack
|
||||
|
||||
### Build & Run
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/WinniePatGG/SMPPlugin.git
|
||||
|
||||
# Navigate into the project folder
|
||||
cd SMPPlugin
|
||||
|
||||
# Build the plugin (example using Gradle)
|
||||
./gradlew build
|
||||
```
|
||||
Made with ❤️ by WinniePatGG.
|
||||
@@ -0,0 +1,70 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||
}
|
||||
|
||||
group = 'de.winniepat'
|
||||
version = '1.0'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
|
||||
maven { url = 'https://jitpack.io' }
|
||||
maven { url 'https://repo.lucko.me' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly('io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT')
|
||||
implementation 'org.xerial:sqlite-jdbc:3.42.0.0'
|
||||
|
||||
compileOnly('com.github.MilkBowl:VaultAPI:1.7') {
|
||||
exclude group: 'org.bukkit', module: 'bukkit'
|
||||
}
|
||||
compileOnly 'net.luckperms:api:5.4'
|
||||
}
|
||||
|
||||
tasks {
|
||||
runServer {
|
||||
minecraftVersion("1.21")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include '**/*.yml'
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('copyPlugin', Copy) {
|
||||
dependsOn build
|
||||
from("$buildDir/libs")
|
||||
include('*.jar')
|
||||
into("$rootDir/srv/plugins")
|
||||
}
|
||||
|
||||
build.finalizedBy(copyPlugin)
|
||||
Vendored
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -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 = 'SMPPlugin'
|
||||
@@ -0,0 +1,238 @@
|
||||
package de.winniepat.SMPPlugin;
|
||||
|
||||
import de.winniepat.SMPPlugin.blackmarket.*;
|
||||
import de.winniepat.SMPPlugin.blockelevator.*;
|
||||
import de.winniepat.SMPPlugin.bloodmoon.*;
|
||||
import de.winniepat.SMPPlugin.commands.*;
|
||||
import de.winniepat.SMPPlugin.listeners.*;
|
||||
import de.winniepat.SMPPlugin.polls.*;
|
||||
import de.winniepat.SMPPlugin.report.*;
|
||||
import de.winniepat.SMPPlugin.report.commands.*;
|
||||
import de.winniepat.SMPPlugin.starter.MoveEvent;
|
||||
import de.winniepat.SMPPlugin.starter.StartCommand;
|
||||
import de.winniepat.SMPPlugin.suggestions.*;
|
||||
import de.winniepat.SMPPlugin.suggestions.commands.*;
|
||||
import de.winniepat.SMPPlugin.waypoints.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.configuration.file.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
public final class SMPPlugin extends JavaPlugin {
|
||||
private static SMPPlugin instance;
|
||||
private WaypointsDatabase waypointsDatabase;
|
||||
private ReportDatabase reportDatabase;
|
||||
private SuggestionManager suggestionManager;
|
||||
CodingCommand codingCommand = new CodingCommand(this, this);
|
||||
private FileConfiguration messages;
|
||||
private BloodmoonManager bloodmoonManager;
|
||||
public static Set<UUID> frozenPlayers = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
saveDefaultMessages();
|
||||
loadMessages();
|
||||
instance = this;
|
||||
|
||||
File dbFile = new File(getDataFolder(), "suggestions.db");
|
||||
try {
|
||||
this.suggestionManager = new SuggestionManager(dbFile);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
registerWaypoints();
|
||||
getLogger().info("Waypoints registered");
|
||||
registerReportDatabase();
|
||||
getLogger().info("Reports registered");
|
||||
registerBloodMoon();
|
||||
getLogger().info("BloodMoon registered");
|
||||
registerCommands();
|
||||
getLogger().info("Commands registered");
|
||||
registerListeners();
|
||||
getLogger().info("Listener registered");
|
||||
registerPollsystem();
|
||||
getLogger().info("PollSystem registered");
|
||||
registerSuggestionDatabase();
|
||||
getLogger().info("Suggestion Database registered");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().warning("Ach Leck Eier!");
|
||||
bloodmoonManager.endBloodmoon();
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
Objects.requireNonNull(getCommand("trash")).setExecutor(new TrashCommand(this, this));
|
||||
Objects.requireNonNull(getCommand("report")).setExecutor(new ReportCommand(reportDatabase, this));
|
||||
Objects.requireNonNull(getCommand("reports")).setExecutor(new ReportsCommand(this, reportDatabase, this));
|
||||
Objects.requireNonNull(getCommand("suggestion")).setExecutor(new SuggestionCommand(suggestionManager, this, this));
|
||||
Objects.requireNonNull(getCommand("suggestions")).setExecutor(new SuggestionListCommand(suggestionManager));
|
||||
Objects.requireNonNull(getCommand("suggestionstatus")).setExecutor(new SuggestionStatusCommand(suggestionManager, this));
|
||||
Objects.requireNonNull(getCommand("coding")).setExecutor(new CodingCommand(this, this));
|
||||
Objects.requireNonNull(getCommand("suggestionsgui")).setExecutor(this::handleGuiCommand);
|
||||
Objects.requireNonNull(getCommand("bloodmoon")).setExecutor(new BloodmoonCommand(bloodmoonManager));
|
||||
Objects.requireNonNull(getCommand("blackmarket")).setExecutor(new BlackMarketCommand(this));
|
||||
Objects.requireNonNull(getCommand("getwaypoint")).setExecutor(new WaypointCommands(waypointsDatabase, this));
|
||||
Objects.requireNonNull(getCommand("addwaypoint")).setExecutor(new WaypointCommands(waypointsDatabase, this));
|
||||
Objects.requireNonNull(getCommand("smp")).setExecutor(new StartCommand());
|
||||
Objects.requireNonNull(getCommand("spawn")).setExecutor(new SpawnCommand());
|
||||
Objects.requireNonNull(getCommand("shop")).setExecutor(new ShopCommand());
|
||||
}
|
||||
|
||||
private boolean handleGuiCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender instanceof Player player) {
|
||||
new SuggestionGui(suggestionManager, this).open(player, null);
|
||||
} else {
|
||||
sender.sendMessage("§cOnly players can open the GUI.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void registerListeners() {
|
||||
getServer().getPluginManager().registerEvents(new CodingCleanupListener(codingCommand), this);
|
||||
getServer().getPluginManager().registerEvents(new BlackMarketEffectListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new WaypointListener(waypointsDatabase, this), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerJumpListener(), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerSneakListener(), this);
|
||||
getServer().getPluginManager().registerEvents(new MoveEvent(), this);
|
||||
getServer().getPluginManager().registerEvents(new QuitLightningListener(), this);
|
||||
Bukkit.getPluginManager().registerEvents(new SuggestionGui(suggestionManager, this), this);
|
||||
Bukkit.getPluginManager().registerEvents(new FirstPlayerJoinTracker(this), this);
|
||||
}
|
||||
|
||||
private void registerPollsystem() {
|
||||
File pollDataFile = new File(getDataFolder(), "polls.yml");
|
||||
PollManager pollManager = new PollManager(pollDataFile);
|
||||
if (!pollDataFile.getParentFile().exists()) {
|
||||
pollDataFile.getParentFile().mkdirs();
|
||||
}
|
||||
Objects.requireNonNull(getCommand("pollstart")).setExecutor(new PollCommand(pollManager, this));
|
||||
Objects.requireNonNull(getCommand("pollvote")).setExecutor((sender, cmd, label, args) -> {
|
||||
if (sender instanceof Player player) {
|
||||
new PollVoteGUI(pollManager, this).openVoteGUI(player);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
Objects.requireNonNull(getCommand("pollresults")).setExecutor((sender, cmd, label, args) -> {
|
||||
if (sender instanceof Player player && player.hasPermission("poll.view")) {
|
||||
new PollResultGUI(pollManager).openResultsGUI(player);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
getServer().getPluginManager().registerEvents(new PollVoteGUI(pollManager, this), this);
|
||||
}
|
||||
|
||||
private void registerSuggestionDatabase() {
|
||||
if (!getDataFolder().exists()) {
|
||||
getDataFolder().mkdirs();
|
||||
}
|
||||
File dbFile = new File(getDataFolder(), "suggestions.db");
|
||||
try {
|
||||
suggestionManager = new SuggestionManager(dbFile);
|
||||
} catch (SQLException e) {
|
||||
getLogger().severe("Couldn't initialize the Suggestion Database.");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
getLogger().info("Suggestion Database connected successfully");
|
||||
}
|
||||
|
||||
private void saveDefaultMessages() {
|
||||
if (!getDataFolder().exists()) {
|
||||
getDataFolder().mkdirs();
|
||||
}
|
||||
|
||||
File file = new File(getDataFolder(), "messages.yml");
|
||||
if (!file.exists()) {
|
||||
saveResource("messages.yml", false);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMessages() {
|
||||
File file = new File(getDataFolder(), "messages.yml");
|
||||
messages = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
Bukkit.getLogger().info("[DEBUG] Loaded keys: " + messages.getKeys(true));
|
||||
}
|
||||
|
||||
public String getMessage(String key, Map<String, String> placeholders) {
|
||||
if (!messages.contains(key)) {
|
||||
getLogger().warning("Missing message key: " + key);
|
||||
getLogger().warning("Available keys: " + messages.getKeys(true));
|
||||
return ChatColor.RED + "Message not found: " + key;
|
||||
}
|
||||
|
||||
String msg = messages.getString(key);
|
||||
|
||||
for (Map.Entry<String, String> entry : placeholders.entrySet()) {
|
||||
msg = msg.replace("%" + entry.getKey() + "%", entry.getValue());
|
||||
}
|
||||
|
||||
return ChatColor.translateAlternateColorCodes('&', msg);
|
||||
}
|
||||
|
||||
private void checkForElevator(Player player) {
|
||||
Block blockBelow = player.getLocation().subtract(0, 0.1, 0).getBlock();
|
||||
if (blockBelow.getType() != Material.LIGHT_WEIGHTED_PRESSURE_PLATE) return;
|
||||
|
||||
// Handle sneaking (go down)
|
||||
if (player.isSneaking() && !CooldownManager.isOnCooldown(player.getUniqueId())) {
|
||||
for (int y = blockBelow.getY() - 1; y >= 0; y--) {
|
||||
Block below = player.getWorld().getBlockAt(blockBelow.getX(), y, blockBelow.getZ());
|
||||
if (below.getType() == Material.LIGHT_WEIGHTED_PRESSURE_PLATE) {
|
||||
player.teleport(new Location(player.getWorld(), below.getX() + 0.5, y + 1, below.getZ() + 0.5));
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_PISTON_CONTRACT, 1f, 1f);
|
||||
player.getWorld().spawnParticle(Particle.CLOUD, player.getLocation(), 20, 0.3, 0.3, 0.3);
|
||||
CooldownManager.setCooldown(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.sendMessage(ChatColor.YELLOW + "No elevator block below!");
|
||||
CooldownManager.setCooldown(player.getUniqueId());
|
||||
}
|
||||
|
||||
if (player.getVelocity().getY() > 0.2 && !CooldownManager.isOnCooldown(player.getUniqueId())) {
|
||||
for (int y = blockBelow.getY() + 2; y <= player.getWorld().getMaxHeight(); y++) {
|
||||
Block above = player.getWorld().getBlockAt(blockBelow.getX(), y, blockBelow.getZ());
|
||||
if (above.getType() == Material.LIGHT_WEIGHTED_PRESSURE_PLATE) {
|
||||
player.teleport(new Location(player.getWorld(), above.getX() + 0.5, y + 1, above.getZ() + 0.5));
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
player.getWorld().spawnParticle(Particle.PORTAL, player.getLocation(), 30, 0.5, 1, 0.5);
|
||||
CooldownManager.setCooldown(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.sendMessage(ChatColor.YELLOW + "No elevator block above!");
|
||||
CooldownManager.setCooldown(player.getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
private void registerBloodMoon() {
|
||||
this.bloodmoonManager = new BloodmoonManager(this);
|
||||
getServer().getPluginManager().registerEvents(new BloodmoonListener(bloodmoonManager, this), this);
|
||||
new BloodmoonTask(this, bloodmoonManager).start();
|
||||
|
||||
}
|
||||
|
||||
private void registerWaypoints() {
|
||||
reportDatabase = new ReportDatabase(this);
|
||||
}
|
||||
|
||||
private void registerReportDatabase() {
|
||||
reportDatabase = new ReportDatabase(this);
|
||||
}
|
||||
|
||||
public static SMPPlugin getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package de.winniepat.SMPPlugin.blackmarket;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class BlackMarketCommand implements CommandExecutor {
|
||||
|
||||
private final BlackMarketManager manager;
|
||||
|
||||
public BlackMarketCommand(JavaPlugin plugin) {
|
||||
this.manager = new BlackMarketManager(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage("This command can only be used by players.");
|
||||
return true;
|
||||
}
|
||||
|
||||
manager.spawnMarket();
|
||||
player.sendMessage(ChatColor.DARK_PURPLE + "You have summoned the Black Market.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package de.winniepat.SMPPlugin.blackmarket;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.*;
|
||||
import org.bukkit.event.player.PlayerExpChangeEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class BlackMarketEffectListener implements Listener {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final Random random = new Random();
|
||||
private final NamespacedKey catchKey;
|
||||
|
||||
public BlackMarketEffectListener(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.catchKey = new NamespacedKey(plugin, "blackmarket_catch");
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
checkCatch(p, EquipmentSlot.HEAD, "hunger_drain", () -> {
|
||||
if (p.getFoodLevel() > 1) p.setFoodLevel(p.getFoodLevel() - 1);
|
||||
});
|
||||
checkCatch(p, EquipmentSlot.HAND, "burn_in_day", () -> {
|
||||
if (isDaylight(p)) p.setFireTicks(40);
|
||||
});
|
||||
checkCatch(p, EquipmentSlot.FEET, "random_blindness", () -> {
|
||||
if (random.nextInt(100) < 5)
|
||||
p.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 0));
|
||||
});
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 40L);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityDamage(EntityDamageByEntityEvent event) {
|
||||
if (!(event.getDamager() instanceof Player p)) return;
|
||||
ItemStack item = p.getInventory().getItemInMainHand();
|
||||
String catchId = getCatch(item);
|
||||
|
||||
if (catchId == null) return;
|
||||
|
||||
switch (catchId) {
|
||||
case "self_damage" -> {
|
||||
p.damage(2);
|
||||
p.sendMessage("§cThe weapon wounds you!");
|
||||
}
|
||||
case "unstable" -> {
|
||||
if (random.nextInt(100) < 10)
|
||||
p.getWorld().createExplosion(p.getLocation(), 2f, false, false, p);
|
||||
}
|
||||
case "lightning_touch" -> {
|
||||
Entity target = event.getEntity();
|
||||
target.getWorld().strikeLightningEffect(target.getLocation());
|
||||
}
|
||||
case "hurt_nearby_allies" -> {
|
||||
for (Player nearby : p.getWorld().getPlayers()) {
|
||||
if (!nearby.equals(p) && nearby.getLocation().distance(p.getLocation()) < 5)
|
||||
nearby.damage(2);
|
||||
}
|
||||
}
|
||||
case "levitate_on_crit" -> {
|
||||
if (p.getAttackCooldown() > 0.9f)
|
||||
p.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 40, 1));
|
||||
}
|
||||
case "arrow_bounceback" -> {
|
||||
if (p.getInventory().getItemInMainHand().getType().toString().endsWith("BOW") && random.nextInt(100) < 20) {
|
||||
p.damage(2);
|
||||
p.sendMessage(ChatColor.DARK_RED + "Your cursed arrow rebounds!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onHitTaken(EntityDamageEvent event) {
|
||||
if (!(event.getEntity() instanceof Player p)) return;
|
||||
checkCatch(p, EquipmentSlot.CHEST, "slowness_when_hit", () -> {
|
||||
p.addPotionEffect(new PotionEffect(PotionEffectType.SLOW_FALLING, 60, 2));
|
||||
});
|
||||
checkCatch(p, EquipmentSlot.FEET, "more_knockback", () -> {
|
||||
p.setVelocity(p.getVelocity().multiply(2));
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onXpGain(PlayerExpChangeEvent event) {
|
||||
Player p = event.getPlayer();
|
||||
checkCatch(p, EquipmentSlot.HEAD, "xp_boost", () -> {
|
||||
event.setAmount(event.getAmount() * 2);
|
||||
});
|
||||
}
|
||||
|
||||
private void checkCatch(Player p, EquipmentSlot slot, String catchId, Runnable action) {
|
||||
ItemStack item = p.getInventory().getItem(slot);
|
||||
if (item != null && item.hasItemMeta()) {
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta.getPersistentDataContainer().has(catchKey, PersistentDataType.STRING)) {
|
||||
String tag = meta.getPersistentDataContainer().get(catchKey, PersistentDataType.STRING);
|
||||
if (tag != null && tag.equals(catchId)) {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getCatch(ItemStack item) {
|
||||
if (item == null || !item.hasItemMeta()) return null;
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (!meta.getPersistentDataContainer().has(catchKey, PersistentDataType.STRING)) return null;
|
||||
return meta.getPersistentDataContainer().get(catchKey, PersistentDataType.STRING);
|
||||
}
|
||||
|
||||
private boolean isDaylight(Player player) {
|
||||
long time = player.getWorld().getTime();
|
||||
return time < 12300 || time > 23850;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package de.winniepat.SMPPlugin.blackmarket;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.NamespacedKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class BlackMarketItems {
|
||||
|
||||
public static List<BlackMarketOffer> getRandomOffers(JavaPlugin plugin, int count) {
|
||||
List<BlackMarketOffer> all = new ArrayList<>();
|
||||
all.add(bloodBlade(plugin));
|
||||
all.add(xpHood(plugin));
|
||||
all.add(vampireAxe(plugin));
|
||||
all.add(swiftBoots(plugin));
|
||||
all.add(witherBow(plugin));
|
||||
all.add(unstableBlade(plugin));
|
||||
all.add(lightningAxe(plugin));
|
||||
all.add(bounceBow(plugin));
|
||||
all.add(levitateChest(plugin));
|
||||
Collections.shuffle(all);
|
||||
return all.subList(0, Math.min(count, all.size()));
|
||||
}
|
||||
|
||||
private static BlackMarketOffer bloodBlade(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.NETHERITE_SWORD);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.DARK_RED + "Blood Blade");
|
||||
meta.addEnchant(Enchantment.SHARPNESS, 5, true);
|
||||
meta.addEnchant(Enchantment.FIRE_ASPECT, 2, true);
|
||||
meta.setLore(List.of("§cDeals devastating damage.", "§7But harms the wielder on hit."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "self_damage");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.NETHERITE_INGOT, 3),
|
||||
new ItemStack(Material.ROTTEN_FLESH, 64)
|
||||
), "self_damage");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer xpHood(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.NETHERITE_HELMET);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GOLD + "Hood of Hunger");
|
||||
meta.addEnchant(Enchantment.THORNS, 3, true);
|
||||
meta.setLore(List.of("§eBoosts XP gain.", "§7But constantly drains hunger."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "hunger_drain");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.EXPERIENCE_BOTTLE, 32)
|
||||
), "hunger_drain");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer vampireAxe(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.NETHERITE_AXE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.DARK_PURPLE + "Vampire Axe");
|
||||
meta.addEnchant(Enchantment.SHARPNESS, 5, true);
|
||||
meta.setLore(List.of("§cHeals on hit.", "§7Burns in sunlight."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "burn_in_day");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.EMERALD, 20)
|
||||
), "burn_in_day");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer swiftBoots(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.NETHERITE_BOOTS);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.AQUA + "Boots of Swiftness");
|
||||
meta.addEnchant(Enchantment.FEATHER_FALLING, 4, true);
|
||||
meta.setLore(List.of("§bIncreases speed.", "§7Causes knockback vulnerability."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "more_knockback");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.EMERALD, 15)
|
||||
), "more_knockback");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer witherBow(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.BOW);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.DARK_GRAY + "Withering Bow");
|
||||
meta.addEnchant(Enchantment.POWER, 5, true);
|
||||
meta.setLore(List.of("§7Applies wither.", "§cHurts allies nearby."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "hurt_nearby_allies");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.EMERALD, 25)
|
||||
), "hurt_nearby_allies");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer unstableBlade(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.DIAMOND_SWORD);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.DARK_PURPLE + "Blade of Instability");
|
||||
meta.addEnchant(Enchantment.SHARPNESS, 6, true);
|
||||
meta.setLore(List.of("§5Massive power.", "§cMight explode on hit."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "unstable");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.NETHERITE_INGOT, 2),
|
||||
new ItemStack(Material.TNT, 16)
|
||||
), "unstable");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer lightningAxe(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.NETHERITE_AXE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GOLD + "Lightning Touch Axe");
|
||||
meta.addEnchant(Enchantment.SHARPNESS, 5, true);
|
||||
meta.setLore(List.of("§eElectrocutes enemies.", "§7Risk of chain lightning."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "lightning_touch");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.GOLD_BLOCK, 4)
|
||||
), "lightning_touch");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer bounceBow(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.BOW);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.GRAY + "Rebounding Bow");
|
||||
meta.addEnchant(Enchantment.POWER, 4, true);
|
||||
meta.addEnchant(Enchantment.PUNCH, 1, true);
|
||||
meta.setLore(List.of("§7Sometimes bounces arrows back... on YOU."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "arrow_bounceback");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.SPECTRAL_ARROW, 64)
|
||||
), "arrow_bounceback");
|
||||
}
|
||||
|
||||
private static BlackMarketOffer levitateChest(JavaPlugin plugin) {
|
||||
ItemStack item = new ItemStack(Material.NETHERITE_CHESTPLATE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.DARK_AQUA + "Wings of the Void");
|
||||
meta.addEnchant(Enchantment.PROTECTION, 4, true);
|
||||
meta.setLore(List.of("§3Grants levitation on crit.", "§8Leaves you floating."));
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(plugin, "blackmarket_catch"),
|
||||
PersistentDataType.STRING, "levitate_on_crit");
|
||||
item.setItemMeta(meta);
|
||||
return new BlackMarketOffer(item, List.of(
|
||||
new ItemStack(Material.ENDER_PEARL, 16),
|
||||
new ItemStack(Material.ELYTRA, 1)
|
||||
), "levitate_on_crit");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package de.winniepat.SMPPlugin.blackmarket;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class BlackMarketManager {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
|
||||
public BlackMarketManager(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void spawnMarket() {
|
||||
Location spawnLoc = getRandomSpawnLocation();
|
||||
Villager trader = spawnBlackMarketVillager(spawnLoc);
|
||||
|
||||
Bukkit.broadcastMessage(ChatColor.GRAY + "☠ A mysterious trader has appeared nearby...");
|
||||
|
||||
String coords = String.format("X: %d, Y: %d, Z: %d",
|
||||
spawnLoc.getBlockX(), spawnLoc.getBlockY(), spawnLoc.getBlockZ());
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.getLocation().distance(spawnLoc) <= 200) {
|
||||
player.sendMessage(ChatColor.GRAY + "§7The trader lurks around §f" + coords);
|
||||
}
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (trader == null || trader.isDead() || !trader.isValid()) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
trader.getWorld().spawnParticle(
|
||||
Particle.ENCHANT,
|
||||
trader.getLocation().add(0, 2, 0),
|
||||
20,
|
||||
0.5, 0.5, 0.5,
|
||||
0.1
|
||||
);
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 20L);
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (trader != null && trader.isValid()) {
|
||||
trader.remove();
|
||||
Bukkit.broadcastMessage(ChatColor.GRAY + "The Black Market fades into the shadows...");
|
||||
}
|
||||
}
|
||||
}.runTaskLater(plugin, 20 * 60 * 5);
|
||||
}
|
||||
|
||||
private Villager spawnBlackMarketVillager(Location loc) {
|
||||
Villager v = loc.getWorld().spawn(loc, Villager.class);
|
||||
v.setAI(false);
|
||||
v.setInvulnerable(true);
|
||||
v.setCustomName(ChatColor.DARK_PURPLE + "Black Market");
|
||||
v.setCustomNameVisible(true);
|
||||
v.setProfession(Villager.Profession.NITWIT);
|
||||
v.setVillagerLevel(5);
|
||||
v.setVillagerExperience(1);
|
||||
v.setCanPickupItems(false);
|
||||
|
||||
BlackMarketTradeHandler.applyTrades(v, plugin);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
private Location getRandomSpawnLocation() {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
Random random = new Random();
|
||||
|
||||
int baseX = -635;
|
||||
int baseZ = -837;
|
||||
int radius = 100;
|
||||
|
||||
int x = baseX + random.nextInt(radius * 2 + 1) - radius;
|
||||
int z = baseZ + random.nextInt(radius * 2 + 1) - radius;
|
||||
int y = world.getHighestBlockYAt(x, z) + 1;
|
||||
|
||||
return new Location(world, x + 0.5, y, z + 0.5);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.winniepat.SMPPlugin.blackmarket;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlackMarketOffer {
|
||||
public final ItemStack item;
|
||||
public final List<ItemStack> price;
|
||||
public final String catchId;
|
||||
|
||||
public BlackMarketOffer(ItemStack item, List<ItemStack> price, String catchId) {
|
||||
this.item = item;
|
||||
this.price = price;
|
||||
this.catchId = catchId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package de.winniepat.SMPPlugin.blackmarket;
|
||||
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MerchantRecipe;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlackMarketTradeHandler {
|
||||
|
||||
public static void applyTrades(Villager v, JavaPlugin plugin) {
|
||||
List<MerchantRecipe> recipes = new ArrayList<>();
|
||||
|
||||
for (BlackMarketOffer offer : BlackMarketItems.getRandomOffers(plugin, 3)) {
|
||||
MerchantRecipe recipe = new MerchantRecipe(offer.item, 9999);
|
||||
recipe.setUses(0);
|
||||
recipe.setExperienceReward(false);
|
||||
for (ItemStack ingredient : offer.price) {
|
||||
recipe.addIngredient(ingredient);
|
||||
}
|
||||
recipes.add(recipe);
|
||||
}
|
||||
|
||||
v.setRecipes(recipes);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package de.winniepat.SMPPlugin.blockelevator;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class CooldownManager {
|
||||
private static final HashMap<UUID, Long> cooldowns = new HashMap<>();
|
||||
private static final long COOLDOWN_TIME_MS = 2;
|
||||
|
||||
public static boolean isOnCooldown(UUID player) {
|
||||
if (!cooldowns.containsKey(player)) return false;
|
||||
long lastUsed = cooldowns.get(player);
|
||||
return (System.currentTimeMillis() - lastUsed) < COOLDOWN_TIME_MS;
|
||||
}
|
||||
|
||||
public static void setCooldown(UUID player) {
|
||||
cooldowns.put(player, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.winniepat.SMPPlugin.blockelevator;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
|
||||
public class PlayerJumpListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Check if player moves upwards
|
||||
if (event.getFrom().getY() < event.getTo().getY()) {
|
||||
// Always check the block below the player's feet
|
||||
Block blockBelow = player.getLocation().subtract(0, 0.1, 0).getBlock();
|
||||
|
||||
if (blockBelow.getType() == Material.CRYING_OBSIDIAN) {
|
||||
if (!CooldownManager.isOnCooldown(player.getUniqueId())) {
|
||||
for (int y = blockBelow.getY() + 2; y <= player.getWorld().getMaxHeight(); y++) {
|
||||
Block above = player.getWorld().getBlockAt(blockBelow.getX(), y, blockBelow.getZ());
|
||||
if (above.getType() == Material.CRYING_OBSIDIAN) {
|
||||
player.teleport(new Location(player.getWorld(), above.getX() + 0.5, y + 1, above.getZ() + 0.5));
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
player.getWorld().spawnParticle(Particle.PORTAL, player.getLocation(), 30, 0.5, 1, 0.5);
|
||||
CooldownManager.setCooldown(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.sendMessage(ChatColor.YELLOW + "No elevator block above!");
|
||||
} else if (!player.hasMetadata("jumpCooldownNotified")) {
|
||||
player.sendMessage(ChatColor.RED + "Elevator is cooling down!");
|
||||
player.setMetadata("jumpCooldownNotified", new FixedMetadataValue(SMPPlugin.getInstance(), true));
|
||||
Bukkit.getScheduler().runTaskLater(SMPPlugin.getInstance(), () -> {
|
||||
player.removeMetadata("jumpCooldownNotified", SMPPlugin.getInstance());
|
||||
}, 20L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.winniepat.SMPPlugin.blockelevator;
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerToggleSneakEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
|
||||
public class PlayerSneakListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerSneak(PlayerToggleSneakEvent event) {
|
||||
if (!event.isSneaking()) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Always check the block **below** the player's feet
|
||||
Block blockBelow = player.getLocation().subtract(0, 0.1, 0).getBlock();
|
||||
|
||||
if (blockBelow.getType() == Material.CRYING_OBSIDIAN) {
|
||||
if (!CooldownManager.isOnCooldown(player.getUniqueId())) {
|
||||
for (int y = blockBelow.getY() - 1; y >= 0; y--) {
|
||||
Block below = player.getWorld().getBlockAt(blockBelow.getX(), y, blockBelow.getZ());
|
||||
if (below.getType() == Material.CRYING_OBSIDIAN) {
|
||||
player.teleport(new Location(player.getWorld(), below.getX() + 0.5, y + 1, below.getZ() + 0.5));
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_PISTON_CONTRACT, 1f, 1f);
|
||||
player.getWorld().spawnParticle(Particle.CLOUD, player.getLocation(), 20, 0.3, 0.3, 0.3);
|
||||
CooldownManager.setCooldown(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.sendMessage(ChatColor.YELLOW + "No elevator block below!");
|
||||
} else if (!player.hasMetadata("sneakCooldownNotified")) {
|
||||
player.sendMessage(ChatColor.RED + "Elevator is cooling down!");
|
||||
player.setMetadata("sneakCooldownNotified", new FixedMetadataValue(SMPPlugin.getInstance(), true));
|
||||
Bukkit.getScheduler().runTaskLater(SMPPlugin.getInstance(), () -> {
|
||||
player.removeMetadata("sneakCooldownNotified", SMPPlugin.getInstance());
|
||||
}, 20L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package de.winniepat.SMPPlugin.bloodmoon;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class BloodmoonCommand implements CommandExecutor {
|
||||
|
||||
private final BloodmoonManager manager;
|
||||
|
||||
public BloodmoonCommand(BloodmoonManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!sender.hasPermission("bloodmoon.toggle")) {
|
||||
sender.sendMessage(ChatColor.RED + "You do not have permission to do that.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (manager.isActive()) {
|
||||
manager.endBloodmoon();
|
||||
sender.sendMessage(ChatColor.GRAY + "☀ Bloodmoon ended.");
|
||||
} else {
|
||||
manager.startBloodmoon();
|
||||
sender.sendMessage(ChatColor.RED + "☠ Bloodmoon started.");
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package de.winniepat.SMPPlugin.bloodmoon;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class BloodmoonListener implements Listener {
|
||||
|
||||
private final BloodmoonManager manager;
|
||||
private final JavaPlugin plugin;
|
||||
private final Random random = new Random();
|
||||
|
||||
public BloodmoonListener(BloodmoonManager manager, JavaPlugin plugin) {
|
||||
this.manager = manager;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBedEnter(PlayerBedEnterEvent event) {
|
||||
if (manager.isActive()) {
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage(ChatColor.RED + "You cannot sleep during a Bloodmoon!");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMobSpawn(CreatureSpawnEvent event) {
|
||||
if (!manager.isActive()) return;
|
||||
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
if (entity instanceof Zombie z && z.isBaby()) return;
|
||||
|
||||
if (random.nextInt(100) < 20) {
|
||||
spawnBoss(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity instanceof Creeper creeper) {
|
||||
creeper.setExplosionRadius(6);
|
||||
if (random.nextInt(100) < 30) {
|
||||
creeper.setPowered(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.getAttribute(Attribute.MAX_HEALTH) != null) {
|
||||
entity.getAttribute(Attribute.MAX_HEALTH).setBaseValue(
|
||||
entity.getAttribute(Attribute.MAX_HEALTH).getBaseValue() * 1.5
|
||||
);
|
||||
entity.setHealth(entity.getAttribute(Attribute.MAX_HEALTH).getBaseValue());
|
||||
}
|
||||
|
||||
if (entity.getAttribute(Attribute.ATTACK_DAMAGE) != null) {
|
||||
entity.getAttribute(Attribute.ATTACK_DAMAGE).setBaseValue(
|
||||
entity.getAttribute(Attribute.ATTACK_DAMAGE).getBaseValue() + 2
|
||||
);
|
||||
}
|
||||
|
||||
if (entity.getAttribute(Attribute.MOVEMENT_SPEED) != null) {
|
||||
entity.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(
|
||||
entity.getAttribute(Attribute.MOVEMENT_SPEED).getBaseValue() * 1.2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnBoss(LivingEntity entity) {
|
||||
if (!(entity instanceof Zombie || entity instanceof Skeleton || entity instanceof Husk || entity instanceof Drowned))
|
||||
return;
|
||||
|
||||
entity.getPersistentDataContainer().set(
|
||||
new NamespacedKey(plugin, "bloodmoon_boss"),
|
||||
PersistentDataType.BYTE,
|
||||
(byte) 1
|
||||
);
|
||||
|
||||
entity.setCustomName(ChatColor.DARK_RED + "Blood Knight");
|
||||
entity.setCustomNameVisible(true);
|
||||
|
||||
if (entity instanceof Zombie || entity instanceof Husk || entity instanceof Drowned) {
|
||||
entity.getEquipment().setHelmet(createItem(Material.DIAMOND_HELMET, "Blood Helmet"));
|
||||
entity.getEquipment().setChestplate(createItem(Material.DIAMOND_CHESTPLATE, "Blood Chestplate"));
|
||||
entity.getEquipment().setLeggings(createItem(Material.DIAMOND_LEGGINGS, "Blood Leggings"));
|
||||
entity.getEquipment().setBoots(createItem(Material.DIAMOND_BOOTS, "Blood Boots"));
|
||||
entity.getEquipment().setItemInMainHand(createItem(Material.DIAMOND_SWORD, "Blood Blade"));
|
||||
} else if (entity instanceof Skeleton) {
|
||||
entity.getEquipment().setHelmet(createItem(Material.DIAMOND_HELMET, "Blood Helmet"));
|
||||
entity.getEquipment().setChestplate(createItem(Material.NETHERITE_CHESTPLATE, "Blood Chestplate"));
|
||||
entity.getEquipment().setItemInMainHand(createItem(Material.BOW, "Blood Bow"));
|
||||
}
|
||||
|
||||
entity.getEquipment().setHelmetDropChance(0.001f);
|
||||
entity.getEquipment().setChestplateDropChance(0.001f);
|
||||
entity.getEquipment().setLeggingsDropChance(0.001f);
|
||||
entity.getEquipment().setBootsDropChance(0.001f);
|
||||
entity.getEquipment().setItemInMainHandDropChance(0.001f);
|
||||
|
||||
if (entity.getAttribute(Attribute.MAX_HEALTH) != null) {
|
||||
entity.getAttribute(Attribute.MAX_HEALTH).setBaseValue(80);
|
||||
entity.setHealth(80);
|
||||
}
|
||||
if (entity.getAttribute(Attribute.MAX_HEALTH) != null) {
|
||||
entity.getAttribute(Attribute.MAX_HEALTH).setBaseValue(12);
|
||||
}
|
||||
if (entity.getAttribute(Attribute.MOVEMENT_SPEED) != null) {
|
||||
entity.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.35);
|
||||
}
|
||||
|
||||
startParticleEffect(entity);
|
||||
}
|
||||
|
||||
private ItemStack createItem(Material material, String name) {
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(ChatColor.RED + name);
|
||||
meta.addEnchant(Enchantment.PROTECTION, 2, true);
|
||||
meta.addEnchant(Enchantment.UNBREAKING, 3, true);
|
||||
meta.addEnchant(Enchantment.SHARPNESS, 2, true);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private void startParticleEffect(LivingEntity entity) {
|
||||
new BukkitRunnable() {
|
||||
int ticks = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (entity == null || entity.isDead() || !entity.isValid()) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
entity.getWorld().spawnParticle(
|
||||
Particle.DUST,
|
||||
entity.getLocation().add(0, 1, 0),
|
||||
8,
|
||||
0.3, 0.5, 0.3,
|
||||
0,
|
||||
new Particle.DustOptions(Color.RED, 1.5f)
|
||||
);
|
||||
|
||||
if ((ticks += 5) > 20 * 300) cancel();
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 5L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package de.winniepat.SMPPlugin.bloodmoon;
|
||||
|
||||
import de.winniepat.SMPPlugin.blackmarket.BlackMarketManager;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class BloodmoonManager {
|
||||
private final JavaPlugin plugin;
|
||||
private boolean active = false;
|
||||
private BossBar bloodmoonBar;
|
||||
private int durationTicks = 20 * 60 * 8;
|
||||
private int ticksElapsed = 0;
|
||||
private BukkitRunnable task;
|
||||
|
||||
public BloodmoonManager(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void startBloodmoon() {
|
||||
if (active) return;
|
||||
active = true;
|
||||
Bukkit.broadcastMessage(ChatColor.DARK_RED + "☠ The Bloodmoon has risen... Be wary!");
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
player.sendTitle(ChatColor.RED + "Bloodmoon", ChatColor.DARK_RED + "Mobs are stronger tonight!", 10, 100, 20);
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.NIGHT_VISION, 20 * 60 * 8, 1, false, false, false));
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_WITHER_SPAWN, 1.0f, 1.0f);
|
||||
|
||||
player.spawnParticle(Particle.DUST, player.getLocation().add(0, 10, 0), 100,5, 5, 5, 0, new Particle.DustOptions(Color.RED, 2));
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTaskTimer(plugin, () -> {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (active) {
|
||||
player.spawnParticle(Particle.DUST, player.getLocation().add(
|
||||
Math.random() * 10 - 5, Math.random() * 5, Math.random() * 10 - 5),
|
||||
5, 0, 0, 0, 0, new Particle.DustOptions(Color.RED, 1));
|
||||
}
|
||||
}
|
||||
}, 0L, 1L);
|
||||
|
||||
bloodmoonBar = Bukkit.createBossBar("§4🌕 Bloodmoon Night", BarColor.RED, BarStyle.SEGMENTED_10);
|
||||
bloodmoonBar.setProgress(1.0);
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
bloodmoonBar.addPlayer(player);
|
||||
}
|
||||
|
||||
task = new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ticksElapsed += 20;
|
||||
double progress = Math.max(0, 1.0 - (double) ticksElapsed / durationTicks);
|
||||
bloodmoonBar.setProgress(progress);
|
||||
|
||||
if (ticksElapsed >= durationTicks) {
|
||||
endBloodmoon();
|
||||
}
|
||||
}
|
||||
};
|
||||
task.runTaskTimer(plugin, 20L, 20L);
|
||||
|
||||
}
|
||||
|
||||
public void endBloodmoon() {
|
||||
if (!active) return;
|
||||
active = false;
|
||||
|
||||
Bukkit.broadcastMessage(ChatColor.GRAY + "☀ The Bloodmoon has ended. It's safe again.");
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
player.sendTitle(ChatColor.YELLOW + "☀", ChatColor.GREEN + "Bloodmoon ended!", 10, 100, 20);
|
||||
}
|
||||
NamespacedKey key = new NamespacedKey(plugin, "bloodmoon_boss");
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (LivingEntity entity : world.getLivingEntities()) {
|
||||
if (entity.getPersistentDataContainer().has(key, PersistentDataType.BYTE)) {
|
||||
entity.getWorld().playSound(entity.getLocation(), Sound.ENTITY_WITHER_DEATH, 1f, 0.5f);
|
||||
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (new Random().nextInt(100) < 5) {
|
||||
//new BlackMarketManager(plugin).spawnMarket();
|
||||
}
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
|
||||
if (bloodmoonBar != null) {
|
||||
bloodmoonBar.removeAll();
|
||||
bloodmoonBar = null;
|
||||
}
|
||||
|
||||
ticksElapsed = 0;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package de.winniepat.SMPPlugin.bloodmoon;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class BloodmoonTask {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final BloodmoonManager manager;
|
||||
|
||||
private boolean checkedThisNight = false;
|
||||
|
||||
public BloodmoonTask(JavaPlugin plugin, BloodmoonManager manager) {
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
long time = world.getTime();
|
||||
if (time >= 13000 && time <= 13100) {
|
||||
if (!checkedThisNight) {
|
||||
checkedThisNight = true;
|
||||
|
||||
if (new Random().nextInt(100) < 5) {
|
||||
manager.startBloodmoon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (time >= 0 && time < 1000) {
|
||||
if (manager.isActive()) {
|
||||
manager.endBloodmoon();
|
||||
}
|
||||
checkedThisNight = false;
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 100L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package de.winniepat.SMPPlugin.commands;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class CodingCommand implements CommandExecutor {
|
||||
|
||||
private Plugin plugin;
|
||||
private SMPPlugin smpPlugin;
|
||||
private final Map<UUID, ArmorStand> codingStands = new HashMap<>();
|
||||
private final Map<UUID, BukkitRunnable> animationTasks = new HashMap<>();
|
||||
|
||||
private static final String[] COLORS = {
|
||||
"#FF0000", "#FF4000", "#FF8000", "#FFBF00", "#FFFF00",
|
||||
"#BFFF00", "#80FF00", "#40FF00", "#00FF00", "#00FF40",
|
||||
"#00FF80", "#00FFBF", "#00FFFF", "#00BFFF", "#0080FF",
|
||||
"#0040FF", "#0000FF", "#4000FF", "#8000FF", "#BF00FF",
|
||||
"#FF00FF"
|
||||
};
|
||||
|
||||
private final String[] frames = new String[21];
|
||||
|
||||
public CodingCommand(Plugin plugin, SMPPlugin smpPlugin) {
|
||||
this.plugin = plugin;
|
||||
this.smpPlugin = smpPlugin;
|
||||
|
||||
char[] glyphs = {
|
||||
'\uE014', '\uE015', '\uE016', '\uE017', '\uE018',
|
||||
'\uE019', '\uE020', '\uE021', '\uE022', '\uE023',
|
||||
'\uE024', '\uE025', '\uE026', '\uE035', '\uE028',
|
||||
'\uE029', '\uE030', '\uE031', '\uE032', '\uE033',
|
||||
'\uE034'
|
||||
};
|
||||
for (int i = 0; i < 21; i++) {
|
||||
frames[i] = glyphs[i] + " " + rgb("Coding...", COLORS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) return false;
|
||||
|
||||
if (args.length != 1 || (!args[0].equalsIgnoreCase("on") && !args[0].equalsIgnoreCase("off"))) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.coding.usage", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
if (args[0].equalsIgnoreCase("on")) {
|
||||
if (codingStands.containsKey(uuid)) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.coding.already", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
Location loc = player.getLocation().add(0, 2.2, 0);
|
||||
ArmorStand stand = player.getWorld().spawn(loc, ArmorStand.class);
|
||||
stand.setVisible(false);
|
||||
stand.setCustomNameVisible(true);
|
||||
stand.setGravity(false);
|
||||
stand.setMarker(true);
|
||||
|
||||
codingStands.put(uuid, stand);
|
||||
|
||||
BukkitRunnable task = new BukkitRunnable() {
|
||||
int tick = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!stand.isValid() || !player.isOnline()) {
|
||||
this.cancel();
|
||||
if (stand.isValid()) stand.remove();
|
||||
codingStands.remove(uuid);
|
||||
animationTasks.remove(uuid);
|
||||
return;
|
||||
}
|
||||
|
||||
stand.teleport(player.getLocation().add(0, 2.2, 0));
|
||||
stand.setCustomName(frames[tick % frames.length]);
|
||||
tick++;
|
||||
}
|
||||
};
|
||||
task.runTaskTimer(plugin, 0L, 4L);
|
||||
|
||||
animationTasks.put(uuid, task);
|
||||
sender.sendMessage(smpPlugin.getMessage("command.coding.marked", Map.of("player", sender.getName())));
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("off")) {
|
||||
if (animationTasks.containsKey(uuid)) {
|
||||
animationTasks.get(uuid).cancel();
|
||||
animationTasks.remove(uuid);
|
||||
}
|
||||
|
||||
if (codingStands.containsKey(uuid)) {
|
||||
ArmorStand stand = codingStands.remove(uuid);
|
||||
if (stand != null && !stand.isDead()) {
|
||||
stand.remove();
|
||||
}
|
||||
player.sendMessage("§aYou are no longer marked as coding.");
|
||||
sender.sendMessage(smpPlugin.getMessage("command.coding.unmarked", Map.of("player", sender.getName())));
|
||||
} else {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.coding.error", Map.of("player", sender.getName())));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String rgb(String text, String hexColor) {
|
||||
StringBuilder out = new StringBuilder("§x");
|
||||
for (char c : hexColor.substring(1).toCharArray()) {
|
||||
out.append('§').append(c);
|
||||
}
|
||||
return out + text;
|
||||
}
|
||||
|
||||
public Map<UUID, ArmorStand> getCodingStands() {
|
||||
return codingStands;
|
||||
}
|
||||
|
||||
public Map<UUID, BukkitRunnable> getAnimationTasks() {
|
||||
return animationTasks;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.winniepat.SMPPlugin.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ShopCommand implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String @NotNull [] args) {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),"minecraft:tp " + sender.getName() + " -696 64 -898 0.0 -7.0");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package de.winniepat.SMPPlugin.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class SpawnCommand implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),"minecraft:tp " + sender.getName() + " -635.5 68 -837.5 -90 0");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package de.winniepat.SMPPlugin.commands;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class TrashCommand implements CommandExecutor, Listener {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public TrashCommand(JavaPlugin plugin, SMPPlugin smpPlugin) {
|
||||
this.plugin = plugin;
|
||||
this.smpPlugin = smpPlugin;
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player p)) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.error.no_player", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
Inventory trash = Bukkit.createInventory(p, 27, "§cTrash");
|
||||
p.openInventory(trash);
|
||||
return true;
|
||||
}
|
||||
|
||||
@org.bukkit.event.EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent event) {
|
||||
if (event.getView().getTitle().equals("§cTrash")) {
|
||||
event.getInventory().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package de.winniepat.SMPPlugin.listeners;
|
||||
|
||||
import de.winniepat.SMPPlugin.commands.CodingCommand;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class CodingCleanupListener implements Listener {
|
||||
|
||||
private final CodingCommand codingCommand;
|
||||
|
||||
public CodingCleanupListener(CodingCommand codingCommand) {
|
||||
this.codingCommand = codingCommand;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
UUID uuid = event.getPlayer().getUniqueId();
|
||||
|
||||
if (codingCommand.getAnimationTasks().containsKey(uuid)) {
|
||||
codingCommand.getAnimationTasks().get(uuid).cancel();
|
||||
codingCommand.getAnimationTasks().remove(uuid);
|
||||
}
|
||||
|
||||
if (codingCommand.getCodingStands().containsKey(uuid)) {
|
||||
ArmorStand stand = codingCommand.getCodingStands().remove(uuid);
|
||||
if (stand != null && !stand.isDead()) {
|
||||
stand.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package de.winniepat.SMPPlugin.listeners;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BookMeta;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.util.*;
|
||||
|
||||
public class FirstPlayerJoinTracker implements Listener {
|
||||
|
||||
String longText = "Einst lebten alle friedlich beisammen in der Stadt Lunaris. " +
|
||||
"Doch eines Abends, als der Blutmond über die Stadt zog, wurde Lunaris von unzähligen Monstern attackiert und fast vollständig zerstört. " +
|
||||
"Die tapferen Bewohner versuchten mit aller Kraft der Attacke standzuhalten – doch es war vergebens. Die Monster waren einfach zu stark, und es waren zu viele. " +
|
||||
"Die Stadtbewohner konnten nichts ausrichten. Alles, was blieb, war das Rathaus am Marktplatz und ein paar Überreste der Häuser… " +
|
||||
"Doch die Hoffnung besteht, dass die Stadt Lunaris bald wieder in vollem Glanz erstrahlen kann und genauso belebt wird, wie sie es einst war.";
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final File file;
|
||||
private final Gson gson = new Gson();
|
||||
private final Set<UUID> joinedPlayers = new HashSet<>();
|
||||
|
||||
public FirstPlayerJoinTracker(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.file = new File(plugin.getDataFolder(), "players.json");
|
||||
load();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
UUID uuid = event.getPlayer().getUniqueId();
|
||||
if (joinedPlayers.add(uuid)) {
|
||||
|
||||
ItemStack book = new ItemStack(Material.WRITTEN_BOOK);
|
||||
BookMeta bookMeta = (BookMeta) book.getItemMeta();
|
||||
|
||||
bookMeta.setAuthor("Unknown Stranger");
|
||||
|
||||
try {
|
||||
bookMeta.getClass().getMethod("setTitle", String.class).invoke(bookMeta, "Willkommen in Lunaris");
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
List<String> pages = splitIntoPages(longText, 250);
|
||||
bookMeta.setPages(pages);
|
||||
|
||||
book.setItemMeta(bookMeta);
|
||||
|
||||
event.getPlayer().getInventory().addItem(book);
|
||||
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
public void load() {
|
||||
if (!file.exists()) {
|
||||
plugin.getDataFolder().mkdirs();
|
||||
save();
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
Set<String> loaded = gson.fromJson(reader, new TypeToken<Set<String>>() {}.getType());
|
||||
if (loaded != null) {
|
||||
for (String id : loaded) {
|
||||
joinedPlayers.add(UUID.fromString(id));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to load players.json: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
Set<String> ids = new HashSet<>();
|
||||
for (UUID uuid : joinedPlayers) {
|
||||
ids.add(uuid.toString());
|
||||
}
|
||||
gson.toJson(ids, writer);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to save players.json: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> splitIntoPages(String text, int maxLength) {
|
||||
List<String> pages = new ArrayList<>();
|
||||
int index = 0;
|
||||
while (index < text.length()) {
|
||||
int endIndex = Math.min(index + maxLength, text.length());
|
||||
pages.add(text.substring(index, endIndex));
|
||||
index = endIndex;
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.winniepat.SMPPlugin.listeners;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class QuitLightningListener implements Listener {
|
||||
@EventHandler
|
||||
public void playerQuitListener(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (player.isOp()) {
|
||||
player.getWorld().strikeLightningEffect(player.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package de.winniepat.SMPPlugin.polls;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Poll {
|
||||
private final String question;
|
||||
private final List<String> options;
|
||||
private final Map<UUID, String> votes = new HashMap<>();
|
||||
private final String creator;
|
||||
private final long endTimeMillis;
|
||||
|
||||
public Poll(String question, List<String> options, String creator, long durationSeconds) {
|
||||
this.question = question;
|
||||
this.options = options;
|
||||
this.creator = creator;
|
||||
this.endTimeMillis = System.currentTimeMillis() + (durationSeconds * 1000);
|
||||
}
|
||||
|
||||
public Poll(String question, List<String> options, String creator, long endTimeMillis, Map<String, Integer> savedVotes) {
|
||||
this.question = question;
|
||||
this.options = options;
|
||||
this.creator = creator;
|
||||
this.endTimeMillis = endTimeMillis;
|
||||
for (Map.Entry<String, Integer> entry : savedVotes.entrySet()) {
|
||||
for (int i = 0; i < entry.getValue(); i++) {
|
||||
votes.put(UUID.randomUUID(), entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getQuestion() {
|
||||
return question;
|
||||
}
|
||||
|
||||
public List<String> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public String getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public long getEndTimeMillis() {
|
||||
return endTimeMillis;
|
||||
}
|
||||
|
||||
public boolean vote(UUID player, String option) {
|
||||
if (!options.contains(option) || isExpired()) return false;
|
||||
votes.put(player, option);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getResults() {
|
||||
Map<String, Integer> results = new HashMap<>();
|
||||
for (String option : options) {
|
||||
results.put(option, 0);
|
||||
}
|
||||
for (String vote : votes.values()) {
|
||||
results.put(vote, results.get(vote) + 1);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public boolean hasVoted(UUID player) {
|
||||
return votes.containsKey(player);
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return System.currentTimeMillis() > endTimeMillis;
|
||||
}
|
||||
|
||||
public long getRemainingTimeSeconds() {
|
||||
long remaining = endTimeMillis - System.currentTimeMillis();
|
||||
return Math.max(remaining / 1000, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package de.winniepat.SMPPlugin.polls;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class PollCommand implements CommandExecutor {
|
||||
|
||||
private final PollManager manager;
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public PollCommand(PollManager manager, SMPPlugin smpPlugin) {
|
||||
this.manager = manager;
|
||||
this.smpPlugin = smpPlugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.poll.usage", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(smpPlugin.getMessage("error.no_player", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("poll.start")) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.error.no_permission", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (manager.hasActivePoll()) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.poll.already_active", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args[0].startsWith("\"") && args[0].endsWith("\"")) {
|
||||
String question = args[0].substring(1, args[0].length() - 1);
|
||||
long duration;
|
||||
try {
|
||||
duration = Long.parseLong(args[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.poll.invalid_time", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
List<String> options = Arrays.asList(Arrays.copyOfRange(args, 2, args.length));
|
||||
manager.startPoll(question, options, player.getName(), duration);
|
||||
Bukkit.broadcastMessage("§6Poll §e" + question + " §7(started " + duration + "s)");
|
||||
|
||||
for (Player online : Bukkit.getOnlinePlayers()) {
|
||||
online.sendTitle(
|
||||
"§6New Poll!",
|
||||
"§7Use §e/vote §7to vote | " + duration + " Seconds left",
|
||||
10, 60, 10
|
||||
);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.poll.usage", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package de.winniepat.SMPPlugin.polls;
|
||||
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class PollManager {
|
||||
private Poll currentPoll = null;
|
||||
private final File dataFile;
|
||||
private final YamlConfiguration data;
|
||||
private final List<Poll> expiredPolls = new ArrayList<>();
|
||||
|
||||
public PollManager(File dataFile) {
|
||||
this.dataFile = dataFile;
|
||||
this.data = YamlConfiguration.loadConfiguration(dataFile);
|
||||
load();
|
||||
}
|
||||
|
||||
public void startPoll(String question, List<String> options, String creator, long durationSeconds) {
|
||||
if (currentPoll != null && currentPoll.isExpired()) {
|
||||
expiredPolls.add(currentPoll);
|
||||
}
|
||||
this.currentPoll = new Poll(question, options, creator, durationSeconds);
|
||||
save();
|
||||
}
|
||||
|
||||
public Poll getCurrentPoll() {
|
||||
return currentPoll;
|
||||
}
|
||||
|
||||
public void clearPoll() {
|
||||
if (currentPoll != null) {
|
||||
expiredPolls.add(currentPoll);
|
||||
}
|
||||
this.currentPoll = null;
|
||||
data.set("poll", null);
|
||||
save();
|
||||
}
|
||||
|
||||
public boolean hasActivePoll() {
|
||||
return currentPoll != null && !currentPoll.isExpired();
|
||||
}
|
||||
|
||||
public List<Poll> getExpiredPolls() {
|
||||
return expiredPolls;
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if (currentPoll == null) return;
|
||||
data.set("poll.question", currentPoll.getQuestion());
|
||||
data.set("poll.options", currentPoll.getOptions());
|
||||
data.set("poll.creator", currentPoll.getCreator());
|
||||
data.set("poll.endTime", currentPoll.getEndTimeMillis());
|
||||
data.set("poll.results", currentPoll.getResults());
|
||||
try {
|
||||
data.save(dataFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void load() {
|
||||
if (!data.contains("poll")) return;
|
||||
String question = data.getString("poll.question");
|
||||
List<String> options = data.getStringList("poll.options");
|
||||
String creator = data.getString("poll.creator");
|
||||
long endTime = data.getLong("poll.endTime");
|
||||
Map<String, Integer> results = new HashMap<>();
|
||||
if (data.contains("poll.results")) {
|
||||
for (String key : data.getConfigurationSection("poll.results").getKeys(false)) {
|
||||
results.put(key, data.getInt("poll.results." + key));
|
||||
}
|
||||
}
|
||||
long duration = (endTime - System.currentTimeMillis()) / 1000;
|
||||
if (duration > 0) {
|
||||
this.currentPoll = new Poll(question, options, creator, duration);
|
||||
} else {
|
||||
this.currentPoll = new Poll(question, options, creator, endTime, results);
|
||||
this.expiredPolls.add(currentPoll);
|
||||
this.currentPoll = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package de.winniepat.SMPPlugin.polls;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PollResultGUI {
|
||||
|
||||
private final PollManager manager;
|
||||
|
||||
public PollResultGUI(PollManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void openResultsGUI(Player player) {
|
||||
int size = 9 * 3;
|
||||
Inventory inv = Bukkit.createInventory(null, size, "§6Poll-Results");
|
||||
|
||||
int slot = 0;
|
||||
|
||||
Poll current = manager.getCurrentPoll();
|
||||
if (current != null) {
|
||||
ItemStack item = new ItemStack(Material.WRITABLE_BOOK);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("§aActive: " + current.getQuestion());
|
||||
meta.setLore(current.getResults().entrySet().stream()
|
||||
.map(e -> "§7" + e.getKey() + ": §e" + e.getValue())
|
||||
.toList());
|
||||
item.setItemMeta(meta);
|
||||
inv.setItem(slot++, item);
|
||||
}
|
||||
|
||||
List<Poll> pastPolls = manager.getExpiredPolls();
|
||||
for (Poll past : pastPolls) {
|
||||
ItemStack item = new ItemStack(Material.BOOK);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("§7Ended: " + past.getQuestion());
|
||||
meta.setLore(past.getResults().entrySet().stream()
|
||||
.map(e -> "§7" + e.getKey() + ": §e" + e.getValue())
|
||||
.toList());
|
||||
item.setItemMeta(meta);
|
||||
inv.setItem(slot++, item);
|
||||
if (slot >= size) break;
|
||||
}
|
||||
|
||||
player.openInventory(inv);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package de.winniepat.SMPPlugin.polls;
|
||||
|
||||
import com.google.gson.annotations.Since;
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PollVoteGUI implements Listener {
|
||||
|
||||
private final PollManager manager;
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public PollVoteGUI(PollManager manager, SMPPlugin smpPlugin) {
|
||||
this.smpPlugin = smpPlugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void openVoteGUI(Player player) {
|
||||
if (!manager.hasActivePoll()) {
|
||||
player.sendMessage("§cNo active Poll.");
|
||||
return;
|
||||
}
|
||||
|
||||
Poll poll = manager.getCurrentPoll();
|
||||
Inventory inv = Bukkit.createInventory(null, 9, "§6Vote: " + poll.getQuestion());
|
||||
|
||||
int i = 0;
|
||||
for (String option : poll.getOptions()) {
|
||||
ItemStack item = new ItemStack(Material.PAPER);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("§b" + option);
|
||||
meta.setLore(List.of("§7Remaining Time: §e" + poll.getRemainingTimeSeconds() + " Seconds"));
|
||||
item.setItemMeta(meta);
|
||||
inv.setItem(i++, item);
|
||||
}
|
||||
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getWhoClicked() instanceof Player player)) return;
|
||||
if (event.getView().getTitle().startsWith("§6Vote:")) {
|
||||
event.setCancelled(true);
|
||||
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) return;
|
||||
|
||||
String vote = clicked.getItemMeta().getDisplayName().replace("§b", "");
|
||||
Poll poll = manager.getCurrentPoll();
|
||||
if (poll != null && !poll.hasVoted(player.getUniqueId())) {
|
||||
poll.vote(player.getUniqueId(), vote);
|
||||
player.sendMessage("§aYour vote for §e" + vote + " §awas registered.");
|
||||
player.closeInventory();
|
||||
} else {
|
||||
player.sendMessage(smpPlugin.getMessage("command.error.no_permission", Map.of("player", player.getName())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package de.winniepat.SMPPlugin.report;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReportActionGUI {
|
||||
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public ReportActionGUI(SMPPlugin smpPlugin) {
|
||||
this.smpPlugin = smpPlugin;
|
||||
}
|
||||
|
||||
public static void open(JavaPlugin plugin, ReportDatabase db, Player p, String reportId, SMPPlugin smpPlugin) {
|
||||
Map<String, String> report = db.getReportById(reportId);
|
||||
if (report == null) {
|
||||
p.sendMessage(smpPlugin.getMessage("command.reportactiongui.not_found", Map.of("player", p.getName())));
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory gui = Bukkit.createInventory(p, 27, "§eActions for the report #" + reportId);
|
||||
|
||||
ItemStack info = new ItemStack(Material.BOOK);
|
||||
ItemMeta im = info.getItemMeta();
|
||||
im.setDisplayName("§bReport Details");
|
||||
im.setLore(List.of(
|
||||
"§7Victim: §f" + report.get("reported"),
|
||||
"§7By: §a" + report.get("reporter"),
|
||||
"§7Reason: §f" + report.get("reason"),
|
||||
"§8ID: " + reportId
|
||||
));
|
||||
info.setItemMeta(im);
|
||||
gui.setItem(11, info);
|
||||
|
||||
ItemStack delete = new ItemStack(Material.BARRIER);
|
||||
ItemMeta dm = delete.getItemMeta();
|
||||
dm.setDisplayName("§cReport löschen");
|
||||
delete.setItemMeta(dm);
|
||||
gui.setItem(13, delete);
|
||||
|
||||
ItemStack ban = new ItemStack(Material.IRON_SWORD);
|
||||
ItemMeta bm = ban.getItemMeta();
|
||||
bm.setDisplayName("§4Ban Victim");
|
||||
bm.setLore(List.of("§7Reason: §cSecurity Ban"));
|
||||
ban.setItemMeta(bm);
|
||||
gui.setItem(15, ban);
|
||||
|
||||
p.openInventory(gui);
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new org.bukkit.event.Listener() {
|
||||
@EventHandler
|
||||
public void onClick(InventoryClickEvent e) {
|
||||
if (!e.getView().getTitle().equals("§eActions for report #" + reportId)) return;
|
||||
if (!(e.getWhoClicked() instanceof Player clicker)) return;
|
||||
|
||||
ItemStack clicked = e.getCurrentItem();
|
||||
if (clicked == null || clicked.getType() == Material.AIR) return;
|
||||
|
||||
if (clicked.getType() == Material.BARRIER) {
|
||||
db.deleteReportById(reportId);
|
||||
clicker.closeInventory();
|
||||
clicker.playSound(clicker.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 0.5f);
|
||||
clicker.sendMessage(smpPlugin.getMessage("reportactiongui.successful_delete", Map.of("player", clicker.getName())));
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
if (clicked.getType() == Material.IRON_SWORD) {
|
||||
String target = report.get("reported");
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
|
||||
"ban " + target + " Security Ban");
|
||||
clicker.closeInventory();
|
||||
clicker.sendMessage("§cPlayer was permanently banned.");
|
||||
clicker.sendMessage(smpPlugin.getMessage("reportactiongui.successful_ban", Map.of("player", clicker.getName())));
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}, plugin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package de.winniepat.SMPPlugin.report;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
public class ReportDatabase {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private Connection connection;
|
||||
|
||||
public ReportDatabase(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
connect();
|
||||
createTable();
|
||||
}
|
||||
|
||||
private void connect() {
|
||||
try {
|
||||
File folder = plugin.getDataFolder();
|
||||
if (!folder.exists()) folder.mkdirs();
|
||||
|
||||
String url = "jdbc:sqlite:" + folder.getAbsolutePath() + "/reports.db";
|
||||
connection = DriverManager.getConnection(url);
|
||||
plugin.getLogger().info("Report database successfully connected.");
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Error while connecting to the database: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void createTable() {
|
||||
if (connection == null) return;
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS reports (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
reporter TEXT,
|
||||
reported TEXT,
|
||||
reason TEXT,
|
||||
timestamp TEXT
|
||||
);
|
||||
""");
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Error while crating the table: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void insertReport(String reporter, String reported, String reason) {
|
||||
if (connection == null) return;
|
||||
try (PreparedStatement ps = connection.prepareStatement(
|
||||
"INSERT INTO reports (reporter, reported, reason, timestamp) VALUES (?, ?, ?, datetime('now'))")) {
|
||||
ps.setString(1, reporter);
|
||||
ps.setString(2, reported);
|
||||
ps.setString(3, reason);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Error while saving the report: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public List<Map<String, String>> getAllReports() {
|
||||
List<Map<String, String>> reports = new ArrayList<>();
|
||||
if (connection == null) return reports;
|
||||
|
||||
try (Statement stmt = connection.createStatement();
|
||||
ResultSet rs = stmt.executeQuery("SELECT * FROM reports ORDER BY id DESC")) {
|
||||
while (rs.next()) {
|
||||
Map<String, String> entry = new HashMap<>();
|
||||
entry.put("id", rs.getString("id"));
|
||||
entry.put("reporter", rs.getString("reporter"));
|
||||
entry.put("reported", rs.getString("reported"));
|
||||
entry.put("reason", rs.getString("reason"));
|
||||
entry.put("timestamp", rs.getString("timestamp"));
|
||||
reports.add(entry);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Error while loading the reports: " + e.getMessage());
|
||||
}
|
||||
return reports;
|
||||
}
|
||||
|
||||
public Map<String, String> getReportById(String id) {
|
||||
if (connection == null) return null;
|
||||
|
||||
try (PreparedStatement ps = connection.prepareStatement("SELECT * FROM reports WHERE id = ?")) {
|
||||
ps.setString(1, id);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
Map<String, String> r = new HashMap<>();
|
||||
r.put("id", rs.getString("id"));
|
||||
r.put("reporter", rs.getString("reporter"));
|
||||
r.put("reported", rs.getString("reported"));
|
||||
r.put("reason", rs.getString("reason"));
|
||||
r.put("timestamp", rs.getString("timestamp"));
|
||||
return r;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Fehler beim Laden Report ID " + id + ": " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void deleteReportById(String id) {
|
||||
if (connection == null) return;
|
||||
|
||||
try (PreparedStatement ps = connection.prepareStatement("DELETE FROM reports WHERE id = ?")) {
|
||||
ps.setString(1, id);
|
||||
ps.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
plugin.getLogger().warning("Fehler beim Löschen Report ID " + id + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package de.winniepat.SMPPlugin.report.commands;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import de.winniepat.SMPPlugin.report.ReportDatabase;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ReportCommand implements CommandExecutor {
|
||||
|
||||
private final ReportDatabase db;
|
||||
private final SMPPlugin plugin;
|
||||
|
||||
public ReportCommand(ReportDatabase db, SMPPlugin plugin) {
|
||||
this.db = db;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String @NotNull [] args) {
|
||||
if (!(sender instanceof Player p)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
p.sendMessage(plugin.getMessage("command.report.usage", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
Player target = Bukkit.getPlayerExact(args[0]);
|
||||
if (target == null || target == p) {
|
||||
sender.sendMessage(plugin.getMessage("command.report.invalid_player", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
String reason = String.join(" ", args).substring(args[0].length()).trim();
|
||||
if (reason.length() < 4) {
|
||||
sender.sendMessage(plugin.getMessage("command.report.reason", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
db.insertReport(p.getName(), target.getName(), reason);
|
||||
sender.sendMessage(plugin.getMessage("command.report.success", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package de.winniepat.SMPPlugin.report.commands;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import de.winniepat.SMPPlugin.report.ReportActionGUI;
|
||||
import de.winniepat.SMPPlugin.report.ReportDatabase;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.*;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ReportsCommand implements CommandExecutor, Listener {
|
||||
|
||||
private final ReportDatabase db;
|
||||
private final SMPPlugin smpPlugin;
|
||||
private final JavaPlugin plugin;
|
||||
private final Map<UUID, Integer> pageMap = new HashMap<>();
|
||||
private final int REPORTS_PER_PAGE = 28;
|
||||
|
||||
public ReportsCommand(JavaPlugin plugin, ReportDatabase db, SMPPlugin smpPlugin) {
|
||||
this.plugin = plugin;
|
||||
this.smpPlugin = smpPlugin;
|
||||
this.db = db;
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||
if (!(sender instanceof Player p)) return true;
|
||||
if (!p.hasPermission("smputils.reports")) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.error.no_permission", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
pageMap.put(p.getUniqueId(), 0);
|
||||
openReportPage(p, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void openReportPage(Player p, int page) {
|
||||
List<Map<String, String>> reports = db.getAllReports();
|
||||
int totalPages = (int) Math.ceil((double) reports.size() / REPORTS_PER_PAGE);
|
||||
if (page < 0 || page >= totalPages) page = 0;
|
||||
|
||||
Inventory inv = Bukkit.createInventory(p, 54, "§cAll Reports - Page " + (page + 1));
|
||||
|
||||
int start = page * REPORTS_PER_PAGE;
|
||||
int end = Math.min(start + REPORTS_PER_PAGE, reports.size());
|
||||
|
||||
for (int i = 10, index = start; index < end; index++, i++) {
|
||||
if ((i + 1) % 9 == 0) i += 2;
|
||||
Map<String, String> report = reports.get(index);
|
||||
ItemStack paper = new ItemStack(Material.PAPER);
|
||||
ItemMeta meta = paper.getItemMeta();
|
||||
meta.setDisplayName("§eVictim: §f" + report.get("reported"));
|
||||
meta.setLore(List.of(
|
||||
"§7By: §a" + report.get("reporter"),
|
||||
"§7Reason: §f" + report.get("reason"),
|
||||
"§8ID: " + report.get("id")
|
||||
));
|
||||
paper.setItemMeta(meta);
|
||||
inv.setItem(i, paper);
|
||||
}
|
||||
|
||||
if (page > 0) {
|
||||
ItemStack prev = new ItemStack(Material.ARROW);
|
||||
ItemMeta meta = prev.getItemMeta();
|
||||
meta.setDisplayName("§a⬅ Back");
|
||||
prev.setItemMeta(meta);
|
||||
inv.setItem(45, prev);
|
||||
}
|
||||
|
||||
if (page < totalPages - 1) {
|
||||
ItemStack next = new ItemStack(Material.ARROW);
|
||||
ItemMeta meta = next.getItemMeta();
|
||||
meta.setDisplayName("§a➡ Next Page");
|
||||
next.setItemMeta(meta);
|
||||
inv.setItem(53, next);
|
||||
}
|
||||
|
||||
p.openInventory(inv);
|
||||
pageMap.put(p.getUniqueId(), page);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClick(InventoryClickEvent e) {
|
||||
if (!(e.getWhoClicked() instanceof Player p)) return;
|
||||
String title = e.getView().getTitle();
|
||||
if (!title.startsWith("§cAll Reports - Page")) return;
|
||||
|
||||
e.setCancelled(true);
|
||||
ItemStack item = e.getCurrentItem();
|
||||
if (item == null || !item.hasItemMeta() || item.getType() == Material.AIR) return;
|
||||
|
||||
UUID uuid = p.getUniqueId();
|
||||
int currentPage = pageMap.getOrDefault(uuid, 0);
|
||||
|
||||
String name = item.getItemMeta().getDisplayName();
|
||||
if (name.equals("§a➡ Next Page")) {
|
||||
openReportPage(p, currentPage + 1);
|
||||
return;
|
||||
}
|
||||
if (name.equals("§a⬅ Back")) {
|
||||
openReportPage(p, currentPage - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
String idLine = item.getItemMeta().getLore().stream()
|
||||
.filter(l -> l.startsWith("§8ID: "))
|
||||
.findFirst().orElse(null);
|
||||
if (idLine == null) return;
|
||||
|
||||
String reportId = idLine.replace("§8ID: ", "");
|
||||
Bukkit.getScheduler().runTask(plugin, () -> ReportActionGUI.open(plugin, db, p, reportId, smpPlugin));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryDrag(InventoryDragEvent e) {
|
||||
if (!(e.getWhoClicked() instanceof Player p)) return;
|
||||
if (e.getView().getTitle().startsWith("§cAll Reports - Page")) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package de.winniepat.SMPPlugin.secrets;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.CommandBlock;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.ItemRarity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SecretButtonHandler implements Listener {
|
||||
private static final String WORLD = "world";
|
||||
private static final int A_X = -652, A_Y = 63, A_Z = -837;
|
||||
private static final int B_X = 0, B_Y = 0, B_Z = 0;
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onButtonPress(PlayerInteractEvent event) {
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
||||
if (event.getClickedBlock() == null) return;
|
||||
|
||||
Block block = event.getClickedBlock();
|
||||
Player player = event.getPlayer();
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
if (block.getType() != Material.STONE_BUTTON) return;
|
||||
|
||||
String world = block.getWorld().getName();
|
||||
int x = block.getX(), y = block.getY(), z = block.getZ();
|
||||
|
||||
if (!world.equals(WORLD)) return;
|
||||
|
||||
if (x == A_X && y == A_Y && z == A_Z) {
|
||||
if (SecretsSQLite.hasClaimedSecret(uuid, "secretA")) {
|
||||
player.sendMessage("§cYou've already claimed this Secret!");
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack secret1 = new ItemStack(Material.SPORE_BLOSSOM);
|
||||
ItemMeta secret1meta = secret1.getItemMeta();
|
||||
secret1meta.setItemName("Prinzessinnen-Enzian");
|
||||
secret1meta.addEnchant(Enchantment.SMITE, 5, false);
|
||||
secret1meta.addEnchant(Enchantment.LOOTING, 3, false);
|
||||
secret1meta.addEnchant(Enchantment.UNBREAKING, 3, false);
|
||||
secret1meta.addEnchant(Enchantment.MENDING, 1, false);
|
||||
secret1meta.setRarity(ItemRarity.EPIC);
|
||||
secret1.setItemMeta(secret1meta);
|
||||
|
||||
player.getInventory().addItem(new ItemStack(secret1));
|
||||
SecretsSQLite.markSecretClaimed(uuid, "secretA");
|
||||
player.sendMessage("§aYou claimed Secret myfcknmelody's secret!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (x == B_X && y == B_Y && z == B_Z) {
|
||||
if (SecretsSQLite.hasClaimedSecret(uuid, "secretB")) {
|
||||
player.sendMessage("§cYou've already claimed Secret B!");
|
||||
return;
|
||||
}
|
||||
player.getInventory().addItem(new ItemStack(Material.DIAMOND));
|
||||
SecretsSQLite.markSecretClaimed(uuid, "secretB");
|
||||
player.sendMessage("§bYou claimed Secret B!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package de.winniepat.SMPPlugin.secrets;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.*;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SecretsSQLite {
|
||||
private static Connection connection;
|
||||
|
||||
public static void initDatabase(JavaPlugin plugin) {
|
||||
try {
|
||||
File dbFile = new File(plugin.getDataFolder(), "data.db");
|
||||
dbFile.getParentFile().mkdirs();
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
|
||||
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.execute("""
|
||||
CREATE TABLE IF NOT EXISTS secrets (
|
||||
uuid TEXT PRIMARY KEY,
|
||||
secretA INTEGER DEFAULT 0,
|
||||
secretB INTEGER DEFAULT 0
|
||||
);
|
||||
""");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasClaimedSecret(UUID uuid, String secret) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("SELECT " + secret + " FROM secrets WHERE uuid = ?")) {
|
||||
stmt.setString(1, uuid.toString());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
return rs.next() && rs.getInt(secret) == 1;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void markSecretClaimed(UUID uuid, String secret) {
|
||||
try {
|
||||
// First ensure row exists
|
||||
try (PreparedStatement insert = connection.prepareStatement("INSERT OR IGNORE INTO secrets(uuid) VALUES (?)")) {
|
||||
insert.setString(1, uuid.toString());
|
||||
insert.executeUpdate();
|
||||
}
|
||||
|
||||
try (PreparedStatement update = connection.prepareStatement("UPDATE secrets SET " + secret + " = 1 WHERE uuid = ?")) {
|
||||
update.setString(1, uuid.toString());
|
||||
update.executeUpdate();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasClaimedBoth(UUID uuid) {
|
||||
return hasClaimedSecret(uuid, "secretA") && hasClaimedSecret(uuid, "secretB");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.winniepat.SMPPlugin.starter;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
public class MoveEvent implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
if (SMPPlugin.frozenPlayers.contains(event.getPlayer().getUniqueId())) {
|
||||
if (!event.getFrom().toVector().equals(event.getTo().toVector())) {
|
||||
event.setTo(event.getFrom());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package de.winniepat.SMPPlugin.starter;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public class StartCommand implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length == 1 && args[0].equalsIgnoreCase("start")) {
|
||||
Location spawn = new Location(Bukkit.getWorlds().get(0), 0, Bukkit.getWorlds().get(0).getHighestBlockYAt(0, 0) + 1, 0);
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (!player.isOp()) {
|
||||
player.teleport(spawn);
|
||||
SMPPlugin.frozenPlayers.add(player.getUniqueId());
|
||||
}
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
int countdown = 3;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (countdown > 0) {
|
||||
Bukkit.broadcastMessage(ChatColor.YELLOW + "Starts in " + countdown + "...");
|
||||
countdown--;
|
||||
} else {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
SMPPlugin.frozenPlayers.remove(player.getUniqueId());
|
||||
player.sendTitle(ChatColor.GREEN + "Have Fun", ChatColor.YELLOW + "-SMP-", 10, 40, 10);
|
||||
}
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(SMPPlugin.getInstance(), 0, 20);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.RED + "Usage: /smp start");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package de.winniepat.SMPPlugin.suggestions;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Suggestion {
|
||||
private final int id;
|
||||
private final UUID playerUuid;
|
||||
private final String playerName;
|
||||
private final String title;
|
||||
private final String content;
|
||||
private SuggestionStatus status;
|
||||
private final Instant timestamp;
|
||||
|
||||
public Suggestion(int id, UUID playerUuid, String playerName, String title, String content) {
|
||||
this.id = id;
|
||||
this.playerUuid = playerUuid;
|
||||
this.playerName = playerName;
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
this.status = SuggestionStatus.OPEN;
|
||||
this.timestamp = Instant.now();
|
||||
}
|
||||
|
||||
public int getId() { return id; }
|
||||
public UUID getPlayerUuid() { return playerUuid; }
|
||||
public String getPlayerName() { return playerName; }
|
||||
public String getTitle() { return title; }
|
||||
public String getContent() { return content; }
|
||||
public SuggestionStatus getStatus() { return status; }
|
||||
public void setStatus(SuggestionStatus status) { this.status = status; }
|
||||
public Instant getTimestamp() { return timestamp; }
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package de.winniepat.SMPPlugin.suggestions;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SuggestionGui implements Listener {
|
||||
|
||||
private final SuggestionManager manager;
|
||||
private final Map<UUID, Integer> pageMap = new HashMap<>();
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public SuggestionGui(SuggestionManager manager, SMPPlugin smpPlugin) {
|
||||
this.smpPlugin = smpPlugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void open(Player player, SuggestionStatus filter) {
|
||||
open(player, filter, pageMap.getOrDefault(player.getUniqueId(), 0));
|
||||
}
|
||||
|
||||
public void open(Player player, SuggestionStatus filter, int page) {
|
||||
List<Suggestion> suggestions = new ArrayList<>(manager.getAllSuggestions());
|
||||
if (filter != null) suggestions.removeIf(s -> s.getStatus() != filter);
|
||||
|
||||
int itemsPerPage = 45;
|
||||
int totalPages = (int) Math.ceil(suggestions.size() / (double) itemsPerPage);
|
||||
page = Math.max(0, Math.min(page, totalPages - 1));
|
||||
pageMap.put(player.getUniqueId(), page);
|
||||
|
||||
Inventory inv = Bukkit.createInventory(null, 54, "§8Suggestions §7Page " + (page + 1));
|
||||
|
||||
int start = page * itemsPerPage;
|
||||
int end = Math.min(start + itemsPerPage, suggestions.size());
|
||||
List<Suggestion> pageItems = suggestions.subList(start, end);
|
||||
|
||||
int i = 0;
|
||||
for (Suggestion s : pageItems) {
|
||||
ItemStack paper = new ItemStack(Material.PAPER);
|
||||
ItemMeta meta = paper.getItemMeta();
|
||||
meta.setDisplayName("§e[#" + s.getId() + "] §f" + s.getTitle());
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Von: §a" + s.getPlayerName());
|
||||
lore.add("§7Status: §b" + s.getStatus().name());
|
||||
lore.add("§8" + s.getContent());
|
||||
lore.add("§7» §dShift-Leftclick: review");
|
||||
lore.add("§7» §aLeftclick: accept");
|
||||
lore.add("§7» §cRightclick: deny");
|
||||
lore.add("§7» §eShift-Rightclick: delete");
|
||||
meta.setLore(lore);
|
||||
paper.setItemMeta(meta);
|
||||
inv.setItem(i++, paper);
|
||||
}
|
||||
|
||||
inv.setItem(45, createControlItem(Material.ARROW, "§7« Bacl", "page:prev"));
|
||||
inv.setItem(46, createFilterItem(Material.GREEN_WOOL, "§aAccepted", SuggestionStatus.ACCEPTED));
|
||||
inv.setItem(47, createFilterItem(Material.YELLOW_WOOL, "§eReview", SuggestionStatus.REVIEW));
|
||||
inv.setItem(48, createFilterItem(Material.RED_WOOL, "§cDenied", SuggestionStatus.REJECTED));
|
||||
inv.setItem(49, createFilterItem(Material.GRAY_WOOL, "§7Show All", SuggestionStatus.NONE));
|
||||
inv.setItem(53, createControlItem(Material.ARROW, "§7Next Page »", "page:next"));
|
||||
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
private ItemStack createFilterItem(Material mat, String name, SuggestionStatus status) {
|
||||
ItemStack item = new ItemStack(mat);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(name);
|
||||
if (status != null) meta.setLore(Collections.singletonList("filter:" + status.name()));
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createControlItem(Material mat, String name, String tag) {
|
||||
ItemStack item = new ItemStack(mat);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(name);
|
||||
meta.setLore(Collections.singletonList(tag));
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onClick(InventoryClickEvent e) {
|
||||
if (!e.getView().getTitle().startsWith("§8Suggestions")) return;
|
||||
e.setCancelled(true);
|
||||
ItemStack clicked = e.getCurrentItem();
|
||||
if (clicked == null || !clicked.hasItemMeta()) return;
|
||||
|
||||
Player p = (Player) e.getWhoClicked();
|
||||
ItemMeta meta = clicked.getItemMeta();
|
||||
String name = meta.getDisplayName();
|
||||
List<String> lore = meta.getLore();
|
||||
|
||||
if (lore == null || lore.isEmpty()) return;
|
||||
String tag = lore.get(0);
|
||||
|
||||
if (tag.startsWith("page:")) {
|
||||
int currentPage = pageMap.getOrDefault(p.getUniqueId(), 0);
|
||||
int newPage = tag.equals("page:next") ? currentPage + 1 : currentPage - 1;
|
||||
open(p, null, newPage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tag.startsWith("filter:")) {
|
||||
String statusName = tag.substring(7);
|
||||
SuggestionStatus status = SuggestionStatus.valueOf(statusName);
|
||||
open(p, status, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!name.startsWith("§e[#")) return;
|
||||
int id;
|
||||
try {
|
||||
id = Integer.parseInt(name.split("#")[1].split("]")[0]);
|
||||
} catch (Exception ex) {
|
||||
p.sendMessage(smpPlugin.getMessage("suggestiongui.processing_error", Map.of("player", p.getName())));
|
||||
return;
|
||||
}
|
||||
|
||||
Suggestion suggestion = manager.getSuggestionById(id);
|
||||
if (suggestion == null) {
|
||||
p.sendMessage("§cSuggestion not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.getClick()) {
|
||||
case LEFT -> {
|
||||
manager.updateStatus(id, SuggestionStatus.ACCEPTED);
|
||||
p.sendMessage("§aSuggestion §e#" + id + " §aaccepted.");
|
||||
}
|
||||
case RIGHT -> {
|
||||
manager.updateStatus(id, SuggestionStatus.REJECTED);
|
||||
p.sendMessage("§cSuggestion §e#" + id + " §cdenied.");
|
||||
}
|
||||
case SHIFT_RIGHT -> {
|
||||
manager.deleteSuggestion(id);
|
||||
p.sendMessage("§eSuggestion §7#" + id + " deleted.");
|
||||
}
|
||||
case SHIFT_LEFT -> {
|
||||
manager.updateStatus(id, SuggestionStatus.REVIEW);
|
||||
p.sendMessage("§aSuggestion §e#" + id + " §awill be reviewedd.");
|
||||
}
|
||||
}
|
||||
|
||||
open(p, null, pageMap.getOrDefault(p.getUniqueId(), 0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package de.winniepat.SMPPlugin.suggestions;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.*;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
|
||||
public class SuggestionManager {
|
||||
private final Connection connection;
|
||||
|
||||
public SuggestionManager(File file) throws SQLException {
|
||||
this.connection = DriverManager.getConnection("jdbc:sqlite:" + file.getAbsolutePath());
|
||||
createTable();
|
||||
}
|
||||
|
||||
private void createTable() throws SQLException {
|
||||
String sql = """
|
||||
CREATE TABLE IF NOT EXISTS suggestions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
uuid TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
timestamp TEXT NOT NULL
|
||||
)
|
||||
""";
|
||||
try (Statement stmt = connection.createStatement()) {
|
||||
stmt.execute(sql);
|
||||
}
|
||||
}
|
||||
|
||||
public Suggestion addSuggestion(UUID uuid, String name, String title, String content) {
|
||||
String sql = "INSERT INTO suggestions(uuid, name, title, content, status, timestamp) VALUES(?,?,?,?,?,?)";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||
stmt.setString(1, uuid.toString());
|
||||
stmt.setString(2, name);
|
||||
stmt.setString(3, title);
|
||||
stmt.setString(4, content);
|
||||
stmt.setString(5, SuggestionStatus.OPEN.name());
|
||||
stmt.setString(6, Instant.now().toString());
|
||||
stmt.executeUpdate();
|
||||
|
||||
ResultSet keys = stmt.getGeneratedKeys();
|
||||
if (keys.next()) {
|
||||
int id = keys.getInt(1);
|
||||
return new Suggestion(id, uuid, name, title, content);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Collection<Suggestion> getAllSuggestions() {
|
||||
List<Suggestion> list = new ArrayList<>();
|
||||
try (Statement stmt = connection.createStatement();
|
||||
ResultSet rs = stmt.executeQuery("SELECT * FROM suggestions")) {
|
||||
while (rs.next()) {
|
||||
int id = rs.getInt("id");
|
||||
UUID uuid = UUID.fromString(rs.getString("uuid"));
|
||||
String name = rs.getString("name");
|
||||
String title = rs.getString("title");
|
||||
String content = rs.getString("content");
|
||||
SuggestionStatus status = SuggestionStatus.valueOf(rs.getString("status"));
|
||||
Suggestion suggestion = new Suggestion(id, uuid, name, title, content);
|
||||
suggestion.setStatus(status);
|
||||
list.add(suggestion);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Suggestion getSuggestionById(int id) {
|
||||
String sql = "SELECT * FROM suggestions WHERE id = ?";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
stmt.setInt(1, id);
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
if (rs.next()) {
|
||||
UUID uuid = UUID.fromString(rs.getString("uuid"));
|
||||
String name = rs.getString("name");
|
||||
String title = rs.getString("title");
|
||||
String content = rs.getString("content");
|
||||
SuggestionStatus status = SuggestionStatus.valueOf(rs.getString("status"));
|
||||
Suggestion suggestion = new Suggestion(id, uuid, name, title, content);
|
||||
suggestion.setStatus(status);
|
||||
return suggestion;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateStatus(int id, SuggestionStatus status) {
|
||||
String sql = "UPDATE suggestions SET status = ? WHERE id = ?";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
stmt.setString(1, status.name());
|
||||
stmt.setInt(2, id);
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void deleteSuggestion(int id) {
|
||||
String sql = "DELETE FROM suggestions WHERE id = ?";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
stmt.setInt(1, id);
|
||||
stmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package de.winniepat.SMPPlugin.suggestions;
|
||||
|
||||
public enum SuggestionStatus {
|
||||
NONE,
|
||||
OPEN,
|
||||
ACCEPTED,
|
||||
REJECTED,
|
||||
REVIEW
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package de.winniepat.SMPPlugin.suggestions.commands;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import de.winniepat.SMPPlugin.suggestions.Suggestion;
|
||||
import de.winniepat.SMPPlugin.suggestions.SuggestionManager;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SuggestionCommand implements CommandExecutor {
|
||||
|
||||
private final SuggestionManager manager;
|
||||
private final SMPPlugin smpPlugin;
|
||||
private final Map<UUID, Long> cooldowns = new HashMap<>();
|
||||
private final long COOLDOWN_MILLIS = 60 * 60 * 1000;
|
||||
|
||||
private final File cooldownFile;
|
||||
private final YamlConfiguration cooldownData;
|
||||
|
||||
public SuggestionCommand(SuggestionManager manager, Plugin plugin, SMPPlugin smpPlugin) {
|
||||
this.manager = manager;
|
||||
this.smpPlugin = smpPlugin;
|
||||
|
||||
this.cooldownFile = new File(plugin.getDataFolder(), "suggestion_cooldowns.yml");
|
||||
if (!cooldownFile.exists()) {
|
||||
try {
|
||||
cooldownFile.getParentFile().mkdirs();
|
||||
cooldownFile.createNewFile();
|
||||
System.out.println("[Suggestion] Created cooldowns.yml at: " + cooldownFile.getAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
this.cooldownData = YamlConfiguration.loadConfiguration(cooldownFile);
|
||||
|
||||
for (String key : cooldownData.getKeys(false)) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(key);
|
||||
long timestamp = cooldownData.getLong(key);
|
||||
cooldowns.put(uuid, timestamp);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.error.no_player", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length == 0) {
|
||||
player.sendMessage(smpPlugin.getMessage("command.suggestion.usage", Map.of("player", player.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (cooldowns.containsKey(uuid)) {
|
||||
long lastUsed = cooldowns.get(uuid);
|
||||
long timeLeft = COOLDOWN_MILLIS - (now - lastUsed);
|
||||
if (timeLeft > 0) {
|
||||
player.sendMessage("§cPlease wait §e" + (timeLeft / 1000) + " seconds§c, before you send another Suggestion.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String input = String.join(" ", args);
|
||||
Matcher matcher = Pattern.compile("^\"([^\"]{1,50})\"\\s+(.{1,300})$").matcher(input);
|
||||
|
||||
if (!matcher.matches()) {
|
||||
player.sendMessage(smpPlugin.getMessage("command.suggestion.usage", Map.of("player", player.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
String title = matcher.group(1).trim();
|
||||
String content = matcher.group(2).trim();
|
||||
|
||||
Suggestion suggestion = manager.addSuggestion(uuid, player.getName(), title, content);
|
||||
if (suggestion != null) {
|
||||
player.sendMessage("§aYour Suggestion was submitted with the ID §e#" + suggestion.getId());
|
||||
cooldowns.put(uuid, now);
|
||||
cooldownData.set(uuid.toString(), now);
|
||||
try {
|
||||
cooldownData.save(cooldownFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
player.sendMessage(smpPlugin.getMessage("command.suggestion.fail", Map.of("player", player.getName())));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.winniepat.SMPPlugin.suggestions.commands;
|
||||
|
||||
import de.winniepat.SMPPlugin.suggestions.Suggestion;
|
||||
import de.winniepat.SMPPlugin.suggestions.SuggestionManager;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SuggestionListCommand implements CommandExecutor {
|
||||
|
||||
private final SuggestionManager manager;
|
||||
|
||||
public SuggestionListCommand(SuggestionManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String @NotNull [] args) {
|
||||
for (Suggestion suggestion : manager.getAllSuggestions()) {
|
||||
sender.sendMessage("§7[#" + suggestion.getId() + "] §e" + suggestion.getTitle() +
|
||||
" §8von §6" + suggestion.getPlayerName() + " §8(§f" + suggestion.getStatus() + "§8)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package de.winniepat.SMPPlugin.suggestions.commands;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import de.winniepat.SMPPlugin.suggestions.Suggestion;
|
||||
import de.winniepat.SMPPlugin.suggestions.SuggestionManager;
|
||||
import de.winniepat.SMPPlugin.suggestions.SuggestionStatus;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SuggestionStatusCommand implements CommandExecutor {
|
||||
|
||||
private final SuggestionManager manager;
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public SuggestionStatusCommand(SuggestionManager manager, SMPPlugin smpPlugin) {
|
||||
this.smpPlugin = smpPlugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(smpPlugin.getMessage("command.suggestionstatus.usage", Map.of("player", sender.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
SuggestionStatus status;
|
||||
switch (args[0].toLowerCase()) {
|
||||
case "accept" -> status = SuggestionStatus.ACCEPTED;
|
||||
case "reject" -> status = SuggestionStatus.REJECTED;
|
||||
case "review" -> status = SuggestionStatus.REVIEW;
|
||||
default -> {
|
||||
sender.sendMessage("§cInvalid Status: " + args[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
int id = Integer.parseInt(args[1]);
|
||||
Suggestion suggestion = manager.getSuggestionById(id);
|
||||
if (suggestion == null) {
|
||||
sender.sendMessage("§cNo suggestion found with ID " + id);
|
||||
return true;
|
||||
}
|
||||
manager.updateStatus(id, status);
|
||||
sender.sendMessage("§aSuggestion #" + id + " was set to " + status);
|
||||
|
||||
Player player = Bukkit.getPlayer(suggestion.getPlayerUuid());
|
||||
if (player != null && player.isOnline()) {
|
||||
player.sendMessage("§aYour suggestion (#" + id + ") was set to §e" + status);
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage("§cInvalid ID: " + args[1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package de.winniepat.SMPPlugin.waypoints;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class GiveWaypointStoneListener implements Listener {
|
||||
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public GiveWaypointStoneListener(SMPPlugin smpPlugin) {
|
||||
this.smpPlugin = smpPlugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (!player.hasPlayedBefore()) {
|
||||
ItemStack item = createWaypointStone();
|
||||
player.getInventory().addItem(item);
|
||||
player.sendMessage(smpPlugin.getMessage("waypoint.first_join", Map.of("player", player.getName())));
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack createWaypointStone() {
|
||||
ItemStack item = new ItemStack(Material.LODESTONE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.AQUA + "Waypoint Stone");
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(SMPPlugin.getInstance(), "waypoint"), PersistentDataType.STRING, "true");
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package de.winniepat.SMPPlugin.waypoints;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class Waypoint {
|
||||
private final String name;
|
||||
private final Location location;
|
||||
|
||||
public Waypoint(String name, Location location) {
|
||||
this.name = name;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public Location getLocation() { return location; }
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package de.winniepat.SMPPlugin.waypoints;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class WaypointCommands implements CommandExecutor {
|
||||
private final WaypointsDatabase sqliteManager;
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public WaypointCommands(WaypointsDatabase sqliteManager, SMPPlugin smpPlugin) {
|
||||
this.sqliteManager = sqliteManager;
|
||||
this.smpPlugin = smpPlugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) return false;
|
||||
|
||||
if (label.equalsIgnoreCase("getwaypoint")) {
|
||||
player.getInventory().addItem(createWaypointStone());
|
||||
player.sendMessage(smpPlugin.getMessage("getwaypoint.success", Map.of("player", player.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (label.equalsIgnoreCase("addwaypoint") && args.length >= 1) {
|
||||
String name = String.join(" ", args);
|
||||
boolean success = sqliteManager.saveWaypoint(player.getUniqueId(), new Waypoint(name, player.getLocation()));
|
||||
if (success) {
|
||||
player.sendMessage(ChatColor.GREEN + "Waypoint '" + name + "' saved.");
|
||||
} else {
|
||||
player.sendMessage(smpPlugin.getMessage("addwaypoint.already_exists", Map.of("player", player.getName())));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private ItemStack createWaypointStone() {
|
||||
ItemStack item = new ItemStack(Material.LODESTONE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.AQUA + "Your Waypoints");
|
||||
meta.getPersistentDataContainer().set(new NamespacedKey(SMPPlugin.getInstance(), "waypoint"), PersistentDataType.STRING, "true");
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package de.winniepat.SMPPlugin.waypoints;
|
||||
|
||||
import de.winniepat.SMPPlugin.SMPPlugin;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class WaypointListener implements Listener {
|
||||
private final WaypointsDatabase sqliteManager;
|
||||
private final Map<UUID, Location> pendingWaypoints = new HashMap<>();
|
||||
private final Map<UUID, Location> pendingLocations = new HashMap<>();
|
||||
private final SMPPlugin smpPlugin;
|
||||
|
||||
public WaypointListener(WaypointsDatabase sqliteManager, SMPPlugin smpPlugin) {
|
||||
this.sqliteManager = sqliteManager;
|
||||
this.smpPlugin = smpPlugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
if (e.getItem() == null || !e.getItem().hasItemMeta()) return;
|
||||
|
||||
ItemMeta meta = e.getItem().getItemMeta();
|
||||
if (!"true".equals(meta.getPersistentDataContainer()
|
||||
.get(new NamespacedKey(SMPPlugin.getInstance(), "waypoint"), PersistentDataType.STRING))) return;
|
||||
|
||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
e.setCancelled(true);
|
||||
Block block = e.getClickedBlock();
|
||||
if (block == null) return;
|
||||
|
||||
Location loc = block.getLocation().add(0.5, 1, 0.5);
|
||||
pendingWaypoints.put(player.getUniqueId(), loc);
|
||||
pendingLocations.put(player.getUniqueId(), player.getLocation().clone());
|
||||
player.sendMessage(ChatColor.YELLOW + "Please enter a name for your waypoint in chat. Don't move!");
|
||||
} else if (e.getAction() == Action.RIGHT_CLICK_AIR) {
|
||||
e.setCancelled(true);
|
||||
openWaypointMenu(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerChat(AsyncPlayerChatEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
if (pendingWaypoints.containsKey(player.getUniqueId())) {
|
||||
e.setCancelled(true);
|
||||
String name = e.getMessage().trim();
|
||||
Location loc = pendingWaypoints.remove(player.getUniqueId());
|
||||
pendingLocations.remove(player.getUniqueId());
|
||||
|
||||
Bukkit.getScheduler().runTask(SMPPlugin.getInstance(), () -> {
|
||||
boolean success = sqliteManager.saveWaypoint(player.getUniqueId(), new Waypoint(name, loc));
|
||||
if (success) {
|
||||
player.sendMessage(ChatColor.GREEN + "Waypoint '" + name + "' set!");
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_BEACON_ACTIVATE, 1f, 1f);
|
||||
} else {
|
||||
player.sendMessage(smpPlugin.getMessage("waypointlistener.already_exists", Map.of("player", player.getName())));
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
if (pendingLocations.containsKey(player.getUniqueId())) {
|
||||
Location from = pendingLocations.get(player.getUniqueId());
|
||||
if (e.getTo() != null && e.getTo().distance(from) > 0.1) {
|
||||
pendingWaypoints.remove(player.getUniqueId());
|
||||
pendingLocations.remove(player.getUniqueId());
|
||||
player.sendMessage(smpPlugin.getMessage("waypointlistener.movement", Map.of("player", player.getName())));
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void openWaypointMenu(Player player) {
|
||||
List<Waypoint> waypoints = sqliteManager.getWaypoints(player.getUniqueId());
|
||||
Inventory gui = Bukkit.createInventory(null, 9 * 3, "Your Waypoints");
|
||||
for (Waypoint wp : waypoints) {
|
||||
ItemStack item = new ItemStack(Material.LODESTONE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.YELLOW + wp.getName());
|
||||
item.setItemMeta(meta);
|
||||
gui.addItem(item);
|
||||
}
|
||||
player.openInventory(gui);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent e) {
|
||||
if (e.getView().getTitle().equals("Your Waypoints")) {
|
||||
e.setCancelled(true);
|
||||
ItemStack clicked = e.getCurrentItem();
|
||||
if (clicked != null && clicked.hasItemMeta()) {
|
||||
String name = ChatColor.stripColor(clicked.getItemMeta().getDisplayName());
|
||||
Player player = (Player) e.getWhoClicked();
|
||||
List<Waypoint> waypoints = sqliteManager.getWaypoints(player.getUniqueId());
|
||||
for (Waypoint wp : waypoints) {
|
||||
if (wp.getName().equals(name)) {
|
||||
player.closeInventory();
|
||||
startTeleportCountdown(player, wp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startTeleportCountdown(Player player, Waypoint waypoint) {
|
||||
Location initialLoc = player.getLocation().clone();
|
||||
player.sendMessage(ChatColor.YELLOW + "Teleporting to " + waypoint.getName() + " in 5 seconds. Don't move!");
|
||||
|
||||
new BukkitRunnable() {
|
||||
int countdown = 5;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!player.isOnline() || player.getLocation().distance(initialLoc) > 0.1) {
|
||||
player.sendMessage(ChatColor.RED + "Teleport cancelled due to movement.");
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (countdown > 0) {
|
||||
player.sendActionBar(ChatColor.YELLOW + "Teleporting in " + countdown + "...");
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1f, 1f);
|
||||
countdown--;
|
||||
} else {
|
||||
player.teleport(waypoint.getLocation());
|
||||
player.sendMessage(ChatColor.GREEN + "Teleported to " + waypoint.getName() + "!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(SMPPlugin.getInstance(), 0L, 20L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package de.winniepat.SMPPlugin.waypoints;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
public class WaypointsDatabase {
|
||||
private final String url = "jdbc:sqlite:plugins/SMPPlugin/waypoints.db";
|
||||
|
||||
public WaypointsDatabase() {
|
||||
try (Connection conn = DriverManager.getConnection(url);
|
||||
Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("""
|
||||
CREATE TABLE IF NOT EXISTS waypoints (
|
||||
player_uuid TEXT,
|
||||
name TEXT,
|
||||
world TEXT,
|
||||
x DOUBLE,
|
||||
y DOUBLE,
|
||||
z DOUBLE
|
||||
)
|
||||
""");
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean saveWaypoint(UUID playerUuid, Waypoint waypoint) {
|
||||
try (Connection conn = DriverManager.getConnection(url);
|
||||
PreparedStatement check = conn.prepareStatement("""
|
||||
SELECT 1 FROM waypoints WHERE player_uuid = ? AND name = ?
|
||||
""")) {
|
||||
check.setString(1, playerUuid.toString());
|
||||
check.setString(2, waypoint.getName());
|
||||
ResultSet rs = check.executeQuery();
|
||||
if (rs.next()) {
|
||||
return false;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(url);
|
||||
PreparedStatement ps = conn.prepareStatement("""
|
||||
INSERT INTO waypoints (player_uuid, name, world, x, y, z) VALUES (?, ?, ?, ?, ?, ?)
|
||||
""")) {
|
||||
ps.setString(1, playerUuid.toString());
|
||||
ps.setString(2, waypoint.getName());
|
||||
ps.setString(3, waypoint.getLocation().getWorld().getName());
|
||||
ps.setDouble(4, waypoint.getLocation().getX());
|
||||
ps.setDouble(5, waypoint.getLocation().getY());
|
||||
ps.setDouble(6, waypoint.getLocation().getZ());
|
||||
ps.executeUpdate();
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Waypoint> getWaypoints(UUID playerUuid) {
|
||||
List<Waypoint> list = new ArrayList<>();
|
||||
try (Connection conn = DriverManager.getConnection(url);
|
||||
PreparedStatement ps = conn.prepareStatement("""
|
||||
SELECT name, world, x, y, z FROM waypoints WHERE player_uuid = ?
|
||||
""")) {
|
||||
ps.setString(1, playerUuid.toString());
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
String name = rs.getString("name");
|
||||
String world = rs.getString("world");
|
||||
double x = rs.getDouble("x"), y = rs.getDouble("y"), z = rs.getDouble("z");
|
||||
list.add(new Waypoint(name, new Location(Bukkit.getWorld(world), x, y, z)));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
command.error.no_player: "§cOnly players are able to execute this command."
|
||||
command.error.no_permission: "§cYou don't have permissions to do that."
|
||||
|
||||
# Coding Command
|
||||
command.coding.usage: "§cUse /coding on or /coding off"
|
||||
command.coding.already: "§eYou're already marked as coding."
|
||||
command.coding.marked: "§aYou are now marked as coding."
|
||||
command.coding.unmarked: "§aYou are no longer marked as coding."
|
||||
command.coding.error: "§cError while marking you as coding."
|
||||
|
||||
# Poll Command
|
||||
command.poll.usage: "§c/pollstart \"question\" Duration Option1 Option2 ..."
|
||||
command.poll.already_active: "§cThere is already an active poll."
|
||||
command.poll.invalid_time: "§cInvalid Time. Choose a number for seconds."
|
||||
|
||||
# Vote GUI
|
||||
pollvotegui.already_voted: "§cYou already voted."
|
||||
|
||||
# Report
|
||||
command.report.invalid_player: "§cInvalid Player."
|
||||
command.report.reason: "§cPlease tell us exactly the reason."
|
||||
command.report.success: "§aReport Saved! Staff will look at it."
|
||||
command.report.usage: "§7Use: §e/report <Player> <Reason>"
|
||||
|
||||
# ReportActionGUI
|
||||
reportactiongui.not_found: "§cReport not found."
|
||||
reportactiongui.successful_delete: "§aReport deleted."
|
||||
reportactiongui.successful_ban: "§cPlayer was permanently banned."
|
||||
|
||||
# Suggestion Command
|
||||
command.suggestion.usage: "§7Use: §e/suggestion \"Title with quotes\" My super Suggestion"
|
||||
command.suggestion.fail: "§cAn Error occurred. Your Suggestion couldn't be submitted."
|
||||
|
||||
# SuggestionStatus Command
|
||||
command.suggestionstatus.usage: "§7Benutze: §e/suggestionstatus <accept|reject|review> <ID>"
|
||||
|
||||
# Suggestion GUI
|
||||
suggestiongui.processing_error: "§cError while processing the suggestion-id."
|
||||
|
||||
# Waypoint System
|
||||
waypoint.first_join: "§6You've received your first Waystone! Use it to set and teleport to waypoints."
|
||||
|
||||
# GiveWaypointStoneListener
|
||||
getwaypoint.success: "&aWaypoint Stone added to your inventory."
|
||||
|
||||
# addwaypoint Command
|
||||
addwaypoint.already_exists: "§cA waypoint with that name already exists."
|
||||
|
||||
# WaypointListener
|
||||
waypointlistener.already_exists: "§cA waypoint with that name already exists."
|
||||
waypointlistener.movement: "§cWaypoint creation cancelled due to movement."
|
||||
|
||||
# PlayerSneakListener
|
||||
blockelevators.on_cooldown: "§cElevator is cooling down"
|
||||
blockelevators.no_elevator_below: "§eNo elevator block below!"
|
||||
blockelevators.no_elevator_above: "§eNo elevator block above!"
|
||||
@@ -0,0 +1,70 @@
|
||||
name: SMPPlugin
|
||||
version: '1.0'
|
||||
main: de.winniepat.SMPPlugin.SMPPlugin
|
||||
api-version: '1.21'
|
||||
load: STARTUP
|
||||
authors: [ WinniePat ]
|
||||
website: https://winniepat.de
|
||||
commands:
|
||||
trash:
|
||||
description: Öffne den Mülleimer zum Löschen von Items
|
||||
report:
|
||||
description: Spieler melden
|
||||
reports:
|
||||
description: Alle Reports anzeigen
|
||||
permission: smputils.reports
|
||||
suggestion:
|
||||
description: Sende einen Vorschlag
|
||||
usage: /<command> <Titel> | <Inhalt>
|
||||
suggestions:
|
||||
description: Zeigt alle Vorschläge im Chat
|
||||
permission: smpplugin.suggestions.use
|
||||
aliases:
|
||||
- vorschlag
|
||||
suggestionstatus:
|
||||
description: Setze den Status eines Vorschlags
|
||||
usage: /<command> <accept|reject|review> <ID>
|
||||
permission: smpplugin.suggestion.status
|
||||
suggestionsgui:
|
||||
description: Öffne die Vorschlags-GUI
|
||||
permission: smpplugin.suggestion.gui
|
||||
coding:
|
||||
description: Toggle coding status
|
||||
usage: /coding <on|off>
|
||||
permission: smpplugin.command.coding.use
|
||||
winnie:
|
||||
description: Toggle winnie status
|
||||
usage: /winnie <on|off>
|
||||
permission: smpplugin.command.winnie.use
|
||||
pollstart:
|
||||
description: Start a poll
|
||||
aliases:
|
||||
- poll
|
||||
pollvote:
|
||||
description: Vote on a poll
|
||||
aliases:
|
||||
- vote
|
||||
pollresults:
|
||||
description: Shows the results
|
||||
bloodmoon:
|
||||
description: Toggle the Bloodmoon event
|
||||
usage: /bloodmoon
|
||||
permission: smpplugin.bloodmoon.toggle
|
||||
blackmarket:
|
||||
description: Manually spawns the Black Market trader
|
||||
usage: /blackmarket
|
||||
permission: smpplugin.blackmarket.spawn
|
||||
getwaypoint:
|
||||
description: Get the waypoint stone
|
||||
permission: smpplugin.waypoints.getwaypoint
|
||||
addwaypoint:
|
||||
description: Add a new waypoint
|
||||
smp:
|
||||
description: start
|
||||
usage: /smp start
|
||||
spawn:
|
||||
description: spawn
|
||||
usage: /spawn
|
||||
shop:
|
||||
description: shop
|
||||
usage: /shop
|
||||
Reference in New Issue
Block a user