first commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/.DS_Store
|
||||
/build
|
||||
BIN
.gradle/9.0.0/checksums/checksums.lock
Normal file
BIN
.gradle/9.0.0/checksums/checksums.lock
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/checksums/md5-checksums.bin
Normal file
BIN
.gradle/9.0.0/checksums/md5-checksums.bin
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/checksums/sha1-checksums.bin
Normal file
BIN
.gradle/9.0.0/checksums/sha1-checksums.bin
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/executionHistory/executionHistory.bin
Normal file
BIN
.gradle/9.0.0/executionHistory/executionHistory.bin
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/executionHistory/executionHistory.lock
Normal file
BIN
.gradle/9.0.0/executionHistory/executionHistory.lock
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/fileChanges/last-build.bin
Normal file
BIN
.gradle/9.0.0/fileChanges/last-build.bin
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/fileHashes/fileHashes.bin
Normal file
BIN
.gradle/9.0.0/fileHashes/fileHashes.bin
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/fileHashes/fileHashes.lock
Normal file
BIN
.gradle/9.0.0/fileHashes/fileHashes.lock
Normal file
Binary file not shown.
BIN
.gradle/9.0.0/fileHashes/resourceHashesCache.bin
Normal file
BIN
.gradle/9.0.0/fileHashes/resourceHashesCache.bin
Normal file
Binary file not shown.
0
.gradle/9.0.0/gc.properties
Normal file
0
.gradle/9.0.0/gc.properties
Normal file
BIN
.gradle/9.2.1/checksums/checksums.lock
Normal file
BIN
.gradle/9.2.1/checksums/checksums.lock
Normal file
Binary file not shown.
BIN
.gradle/9.2.1/executionHistory/executionHistory.bin
Normal file
BIN
.gradle/9.2.1/executionHistory/executionHistory.bin
Normal file
Binary file not shown.
BIN
.gradle/9.2.1/executionHistory/executionHistory.lock
Normal file
BIN
.gradle/9.2.1/executionHistory/executionHistory.lock
Normal file
Binary file not shown.
BIN
.gradle/9.2.1/fileChanges/last-build.bin
Normal file
BIN
.gradle/9.2.1/fileChanges/last-build.bin
Normal file
Binary file not shown.
BIN
.gradle/9.2.1/fileHashes/fileHashes.bin
Normal file
BIN
.gradle/9.2.1/fileHashes/fileHashes.bin
Normal file
Binary file not shown.
BIN
.gradle/9.2.1/fileHashes/fileHashes.lock
Normal file
BIN
.gradle/9.2.1/fileHashes/fileHashes.lock
Normal file
Binary file not shown.
BIN
.gradle/9.2.1/fileHashes/resourceHashesCache.bin
Normal file
BIN
.gradle/9.2.1/fileHashes/resourceHashesCache.bin
Normal file
Binary file not shown.
0
.gradle/9.2.1/gc.properties
Normal file
0
.gradle/9.2.1/gc.properties
Normal file
BIN
.gradle/buildOutputCleanup/buildOutputCleanup.lock
Normal file
BIN
.gradle/buildOutputCleanup/buildOutputCleanup.lock
Normal file
Binary file not shown.
2
.gradle/buildOutputCleanup/cache.properties
Normal file
2
.gradle/buildOutputCleanup/cache.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
#Fri Jan 16 17:25:37 NOVT 2026
|
||||
gradle.version=9.0.0
|
||||
BIN
.gradle/buildOutputCleanup/outputFiles.bin
Normal file
BIN
.gradle/buildOutputCleanup/outputFiles.bin
Normal file
Binary file not shown.
BIN
.gradle/file-system.probe
Normal file
BIN
.gradle/file-system.probe
Normal file
Binary file not shown.
BIN
.gradle/nb-cache/AdminMode-1632350505/project-info.ser
Normal file
BIN
.gradle/nb-cache/AdminMode-1632350505/project-info.ser
Normal file
Binary file not shown.
BIN
.gradle/nb-cache/subprojects.ser
Normal file
BIN
.gradle/nb-cache/subprojects.ser
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
A0EDDFD9DCFA42B28E98A596AFD8237AB506F0D6CE2E10D64BEA80C21CB3949A
|
||||
0
.gradle/vcs-1/gc.properties
Normal file
0
.gradle/vcs-1/gc.properties
Normal file
10
.idea/.gitignore
generated
vendored
Normal file
10
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Игнорируемые файлы по умолчанию
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# HTTP-клиент на основе редактора
|
||||
/httpRequests/
|
||||
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="21" />
|
||||
</component>
|
||||
</project>
|
||||
13
.idea/easycode.ignore
generated
Normal file
13
.idea/easycode.ignore
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
.idea
|
||||
.vscode
|
||||
node_modules/
|
||||
dist/
|
||||
vendor/
|
||||
cache/
|
||||
.*/
|
||||
*.min.*
|
||||
*.test.*
|
||||
*.spec.*
|
||||
*.bundle.*
|
||||
*.bundle-min.*
|
||||
*.log
|
||||
17
.idea/gradle.xml
generated
Normal file
17
.idea/gradle.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="ms-21" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/misc.xml
generated
Normal file
8
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="ms-21" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/AdminMode.main.iml" filepath="$PROJECT_DIR$/.idea/modules/AdminMode.main.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
14
.idea/modules/AdminMode.main.iml
generated
Normal file
14
.idea/modules/AdminMode.main.iml
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>PAPER</platformType>
|
||||
<platformType>ADVENTURE</platformType>
|
||||
</autoDetectTypes>
|
||||
<projectReimportVersion>1</projectReimportVersion>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
||||
119
bin/main/config.yml
Normal file
119
bin/main/config.yml
Normal file
@@ -0,0 +1,119 @@
|
||||
# AdminMode Configuration
|
||||
|
||||
#РЕЖИМ АДМИНИСТРАТОРА
|
||||
admin_mode:
|
||||
# Включен ли режим администратора
|
||||
enabled: true
|
||||
|
||||
# LuckPerms настройки
|
||||
luckperms:
|
||||
# Использовать ли LuckPerms (если false - используется стандартный OP)
|
||||
enabled: true
|
||||
|
||||
# Группы которые выдаются при активации режима
|
||||
# Можно указать несколько групп через запятую
|
||||
groups:
|
||||
- "moder_adm"
|
||||
|
||||
# Удалять ли группы при деактивации (если false - группы останутся)
|
||||
remove_on_disable: true
|
||||
|
||||
# Настройки игрового режима
|
||||
gamemode:
|
||||
# Принудительно ставить спектатор (если false - креатив)
|
||||
force_spectator: true
|
||||
|
||||
# Мобы игнорируют игрока в админ моде
|
||||
mobs_ignore_player: true
|
||||
|
||||
# Разрешить полет в режиме выживания (в админ моде)
|
||||
allow_flight_in_survival: true
|
||||
|
||||
# Режим бога (неуязвимость)
|
||||
god_mode: true
|
||||
|
||||
# Кастомная скорость полета (0.1 = медленно, 0.2 = нормально, 0.5 = быстро, 1.0 = очень быстро)
|
||||
custom_fly_speed: 0.2
|
||||
|
||||
# Кастомная скорость ходьбы (0.1 = медленно, 0.2 = нормально, 0.5 = быстро)
|
||||
custom_walk_speed: 0.2
|
||||
|
||||
# Разрешенные режимы игры для переключения в админ моде
|
||||
# Если список пустой - можно переключаться на любые режимы
|
||||
# Доступные: SURVIVAL, CREATIVE, ADVENTURE, SPECTATOR
|
||||
allowed_gamemodes:
|
||||
- "CREATIVE"
|
||||
- "SPECTATOR"
|
||||
|
||||
# Ограничения в режиме администратора
|
||||
restrictions:
|
||||
# Запретить выбрасывание предметов
|
||||
prevent_item_drop: true
|
||||
|
||||
# Запретить поднятие предметов
|
||||
prevent_item_pickup: false
|
||||
|
||||
# Запретить перемещение предметов в контейнеры (сундуки, бочки и т.д.)
|
||||
prevent_container_transfer: true
|
||||
|
||||
# Запретить использование предметов (кроме открытия контейнеров)
|
||||
prevent_item_use: true
|
||||
|
||||
# Разрешить управление своим инвентарем
|
||||
allow_own_inventory: true
|
||||
|
||||
# Разрешенные блоки для взаимодействия (открытие, использование)
|
||||
allowed_blocks:
|
||||
- "CHEST"
|
||||
- "TRAPPED_CHEST"
|
||||
- "BARREL"
|
||||
- "SHULKER_BOX"
|
||||
- "FURNACE"
|
||||
- "BLAST_FURNACE"
|
||||
- "SMOKER"
|
||||
- "HOPPER"
|
||||
- "DISPENSER"
|
||||
- "DROPPER"
|
||||
- "DOOR"
|
||||
- "TRAPDOOR"
|
||||
- "FENCE_GATE"
|
||||
- "BUTTON"
|
||||
- "LEVER"
|
||||
- "ENDER_CHEST"
|
||||
- "CRAFTING_TABLE"
|
||||
- "ENCHANTING_TABLE"
|
||||
- "ANVIL"
|
||||
- "BREWING_STAND"
|
||||
|
||||
# Разрешенные блоки для постановки (whitelist)
|
||||
# Если список пустой - можно ставить любые блоки
|
||||
# Если список заполнен - можно ставить только эти блоки
|
||||
allowed_place_blocks:
|
||||
- "BARRIER"
|
||||
- "LIGHT"
|
||||
- "STRUCTURE_VOID"
|
||||
- "STRUCTURE_BLOCK"
|
||||
|
||||
# Выдавать пресет блоков при входе в админ мод
|
||||
give_preset_blocks: true
|
||||
|
||||
# Пресет блоков (формат: МАТЕРИАЛ:КОЛИЧЕСТВО)
|
||||
preset_blocks:
|
||||
- "BARRIER:64"
|
||||
- "LIGHT:64"
|
||||
- "STRUCTURE_VOID:64"
|
||||
|
||||
# Сообщения
|
||||
messages:
|
||||
enabled: "✓ Режим администратора активирован!"
|
||||
enabled_subtitle: "Ваше состояние сохранено."
|
||||
permissions_granted: "⚠ Вам выданы временные права администратора!"
|
||||
disabled: "✓ Режим администратора отключен!"
|
||||
disabled_subtitle: "Ваше состояние восстановлено."
|
||||
permissions_removed: "✓ Права администратора отозваны!"
|
||||
no_permission: "У вас нет прав для использования этой команды!"
|
||||
item_drop_denied: "✖ В режиме администратора нельзя выбрасывать предметы!"
|
||||
container_transfer_denied: "✖ В режиме администратора нельзя перемещать предметы в контейнеры!"
|
||||
item_use_denied: "✖ В режиме администратора нельзя использовать предметы!"
|
||||
block_place_denied: "✖ Вы можете ставить только разрешенные блоки!"
|
||||
reloaded: "✓ Конфигурация AdminMode перезагружена!"
|
||||
21
bin/main/plugin.yml
Normal file
21
bin/main/plugin.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
name: AdminMode
|
||||
version: '1.1.0'
|
||||
main: org.blz.adminmode.AdminMode
|
||||
api-version: '1.21'
|
||||
author: BelzeBool, Kilka_v_HJIebe
|
||||
description: Плагин режима администратора с сохранением состояния игрока
|
||||
softdepend: [LuckPerms]
|
||||
|
||||
commands:
|
||||
adminmode:
|
||||
description: Режим администратора с сохранением состояния
|
||||
usage: /<command>
|
||||
aliases: [adm, am]
|
||||
|
||||
permissions:
|
||||
adminmode.use:
|
||||
description: Разрешает использовать режим администратора
|
||||
default: op
|
||||
adminmode.reload:
|
||||
description: Разрешает перезагружать конфигурацию AdminMode
|
||||
default: op
|
||||
41
build.gradle
Normal file
41
build.gradle
Normal file
@@ -0,0 +1,41 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'org.blz'
|
||||
version = '1.21.11'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = 'papermc'
|
||||
url = 'https://repo.papermc.io/repository/maven-public/'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT'
|
||||
compileOnly 'net.luckperms:api:5.4'
|
||||
compileOnly 'com.google.code.gson:gson:2.10.1'
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
processResources {
|
||||
def props = [version: version]
|
||||
inputs.properties props
|
||||
filteringCharset 'UTF-8'
|
||||
filesMatching('plugin.yml') {
|
||||
expand props
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveFileName.set("${project.name}-${project.version}.jar")
|
||||
}
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
251
gradlew
vendored
Executable file
251
gradlew
vendored
Executable file
@@ -0,0 +1,251 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 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.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# 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 -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || 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="\\\"\\\""
|
||||
|
||||
|
||||
# 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, 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" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# 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" "$@"
|
||||
94
gradlew.bat
vendored
Normal file
94
gradlew.bat
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
@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
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@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=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
: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
|
||||
63
src/main/java/org/blz/adminmode/AdminMode.java
Normal file
63
src/main/java/org/blz/adminmode/AdminMode.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package org.blz.adminmode;
|
||||
|
||||
import org.blz.adminmode.commands.AdminModeCommand;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.blz.adminmode.dialog.AdminDialogService;
|
||||
import org.blz.adminmode.listeners.AdminModeListener;
|
||||
import org.blz.adminmode.listeners.GameModeChangeListener;
|
||||
import org.blz.adminmode.listeners.MobTargetListener;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class AdminMode extends JavaPlugin {
|
||||
|
||||
private static AdminMode instance;
|
||||
private ConfigManager configManager;
|
||||
private AdminModeCommand adminModeCommand;
|
||||
private AdminDialogService dialogService;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
saveDefaultConfig();
|
||||
|
||||
configManager = new ConfigManager(this);
|
||||
adminModeCommand = new AdminModeCommand(this, configManager);
|
||||
dialogService = new AdminDialogService(this, configManager, adminModeCommand);
|
||||
adminModeCommand.setDialogService(dialogService);
|
||||
getCommand("adminmode").setExecutor(adminModeCommand);
|
||||
getCommand("admfix").setExecutor(new org.blz.adminmode.commands.AdminFixCommand(adminModeCommand));
|
||||
|
||||
getServer().getPluginManager().registerEvents(new AdminModeListener(this, adminModeCommand, configManager),
|
||||
this);
|
||||
getServer().getPluginManager().registerEvents(new MobTargetListener(adminModeCommand, configManager), this);
|
||||
getServer().getPluginManager().registerEvents(new GameModeChangeListener(adminModeCommand, configManager),
|
||||
this);
|
||||
|
||||
// Load Pocket Dimension World
|
||||
new org.blz.adminmode.utils.WorldLoader(this, "pocket_dimension").loadWorld();
|
||||
|
||||
// Register Abilities
|
||||
belzeManager = new org.blz.adminmode.managers.BelzeBoolManager(this);
|
||||
|
||||
getLogger().info("AdminMode успешно включен!");
|
||||
}
|
||||
|
||||
private org.blz.adminmode.managers.BelzeBoolManager belzeManager; // Field to store manager
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().info("AdminMode отключен!");
|
||||
}
|
||||
|
||||
public static AdminMode getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public AdminModeCommand getAdminModeCommand() {
|
||||
return adminModeCommand;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.blz.adminmode.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class AdminFixCommand implements CommandExecutor {
|
||||
|
||||
private final AdminModeCommand adminModeCommand;
|
||||
|
||||
public AdminFixCommand(AdminModeCommand adminModeCommand) {
|
||||
this.adminModeCommand = adminModeCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!sender.hasPermission("adminmode.admin")) {
|
||||
sender.sendMessage(ChatColor.RED + "У вас нет прав для использования этой команды!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 1) {
|
||||
sender.sendMessage(ChatColor.RED + "Использование: /admfix <игрок>");
|
||||
return true;
|
||||
}
|
||||
|
||||
Player target = Bukkit.getPlayer(args[0]);
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Игрок не найден!");
|
||||
return true;
|
||||
}
|
||||
|
||||
adminModeCommand.forceDisableAbilities(target);
|
||||
|
||||
sender.sendMessage(ChatColor.GREEN + "✓ Все способности отключены для игрока " + target.getName());
|
||||
target.sendMessage(ChatColor.YELLOW + "⚠ Ваши способности были сброшены администратором");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
632
src/main/java/org/blz/adminmode/commands/AdminModeCommand.java
Normal file
632
src/main/java/org/blz/adminmode/commands/AdminModeCommand.java
Normal file
@@ -0,0 +1,632 @@
|
||||
package org.blz.adminmode.commands;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.node.Node;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.blz.adminmode.dialog.AdminDialogService;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.blz.adminmode.data.AdminModeDataManager;
|
||||
import org.blz.adminmode.data.AdminModeDataManager.PlayerStateData;
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AdminModeCommand implements CommandExecutor {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final ConfigManager configManager;
|
||||
private final Map<UUID, PlayerState> savedStates = new HashMap<>();
|
||||
private final Map<UUID, ModeratorProfile> activeProfiles = new HashMap<>();
|
||||
private final AdminModeDataManager dataManager;
|
||||
private AdminDialogService dialogService;
|
||||
|
||||
public AdminModeCommand(Plugin plugin, ConfigManager configManager) {
|
||||
this.plugin = plugin;
|
||||
this.configManager = configManager;
|
||||
this.dataManager = new AdminModeDataManager(plugin);
|
||||
loadAllStates();
|
||||
}
|
||||
|
||||
public void setDialogService(AdminDialogService dialogService) {
|
||||
this.dialogService = dialogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("reload")) {
|
||||
if (!sender.hasPermission("adminmode.reload")) {
|
||||
sender.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
|
||||
return true;
|
||||
}
|
||||
configManager.loadConfig();
|
||||
sender.sendMessage(ChatColor.GREEN + configManager.getMsgReloaded());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Команда disable <игрок> - принудительно отключить способности
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("disable")) {
|
||||
if (!canUseHardActions(sender)) {
|
||||
sender.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage(ChatColor.RED + "Использование: /adminmode disable <игрок>");
|
||||
return true;
|
||||
}
|
||||
|
||||
forceDisableTarget(sender, args[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage(ChatColor.RED + "Эта команда доступна только игрокам!");
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = (Player) sender;
|
||||
|
||||
if (!configManager.isEnabled()) {
|
||||
player.sendMessage(ChatColor.RED + "Режим администратора отключен!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0 && args[0].equalsIgnoreCase("dialog")) {
|
||||
if (!openRelevantDialog(player)) {
|
||||
player.sendMessage(ChatColor.YELLOW + "Dialog-панель недоступна. Используйте /adminmode enable <soft|hard>.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 0 && (args[0].equalsIgnoreCase("enable") || args[0].equalsIgnoreCase("profile"))) {
|
||||
if (args.length < 2) {
|
||||
if (!openRelevantDialog(player)) {
|
||||
player.sendMessage(ChatColor.YELLOW + "Использование: /adminmode enable <soft|hard>");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ModeratorProfile profile = ModeratorProfile.fromInput(args[1]).orElse(null);
|
||||
if (profile == null) {
|
||||
player.sendMessage(ChatColor.RED + "Неизвестный профиль. Доступно: soft, hard.");
|
||||
return true;
|
||||
}
|
||||
|
||||
toggleAdminMode(player, profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isInAdminMode(player.getUniqueId()) && getAvailableProfiles(player).isEmpty()) {
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
|
||||
return true;
|
||||
}
|
||||
|
||||
toggleAdminMode(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void toggleAdminMode(Player player) {
|
||||
if (isInAdminMode(player.getUniqueId())) {
|
||||
disableAdminMode(player);
|
||||
return;
|
||||
}
|
||||
|
||||
List<ModeratorProfile> availableProfiles = getAvailableProfiles(player);
|
||||
if (availableProfiles.isEmpty()) {
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
|
||||
return;
|
||||
}
|
||||
|
||||
if (availableProfiles.size() == 1) {
|
||||
enableAdminMode(player, availableProfiles.get(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!openRelevantDialog(player)) {
|
||||
player.sendMessage(ChatColor.YELLOW + "Доступно несколько профилей. Используйте /adminmode enable <soft|hard>.");
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleAdminMode(Player player, ModeratorProfile profile) {
|
||||
if (profile == null) {
|
||||
toggleAdminMode(player);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInAdminMode(player.getUniqueId())) {
|
||||
ModeratorProfile activeProfile = getActiveProfile(player.getUniqueId());
|
||||
if (activeProfile == profile) {
|
||||
disableAdminMode(player);
|
||||
} else {
|
||||
player.sendMessage(ChatColor.YELLOW + "Сначала выключите текущий режим модерации, затем включите новый профиль.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!profile.isAvailableFor(player)) {
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
|
||||
return;
|
||||
}
|
||||
|
||||
enableAdminMode(player, profile);
|
||||
}
|
||||
|
||||
public List<ModeratorProfile> getAvailableProfiles(Player player) {
|
||||
return ModeratorProfile.availableFor(player);
|
||||
}
|
||||
|
||||
public ModeratorProfile getActiveProfile(UUID playerId) {
|
||||
return activeProfiles.get(playerId);
|
||||
}
|
||||
|
||||
public void applyAdminSettings(Player player, float flySpeed, float walkSpeed, boolean godMode) {
|
||||
if (!isInAdminMode(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.setAllowFlight(true);
|
||||
player.setFlying(true);
|
||||
player.setFlySpeed(clampSpeed(flySpeed, 0.1f));
|
||||
player.setWalkSpeed(clampSpeed(walkSpeed, 0.1f));
|
||||
player.setInvulnerable(godMode);
|
||||
player.sendMessage(ChatColor.GREEN + "✓ Настройки admin mode обновлены.");
|
||||
}
|
||||
|
||||
public boolean teleportToPlayer(Player moderator, String targetName) {
|
||||
if (!validateHardActionPlayer(moderator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player target = resolveOnlinePlayer(targetName, moderator);
|
||||
if (target == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
moderator.teleport(target.getLocation());
|
||||
moderator.sendMessage(ChatColor.GREEN + "✓ Вы телепортированы к игроку " + target.getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean teleportPlayerHere(Player moderator, String targetName) {
|
||||
if (!validateHardActionPlayer(moderator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player target = resolveOnlinePlayer(targetName, moderator);
|
||||
if (target == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
target.teleport(moderator.getLocation());
|
||||
moderator.sendMessage(ChatColor.GREEN + "✓ Игрок " + target.getName() + " телепортирован к вам.");
|
||||
target.sendMessage(ChatColor.YELLOW + "⚠ Вас телепортировал модератор " + moderator.getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean forceDisableTarget(CommandSender sender, String targetName) {
|
||||
if (!canUseHardActions(sender)) {
|
||||
sender.sendMessage(ChatColor.RED + configManager.getMsgNoPermission());
|
||||
return false;
|
||||
}
|
||||
|
||||
Player target = resolveOnlinePlayer(targetName, sender);
|
||||
if (target == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
forceDisableAbilities(target);
|
||||
sender.sendMessage(ChatColor.GREEN + "✓ Все способности отключены для игрока " + target.getName());
|
||||
target.sendMessage(ChatColor.YELLOW + "⚠ Ваши способности были сброшены модератором");
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean openRelevantDialog(Player player) {
|
||||
if (dialogService == null || !configManager.isDialogsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isInAdminMode(player.getUniqueId())) {
|
||||
return dialogService.openModerationPanel(player);
|
||||
}
|
||||
|
||||
return dialogService.openProfileSelectionDialog(player);
|
||||
}
|
||||
|
||||
private void enableAdminMode(Player player, ModeratorProfile profile) {
|
||||
savePlayerState(player, profile);
|
||||
activeProfiles.put(player.getUniqueId(), profile);
|
||||
clearPlayerState(player);
|
||||
givePresetBlocks(player);
|
||||
setAdminGameMode(player);
|
||||
savePlayerStateToFile(player);
|
||||
grantLuckPermsPermissions(player, profile);
|
||||
|
||||
player.sendMessage(ChatColor.AQUA + configManager.getMsgEnabled());
|
||||
player.sendMessage(ChatColor.GRAY + configManager.getMsgEnabledSubtitle());
|
||||
player.sendMessage(ChatColor.YELLOW + configManager.getMsgPermissionsGranted());
|
||||
player.sendMessage(ChatColor.GRAY + "Профиль: " + profile.getDisplayName());
|
||||
}
|
||||
|
||||
private void disableAdminMode(Player player) {
|
||||
UUID playerId = player.getUniqueId();
|
||||
ModeratorProfile profile = activeProfiles.getOrDefault(playerId, ModeratorProfile.SOFT_MODER);
|
||||
|
||||
removeLuckPermsPermissions(player, profile);
|
||||
restorePlayerState(player);
|
||||
dataManager.deletePlayerState(playerId);
|
||||
|
||||
player.sendMessage(ChatColor.GREEN + configManager.getMsgDisabled());
|
||||
player.sendMessage(ChatColor.GRAY + configManager.getMsgDisabledSubtitle());
|
||||
}
|
||||
|
||||
private void savePlayerState(Player player, ModeratorProfile profile) {
|
||||
PlayerState state = new PlayerState();
|
||||
|
||||
state.inventory = player.getInventory().getContents().clone();
|
||||
state.armorContents = player.getInventory().getArmorContents().clone();
|
||||
state.offHand = player.getInventory().getItemInOffHand().clone();
|
||||
|
||||
state.location = player.getLocation().clone();
|
||||
|
||||
state.health = player.getHealth();
|
||||
state.foodLevel = player.getFoodLevel();
|
||||
state.saturation = player.getSaturation();
|
||||
state.exhaustion = player.getExhaustion();
|
||||
|
||||
state.exp = player.getExp();
|
||||
state.level = player.getLevel();
|
||||
state.totalExperience = player.getTotalExperience();
|
||||
state.gameMode = player.getGameMode();
|
||||
|
||||
state.allowFlight = player.getAllowFlight();
|
||||
state.flying = player.isFlying();
|
||||
state.flySpeed = player.getFlySpeed();
|
||||
state.walkSpeed = player.getWalkSpeed();
|
||||
state.potionEffects = player.getActivePotionEffects();
|
||||
state.fireTicks = player.getFireTicks();
|
||||
state.profile = profile;
|
||||
|
||||
savedStates.put(player.getUniqueId(), state);
|
||||
}
|
||||
|
||||
private void clearPlayerState(Player player) {
|
||||
player.getInventory().clear();
|
||||
player.getInventory().setArmorContents(new ItemStack[4]);
|
||||
player.getInventory().setItemInOffHand(new ItemStack(Material.AIR));
|
||||
|
||||
player.setHealth(20.0);
|
||||
player.setFoodLevel(20);
|
||||
player.setSaturation(5.0f);
|
||||
player.setExhaustion(0.0f);
|
||||
|
||||
player.setExp(0);
|
||||
player.setLevel(0);
|
||||
player.setTotalExperience(0);
|
||||
|
||||
for (PotionEffect effect : player.getActivePotionEffects()) {
|
||||
player.removePotionEffect(effect.getType());
|
||||
}
|
||||
|
||||
player.setFireTicks(0);
|
||||
}
|
||||
|
||||
private void givePresetBlocks(Player player) {
|
||||
if (!configManager.isGivePresetBlocks())
|
||||
return;
|
||||
|
||||
List<String> presetBlocks = configManager.getPresetBlocks();
|
||||
for (String blockStr : presetBlocks) {
|
||||
try {
|
||||
String[] parts = blockStr.split(":");
|
||||
Material material = Material.valueOf(parts[0].toUpperCase());
|
||||
int amount = parts.length > 1 ? Integer.parseInt(parts[1]) : 64;
|
||||
|
||||
ItemStack item = new ItemStack(material, amount);
|
||||
player.getInventory().addItem(item);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Неверный блок в preset_blocks: " + blockStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setAdminGameMode(Player player) {
|
||||
if (configManager.isForceSpectator()) {
|
||||
player.setGameMode(GameMode.SPECTATOR);
|
||||
} else {
|
||||
// ВАЖНО: Не используем CREATIVE для модеров, только SURVIVAL!
|
||||
player.setGameMode(GameMode.SURVIVAL);
|
||||
}
|
||||
// Всегда разрешаем полет в админ моде (даже в выживании)
|
||||
player.setAllowFlight(true);
|
||||
player.setFlying(true);
|
||||
|
||||
// Дополнительные возможности
|
||||
if (configManager.isGodMode()) {
|
||||
player.setInvulnerable(true);
|
||||
}
|
||||
if (configManager.getCustomFlySpeed() > 0) {
|
||||
player.setFlySpeed(configManager.getCustomFlySpeed());
|
||||
}
|
||||
if (configManager.getCustomWalkSpeed() > 0) {
|
||||
player.setWalkSpeed(configManager.getCustomWalkSpeed());
|
||||
}
|
||||
}
|
||||
|
||||
private void savePlayerStateToFile(Player player) {
|
||||
UUID playerId = player.getUniqueId();
|
||||
PlayerState state = savedStates.get(playerId);
|
||||
|
||||
if (state == null)
|
||||
return;
|
||||
|
||||
PlayerStateData data = new PlayerStateData();
|
||||
data.inventory = state.inventory;
|
||||
data.armorContents = state.armorContents;
|
||||
data.offHand = state.offHand;
|
||||
data.location = state.location;
|
||||
data.health = state.health;
|
||||
data.foodLevel = state.foodLevel;
|
||||
data.saturation = state.saturation;
|
||||
data.exhaustion = state.exhaustion;
|
||||
data.exp = state.exp;
|
||||
data.level = state.level;
|
||||
data.totalExperience = state.totalExperience;
|
||||
data.gameMode = state.gameMode;
|
||||
data.allowFlight = state.allowFlight;
|
||||
data.flying = state.flying;
|
||||
data.flySpeed = state.flySpeed;
|
||||
data.walkSpeed = state.walkSpeed;
|
||||
data.potionEffects = state.potionEffects;
|
||||
data.fireTicks = state.fireTicks;
|
||||
data.profileKey = state.profile == null ? null : state.profile.getConfigKey();
|
||||
|
||||
dataManager.savePlayerState(playerId, data);
|
||||
}
|
||||
|
||||
private void loadAllStates() {
|
||||
for (UUID playerId : dataManager.getAllSavedStates()) {
|
||||
PlayerStateData data = dataManager.loadPlayerState(playerId);
|
||||
|
||||
if (data == null)
|
||||
continue;
|
||||
|
||||
PlayerState state = new PlayerState();
|
||||
state.inventory = data.inventory;
|
||||
state.armorContents = data.armorContents;
|
||||
state.offHand = data.offHand;
|
||||
state.location = data.location;
|
||||
state.health = data.health;
|
||||
state.foodLevel = data.foodLevel;
|
||||
state.saturation = data.saturation;
|
||||
state.exhaustion = data.exhaustion;
|
||||
state.exp = data.exp;
|
||||
state.level = data.level;
|
||||
state.totalExperience = data.totalExperience;
|
||||
state.gameMode = data.gameMode;
|
||||
state.allowFlight = data.allowFlight;
|
||||
state.flying = data.flying;
|
||||
state.flySpeed = data.flySpeed;
|
||||
state.walkSpeed = data.walkSpeed;
|
||||
state.potionEffects = data.potionEffects;
|
||||
state.fireTicks = data.fireTicks;
|
||||
state.profile = ModeratorProfile.fromConfigKey(data.profileKey).orElse(ModeratorProfile.SOFT_MODER);
|
||||
|
||||
savedStates.put(playerId, state);
|
||||
activeProfiles.put(playerId, state.profile);
|
||||
plugin.getLogger().info("Загружено состояние админ мода для: " + playerId);
|
||||
}
|
||||
}
|
||||
|
||||
private void restorePlayerState(Player player) {
|
||||
UUID playerId = player.getUniqueId();
|
||||
PlayerState state = savedStates.get(playerId);
|
||||
|
||||
if (state == null)
|
||||
return;
|
||||
|
||||
// КРИТИЧНО: Удаляем из savedStates ДО восстановления режима!
|
||||
// Это предотвратит срабатывание GameModeChangeListener, который мог бы снова
|
||||
// включить полет
|
||||
savedStates.remove(playerId);
|
||||
activeProfiles.remove(playerId);
|
||||
|
||||
// Восстанавливаем инвентарь
|
||||
player.getInventory().setContents(state.inventory);
|
||||
player.getInventory().setArmorContents(state.armorContents);
|
||||
player.getInventory().setItemInOffHand(state.offHand);
|
||||
|
||||
if (state.location != null) {
|
||||
player.teleport(state.location);
|
||||
}
|
||||
|
||||
player.setHealth(state.health);
|
||||
player.setFoodLevel(state.foodLevel);
|
||||
player.setSaturation(state.saturation);
|
||||
player.setExhaustion(state.exhaustion);
|
||||
|
||||
player.setExp(state.exp);
|
||||
player.setLevel(state.level);
|
||||
player.setTotalExperience(state.totalExperience);
|
||||
|
||||
// ВАЖНО: Сначала восстанавливаем gameMode
|
||||
player.setGameMode(state.gameMode);
|
||||
|
||||
// КРИТИЧНО: ПОТОМ применяем железную очистку способностей!
|
||||
// Это гарантирует, что даже в SPECTATOR режиме у игрока не будет полета
|
||||
forceDisableAbilities(player);
|
||||
|
||||
for (PotionEffect effect : player.getActivePotionEffects()) {
|
||||
player.removePotionEffect(effect.getType());
|
||||
}
|
||||
for (PotionEffect effect : state.potionEffects) {
|
||||
player.addPotionEffect(effect);
|
||||
}
|
||||
|
||||
player.setFireTicks(state.fireTicks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Железное отключение всех админ способностей
|
||||
* Используется при выходе из режима и в команде /admfix
|
||||
*/
|
||||
public void forceDisableAbilities(Player player) {
|
||||
player.setInvulnerable(false); // Убираем бессмертие
|
||||
player.setFlying(false); // Принудительно отключаем полет
|
||||
player.setAllowFlight(false); // Запрещаем полет
|
||||
player.setFlySpeed(0.1f); // Сброс скорости полета на дефолт
|
||||
player.setWalkSpeed(0.2f); // Сброс скорости ходьбы на дефолт
|
||||
}
|
||||
|
||||
public boolean isInAdminMode(UUID playerId) {
|
||||
return savedStates.containsKey(playerId);
|
||||
}
|
||||
|
||||
private boolean canUseHardActions(CommandSender sender) {
|
||||
if (sender.hasPermission("adminmode.admin")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(sender instanceof Player player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isInAdminMode(player.getUniqueId()) && getActiveProfile(player.getUniqueId()) == ModeratorProfile.HARD_MODER;
|
||||
}
|
||||
|
||||
private boolean validateHardActionPlayer(Player moderator) {
|
||||
if (!canUseHardActions(moderator)) {
|
||||
moderator.sendMessage(ChatColor.RED + "Для этого действия нужен активный профиль Hard Moder.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Player resolveOnlinePlayer(String targetName, CommandSender sender) {
|
||||
if (targetName == null || targetName.isBlank()) {
|
||||
sender.sendMessage(ChatColor.RED + "Укажите ник игрока.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Player target = Bukkit.getPlayerExact(targetName.trim());
|
||||
if (target == null) {
|
||||
target = Bukkit.getPlayer(targetName.trim());
|
||||
}
|
||||
|
||||
if (target == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Игрок не найден!");
|
||||
return null;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
private float clampSpeed(float value, float min) {
|
||||
return Math.max(min, Math.min(1.0f, value));
|
||||
}
|
||||
|
||||
private void grantLuckPermsPermissions(Player player, ModeratorProfile profile) {
|
||||
if (!configManager.isUseLuckPerms()) {
|
||||
player.setOp(true);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
LuckPerms luckPerms = LuckPermsProvider.get();
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
|
||||
if (user == null) {
|
||||
player.sendMessage(ChatColor.RED + "⚠ Не удалось получить данные LuckPerms!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> groups = configManager.getLuckPermsGroups(profile);
|
||||
|
||||
for (String group : groups) {
|
||||
Node groupNode = Node.builder("group." + group).build();
|
||||
user.data().add(groupNode);
|
||||
}
|
||||
|
||||
luckPerms.getUserManager().saveUser(user);
|
||||
|
||||
player.sendMessage(ChatColor.GREEN + "✓ Права администратора выданы!");
|
||||
} catch (IllegalStateException e) {
|
||||
player.setOp(true);
|
||||
player.sendMessage(ChatColor.YELLOW + "⚠ LuckPerms не найден, используется стандартный OP");
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLuckPermsPermissions(Player player, ModeratorProfile profile) {
|
||||
if (!configManager.isUseLuckPerms()) {
|
||||
player.setOp(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!configManager.isRemoveGroupsOnDisable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
LuckPerms luckPerms = LuckPermsProvider.get();
|
||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
||||
|
||||
if (user == null) {
|
||||
player.sendMessage(ChatColor.RED + "⚠ Не удалось получить данные LuckPerms!");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> groups = configManager.getLuckPermsGroups(profile);
|
||||
|
||||
for (String group : groups) {
|
||||
Node groupNode = Node.builder("group." + group).build();
|
||||
user.data().remove(groupNode);
|
||||
}
|
||||
|
||||
luckPerms.getUserManager().saveUser(user);
|
||||
|
||||
player.sendMessage(ChatColor.GREEN + configManager.getMsgPermissionsRemoved());
|
||||
} catch (IllegalStateException e) {
|
||||
player.setOp(false);
|
||||
player.sendMessage(ChatColor.YELLOW + "⚠ LuckPerms не найден, убран стандартный OP");
|
||||
}
|
||||
}
|
||||
|
||||
private static class PlayerState {
|
||||
ItemStack[] inventory;
|
||||
ItemStack[] armorContents;
|
||||
ItemStack offHand;
|
||||
Location location;
|
||||
double health;
|
||||
int foodLevel;
|
||||
float saturation;
|
||||
float exhaustion;
|
||||
float exp;
|
||||
int level;
|
||||
int totalExperience;
|
||||
GameMode gameMode;
|
||||
boolean allowFlight;
|
||||
boolean flying;
|
||||
float flySpeed;
|
||||
float walkSpeed;
|
||||
Collection<PotionEffect> potionEffects;
|
||||
int fireTicks;
|
||||
ModeratorProfile profile;
|
||||
}
|
||||
}
|
||||
257
src/main/java/org/blz/adminmode/config/ConfigManager.java
Normal file
257
src/main/java/org/blz/adminmode/config/ConfigManager.java
Normal file
@@ -0,0 +1,257 @@
|
||||
package org.blz.adminmode.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private final Plugin plugin;
|
||||
private FileConfiguration config;
|
||||
|
||||
private boolean enabled;
|
||||
private boolean useLuckPerms;
|
||||
private Map<ModeratorProfile, List<String>> luckPermsGroups;
|
||||
private boolean removeGroupsOnDisable;
|
||||
private boolean dialogsEnabled;
|
||||
|
||||
private boolean preventItemDrop;
|
||||
private boolean preventItemPickup;
|
||||
private boolean preventContainerTransfer;
|
||||
private boolean preventItemUse;
|
||||
private boolean allowOwnInventory;
|
||||
private List<String> allowedBlocks;
|
||||
private List<String> allowedPlaceBlocks;
|
||||
private boolean givePresetBlocks;
|
||||
private List<String> presetBlocks;
|
||||
|
||||
private boolean forceSpectator;
|
||||
private boolean mobsIgnorePlayer;
|
||||
private boolean allowFlightInSurvival;
|
||||
private boolean godMode;
|
||||
private float customFlySpeed;
|
||||
private float customWalkSpeed;
|
||||
private List<String> allowedGameModes;
|
||||
|
||||
private String msgEnabled;
|
||||
private String msgEnabledSubtitle;
|
||||
private String msgPermissionsGranted;
|
||||
private String msgDisabled;
|
||||
private String msgDisabledSubtitle;
|
||||
private String msgPermissionsRemoved;
|
||||
private String msgNoPermission;
|
||||
private String msgItemDropDenied;
|
||||
private String msgContainerTransferDenied;
|
||||
private String msgItemUseDenied;
|
||||
private String msgBlockPlaceDenied;
|
||||
private String msgReloaded;
|
||||
|
||||
public ConfigManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
public void loadConfig() {
|
||||
plugin.reloadConfig();
|
||||
config = plugin.getConfig();
|
||||
|
||||
enabled = config.getBoolean("admin_mode.enabled", true);
|
||||
|
||||
useLuckPerms = config.getBoolean("admin_mode.luckperms.enabled", true);
|
||||
removeGroupsOnDisable = config.getBoolean("admin_mode.luckperms.remove_on_disable", true);
|
||||
dialogsEnabled = config.getBoolean("admin_mode.dialogs.enabled", true);
|
||||
|
||||
List<String> legacyGroups = config.getStringList("admin_mode.luckperms.groups");
|
||||
List<String> softGroups = config.getStringList("admin_mode.luckperms.profile_groups.soft_moder");
|
||||
List<String> hardGroups = config.getStringList("admin_mode.luckperms.profile_groups.hard_moder");
|
||||
if (softGroups.isEmpty()) {
|
||||
softGroups = new ArrayList<>(legacyGroups);
|
||||
}
|
||||
if (hardGroups.isEmpty()) {
|
||||
hardGroups = legacyGroups.isEmpty() ? new ArrayList<>(softGroups) : new ArrayList<>(legacyGroups);
|
||||
}
|
||||
luckPermsGroups = new EnumMap<>(ModeratorProfile.class);
|
||||
luckPermsGroups.put(ModeratorProfile.SOFT_MODER, new ArrayList<>(softGroups));
|
||||
luckPermsGroups.put(ModeratorProfile.HARD_MODER, new ArrayList<>(hardGroups));
|
||||
|
||||
preventItemDrop = config.getBoolean("admin_mode.restrictions.prevent_item_drop", true);
|
||||
preventItemPickup = config.getBoolean("admin_mode.restrictions.prevent_item_pickup", false);
|
||||
preventContainerTransfer = config.getBoolean("admin_mode.restrictions.prevent_container_transfer", true);
|
||||
preventItemUse = config.getBoolean("admin_mode.restrictions.prevent_item_use", true);
|
||||
allowOwnInventory = config.getBoolean("admin_mode.restrictions.allow_own_inventory", true);
|
||||
allowedBlocks = config.getStringList("admin_mode.restrictions.allowed_blocks");
|
||||
allowedPlaceBlocks = config.getStringList("admin_mode.restrictions.allowed_place_blocks");
|
||||
givePresetBlocks = config.getBoolean("admin_mode.restrictions.give_preset_blocks", true);
|
||||
presetBlocks = config.getStringList("admin_mode.restrictions.preset_blocks");
|
||||
|
||||
forceSpectator = config.getBoolean("admin_mode.gamemode.force_spectator", false);
|
||||
mobsIgnorePlayer = config.getBoolean("admin_mode.gamemode.mobs_ignore_player", true);
|
||||
allowFlightInSurvival = config.getBoolean("admin_mode.gamemode.allow_flight_in_survival", true);
|
||||
godMode = config.getBoolean("admin_mode.gamemode.god_mode", true);
|
||||
customFlySpeed = (float) config.getDouble("admin_mode.gamemode.custom_fly_speed", 0.2);
|
||||
customWalkSpeed = (float) config.getDouble("admin_mode.gamemode.custom_walk_speed", 0.2);
|
||||
allowedGameModes = config.getStringList("admin_mode.gamemode.allowed_gamemodes");
|
||||
|
||||
msgEnabled = config.getString("admin_mode.messages.enabled", "✓ Режим администратора активирован!");
|
||||
msgEnabledSubtitle = config.getString("admin_mode.messages.enabled_subtitle", "Ваше состояние сохранено.");
|
||||
msgPermissionsGranted = config.getString("admin_mode.messages.permissions_granted",
|
||||
"⚠ Вам выданы временные права администратора!");
|
||||
msgDisabled = config.getString("admin_mode.messages.disabled", "✓ Режим администратора отключен!");
|
||||
msgDisabledSubtitle = config.getString("admin_mode.messages.disabled_subtitle",
|
||||
"Ваше состояние восстановлено.");
|
||||
msgPermissionsRemoved = config.getString("admin_mode.messages.permissions_removed",
|
||||
"✓ Права администратора отозваны!");
|
||||
msgNoPermission = config.getString("admin_mode.messages.no_permission",
|
||||
"У вас нет прав для использования этой команды!");
|
||||
msgItemDropDenied = config.getString("admin_mode.messages.item_drop_denied",
|
||||
"✖ В режиме администратора нельзя выбрасывать предметы!");
|
||||
msgContainerTransferDenied = config.getString("admin_mode.messages.container_transfer_denied",
|
||||
"✖ В режиме администратора нельзя перемещать предметы в контейнеры!");
|
||||
msgItemUseDenied = config.getString("admin_mode.messages.item_use_denied",
|
||||
"✖ В режиме администратора нельзя использовать предметы!");
|
||||
msgBlockPlaceDenied = config.getString("admin_mode.messages.block_place_denied",
|
||||
"✖ Вы можете ставить только разрешенные блоки!");
|
||||
msgReloaded = config.getString("admin_mode.messages.reloaded", "✓ Конфигурация AdminMode перезагружена!");
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public boolean isUseLuckPerms() {
|
||||
return useLuckPerms;
|
||||
}
|
||||
|
||||
public List<String> getLuckPermsGroups() {
|
||||
return getLuckPermsGroups(ModeratorProfile.SOFT_MODER);
|
||||
}
|
||||
|
||||
public List<String> getLuckPermsGroups(ModeratorProfile profile) {
|
||||
return new ArrayList<>(luckPermsGroups.getOrDefault(profile, List.of()));
|
||||
}
|
||||
|
||||
public boolean isRemoveGroupsOnDisable() {
|
||||
return removeGroupsOnDisable;
|
||||
}
|
||||
|
||||
public boolean isDialogsEnabled() {
|
||||
return dialogsEnabled;
|
||||
}
|
||||
|
||||
public boolean isPreventItemDrop() {
|
||||
return preventItemDrop;
|
||||
}
|
||||
|
||||
public boolean isPreventItemPickup() {
|
||||
return preventItemPickup;
|
||||
}
|
||||
|
||||
public boolean isPreventContainerTransfer() {
|
||||
return preventContainerTransfer;
|
||||
}
|
||||
|
||||
public boolean isPreventItemUse() {
|
||||
return preventItemUse;
|
||||
}
|
||||
|
||||
public boolean isAllowOwnInventory() {
|
||||
return allowOwnInventory;
|
||||
}
|
||||
|
||||
public List<String> getAllowedBlocks() {
|
||||
return allowedBlocks;
|
||||
}
|
||||
|
||||
public List<String> getAllowedPlaceBlocks() {
|
||||
return allowedPlaceBlocks;
|
||||
}
|
||||
|
||||
public boolean isGivePresetBlocks() {
|
||||
return givePresetBlocks;
|
||||
}
|
||||
|
||||
public List<String> getPresetBlocks() {
|
||||
return presetBlocks;
|
||||
}
|
||||
|
||||
public boolean isForceSpectator() {
|
||||
return forceSpectator;
|
||||
}
|
||||
|
||||
public boolean isMobsIgnorePlayer() {
|
||||
return mobsIgnorePlayer;
|
||||
}
|
||||
|
||||
public boolean isAllowFlightInSurvival() {
|
||||
return allowFlightInSurvival;
|
||||
}
|
||||
|
||||
public boolean isGodMode() {
|
||||
return godMode;
|
||||
}
|
||||
|
||||
public float getCustomFlySpeed() {
|
||||
return customFlySpeed;
|
||||
}
|
||||
|
||||
public float getCustomWalkSpeed() {
|
||||
return customWalkSpeed;
|
||||
}
|
||||
|
||||
public List<String> getAllowedGameModes() {
|
||||
return allowedGameModes;
|
||||
}
|
||||
|
||||
public String getMsgEnabled() {
|
||||
return msgEnabled;
|
||||
}
|
||||
|
||||
public String getMsgEnabledSubtitle() {
|
||||
return msgEnabledSubtitle;
|
||||
}
|
||||
|
||||
public String getMsgPermissionsGranted() {
|
||||
return msgPermissionsGranted;
|
||||
}
|
||||
|
||||
public String getMsgDisabled() {
|
||||
return msgDisabled;
|
||||
}
|
||||
|
||||
public String getMsgDisabledSubtitle() {
|
||||
return msgDisabledSubtitle;
|
||||
}
|
||||
|
||||
public String getMsgPermissionsRemoved() {
|
||||
return msgPermissionsRemoved;
|
||||
}
|
||||
|
||||
public String getMsgNoPermission() {
|
||||
return msgNoPermission;
|
||||
}
|
||||
|
||||
public String getMsgItemDropDenied() {
|
||||
return msgItemDropDenied;
|
||||
}
|
||||
|
||||
public String getMsgContainerTransferDenied() {
|
||||
return msgContainerTransferDenied;
|
||||
}
|
||||
|
||||
public String getMsgItemUseDenied() {
|
||||
return msgItemUseDenied;
|
||||
}
|
||||
|
||||
public String getMsgBlockPlaceDenied() {
|
||||
return msgBlockPlaceDenied;
|
||||
}
|
||||
|
||||
public String getMsgReloaded() {
|
||||
return msgReloaded;
|
||||
}
|
||||
}
|
||||
314
src/main/java/org/blz/adminmode/data/AdminModeDataManager.java
Normal file
314
src/main/java/org/blz/adminmode/data/AdminModeDataManager.java
Normal file
@@ -0,0 +1,314 @@
|
||||
package org.blz.adminmode.data;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
public class AdminModeDataManager {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final File dataFolder;
|
||||
private final Gson gson;
|
||||
|
||||
public AdminModeDataManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.dataFolder = new File(plugin.getDataFolder(), "adminmode");
|
||||
this.gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
if (!dataFolder.exists()) {
|
||||
dataFolder.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public void savePlayerState(UUID playerId, PlayerStateData state) {
|
||||
File playerFile = new File(dataFolder, playerId.toString() + ".json");
|
||||
|
||||
try (FileWriter writer = new FileWriter(playerFile)) {
|
||||
JsonObject json = new JsonObject();
|
||||
|
||||
json.addProperty("inventory", serializeItemArray(state.inventory));
|
||||
json.addProperty("armorContents", serializeItemArray(state.armorContents));
|
||||
json.addProperty("offHand", serializeItem(state.offHand));
|
||||
|
||||
JsonObject locationJson = new JsonObject();
|
||||
locationJson.addProperty("world", state.location.getWorld().getName());
|
||||
locationJson.addProperty("x", state.location.getX());
|
||||
locationJson.addProperty("y", state.location.getY());
|
||||
locationJson.addProperty("z", state.location.getZ());
|
||||
locationJson.addProperty("yaw", state.location.getYaw());
|
||||
locationJson.addProperty("pitch", state.location.getPitch());
|
||||
json.add("location", locationJson);
|
||||
|
||||
json.addProperty("health", state.health);
|
||||
json.addProperty("foodLevel", state.foodLevel);
|
||||
json.addProperty("saturation", state.saturation);
|
||||
json.addProperty("exhaustion", state.exhaustion);
|
||||
|
||||
json.addProperty("exp", state.exp);
|
||||
json.addProperty("level", state.level);
|
||||
json.addProperty("totalExperience", state.totalExperience);
|
||||
json.addProperty("gameMode", state.gameMode.name());
|
||||
|
||||
json.addProperty("allowFlight", state.allowFlight);
|
||||
json.addProperty("flying", state.flying);
|
||||
json.addProperty("flySpeed", state.flySpeed);
|
||||
json.addProperty("walkSpeed", state.walkSpeed);
|
||||
json.addProperty("potionEffects", serializePotionEffects(state.potionEffects));
|
||||
json.addProperty("fireTicks", state.fireTicks);
|
||||
json.addProperty("profileKey", state.profileKey);
|
||||
|
||||
writer.write(gson.toJson(json));
|
||||
plugin.getLogger().info("Сохранено состояние игрока: " + playerId);
|
||||
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().severe("Не удалось сохранить состояние игрока " + playerId);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerStateData loadPlayerState(UUID playerId) {
|
||||
File playerFile = new File(dataFolder, playerId.toString() + ".json");
|
||||
|
||||
if (!playerFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(playerFile)) {
|
||||
JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
|
||||
PlayerStateData state = new PlayerStateData();
|
||||
|
||||
state.inventory = deserializeItemArray(json.get("inventory").getAsString());
|
||||
state.armorContents = deserializeItemArray(json.get("armorContents").getAsString());
|
||||
state.offHand = deserializeItem(json.get("offHand").getAsString());
|
||||
|
||||
JsonObject locationJson = json.getAsJsonObject("location");
|
||||
World world = Bukkit.getWorld(locationJson.get("world").getAsString());
|
||||
if (world != null) {
|
||||
state.location = new Location(
|
||||
world,
|
||||
locationJson.get("x").getAsDouble(),
|
||||
locationJson.get("y").getAsDouble(),
|
||||
locationJson.get("z").getAsDouble(),
|
||||
locationJson.get("yaw").getAsFloat(),
|
||||
locationJson.get("pitch").getAsFloat()
|
||||
);
|
||||
}
|
||||
|
||||
state.health = json.get("health").getAsDouble();
|
||||
state.foodLevel = json.get("foodLevel").getAsInt();
|
||||
state.saturation = json.get("saturation").getAsFloat();
|
||||
state.exhaustion = json.get("exhaustion").getAsFloat();
|
||||
|
||||
state.exp = json.get("exp").getAsFloat();
|
||||
state.level = json.get("level").getAsInt();
|
||||
state.totalExperience = json.get("totalExperience").getAsInt();
|
||||
state.gameMode = GameMode.valueOf(json.get("gameMode").getAsString());
|
||||
|
||||
state.allowFlight = json.get("allowFlight").getAsBoolean();
|
||||
state.flying = json.get("flying").getAsBoolean();
|
||||
state.flySpeed = json.get("flySpeed").getAsFloat();
|
||||
state.walkSpeed = json.get("walkSpeed").getAsFloat();
|
||||
state.potionEffects = deserializePotionEffects(json.get("potionEffects").getAsString());
|
||||
state.fireTicks = json.get("fireTicks").getAsInt();
|
||||
if (json.has("profileKey") && !json.get("profileKey").isJsonNull()) {
|
||||
state.profileKey = json.get("profileKey").getAsString();
|
||||
}
|
||||
|
||||
plugin.getLogger().info("Загружено состояние игрока: " + playerId);
|
||||
return state;
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe("Не удалось загрузить состояние игрока " + playerId);
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void deletePlayerState(UUID playerId) {
|
||||
File playerFile = new File(dataFolder, playerId.toString() + ".json");
|
||||
|
||||
if (playerFile.exists()) {
|
||||
if (playerFile.delete()) {
|
||||
plugin.getLogger().info("Удалено состояние игрока: " + playerId);
|
||||
} else {
|
||||
plugin.getLogger().warning("Не удалось удалить файл состояния: " + playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPlayerState(UUID playerId) {
|
||||
File playerFile = new File(dataFolder, playerId.toString() + ".json");
|
||||
return playerFile.exists();
|
||||
}
|
||||
|
||||
public Set<UUID> getAllSavedStates() {
|
||||
Set<UUID> states = new HashSet<>();
|
||||
File[] files = dataFolder.listFiles((dir, name) -> name.endsWith(".json"));
|
||||
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
try {
|
||||
String uuidStr = file.getName().replace(".json", "");
|
||||
states.add(UUID.fromString(uuidStr));
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getLogger().warning("Некорректный файл состояния: " + file.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
private String serializeItemArray(ItemStack[] items) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
|
||||
dataOutput.writeInt(items.length);
|
||||
|
||||
for (ItemStack item : items) {
|
||||
dataOutput.writeObject(item);
|
||||
}
|
||||
|
||||
dataOutput.close();
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack[] deserializeItemArray(String data) {
|
||||
try {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(data));
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
|
||||
int length = dataInput.readInt();
|
||||
ItemStack[] items = new ItemStack[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
items[i] = (ItemStack) dataInput.readObject();
|
||||
}
|
||||
|
||||
dataInput.close();
|
||||
return items;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new ItemStack[0];
|
||||
}
|
||||
}
|
||||
|
||||
private String serializeItem(ItemStack item) {
|
||||
try {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
|
||||
dataOutput.writeObject(item);
|
||||
dataOutput.close();
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack deserializeItem(String data) {
|
||||
try {
|
||||
if (data.isEmpty()) {
|
||||
return new ItemStack(Material.AIR);
|
||||
}
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(data));
|
||||
BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
|
||||
ItemStack item = (ItemStack) dataInput.readObject();
|
||||
dataInput.close();
|
||||
return item;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new ItemStack(Material.AIR);
|
||||
}
|
||||
}
|
||||
|
||||
private String serializePotionEffects(Collection<PotionEffect> effects) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (PotionEffect effect : effects) {
|
||||
sb.append(effect.getType().getName()).append(":")
|
||||
.append(effect.getDuration()).append(":")
|
||||
.append(effect.getAmplifier()).append(":")
|
||||
.append(effect.isAmbient()).append(":")
|
||||
.append(effect.hasParticles()).append(":")
|
||||
.append(effect.hasIcon()).append(";");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Collection<PotionEffect> deserializePotionEffects(String data) {
|
||||
Collection<PotionEffect> effects = new ArrayList<>();
|
||||
if (data.isEmpty()) return effects;
|
||||
|
||||
String[] effectStrings = data.split(";");
|
||||
for (String effectStr : effectStrings) {
|
||||
if (effectStr.isEmpty()) continue;
|
||||
|
||||
try {
|
||||
String[] parts = effectStr.split(":");
|
||||
PotionEffectType type = PotionEffectType.getByName(parts[0]);
|
||||
int duration = Integer.parseInt(parts[1]);
|
||||
int amplifier = Integer.parseInt(parts[2]);
|
||||
boolean ambient = Boolean.parseBoolean(parts[3]);
|
||||
boolean particles = Boolean.parseBoolean(parts[4]);
|
||||
boolean icon = Boolean.parseBoolean(parts[5]);
|
||||
|
||||
effects.add(new PotionEffect(type, duration, amplifier, ambient, particles, icon));
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Ошибка десериализации эффекта: " + effectStr);
|
||||
}
|
||||
}
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
||||
public static class PlayerStateData {
|
||||
public ItemStack[] inventory;
|
||||
public ItemStack[] armorContents;
|
||||
public ItemStack offHand;
|
||||
public Location location;
|
||||
public double health;
|
||||
public int foodLevel;
|
||||
public float saturation;
|
||||
public float exhaustion;
|
||||
public float exp;
|
||||
public int level;
|
||||
public int totalExperience;
|
||||
public GameMode gameMode;
|
||||
public boolean allowFlight;
|
||||
public boolean flying;
|
||||
public float flySpeed;
|
||||
public float walkSpeed;
|
||||
public Collection<PotionEffect> potionEffects;
|
||||
public int fireTicks;
|
||||
public String profileKey;
|
||||
}
|
||||
}
|
||||
297
src/main/java/org/blz/adminmode/dialog/AdminDialogService.java
Normal file
297
src/main/java/org/blz/adminmode/dialog/AdminDialogService.java
Normal file
@@ -0,0 +1,297 @@
|
||||
package org.blz.adminmode.dialog;
|
||||
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogActionCallback;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.input.DialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickCallback;
|
||||
import org.blz.adminmode.commands.AdminModeCommand;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.blz.adminmode.moderation.ModeratorProfile;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AdminDialogService {
|
||||
|
||||
private static final ClickCallback.Options CALLBACK_OPTIONS = ClickCallback.Options.builder()
|
||||
.uses(1)
|
||||
.lifetime(Duration.ofMinutes(5))
|
||||
.build();
|
||||
|
||||
private final Plugin plugin;
|
||||
private final ConfigManager configManager;
|
||||
private final AdminModeCommand adminModeCommand;
|
||||
|
||||
public AdminDialogService(Plugin plugin, ConfigManager configManager, AdminModeCommand adminModeCommand) {
|
||||
this.plugin = plugin;
|
||||
this.configManager = configManager;
|
||||
this.adminModeCommand = adminModeCommand;
|
||||
}
|
||||
|
||||
public boolean openProfileSelectionDialog(Player player) {
|
||||
if (!configManager.isDialogsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ModeratorProfile> profiles = adminModeCommand.getAvailableProfiles(player);
|
||||
if (profiles.isEmpty()) {
|
||||
player.sendMessage(configManager.getMsgNoPermission());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (profiles.size() == 1) {
|
||||
adminModeCommand.toggleAdminMode(player, profiles.get(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
List<ActionButton> buttons = new ArrayList<>();
|
||||
for (ModeratorProfile profile : profiles) {
|
||||
buttons.add(actionButton(
|
||||
profile.getDisplayName(),
|
||||
profile.isHardProfile()
|
||||
? "Полный режим модерации с сильными действиями"
|
||||
: "Базовый режим модерации для повседневной работы",
|
||||
(response, audience) -> withPlayer(audience, moderator -> {
|
||||
adminModeCommand.toggleAdminMode(moderator, profile);
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
if (adminModeCommand.isInAdminMode(moderator.getUniqueId())) {
|
||||
openModerationPanel(moderator);
|
||||
}
|
||||
});
|
||||
})));
|
||||
}
|
||||
|
||||
DialogBase base = DialogBase.builder(Component.text("Выбор профиля модерации"))
|
||||
.canCloseWithEscape(true)
|
||||
.pause(false)
|
||||
.afterAction(DialogBase.DialogAfterAction.CLOSE)
|
||||
.body(List.of(DialogBody.plainMessage(Component.text(
|
||||
"Выберите профиль, с которым хотите войти в admin mode. Soft — для обычной модерации, Hard — для телепортов и сильных действий."),
|
||||
360)))
|
||||
.inputs(List.of())
|
||||
.build();
|
||||
|
||||
showDialog(player, base, DialogType.multiAction(buttons, closeButton(), 2));
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось открыть dialog выбора профиля: " + exception.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean openModerationPanel(Player player) {
|
||||
if (!configManager.isDialogsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
UUID playerId = player.getUniqueId();
|
||||
ModeratorProfile profile = adminModeCommand.getActiveProfile(playerId);
|
||||
boolean hardProfile = profile != null && profile.isHardProfile();
|
||||
|
||||
List<ActionButton> buttons = new ArrayList<>();
|
||||
buttons.add(actionButton(
|
||||
"Скорости и режим",
|
||||
"Открыть слайдеры скорости и переключатель бессмертия",
|
||||
(response, audience) -> withPlayer(audience, moderator -> schedule(() -> openSpeedPanel(moderator)))));
|
||||
buttons.add(actionButton(
|
||||
"Выключить admin mode",
|
||||
"Восстановить сохраненное состояние и снять временные права",
|
||||
(response, audience) -> withPlayer(audience, adminModeCommand::toggleAdminMode)));
|
||||
|
||||
if (hardProfile) {
|
||||
buttons.add(actionButton(
|
||||
"Телепорт к игроку",
|
||||
"Телепортировать себя к цели из поля ниже",
|
||||
(response, audience) -> withPlayer(audience, moderator -> {
|
||||
String targetName = normalizeTarget(response.getText("target_player"));
|
||||
adminModeCommand.teleportToPlayer(moderator, targetName);
|
||||
})));
|
||||
buttons.add(actionButton(
|
||||
"Игрок ко мне",
|
||||
"Телепортировать цель к себе",
|
||||
(response, audience) -> withPlayer(audience, moderator -> {
|
||||
String targetName = normalizeTarget(response.getText("target_player"));
|
||||
adminModeCommand.teleportPlayerHere(moderator, targetName);
|
||||
})));
|
||||
buttons.add(actionButton(
|
||||
"Сбросить способности",
|
||||
"Отключить полет, бессмертие и скорости у цели",
|
||||
(response, audience) -> withPlayer(audience, moderator -> {
|
||||
String targetName = normalizeTarget(response.getText("target_player"));
|
||||
adminModeCommand.forceDisableTarget(moderator, targetName);
|
||||
})));
|
||||
}
|
||||
|
||||
List<Component> lines = new ArrayList<>();
|
||||
lines.add(Component.text("Активный профиль: " + (profile == null ? "unknown" : profile.getDisplayName())));
|
||||
lines.add(Component.text(hardProfile
|
||||
? "Hard профиль открывает телепорты и сильные действия."
|
||||
: "Soft профиль оставляет только безопасные действия и настройку режима."));
|
||||
lines.add(Component.text("Для действий по цели используйте поле с ником игрока."));
|
||||
|
||||
DialogBase base = DialogBase.builder(Component.text("Панель модератора"))
|
||||
.canCloseWithEscape(true)
|
||||
.pause(false)
|
||||
.afterAction(DialogBase.DialogAfterAction.CLOSE)
|
||||
.body(List.of(DialogBody.plainMessage(joinLines(lines), 360)))
|
||||
.inputs(List.of(DialogInput.text(
|
||||
"target_player",
|
||||
320,
|
||||
Component.text("Ник цели"),
|
||||
true,
|
||||
"",
|
||||
16,
|
||||
null)))
|
||||
.build();
|
||||
|
||||
showDialog(player, base, DialogType.multiAction(buttons, closeButton(), 2));
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось открыть moderation dialog: " + exception.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean openSpeedPanel(Player player) {
|
||||
if (!configManager.isDialogsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
float currentFly = clamp(player.getFlySpeed(), 0.1f, 1.0f);
|
||||
float currentWalk = clamp(player.getWalkSpeed(), 0.1f, 1.0f);
|
||||
|
||||
ActionButton applyButton = actionButton(
|
||||
"Применить",
|
||||
"Сохранить выбранные значения скорости и бессмертия",
|
||||
(response, audience) -> withPlayer(audience, moderator -> {
|
||||
Float flySpeed = response.getFloat("fly_speed");
|
||||
Float walkSpeed = response.getFloat("walk_speed");
|
||||
Boolean godMode = response.getBoolean("god_mode");
|
||||
adminModeCommand.applyAdminSettings(
|
||||
moderator,
|
||||
flySpeed == null ? currentFly : flySpeed,
|
||||
walkSpeed == null ? currentWalk : walkSpeed,
|
||||
godMode != null && godMode);
|
||||
schedule(() -> openModerationPanel(moderator));
|
||||
}));
|
||||
|
||||
ActionButton backButton = actionButton(
|
||||
"Назад",
|
||||
"Вернуться в основную панель модератора",
|
||||
(response, audience) -> withPlayer(audience, moderator -> schedule(() -> openModerationPanel(moderator))));
|
||||
|
||||
DialogBase base = DialogBase.builder(Component.text("Настройка admin mode"))
|
||||
.canCloseWithEscape(true)
|
||||
.pause(false)
|
||||
.afterAction(DialogBase.DialogAfterAction.CLOSE)
|
||||
.body(List.of(DialogBody.plainMessage(Component.text(
|
||||
"Настройте полет, скорость передвижения и режим бессмертия через новые элементы dialog API."),
|
||||
360)))
|
||||
.inputs(List.of(
|
||||
DialogInput.numberRange(
|
||||
"fly_speed",
|
||||
320,
|
||||
Component.text("Скорость полета"),
|
||||
"%s: %s",
|
||||
0.1f,
|
||||
1.0f,
|
||||
currentFly,
|
||||
0.05f),
|
||||
DialogInput.numberRange(
|
||||
"walk_speed",
|
||||
320,
|
||||
Component.text("Скорость ходьбы"),
|
||||
"%s: %s",
|
||||
0.1f,
|
||||
1.0f,
|
||||
currentWalk,
|
||||
0.05f),
|
||||
DialogInput.bool(
|
||||
"god_mode",
|
||||
Component.text("Бессмертие"),
|
||||
player.isInvulnerable(),
|
||||
"true",
|
||||
"false")))
|
||||
.build();
|
||||
|
||||
showDialog(player, base, DialogType.multiAction(List.of(applyButton), backButton, 1));
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
plugin.getLogger().warning("Не удалось открыть dialog настройки скоростей: " + exception.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void showDialog(Player player, DialogBase base, io.papermc.paper.registry.data.dialog.type.DialogType type) {
|
||||
Dialog dialog = Dialog.create(factory -> {
|
||||
var builder = factory.empty();
|
||||
builder.base(base);
|
||||
builder.type(type);
|
||||
});
|
||||
player.showDialog(dialog);
|
||||
}
|
||||
|
||||
private ActionButton actionButton(String label, String tooltip, DialogActionCallback callback) {
|
||||
return ActionButton.builder(Component.text(label))
|
||||
.tooltip(Component.text(tooltip))
|
||||
.width(170)
|
||||
.action(DialogAction.customClick(callback, CALLBACK_OPTIONS))
|
||||
.build();
|
||||
}
|
||||
|
||||
private ActionButton closeButton() {
|
||||
return ActionButton.builder(Component.text("Закрыть"))
|
||||
.width(140)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void withPlayer(net.kyori.adventure.audience.Audience audience, java.util.function.Consumer<Player> consumer) {
|
||||
if (audience instanceof Player player) {
|
||||
consumer.accept(player);
|
||||
}
|
||||
}
|
||||
|
||||
private Component joinLines(List<Component> lines) {
|
||||
Component result = Component.empty();
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (i > 0) {
|
||||
result = result.append(Component.newline());
|
||||
}
|
||||
result = result.append(lines.get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void schedule(Runnable runnable) {
|
||||
plugin.getServer().getScheduler().runTask(plugin, runnable);
|
||||
}
|
||||
|
||||
private String normalizeTarget(String targetName) {
|
||||
return targetName == null ? "" : targetName.trim();
|
||||
}
|
||||
|
||||
private float clamp(float value, float min, float max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
}
|
||||
129
src/main/java/org/blz/adminmode/listeners/AdminModeListener.java
Normal file
129
src/main/java/org/blz/adminmode/listeners/AdminModeListener.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package org.blz.adminmode.listeners;
|
||||
|
||||
import org.blz.adminmode.commands.AdminModeCommand;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AdminModeListener implements Listener {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final AdminModeCommand adminModeCommand;
|
||||
private final ConfigManager configManager;
|
||||
|
||||
public AdminModeListener(Plugin plugin, AdminModeCommand adminModeCommand, ConfigManager configManager) {
|
||||
this.plugin = plugin;
|
||||
this.adminModeCommand = adminModeCommand;
|
||||
this.configManager = configManager;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onItemDrop(PlayerDropItemEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
if (!configManager.isPreventItemDrop()) return;
|
||||
|
||||
e.setCancelled(true);
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgItemDropDenied());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onItemPickup(EntityPickupItemEvent e) {
|
||||
if (!(e.getEntity() instanceof Player)) return;
|
||||
|
||||
Player player = (Player) e.getEntity();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
if (!configManager.isPreventItemPickup()) return;
|
||||
|
||||
e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInventoryClick(InventoryClickEvent e) {
|
||||
if (!(e.getWhoClicked() instanceof Player)) return;
|
||||
|
||||
Player player = (Player) e.getWhoClicked();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
if (!configManager.isPreventContainerTransfer()) return;
|
||||
|
||||
if (e.getClickedInventory() != null) {
|
||||
if (e.getClickedInventory().getHolder() != null &&
|
||||
!e.getClickedInventory().getHolder().equals(player)) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgContainerTransferDenied());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.isShiftClick()) {
|
||||
if (e.getView().getTopInventory().getHolder() != null &&
|
||||
!e.getView().getTopInventory().getHolder().equals(player)) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgContainerTransferDenied());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onPlayerInteract(PlayerInteractEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
if (!configManager.isPreventItemUse()) return;
|
||||
|
||||
if (e.getAction() == org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK) {
|
||||
if (e.getClickedBlock() != null) {
|
||||
Material blockType = e.getClickedBlock().getType();
|
||||
|
||||
List<String> allowedBlocks = configManager.getAllowedBlocks();
|
||||
|
||||
for (String allowed : allowedBlocks) {
|
||||
if (blockType.name().contains(allowed.toUpperCase())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.getItem() != null && e.getItem().getType() != Material.AIR) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgItemUseDenied());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onBlockPlace(BlockPlaceEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) return;
|
||||
|
||||
List<String> allowedPlaceBlocks = configManager.getAllowedPlaceBlocks();
|
||||
if (allowedPlaceBlocks.isEmpty()) return;
|
||||
|
||||
Material blockType = e.getBlock().getType();
|
||||
|
||||
for (String allowed : allowedPlaceBlocks) {
|
||||
if (blockType.name().equalsIgnoreCase(allowed)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
e.setCancelled(true);
|
||||
player.sendMessage(ChatColor.RED + configManager.getMsgBlockPlaceDenied());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.blz.adminmode.listeners;
|
||||
|
||||
import org.blz.adminmode.commands.AdminModeCommand;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerGameModeChangeEvent;
|
||||
import org.bukkit.event.player.PlayerToggleFlightEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GameModeChangeListener implements Listener {
|
||||
|
||||
private final AdminModeCommand adminModeCommand;
|
||||
private final ConfigManager configManager;
|
||||
|
||||
public GameModeChangeListener(AdminModeCommand adminModeCommand, ConfigManager configManager) {
|
||||
this.adminModeCommand = adminModeCommand;
|
||||
this.configManager = configManager;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onGameModeChange(PlayerGameModeChangeEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// КРИТИЧНО: Блокируем CREATIVE для всех в админ моде!
|
||||
if (event.getNewGameMode() == GameMode.CREATIVE) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage(ChatColor.RED + "✖ В режиме модератора КРЕАТИВ запрещен!");
|
||||
player.sendMessage(ChatColor.GRAY + "Доступные режимы: SURVIVAL, SPECTATOR");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> allowedModes = configManager.getAllowedGameModes();
|
||||
|
||||
if (!allowedModes.isEmpty()) {
|
||||
String newMode = event.getNewGameMode().name();
|
||||
|
||||
if (!allowedModes.contains(newMode)) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage(ChatColor.RED + "✖ В админ моде можно переключаться только на разрешенные режимы!");
|
||||
player.sendMessage(ChatColor.GRAY + "Разрешенные режимы: " + String.join(", ", allowedModes));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Включаем полет после смены режима, если это разрешено
|
||||
if (configManager.isAllowFlightInSurvival()) {
|
||||
player.getServer().getScheduler().runTaskLater(
|
||||
player.getServer().getPluginManager().getPlugin("AdminMode"),
|
||||
() -> {
|
||||
player.setAllowFlight(true);
|
||||
if (!player.isFlying()) {
|
||||
player.setFlying(true);
|
||||
}
|
||||
},
|
||||
1L);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onToggleFlight(PlayerToggleFlightEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (!adminModeCommand.isInAdminMode(player.getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!configManager.isAllowFlightInSurvival()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Всегда разрешаем полет в админ моде
|
||||
if (!player.getAllowFlight()) {
|
||||
player.setAllowFlight(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.blz.adminmode.listeners;
|
||||
|
||||
import org.blz.adminmode.commands.AdminModeCommand;
|
||||
import org.blz.adminmode.config.ConfigManager;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityTargetEvent;
|
||||
|
||||
public class MobTargetListener implements Listener {
|
||||
|
||||
private final AdminModeCommand adminModeCommand;
|
||||
private final ConfigManager configManager;
|
||||
|
||||
public MobTargetListener(AdminModeCommand adminModeCommand, ConfigManager configManager) {
|
||||
this.adminModeCommand = adminModeCommand;
|
||||
this.configManager = configManager;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onMobTarget(EntityTargetEvent e) {
|
||||
if (!configManager.isMobsIgnorePlayer()) return;
|
||||
|
||||
if (e.getTarget() instanceof Player) {
|
||||
Player player = (Player) e.getTarget();
|
||||
|
||||
if (adminModeCommand.isInAdminMode(player.getUniqueId())) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
413
src/main/java/org/blz/adminmode/managers/BelzeBoolManager.java
Normal file
413
src/main/java/org/blz/adminmode/managers/BelzeBoolManager.java
Normal file
@@ -0,0 +1,413 @@
|
||||
package org.blz.adminmode.managers;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.blz.adminmode.utils.ScreenEffects;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.Entity;
|
||||
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.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BelzeBoolManager implements Listener {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final String BELZEBOOL_NAME = "BelzeBool";
|
||||
private final String POCKET_DIMENSION_WORLD = "pocket_dimension";
|
||||
private final long COOLDOWN_MS = 16000; // 16 seconds
|
||||
|
||||
// Casting Mode State
|
||||
private final Set<UUID> castingModePlayers = new HashSet<>();
|
||||
private final Map<UUID, Integer> selectedSpellIndex = new HashMap<>();
|
||||
private final List<String> spells = Arrays.asList("POCKET DIMENSION", "DEADLY KISS", "VANISH");
|
||||
|
||||
// Cooldowns: UUID -> SpellName -> Timestamp
|
||||
private final Map<UUID, Map<String, Long>> cooldowns = new HashMap<>();
|
||||
|
||||
// Vanish State: UUID -> isVanished
|
||||
private final Set<UUID> vanishedPlayers = new HashSet<>();
|
||||
|
||||
// Input Tracking
|
||||
private final Map<UUID, List<Long>> rightClickTimestamps = new HashMap<>();
|
||||
|
||||
public BelzeBoolManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
startActionBarTask();
|
||||
}
|
||||
|
||||
public boolean isBelzeBool(Player player) {
|
||||
return player.getName().equalsIgnoreCase(BELZEBOOL_NAME);
|
||||
}
|
||||
|
||||
// --- Casting Mode Logic ---
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
if (!isBelzeBool(event.getPlayer()))
|
||||
return;
|
||||
Player player = event.getPlayer();
|
||||
|
||||
// Casting Mode Toggle: Shift + Right Click x5 (only with empty hands)
|
||||
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
if (player.isSneaking() && event.getHand() == EquipmentSlot.HAND) {
|
||||
// Only allow if hands are empty
|
||||
ItemStack mainHand = player.getInventory().getItemInMainHand();
|
||||
ItemStack offHand = player.getInventory().getItemInOffHand();
|
||||
|
||||
if ((mainHand == null || mainHand.getType() == Material.AIR) &&
|
||||
(offHand == null || offHand.getType() == Material.AIR)) {
|
||||
trackRightClick(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!castingModePlayers.contains(player.getUniqueId()))
|
||||
return;
|
||||
|
||||
// Spell Cycle: Left Click (In Casting Mode)
|
||||
if (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) {
|
||||
if (event.getHand() == EquipmentSlot.HAND) { // Prevent double firing
|
||||
event.setCancelled(true);
|
||||
cycleSpell(player);
|
||||
}
|
||||
}
|
||||
|
||||
// Cast Spell: Right Click (In Casting Mode)
|
||||
// If spell is VANISH, we can cast it on Air/Block too
|
||||
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
if (event.getHand() == EquipmentSlot.HAND) {
|
||||
String spell = getSelectedSpell(player);
|
||||
if (spell.equals("VANISH")) {
|
||||
event.setCancelled(true);
|
||||
castVanish(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityInteract(PlayerInteractEntityEvent event) {
|
||||
if (!isBelzeBool(event.getPlayer()))
|
||||
return;
|
||||
if (event.getHand() != EquipmentSlot.HAND)
|
||||
return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
Entity target = event.getRightClicked();
|
||||
|
||||
if (castingModePlayers.contains(player.getUniqueId())) {
|
||||
event.setCancelled(true);
|
||||
castSpell(player, target);
|
||||
}
|
||||
}
|
||||
|
||||
private void trackRightClick(Player player) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
List<Long> clicks = rightClickTimestamps.getOrDefault(uuid, new ArrayList<>());
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
// Remove old clicks (>2s ago)
|
||||
clicks.removeIf(time -> now - time > 2000);
|
||||
clicks.add(now);
|
||||
|
||||
if (clicks.size() >= 5) {
|
||||
toggleCastingMode(player);
|
||||
clicks.clear();
|
||||
}
|
||||
rightClickTimestamps.put(uuid, clicks);
|
||||
}
|
||||
|
||||
private void toggleCastingMode(Player player) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
if (castingModePlayers.contains(uuid)) {
|
||||
castingModePlayers.remove(uuid);
|
||||
player.sendActionBar(Component.text("Casting Mode Deactivated", NamedTextColor.RED));
|
||||
} else {
|
||||
castingModePlayers.add(uuid);
|
||||
selectedSpellIndex.putIfAbsent(uuid, 0);
|
||||
player.sendActionBar(Component.text("Casting Mode Activated", NamedTextColor.GREEN));
|
||||
}
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_BEACON_ACTIVATE, 1f, 2f);
|
||||
}
|
||||
|
||||
public void cycleSpell(Player player) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
int index = selectedSpellIndex.getOrDefault(uuid, 0);
|
||||
index = (index + 1) % spells.size();
|
||||
selectedSpellIndex.put(uuid, index);
|
||||
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 1f);
|
||||
}
|
||||
|
||||
public void castCurrentSpell(Player player) {
|
||||
if (!castingModePlayers.contains(player.getUniqueId())) {
|
||||
// Optional: Auto-activate casting mode if key pressed?
|
||||
// Or just ignore. User logic says key is for "ability".
|
||||
// Logic in onInteract checks castingModePlayers.
|
||||
// I will adhere to that.
|
||||
return;
|
||||
}
|
||||
|
||||
String spell = getSelectedSpell(player);
|
||||
|
||||
if (spell.equals("VANISH")) {
|
||||
castVanish(player);
|
||||
return;
|
||||
}
|
||||
|
||||
// RayTrace for target
|
||||
Entity target = rayTraceEntity(player, 20); // 20 blocks range
|
||||
if (target != null) {
|
||||
castSpell(player, target);
|
||||
} else {
|
||||
player.sendMessage(Component.text("No target found!", NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
|
||||
private Entity rayTraceEntity(Player player, double range) {
|
||||
// Simple RayTrace
|
||||
org.bukkit.util.RayTraceResult result = player.getWorld().rayTraceEntities(
|
||||
player.getEyeLocation(),
|
||||
player.getEyeLocation().getDirection(),
|
||||
range,
|
||||
entity -> entity != player && entity instanceof org.bukkit.entity.LivingEntity);
|
||||
return result != null ? result.getHitEntity() : null;
|
||||
}
|
||||
|
||||
private String getSelectedSpell(Player player) {
|
||||
int index = selectedSpellIndex.getOrDefault(player.getUniqueId(), 0);
|
||||
return spells.get(index);
|
||||
}
|
||||
|
||||
private void startActionBarTask() {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (UUID uuid : castingModePlayers) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null && player.isOnline()) {
|
||||
String spell = getSelectedSpell(player);
|
||||
long cooldown = getCooldownRemaining(uuid, spell);
|
||||
|
||||
Component text;
|
||||
if (cooldown > 0) {
|
||||
text = Component.text("< " + spell + " (" + (cooldown / 1000) + "s) >", NamedTextColor.RED,
|
||||
TextDecoration.BOLD);
|
||||
} else {
|
||||
if (spell.equals("VANISH") && vanishedPlayers.contains(uuid)) {
|
||||
text = Component.text("< " + spell + " (ACTIVE) >", NamedTextColor.AQUA,
|
||||
TextDecoration.BOLD);
|
||||
} else {
|
||||
text = Component.text("< " + spell + " >", NamedTextColor.GOLD, TextDecoration.BOLD);
|
||||
}
|
||||
}
|
||||
player.sendActionBar(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 5L);
|
||||
}
|
||||
|
||||
private long getCooldownRemaining(UUID uuid, String spell) {
|
||||
if (!cooldowns.containsKey(uuid))
|
||||
return 0;
|
||||
Long timestamp = cooldowns.get(uuid).get(spell);
|
||||
if (timestamp == null)
|
||||
return 0;
|
||||
|
||||
long remaining = (timestamp + COOLDOWN_MS) - System.currentTimeMillis();
|
||||
return Math.max(0, remaining);
|
||||
}
|
||||
|
||||
private void setCooldown(UUID uuid, String spell) {
|
||||
cooldowns.computeIfAbsent(uuid, k -> new HashMap<>()).put(spell, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private void castSpell(Player player, Entity target) {
|
||||
String spell = getSelectedSpell(player);
|
||||
|
||||
// Vanish is self-targeted, but we allow clicking on entity to trigger it too if
|
||||
// selected
|
||||
if (spell.equals("VANISH")) {
|
||||
castVanish(player);
|
||||
return;
|
||||
}
|
||||
|
||||
if (getCooldownRemaining(player.getUniqueId(), spell) > 0) {
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
|
||||
return;
|
||||
}
|
||||
|
||||
setCooldown(player.getUniqueId(), spell);
|
||||
|
||||
switch (spell) {
|
||||
case "POCKET DIMENSION" -> castPocketDimension(player, target);
|
||||
case "DEADLY KISS" -> castDeadlyKiss(player, target);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Ability: Pocket Dimension ---
|
||||
|
||||
private void castPocketDimension(Player player, Entity target) {
|
||||
World pocketWorld = Bukkit.getWorld(POCKET_DIMENSION_WORLD);
|
||||
if (pocketWorld == null) {
|
||||
player.sendMessage(Component.text("Error: Pocket Dimension world not loaded!", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Abduction Sequence (Visuals)
|
||||
if (target instanceof Player targetP) {
|
||||
targetP.addPotionEffect(new PotionEffect(PotionEffectType.DARKNESS, 140, 0));
|
||||
targetP.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, 140, 4));
|
||||
}
|
||||
|
||||
target.getWorld().playSound(target.getLocation(), Sound.ENTITY_WARDEN_HEARTBEAT, 1f, 0.5f);
|
||||
target.getWorld().spawnParticle(Particle.SCULK_SOUL, target.getLocation(), 50, 0.5, 1, 0.5, 0.1);
|
||||
|
||||
Location originalLoc = target.getLocation();
|
||||
|
||||
// 2. Teleport after 5 seconds
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!target.isValid())
|
||||
return;
|
||||
|
||||
// Coordinates: 9 -56 17
|
||||
Location dimLoc = new Location(pocketWorld, 9.5, -56, 17.5);
|
||||
dimLoc.setYaw(originalLoc.getYaw());
|
||||
dimLoc.setPitch(originalLoc.getPitch());
|
||||
|
||||
target.teleport(dimLoc);
|
||||
target.getWorld().playSound(target.getLocation(), Sound.AMBIENT_BASALT_DELTAS_LOOP, 1f, 0.5f);
|
||||
|
||||
// 3. Return Sequence (Total 60s in Dimension)
|
||||
// At 55s (1100 ticks from now), start ascension effects
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!target.isValid())
|
||||
return;
|
||||
|
||||
if (target instanceof Player targetP) {
|
||||
targetP.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 100, 4)); // Fast up
|
||||
targetP.playSound(targetP.getLocation(), Sound.ITEM_ELYTRA_FLYING, 1f, 0.5f);
|
||||
}
|
||||
}
|
||||
}.runTaskLater(plugin, 1100L); // 55 seconds
|
||||
|
||||
// At 60s (1200 ticks), teleport back
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (target.isValid()) {
|
||||
target.teleport(originalLoc);
|
||||
target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
// Remove effects
|
||||
if (target instanceof Player targetP) {
|
||||
targetP.removePotionEffect(PotionEffectType.LEVITATION);
|
||||
targetP.removePotionEffect(PotionEffectType.DARKNESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.runTaskLater(plugin, 1200L); // 60 seconds
|
||||
}
|
||||
}.runTaskLater(plugin, 100L); // 5 seconds delay
|
||||
}
|
||||
|
||||
// --- Ability: Deadly Kiss ---
|
||||
|
||||
private void castDeadlyKiss(Player player, Entity target) {
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_GHAST_SCREAM, 1f, 0.5f);
|
||||
|
||||
if (target instanceof Player targetP) {
|
||||
ScreenEffects.shake(plugin, targetP, 2.0f, 100);
|
||||
}
|
||||
|
||||
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 1f, 0.5f);
|
||||
target.getWorld().spawnParticle(Particle.SMOKE, target.getLocation(), 20, 0.5, 0.5, 0.5, 0.1);
|
||||
|
||||
Location originalLoc = target.getLocation();
|
||||
|
||||
// Slow Drag Down (10 blocks over 5 seconds)
|
||||
new BukkitRunnable() {
|
||||
int ticks = 0;
|
||||
final int totalTicks = 100; // 5 seconds
|
||||
final double distance = 10.0;
|
||||
final double blocksPerTick = distance / totalTicks;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!target.isValid() || ticks >= totalTicks) {
|
||||
this.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
Location currentLoc = target.getLocation();
|
||||
// Ensure we don't drag them into void damage if world doesn't support it
|
||||
if (currentLoc.getY() > -63) {
|
||||
Location newLoc = currentLoc.subtract(0, blocksPerTick, 0);
|
||||
target.teleport(newLoc);
|
||||
}
|
||||
|
||||
if (ticks % 5 == 0) {
|
||||
target.getWorld().spawnParticle(Particle.SMOKE, target.getLocation(), 2, 0.2, 0.5, 0.2, 0);
|
||||
}
|
||||
|
||||
ticks++;
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 1L);
|
||||
}
|
||||
|
||||
// --- Ability: Vanish ---
|
||||
|
||||
private void castVanish(Player player) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
if (vanishedPlayers.contains(uuid)) {
|
||||
// Deactivate
|
||||
vanishedPlayers.remove(uuid);
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
p.showPlayer(plugin, player);
|
||||
}
|
||||
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1f, 1f);
|
||||
player.getWorld().spawnParticle(Particle.WITCH, player.getLocation(), 50, 0.5, 1, 0.5, 0.1);
|
||||
player.sendMessage(Component.text("You are now visible.", NamedTextColor.GREEN));
|
||||
|
||||
// COOLDOWN STARTS NOW
|
||||
setCooldown(uuid, "VANISH");
|
||||
|
||||
} else {
|
||||
// Activate
|
||||
if (getCooldownRemaining(uuid, "VANISH") > 0) {
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 0.5f);
|
||||
return;
|
||||
}
|
||||
|
||||
vanishedPlayers.add(uuid);
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
p.hidePlayer(plugin, player);
|
||||
}
|
||||
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 1f, 1f);
|
||||
player.getWorld().spawnParticle(Particle.CLOUD, player.getLocation(), 50, 0.5, 1, 0.5, 0.1);
|
||||
player.sendMessage(Component.text("You have vanished.", NamedTextColor.AQUA));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.blz.adminmode.moderation;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum ModeratorProfile {
|
||||
SOFT_MODER("soft_moder", "Soft Moder", "adminmode.profile.soft"),
|
||||
HARD_MODER("hard_moder", "Hard Moder", "adminmode.profile.hard");
|
||||
|
||||
private final String configKey;
|
||||
private final String displayName;
|
||||
private final String permission;
|
||||
|
||||
ModeratorProfile(String configKey, String displayName, String permission) {
|
||||
this.configKey = configKey;
|
||||
this.displayName = displayName;
|
||||
this.permission = permission;
|
||||
}
|
||||
|
||||
public String getConfigKey() {
|
||||
return configKey;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
public boolean isHardProfile() {
|
||||
return this == HARD_MODER;
|
||||
}
|
||||
|
||||
public boolean isAvailableFor(Player player) {
|
||||
return switch (this) {
|
||||
case SOFT_MODER -> player.hasPermission("adminmode.use")
|
||||
|| player.hasPermission(permission)
|
||||
|| player.hasPermission(HARD_MODER.permission);
|
||||
case HARD_MODER -> player.hasPermission(permission);
|
||||
};
|
||||
}
|
||||
|
||||
public static List<ModeratorProfile> availableFor(Player player) {
|
||||
List<ModeratorProfile> profiles = new ArrayList<>();
|
||||
for (ModeratorProfile profile : values()) {
|
||||
if (profile.isAvailableFor(player)) {
|
||||
profiles.add(profile);
|
||||
}
|
||||
}
|
||||
return profiles;
|
||||
}
|
||||
|
||||
public static Optional<ModeratorProfile> fromConfigKey(String key) {
|
||||
if (key == null || key.isBlank()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String normalized = key.toLowerCase(Locale.ROOT);
|
||||
for (ModeratorProfile profile : values()) {
|
||||
if (profile.configKey.equals(normalized)) {
|
||||
return Optional.of(profile);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static Optional<ModeratorProfile> fromInput(String input) {
|
||||
if (input == null || input.isBlank()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String normalized = input.trim().toLowerCase(Locale.ROOT);
|
||||
return switch (normalized) {
|
||||
case "soft", "soft_moder", "soft-moder", "softmoder" -> Optional.of(SOFT_MODER);
|
||||
case "hard", "hard_moder", "hard-moder", "hardmoder" -> Optional.of(HARD_MODER);
|
||||
default -> Optional.empty();
|
||||
};
|
||||
}
|
||||
}
|
||||
53
src/main/java/org/blz/adminmode/utils/ScreenEffects.java
Normal file
53
src/main/java/org/blz/adminmode/utils/ScreenEffects.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package org.blz.adminmode.utils;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class ScreenEffects {
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
/**
|
||||
* Shakes the player's screen by jittering their view direction.
|
||||
*
|
||||
* @param plugin Plugin instance
|
||||
* @param player Player to shake
|
||||
* @param intensity Intensity of shake (1-15)
|
||||
* @param durationTicks Duration in ticks
|
||||
*/
|
||||
public static void shake(Plugin plugin, Player player, float intensity, int durationTicks) {
|
||||
final float originalYaw = player.getLocation().getYaw();
|
||||
final float originalPitch = player.getLocation().getPitch();
|
||||
final float maxShake = Math.min(intensity, 15f);
|
||||
|
||||
new BukkitRunnable() {
|
||||
int ticksElapsed = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (ticksElapsed >= durationTicks || !player.isOnline()) {
|
||||
Location loc = player.getLocation();
|
||||
loc.setYaw(originalYaw);
|
||||
loc.setPitch(originalPitch);
|
||||
player.teleport(loc);
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
float shakeYaw = (random.nextFloat() - 0.5f) * 2 * maxShake;
|
||||
float shakePitch = (random.nextFloat() - 0.5f) * 2 * maxShake;
|
||||
|
||||
Location loc = player.getLocation();
|
||||
loc.setYaw(originalYaw + shakeYaw);
|
||||
loc.setPitch(originalPitch + shakePitch);
|
||||
player.teleport(loc);
|
||||
|
||||
ticksElapsed++;
|
||||
}
|
||||
}.runTaskTimer(plugin, 0L, 1L);
|
||||
}
|
||||
}
|
||||
94
src/main/java/org/blz/adminmode/utils/WorldLoader.java
Normal file
94
src/main/java/org/blz/adminmode/utils/WorldLoader.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package org.blz.adminmode.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class WorldLoader {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final String worldName;
|
||||
|
||||
public WorldLoader(Plugin plugin, String worldName) {
|
||||
this.plugin = plugin;
|
||||
this.worldName = worldName;
|
||||
}
|
||||
|
||||
public void loadWorld() {
|
||||
if (Bukkit.getWorld(worldName) != null) {
|
||||
plugin.getLogger().info("Мир " + worldName + " уже загружен.");
|
||||
return;
|
||||
}
|
||||
|
||||
File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
|
||||
if (!worldFolder.exists()) {
|
||||
plugin.getLogger().info("Мир " + worldName + " не найден. Распаковка из ресурсов...");
|
||||
if (extractWorld(worldFolder)) {
|
||||
plugin.getLogger().info("Мир успешно распакован.");
|
||||
} else {
|
||||
plugin.getLogger().severe("Не удалось распаковать мир " + worldName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
plugin.getLogger().info("Загрузка мира " + worldName + "...");
|
||||
WorldCreator creator = new WorldCreator(worldName);
|
||||
creator.environment(World.Environment.NORMAL); // Or whatever environment it should be
|
||||
World world = creator.createWorld();
|
||||
|
||||
if (world != null) {
|
||||
// Apply specific rules for the pocket dimension
|
||||
world.setGameRule(org.bukkit.GameRules.ADVANCE_TIME, false);
|
||||
world.setGameRule(org.bukkit.GameRules.SPAWN_MOBS, false);
|
||||
world.setTime(18000); // Midnight
|
||||
plugin.getLogger().info("Мир " + worldName + " успешно загружен!");
|
||||
} else {
|
||||
plugin.getLogger().severe("Не удалось создать/загрузить мир " + worldName);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean extractWorld(File destination) {
|
||||
try (InputStream in = plugin.getResource("pocket_dimension.zip")) {
|
||||
if (in == null) {
|
||||
plugin.getLogger().severe("Resource pocket_dimension.zip not found in plugin JAR!");
|
||||
return false;
|
||||
}
|
||||
|
||||
try (ZipInputStream zipIn = new ZipInputStream(in)) {
|
||||
ZipEntry entry = zipIn.getNextEntry();
|
||||
while (entry != null) {
|
||||
File file = new File(destination, entry.getName());
|
||||
if (entry.isDirectory()) {
|
||||
file.mkdirs();
|
||||
} else {
|
||||
// Ensure parent directories exist
|
||||
if (file.getParentFile() != null) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
try (FileOutputStream out = new FileOutputStream(file)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = zipIn.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
zipIn.closeEntry();
|
||||
entry = zipIn.getNextEntry();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
124
src/main/resources/config.yml
Normal file
124
src/main/resources/config.yml
Normal file
@@ -0,0 +1,124 @@
|
||||
# AdminMode Configuration
|
||||
|
||||
#РЕЖИМ АДМИНИСТРАТОРА
|
||||
admin_mode:
|
||||
# Включен ли режим администратора
|
||||
enabled: true
|
||||
|
||||
# LuckPerms настройки
|
||||
luckperms:
|
||||
# Использовать ли LuckPerms (если false - используется стандартный OP)
|
||||
enabled: true
|
||||
|
||||
# Группы которые выдаются при активации режима
|
||||
# Можно указать несколько групп через запятую
|
||||
groups:
|
||||
- "soft_moder"
|
||||
profile_groups:
|
||||
soft_moder:
|
||||
- "soft_moder"
|
||||
hard_moder:
|
||||
- "hard_moder"
|
||||
|
||||
# Удалять ли группы при деактивации (если false - группы останутся)
|
||||
remove_on_disable: true
|
||||
|
||||
dialogs:
|
||||
enabled: true
|
||||
|
||||
# Настройки игрового режима
|
||||
gamemode:
|
||||
# Принудительно ставить спектатор (если false - survival)
|
||||
force_spectator: false
|
||||
|
||||
# Мобы игнорируют игрока в админ моде
|
||||
mobs_ignore_player: true
|
||||
|
||||
# Разрешить полет в режиме выживания (в админ моде)
|
||||
allow_flight_in_survival: true
|
||||
|
||||
# Режим бога (неуязвимость)
|
||||
god_mode: true
|
||||
|
||||
# Кастомная скорость полета (0.1 = медленно, 0.2 = нормально, 0.5 = быстро, 1.0 = очень быстро)
|
||||
custom_fly_speed: 0.2
|
||||
|
||||
# Кастомная скорость ходьбы (0.1 = медленно, 0.2 = нормально, 0.5 = быстро)
|
||||
custom_walk_speed: 0.2
|
||||
|
||||
# Разрешенные режимы игры для переключения в админ моде
|
||||
# Если список пустой - можно переключаться на любые режимы
|
||||
# Доступные: SURVIVAL, CREATIVE, ADVENTURE, SPECTATOR
|
||||
# ВАЖНО: CREATIVE убран - модеры не должны иметь доступ к креативу!
|
||||
allowed_gamemodes:
|
||||
- "SURVIVAL"
|
||||
- "SPECTATOR"
|
||||
|
||||
# Ограничения в режиме администратора
|
||||
restrictions:
|
||||
# Запретить выбрасывание предметов
|
||||
prevent_item_drop: false
|
||||
|
||||
# Запретить поднятие предметов
|
||||
prevent_item_pickup: false
|
||||
|
||||
# Запретить перемещение предметов в контейнеры (сундуки, бочки и т.д.)
|
||||
prevent_container_transfer: true
|
||||
|
||||
# Запретить использование предметов (кроме открытия контейнеров)
|
||||
prevent_item_use: false
|
||||
|
||||
# Разрешить управление своим инвентарем
|
||||
allow_own_inventory: true
|
||||
|
||||
# Разрешенные блоки для взаимодействия (открытие, использование)
|
||||
allowed_blocks:
|
||||
- "CHEST"
|
||||
- "TRAPPED_CHEST"
|
||||
- "BARREL"
|
||||
- "SHULKER_BOX"
|
||||
- "FURNACE"
|
||||
- "BLAST_FURNACE"
|
||||
- "SMOKER"
|
||||
- "HOPPER"
|
||||
- "DISPENSER"
|
||||
- "DROPPER"
|
||||
- "DOOR"
|
||||
- "TRAPDOOR"
|
||||
- "FENCE_GATE"
|
||||
- "BUTTON"
|
||||
- "LEVER"
|
||||
- "ENDER_CHEST"
|
||||
- "CRAFTING_TABLE"
|
||||
- "ENCHANTING_TABLE"
|
||||
- "ANVIL"
|
||||
- "BREWING_STAND"
|
||||
|
||||
# Разрешенные блоки для постановки (whitelist)
|
||||
# Если список пустой - можно ставить любые блоки
|
||||
# Если список заполнен - можно ставить только эти блоки
|
||||
allowed_place_blocks:
|
||||
|
||||
# Выдавать пресет блоков при входе в админ мод
|
||||
give_preset_blocks: false
|
||||
|
||||
# Пресет блоков (формат: МАТЕРИАЛ:КОЛИЧЕСТВО)
|
||||
preset_blocks:
|
||||
- "BARRIER:64"
|
||||
- "LIGHT:64"
|
||||
- "STRUCTURE_VOID:64"
|
||||
|
||||
# Сообщения
|
||||
messages:
|
||||
enabled: "✓ Режим администратора активирован!"
|
||||
enabled_subtitle: "Ваше состояние сохранено."
|
||||
permissions_granted: "⚠ Вам выданы временные права администратора!"
|
||||
disabled: "✓ Режим администратора отключен!"
|
||||
disabled_subtitle: "Ваше состояние восстановлено."
|
||||
permissions_removed: "✓ Права администратора отозваны!"
|
||||
no_permission: "У вас нет прав для использования этой команды!"
|
||||
item_drop_denied: "✖ В режиме администратора нельзя выбрасывать предметы!"
|
||||
container_transfer_denied: "✖ В режиме администратора нельзя перемещать предметы в контейнеры!"
|
||||
item_use_denied: "✖ В режиме администратора нельзя использовать предметы!"
|
||||
block_place_denied: "✖ Вы можете ставить только разрешенные блоки!"
|
||||
reloaded: "✓ Конфигурация AdminMode перезагружена!"
|
||||
33
src/main/resources/plugin.yml
Normal file
33
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
name: AdminMode
|
||||
version: '1.21.11'
|
||||
main: org.blz.adminmode.AdminMode
|
||||
api-version: '1.21'
|
||||
author: BelzeBool, Kilka_v_HJIebe
|
||||
description: Плагин режима администратора с сохранением состояния игрока
|
||||
softdepend: [LuckPerms]
|
||||
|
||||
commands:
|
||||
adminmode:
|
||||
description: Режим администратора с сохранением состояния
|
||||
usage: /<command>
|
||||
aliases: [adm, am]
|
||||
admfix:
|
||||
description: Отключить все способности у игрока (полет, бессмертие)
|
||||
usage: /<command> <игрок>
|
||||
|
||||
permissions:
|
||||
adminmode.use:
|
||||
description: Разрешает использовать режим администратора
|
||||
default: op
|
||||
adminmode.profile.soft:
|
||||
description: Разрешает использовать профиль soft_moder
|
||||
default: op
|
||||
adminmode.profile.hard:
|
||||
description: Разрешает использовать профиль hard_moder
|
||||
default: op
|
||||
adminmode.reload:
|
||||
description: Разрешает перезагружать конфигурацию AdminMode
|
||||
default: op
|
||||
adminmode.admin:
|
||||
description: Разрешает использовать сильные действия и админ команды (disable, admfix)
|
||||
default: op
|
||||
BIN
src/main/resources/pocket_dimension.zip
Normal file
BIN
src/main/resources/pocket_dimension.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user