diff --git a/.gradle/8.5/checksums/checksums.lock b/.gradle/8.5/checksums/checksums.lock
index d435398..deaf1de 100644
Binary files a/.gradle/8.5/checksums/checksums.lock and b/.gradle/8.5/checksums/checksums.lock differ
diff --git a/.gradle/8.5/checksums/md5-checksums.bin b/.gradle/8.5/checksums/md5-checksums.bin
index 1327cc1..c977742 100644
Binary files a/.gradle/8.5/checksums/md5-checksums.bin and b/.gradle/8.5/checksums/md5-checksums.bin differ
diff --git a/.gradle/8.5/checksums/sha1-checksums.bin b/.gradle/8.5/checksums/sha1-checksums.bin
index 64ead5c..50d3eaf 100644
Binary files a/.gradle/8.5/checksums/sha1-checksums.bin and b/.gradle/8.5/checksums/sha1-checksums.bin differ
diff --git a/.gradle/8.5/executionHistory/executionHistory.bin b/.gradle/8.5/executionHistory/executionHistory.bin
index c7e119f..8867684 100644
Binary files a/.gradle/8.5/executionHistory/executionHistory.bin and b/.gradle/8.5/executionHistory/executionHistory.bin differ
diff --git a/.gradle/8.5/executionHistory/executionHistory.lock b/.gradle/8.5/executionHistory/executionHistory.lock
index 4d01cad..15e9ecc 100644
Binary files a/.gradle/8.5/executionHistory/executionHistory.lock and b/.gradle/8.5/executionHistory/executionHistory.lock differ
diff --git a/.gradle/8.5/fileHashes/fileHashes.bin b/.gradle/8.5/fileHashes/fileHashes.bin
index 90adcf0..c66027e 100644
Binary files a/.gradle/8.5/fileHashes/fileHashes.bin and b/.gradle/8.5/fileHashes/fileHashes.bin differ
diff --git a/.gradle/8.5/fileHashes/fileHashes.lock b/.gradle/8.5/fileHashes/fileHashes.lock
index 37407a2..b3beaa8 100644
Binary files a/.gradle/8.5/fileHashes/fileHashes.lock and b/.gradle/8.5/fileHashes/fileHashes.lock differ
diff --git a/.gradle/8.5/fileHashes/resourceHashesCache.bin b/.gradle/8.5/fileHashes/resourceHashesCache.bin
index 5db5d1b..e90fe79 100644
Binary files a/.gradle/8.5/fileHashes/resourceHashesCache.bin and b/.gradle/8.5/fileHashes/resourceHashesCache.bin differ
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
index 29c9dce..c3e7da7 100644
Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin
index 4404307..ac36257 100644
Binary files a/.gradle/buildOutputCleanup/outputFiles.bin and b/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe
index c39cd17..483f7bc 100644
Binary files a/.gradle/file-system.probe and b/.gradle/file-system.probe differ
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 7d3b3e8..905bd6f 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -5,7 +5,7 @@
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 03872dd..2e5e6a4 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 7377310..777feb1 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,9 @@
-
+
+
+
diff --git a/.idea/modules/Sentinel.main.iml b/.idea/modules/Sentinel.main.iml
index bbeeb3e..746f1fd 100644
--- a/.idea/modules/Sentinel.main.iml
+++ b/.idea/modules/Sentinel.main.iml
@@ -11,4 +11,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 04dbda4..8128301 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,18 +3,21 @@ import java.nio.file.Paths
plugins {
id 'java'
- id("com.github.johnrengelman.shadow") version "8.1.1"
+ id 'com.gradleup.shadow' version '9.0.0-beta10'
+ id("xyz.jpenilla.run-paper") version "2.3.1"
}
group = project.group
version = project.version
-jar {
- from {
- duplicatesStrategy = DuplicatesStrategy.EXCLUDE
- configurations.runtimeClasspath.collect {
- it.isDirectory() ? it : zipTree(it)
- }
+def targetJavaVersion = 21
+java {
+ def javaVersion = JavaVersion.toVersion(targetJavaVersion)
+ sourceCompatibility = javaVersion
+ targetCompatibility = javaVersion
+ toolchain.languageVersion.set(JavaLanguageVersion.of(21))
+ if (JavaVersion.current() < javaVersion) {
+ toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
}
}
@@ -36,105 +39,76 @@ repositories {
url = 'https://oss.sonatype.org/content/groups/public/'
}
maven {
- url = uri("https://repo.codemc.io/repository/maven-releases/")
- }
- maven {
- url = uri("https://repo.codemc.io/repository/maven-snapshots/")
+ name = "CodeMC"
+ url = uri("https://repo.codemc.io/repository/maven-public/")
}
+ maven { url 'https://jitpack.io' }
}
dependencies {
- compileOnly "io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT"
+ testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.0")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.11.0")
+ compileOnly "io.papermc.paper:paper-api:1.21.5-R0.1-SNAPSHOT"
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'org.ow2.asm:asm-commons:9.5'
- implementation files("deps/PDK-1.4.0.jar")
- implementation "com.github.retrooper:packetevents-spigot:2.7.0"
+ implementation files("libs/PDK-1.4.0.jar")
+ implementation "com.github.retrooper:packetevents-spigot:2.8.0"
+ implementation("de.tr7zw:item-nbt-api:2.15.0")
}
-def targetJavaVersion = 21
-java {
- def javaVersion = JavaVersion.toVersion(targetJavaVersion)
- sourceCompatibility = javaVersion
- targetCompatibility = javaVersion
- toolchain.languageVersion.set(JavaLanguageVersion.of(21))
- if (JavaVersion.current() < javaVersion) {
- toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
- }
+static def generateBuildId() {
+ return new Date().format('HH:mm:ss dd/MM/yyyy')
}
-tasks.withType(JavaCompile).configureEach {
- if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
- options.release = targetJavaVersion
- }
-}
-
-tasks.register('copyDeps', Copy) {
- from configurations.runtimeClasspath
- into 'build/deps'
- include '*.jar'
-}
-
-
processResources {
- def props = [version: version]
- inputs.properties props
- filteringCharset 'UTF-8'
filesMatching('plugin.yml') {
- expand props
+ expand(
+ version: project.version,
+ build: generateBuildId()
+ )
}
}
-compileJava.options.encoding("UTF-8")
+shadowJar {
+ archiveClassifier.set('')
+ minimize()
+ mergeServiceFiles()
+
+ filesMatching('**/plugin.yml') { fileCopyDetails ->
+ def content = fileCopyDetails.file.text
+ def lines = content.split('\n')
+
+ if (lines.length == 0 || !lines[0].trim().equals('name: SentinelAntiNuke')) {
+ fileCopyDetails.exclude()
+ }
+ }
-tasks.withType(JavaCompile) {
- options.encoding = "UTF-8"
-}
-tasks.shadowJar {
relocate("com.github.retrooper.packetevents", "me.trouper.sentinel.packetevents.api")
relocate("io.github.retrooper.packetevents", "me.trouper.sentinel.packetevents.impl")
-}
-
-task obfuscate(type: JavaExec) {
- // Specify the main class in the obfuscator JAR (if required)
-
- // Path to the obfuscator JAR
- classpath = files('obf/grunt-main.jar')
-
- // Arguments to pass to the obfuscator (e.g., input and output directories)
- args = [
- '--config', '.\\obf\\config.json'
- ]
+ relocate("de.tr7zw.changeme.nbtapi", "me.trouper.sentinel.nbtapi.api")
}
task copyLibs {
doLast {
- // Define the source directory (Gradle cache) and the target directory
- def sourceDir = Paths.get("C:/Users/crvic/.gradle/caches/modules-2/files-2.1")
- def targetDir = Paths.get("${buildDir}/../deps") // Output directory
+ def sourceDir = Paths.get("${System.getProperty('user.home')}/.gradle/caches/modules-2/files-2.1")
+ def targetDir = Paths.get("${buildDir}/../deps")
- // Create the target directory if it doesn't exist
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir)
}
- // Recursively traverse the source directory and copy JAR files
Files.walk(sourceDir)
.filter { Files.isRegularFile(it) && it.toString().endsWith(".jar") }
.forEach { jarFile ->
- // Extract the file name (without the directory structure)
def fileName = jarFile.fileName.toString()
-
- // Define the target file path (flat structure)
def targetFile = targetDir.resolve(fileName)
- // Handle duplicate file names (if any)
if (Files.exists(targetFile)) {
println "Skipping duplicate file: ${fileName}"
return
}
- // Copy the JAR file to the target directory
Files.copy(jarFile, targetFile)
println "Copied: ${jarFile} -> ${targetFile}"
}
@@ -143,6 +117,31 @@ task copyLibs {
}
}
+task obfuscate(type: JavaExec) {
+ classpath = files('obf/grunt-main.jar')
+ args = [
+ '--config', 'obf/config.json'
+ ]
+}
+
+tasks.withType(JavaCompile).configureEach {
+ options.encoding = "UTF-8"
+ if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
+ options.release = targetJavaVersion
+ }
+}
+
test {
useJUnitPlatform()
+}
+
+build {
+ dependsOn(shadowJar)
+}
+
+tasks {
+ runServer {
+ dependsOn(shadowJar)
+ minecraftVersion("1.21.5")
+ }
}
\ No newline at end of file
diff --git a/build/classes/java/main/me/trouper/sentinel/Sentinel.class b/build/classes/java/main/me/trouper/sentinel/Sentinel.class
index 3c6e291..21408e6 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/Sentinel.class and b/build/classes/java/main/me/trouper/sentinel/Sentinel.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/Emojis.class b/build/classes/java/main/me/trouper/sentinel/data/Emojis.class
deleted file mode 100644
index 5b5129d..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/Emojis.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/WhitelistStorage.class b/build/classes/java/main/me/trouper/sentinel/data/WhitelistStorage.class
deleted file mode 100644
index d72fab4..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/WhitelistStorage.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig$1.class b/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig$1.class
index d4dce8a..d222ac0 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig$1.class and b/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig$1.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig.class b/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig.class
index eed028c..ad799af 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig.class and b/build/classes/java/main/me/trouper/sentinel/data/config/AdvancedConfig.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/FPConfig.class b/build/classes/java/main/me/trouper/sentinel/data/config/FPConfig.class
deleted file mode 100644
index e6cc7f2..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/FPConfig.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Chat.class b/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Chat.class
index a208275..5f9c2bf 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Chat.class and b/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Chat.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Plugin.class b/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Plugin.class
index 8da10d1..ad20e3c 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Plugin.class and b/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig$Plugin.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig.class b/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig.class
index 2596005..dc43403 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig.class and b/build/classes/java/main/me/trouper/sentinel/data/config/MainConfig.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/NBTConfig.class b/build/classes/java/main/me/trouper/sentinel/data/config/NBTConfig.class
index f9c5cfd..0468c7b 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/NBTConfig.class and b/build/classes/java/main/me/trouper/sentinel/data/config/NBTConfig.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/StrictConfig.class b/build/classes/java/main/me/trouper/sentinel/data/config/StrictConfig.class
deleted file mode 100644
index fc1f0f2..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/StrictConfig.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/SwearsConfig.class b/build/classes/java/main/me/trouper/sentinel/data/config/SwearsConfig.class
deleted file mode 100644
index 26f2de3..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/SwearsConfig.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockEdit.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockEdit.class
index 51427e1..75be86a 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockEdit.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockEdit.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockExecute.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockExecute.class
deleted file mode 100644
index 883e1dd..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockExecute.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartPlace.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartPlace.class
index 7342f6a..b22d677 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartPlace.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartPlace.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartUse.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartUse.class
index 0df988d..926ca69 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartUse.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockMinecartUse.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockPlace.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockPlace.class
index 9157937..8c313fa 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockPlace.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockPlace.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockUse.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockUse.class
index cdfdc77..1531098 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockUse.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandBlockUse.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Dangerous.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Dangerous.class
index 07d2780..44d0486 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Dangerous.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Dangerous.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Logged.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Logged.class
index 172f4cf..37f7b79 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Logged.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Logged.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Specific.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Specific.class
index 4d029f6..61e9cc8 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Specific.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute$Specific.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute.class
index 93a8453..c8063e1 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CommandExecute.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CreativeHotbarAction.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CreativeHotbarAction.class
index ac27fe8..d465ef2 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CreativeHotbarAction.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig$CreativeHotbarAction.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig.class b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig.class
index 927e0f4..fe74770 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig.class and b/build/classes/java/main/me/trouper/sentinel/data/config/ViolationConfig.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$AutomatedActions.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$AutomatedActions.class
index d0fab20..8b039ac 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$AutomatedActions.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$AutomatedActions.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Cooldown.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Cooldown.class
index 4d4db70..a02e4de 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Cooldown.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Cooldown.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Permissions.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Permissions.class
index fb2c442..76aceed 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Permissions.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Permissions.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$PlayerInteraction.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$PlayerInteraction.class
index 40830f9..4bcf20b 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$PlayerInteraction.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$PlayerInteraction.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Reports.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Reports.class
index f14191c..7512a38 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Reports.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Reports.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$SocialSpy.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$SocialSpy.class
index 1e1b73e..21c738b 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$SocialSpy.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$SocialSpy.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Profanity.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Profanity.class
index e6503fe..6e091db 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Profanity.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Profanity.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Spam.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Spam.class
index 574ca06..36d4d17 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Spam.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile$Violations$Chat$Spam.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile.class b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile.class
index 634ef00..403f8bd 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile.class and b/build/classes/java/main/me/trouper/sentinel/data/config/lang/LanguageFile.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/types/CMDBlockType.class b/build/classes/java/main/me/trouper/sentinel/data/types/CMDBlockType.class
deleted file mode 100644
index 30f9f83..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/types/CMDBlockType.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/types/Location.class b/build/classes/java/main/me/trouper/sentinel/data/types/Location.class
deleted file mode 100644
index 4ec9547..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/types/Location.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/data/types/WhitelistedBlock.class b/build/classes/java/main/me/trouper/sentinel/data/types/WhitelistedBlock.class
deleted file mode 100644
index 12d1d24..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/data/types/WhitelistedBlock.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/commands/CallbackCommand.class b/build/classes/java/main/me/trouper/sentinel/server/commands/CallbackCommand.class
index f599c1c..2fbd093 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/commands/CallbackCommand.class and b/build/classes/java/main/me/trouper/sentinel/server/commands/CallbackCommand.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/commands/MessageCommand.class b/build/classes/java/main/me/trouper/sentinel/server/commands/MessageCommand.class
index e1bacc4..9a2bdd8 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/commands/MessageCommand.class and b/build/classes/java/main/me/trouper/sentinel/server/commands/MessageCommand.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/commands/ReopCommand.class b/build/classes/java/main/me/trouper/sentinel/server/commands/ReopCommand.class
index 6b390f6..bd10657 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/commands/ReopCommand.class and b/build/classes/java/main/me/trouper/sentinel/server/commands/ReopCommand.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/commands/ReplyCommand.class b/build/classes/java/main/me/trouper/sentinel/server/commands/ReplyCommand.class
index 7e969b9..2830c7e 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/commands/ReplyCommand.class and b/build/classes/java/main/me/trouper/sentinel/server/commands/ReplyCommand.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/commands/SentinelCommand.class b/build/classes/java/main/me/trouper/sentinel/server/commands/SentinelCommand.class
index 1fee522..631b8e8 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/commands/SentinelCommand.class and b/build/classes/java/main/me/trouper/sentinel/server/commands/SentinelCommand.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/commands/TrapCommand.class b/build/classes/java/main/me/trouper/sentinel/server/commands/TrapCommand.class
index 8ea7d50..94ad539 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/commands/TrapCommand.class and b/build/classes/java/main/me/trouper/sentinel/server/commands/TrapCommand.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/events/ChatEvent.class b/build/classes/java/main/me/trouper/sentinel/server/events/ChatEvent.class
deleted file mode 100644
index d9fbde0..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/events/ChatEvent.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.class b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.class
index 591af60..390386b 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.class and b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.class b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.class
index 9c33274..8e94ea8 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.class and b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.class b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.class
index fdccff9..0fbe4b2 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.class and b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.class b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.class
index 2e08c6f..c6903ca 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.class and b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.class b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.class
index 3dc6682..ecff3ac 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.class and b/build/classes/java/main/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/ConfigGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/ConfigGUI.class
deleted file mode 100644
index 1e69919..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/ConfigGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/Items.class b/build/classes/java/main/me/trouper/sentinel/server/gui/Items.class
index f823183..9b20bad 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/Items.class and b/build/classes/java/main/me/trouper/sentinel/server/gui/Items.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/MainGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/MainGUI.class
index afd9141..1419f12 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/MainGUI.class and b/build/classes/java/main/me/trouper/sentinel/server/gui/MainGUI.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/AntiNukeGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/AntiNukeGUI.class
index 02f92d6..d44ca9f 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/AntiNukeGUI.class and b/build/classes/java/main/me/trouper/sentinel/server/gui/config/AntiNukeGUI.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/ChatGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/ChatGUI.class
deleted file mode 100644
index 7b82353..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/ChatGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.class
index d970d7d..d0d1886 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.class and b/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.class
index e3f79b4..92dbdc9 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.class and b/build/classes/java/main/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/CommandGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/CommandGUI.class
deleted file mode 100644
index 84212a7..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/CommandGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBEditGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBEditGUI.class
deleted file mode 100644
index 5236fa2..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBEditGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBExecuteGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBExecuteGUI.class
deleted file mode 100644
index 22435ab..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBExecuteGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCPlaceGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCPlaceGUI.class
deleted file mode 100644
index d39fc31..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCPlaceGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCUseGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCUseGUI.class
deleted file mode 100644
index e6c60e7..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCUseGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBPlaceGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBPlaceGUI.class
deleted file mode 100644
index 22ce165..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBPlaceGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBUseGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBUseGUI.class
deleted file mode 100644
index f53df53..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/CBUseGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/HotbarActionGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/HotbarActionGUI.class
deleted file mode 100644
index c796e84..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/HotbarActionGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/DangerousCMDGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/DangerousCMDGUI.class
deleted file mode 100644
index 3fe52bb..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/DangerousCMDGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/LoggedCMDGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/LoggedCMDGUI.class
deleted file mode 100644
index e14f58c..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/LoggedCMDGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/SpecificCMDGUI.class b/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/SpecificCMDGUI.class
deleted file mode 100644
index fc827ca..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/server/gui/config/nuke/checks/command/SpecificCMDGUI.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/startup/Auth$1.class b/build/classes/java/main/me/trouper/sentinel/startup/Auth$1.class
deleted file mode 100644
index 4d97609..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/startup/Auth$1.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/startup/Auth.class b/build/classes/java/main/me/trouper/sentinel/startup/Auth.class
deleted file mode 100644
index 5cc5abc..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/startup/Auth.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/startup/Load.class b/build/classes/java/main/me/trouper/sentinel/startup/Load.class
deleted file mode 100644
index 3ec683e..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/startup/Load.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/startup/Telemetry.class b/build/classes/java/main/me/trouper/sentinel/startup/Telemetry.class
index 5541fb6..d86c2b3 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/startup/Telemetry.class and b/build/classes/java/main/me/trouper/sentinel/startup/Telemetry.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/CipherUtils.class b/build/classes/java/main/me/trouper/sentinel/utils/CipherUtils.class
deleted file mode 100644
index a117bbb..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/CipherUtils.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/FileUtils.class b/build/classes/java/main/me/trouper/sentinel/utils/FileUtils.class
index ca347fe..fabf7a0 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/FileUtils.class and b/build/classes/java/main/me/trouper/sentinel/utils/FileUtils.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/ItemUtils.class b/build/classes/java/main/me/trouper/sentinel/utils/ItemUtils.class
deleted file mode 100644
index 25e9249..0000000
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/ItemUtils.class and /dev/null differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/MathUtils.class b/build/classes/java/main/me/trouper/sentinel/utils/MathUtils.class
index ced59e0..e3e8f57 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/MathUtils.class and b/build/classes/java/main/me/trouper/sentinel/utils/MathUtils.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/PlayerUtils.class b/build/classes/java/main/me/trouper/sentinel/utils/PlayerUtils.class
index 0286292..340ea85 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/PlayerUtils.class and b/build/classes/java/main/me/trouper/sentinel/utils/PlayerUtils.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/ServerUtils.class b/build/classes/java/main/me/trouper/sentinel/utils/ServerUtils.class
index 5b5c16b..bc8f767 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/ServerUtils.class and b/build/classes/java/main/me/trouper/sentinel/utils/ServerUtils.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/Text.class b/build/classes/java/main/me/trouper/sentinel/utils/Text.class
index 548d9f1..b0d6514 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/Text.class and b/build/classes/java/main/me/trouper/sentinel/utils/Text.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/trees/ConsoleFormatter.class b/build/classes/java/main/me/trouper/sentinel/utils/trees/ConsoleFormatter.class
index 638fd98..2c44db7 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/trees/ConsoleFormatter.class and b/build/classes/java/main/me/trouper/sentinel/utils/trees/ConsoleFormatter.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/trees/EmbedFormatter.class b/build/classes/java/main/me/trouper/sentinel/utils/trees/EmbedFormatter.class
index e81db28..fdf424e 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/trees/EmbedFormatter.class and b/build/classes/java/main/me/trouper/sentinel/utils/trees/EmbedFormatter.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/trees/HoverFormatter.class b/build/classes/java/main/me/trouper/sentinel/utils/trees/HoverFormatter.class
index a596fce..b943674 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/trees/HoverFormatter.class and b/build/classes/java/main/me/trouper/sentinel/utils/trees/HoverFormatter.class differ
diff --git a/build/classes/java/main/me/trouper/sentinel/utils/trees/Node.class b/build/classes/java/main/me/trouper/sentinel/utils/trees/Node.class
index 3b2a13c..0b1a79c 100644
Binary files a/build/classes/java/main/me/trouper/sentinel/utils/trees/Node.class and b/build/classes/java/main/me/trouper/sentinel/utils/trees/Node.class differ
diff --git a/build/resources/main/plugin.yml b/build/resources/main/plugin.yml
deleted file mode 100644
index fc2faf1..0000000
--- a/build/resources/main/plugin.yml
+++ /dev/null
@@ -1,178 +0,0 @@
-name: SentinelAntiNuke
-version: '0.3.0'
-main: me.trouper.sentinel.Sentinel
-api-version: 1.21
-authors: [ TheTrouper ]
-description: Detect, Block, and Ban players who attempt to grief your server.
-website: https://thetrouper.github.io/
-softdepend:
- - ProtocolLib
- - ProtocolSupport
- - ViaVersion
- - ViaBackwards
- - ViaRewind
- - Geyser-Spigot
-load: STARTUP
-permissions:
- sentinel.admin:
- description: Allows access to all Sentinel admin commands.
- default: op
- children:
- sentinel.reload: true
- sentinel.config: true
- sentinel.debug: true
- sentinel.staff:
- description: Allows access to Sentinel staff commands.
- default: false
- children:
- sentinel.socialspy: true
- sentinel.false-positive: true
- sentinel.reload:
- description: Allows the user to reload the Sentinel plugin.
- default: false
- sentinel.config:
- description: Allows the user to modify the Sentinel configuration.
- default: false
- sentinel.false-positive:
- description: Allows the user to manage false positives.
- default: false
- children:
- sentinel.false-positive.add: true
- sentinel.false-positive.remove: true
- sentinel.false-positive.add:
- description: Allows the user to add a false positive.
- default: false
- sentinel.false-positive.remove:
- description: Allows the user to remove a false positive.
- default: false
- sentinel.debug:
- description: Allows the user to toggle debug mode.
- default: false
- sentinel.commandblock:
- description: Allows the user to manage command blocks.
- default: false
- sentinel.socialspy:
- description: Allows the user to spy on social interactions.
- default: false
- sentinel.callbacks:
- description: Allows access to all Sentinel callback commands.
- default: op
- children:
- sentinel.callbacks.fpreport: true
- sentinel.callbacks.fpreport:
- description: Allows the user to report false positives.
- default: false
- sentinel.message:
- description: Allows the user to send messages.
- default: true
- sentinel.reply:
- description: Allows the user to reply to messages.
- default: true
- sentinel.chatfilter:
- description: Parent permission for all chat-related features.
- default: false
- children:
- sentinel.chatfilter.profanity: true
- sentinel.chatfilter.spam: true
- sentinel.chatfilter.unicode: true
- sentinel.chatfilter.url: true
- sentinel.chatfilter.profanity:
- description: Parent permission for profanity filter features.
- default: false
- children:
- sentinel.chatfilter.profanity.view: true
- sentinel.chatfilter.profanity.bypass: true
- sentinel.chatfilter.profanity.view:
- description: Allows the user to view profanity filter logs.
- default: false
- sentinel.chatfilter.profanity.bypass:
- description: Allows the user to bypass the profanity filter.
- default: false
- sentinel.chatfilter.spam:
- description: Parent permission for spam filter features.
- default: false
- children:
- sentinel.chatfilter.spam.view: true
- sentinel.chatfilter.spam.bypass: true
- sentinel.chatfilter.spam.view:
- description: Allows the user to view spam filter logs.
- default: false
- sentinel.chatfilter.spam.bypass:
- description: Allows the user to bypass the spam filter.
- default: false
- sentinel.chatfilter.unicode:
- description: Parent permission for unicode filter features.
- default: false
- children:
- sentinel.chatfilter.unicode.view: true
- sentinel.chatfilter.unicode.bypass: true
- sentinel.chatfilter.unicode.view:
- description: Allows the user to view unicode filter logs.
- default: false
- sentinel.chatfilter.unicode.bypass:
- description: Allows the user to bypass the unicode filter.
- default: false
- sentinel.chatfilter.url:
- description: Parent permission for URL filter features.
- default: false
- children:
- sentinel.chatfilter.url.view: true
- sentinel.chatfilter.url.bypass: true
- sentinel.chatfilter.url.view:
- description: Allows the user to view URL filter logs.
- default: false
- sentinel.chatfilter.url.bypass:
- description: Allows the user to bypass the URL filter.
- default: false
-commands:
- sentinel:
- description: Main command for Sentinel.
- usage: /sentinel
- permission: sentinel.staff
- permission-message: You do not have permission to use this command.
- sentinelcallback:
- description: Callback command for Sentinel.
- usage: /callback
- permission: sentinel.callbacks
- permission-message: You do not have permission to use this command.
- message:
- description: Send a message to another player.
- usage: /message
- permission: sentinel.message
- permission-message: You do not have permission to use this command.
- aliases:
- - msg
- - etell
- - tell
- - t
- - ewhisper
- - whisper
- - w
- - privatemessage
- - pm
- - m
- - directmessage
- - dm
- - sentinelmessage
- - sm
- - stell
- - smsg
- reply:
- description: Reply to a message.
- usage: /reply
- permission: sentinel.reply
- permission-message: You do not have permission to use this command.
- aliases:
- - r
- - er
- - rply
- - ereply
- - sr
- - sreply
- - sentinelreply
- sentineltab:
- description: tab completion redirects for sentinel
- usage: /sentineltab []
- reop:
- description: Allows trusted players to elevate their permissions
- usage: /reop
\ No newline at end of file
diff --git a/build/tmp/.cache/expanded/expanded.lock b/build/tmp/.cache/expanded/expanded.lock
index ea05fba..9d67bf4 100644
Binary files a/build/tmp/.cache/expanded/expanded.lock and b/build/tmp/.cache/expanded/expanded.lock differ
diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin
index a89e01c..f1d3da6 100644
Binary files a/build/tmp/compileJava/previous-compilation-data.bin and b/build/tmp/compileJava/previous-compilation-data.bin differ
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..5a64fe0
--- /dev/null
+++ b/config.json
@@ -0,0 +1,368 @@
+{
+ "Settings": {
+ "Input": "./build/libs/Sentinel-1.0.0.jar",
+ "Output": "./build/libs/Sentinel-1.0.0-alfa.jar",
+ "Libraries": [
+ "./deps"
+ ],
+ "Exclusions": [
+ "com/",
+ "io/",
+ "me/trouper/sentinel/data/",
+ "me/trouper/sentinel/packetevents/",
+ "me/trouper/sentinel/nbtapi/",
+ "org/",
+ "net/",
+ "module-info"
+ ],
+ "MixinPackage": [
+ "net/spartanb312/client/mixins/"
+ ],
+ "DumpMappings": false,
+ "Multithreading": true,
+ "PrintTimeUsage": true,
+ "ForceUseComputeMax": false,
+ "LibsMissingCheck": true,
+ "CustomDictionaryFile": "./obf/dictionary.txt",
+ "DictionaryStartIndex": 0,
+ "CorruptOutput": false,
+ "FileRemovePrefix": [],
+ "FileRemoveSuffix": []
+ },
+ "UI": {
+ "DarkTheme": true
+ },
+ "SourceDebugRemove": {
+ "Enabled": true,
+ "SourceDebug": true,
+ "LineDebug": true,
+ "RenameSourceDebug": true,
+ "SourceNames": [
+ "AhAhAhYouDidntSayTheMagicWord.java",
+ "SentinelIsClosedSource.java",
+ "YourHonor-FreeBirdWasPlaying.kt",
+ "Officer-IDropKickedThatChildInSelfDefense.kt",
+ "NotTheBees.java",
+ "Youve-been-trolled.java",
+ "tuco-get-out.mp3.kt"
+ ],
+ "Exclusion": []
+ },
+ "Shrinking": {
+ "Enabled": true,
+ "RemoveInnerClass": true,
+ "RemoveUnusedLabel": true,
+ "RemoveNOP": false,
+ "AnnotationRemovals": [
+ "Ljava/lang/Override;"
+ ],
+ "Exclusion": []
+ },
+ "KotlinOptimizer": {
+ "Enabled": false,
+ "Annotations": true,
+ "Intrinsics": true,
+ "IntrinsicsRemoval": [
+ "checkExpressionValueIsNotNull",
+ "checkNotNullExpressionValue",
+ "checkReturnedValueIsNotNull",
+ "checkFieldIsNotNull",
+ "checkParameterIsNotNull",
+ "checkNotNullParameter"
+ ],
+ "ReplaceLdc": true,
+ "IntrinsicsExclusion": [],
+ "MetadataExclusion": []
+ },
+ "EnumOptimize": {
+ "Enabled": false,
+ "Exclusion": []
+ },
+ "DeadCodeRemove": {
+ "Enabled": false,
+ "Exclusion": []
+ },
+ "ClonedClass": {
+ "Enabled": false,
+ "Count": 2048,
+ "Suffix": "-on-top",
+ "RemoveAnnotations": true,
+ "Exclusion": []
+ },
+ "TrashClass": {
+ "Enabled": false,
+ "Package": "sentinel/",
+ "Prefix": "NUKE_",
+ "Count": 2048
+ },
+ "HWIDAuthentication": {
+ "Enabled": false,
+ "OnlineMode": true,
+ "OfflineHWID": [
+ "Put HWID here (For offline mode only)"
+ ],
+ "OnlineURL": "https://pastebin.com/XXXXX",
+ "EncryptKey": "1186118611861186",
+ "CachePools": 5,
+ "ShowHWIDWhenFailed": true,
+ "EncryptConst": true,
+ "Exclusion": []
+ },
+ "HideDeclaredFields": {
+ "Enabled": false,
+ "Exclusion": []
+ },
+ "ReflectionSupport": {
+ "Enabled": false,
+ "PrintLog": true,
+ "Class": true,
+ "Method": true,
+ "Field": true
+ },
+ "StringEncrypt": {
+ "Enabled": true,
+ "Arrayed": false,
+ "ReplaceInvokeDynamics": true,
+ "Exclusion": []
+ },
+ "NumberEncrypt": {
+ "Enabled": true,
+ "Intensity": 1,
+ "FloatingPoint": true,
+ "Arrayed": false,
+ "MaxInsnSize": 16384,
+ "Exclusion": []
+ },
+ "ArithmeticEncrypt": {
+ "Enabled": true,
+ "Intensity": 1,
+ "MaxInsnSize": 16384,
+ "Exclusion": []
+ },
+ "Controlflow": {
+ "Enabled": true,
+ "Intensity": 1,
+ "ExecuteBeforeEncrypt": false,
+ "SwitchExtractor": true,
+ "ExtractRate": 25,
+ "BogusConditionJump": true,
+ "GotoReplaceRate": 50,
+ "MangledCompareJump": true,
+ "IfReplaceRate": 48,
+ "IfICompareReplaceRate": 25,
+ "SwitchProtect": true,
+ "ProtectRate": 30,
+ "TableSwitchJump": true,
+ "MutateJumps": true,
+ "MutateRate": 10,
+ "SwitchReplaceRate": 30,
+ "MaxSwitchCase": 5,
+ "ReverseExistedIf": true,
+ "ReverseChance": 50,
+ "TrappedSwitchCase": true,
+ "TrapChance": 25,
+ "ArithmeticExprBuilder": true,
+ "BuilderIntensity": 1,
+ "JunkBuilderParameter": true,
+ "BuilderNativeAnnotation": false,
+ "UseLocalVar": true,
+ "JunkCode": true,
+ "MaxJunkCode": 2,
+ "ExpandedJunkCode": true,
+ "Exclusion": []
+ },
+ "ConstBuilder": {
+ "Enabled": true,
+ "NumberSwitchBuilder": true,
+ "SplitLong": true,
+ "HeavyEncrypt": false,
+ "SkipControlFlow": true,
+ "ReplacePercentage": 25,
+ "MaxCases": 3,
+ "Exclusion": []
+ },
+ "ConstPollEncrypt": {
+ "Enabled": false,
+ "Integer": true,
+ "Long": true,
+ "Float": true,
+ "Double": true,
+ "String": true,
+ "HeavyEncrypt": false,
+ "DontScramble": true,
+ "NativeAnnotation": false,
+ "Exclusion": []
+ },
+ "RedirectStringEquals": {
+ "Enabled": true,
+ "IgnoreCase": true,
+ "Exclusion": []
+ },
+ "FieldScramble": {
+ "Enabled": false,
+ "Intensity": 1,
+ "ReplacePercentage": 25,
+ "RandomName": false,
+ "GetStatic": true,
+ "SetStatic": true,
+ "GetValue": true,
+ "SetField": true,
+ "GenerateOuterClass": false,
+ "NativeAnnotation": false,
+ "ExcludedClasses": [],
+ "ExcludedFieldName": []
+ },
+ "MethodScramble": {
+ "Enabled": false,
+ "ReplacePercentage": 25,
+ "GenerateOuterClass": true,
+ "RandomCall": true,
+ "NativeAnnotation": false,
+ "ExcludedClasses": [],
+ "ExcludedMethodName": []
+ },
+ "NativeCandidate": {
+ "Enabled": false,
+ "NativeAnnotation": "Lnet/spartanb312/example/Native;",
+ "SearchCandidate": true,
+ "UpCallLimit": 0,
+ "Exclusion": [],
+ "AnnotationGroups": [
+ "{ \"annotation\": \"Lnet/spartanb312/grunt/Native;\", \"includeRegexes\": [\"^(?:[^./\\\\[;]+/)*[^./\\\\[;]+$\"], \"excludeRegexes\": [] }",
+ "{ \"annotation\": \"Lnet/spartanb312/grunt/VMProtect;\", \"includeRegexes\": [\"^(?:[^./\\\\[;]+\\\\/)*(?:[^./\\\\[;])+\\\\.(?:[^./\\\\[;()\\\\/])+(?:\\\\(((\\\\[*L[^./\\\\[;]([^./\\\\[;]*[^.\\\\[;][^./\\\\[;])*;)|(\\\\[*[ZBCSIJFD]+))*\\\\))((\\\\[*L[^./\\\\[;]([^./\\\\[;]*[^.\\\\[;][^./\\\\[;])*;)|V|(\\\\[*[ZBCSIJFD]))$\"], \"excludeRegexes\": [] }"
+ ]
+ },
+ "SyntheticBridge": {
+ "Enabled": false,
+ "Exclusion": [
+ "do not use this! (All Events will break)"
+ ]
+ },
+ "LocalVariableRename": {
+ "Enabled": true,
+ "Dictionary": "Custom",
+ "ThisReference": false,
+ "DeleteLocalVars": false,
+ "DeleteParameters": false,
+ "Exclusion": []
+ },
+ "MethodRename": {
+ "Enabled": true,
+ "Enums": true,
+ "Interfaces": false,
+ "Dictionary": "Custom",
+ "HeavyOverloads": false,
+ "RandomKeywordPrefix": false,
+ "Prefix": "",
+ "Reversed": false,
+ "Exclusion": [],
+ "ExcludedName": []
+ },
+ "FieldRename": {
+ "Enabled": true,
+ "Dictionary": "Custom",
+ "RandomKeywordPrefix": false,
+ "Prefix": "",
+ "Reversed": false,
+ "Exclusion": [],
+ "ExcludedName": [
+ "INSTANCE",
+ "Companion"
+ ]
+ },
+ "ClassRename": {
+ "Enabled": true,
+ "Dictionary": "Custom",
+ "Parent": "this/is/a/dying/meme/",
+ "Prefix": "",
+ "Reversed": false,
+ "Shuffled": false,
+ "CorruptedName": false,
+ "CorruptedNameExclusion": [],
+ "Exclusion": [
+ "me/trouper/sentinel/Sentinel"
+ ]
+ },
+ "MixinFieldRename": {
+ "Enabled": false,
+ "Dictionary": "Alphabet",
+ "Prefix": "",
+ "Exclusion": [],
+ "ExcludedName": [
+ "INSTANCE",
+ "Companion"
+ ]
+ },
+ "MixinClassRename": {
+ "Enabled": false,
+ "Dictionary": "Alphabet",
+ "TargetMixinPackage": "net/spartanb312/obf/mixins/",
+ "MixinFile": "mixins.example.json",
+ "RefmapFile": "mixins.example.refmap.json",
+ "Exclusion": []
+ },
+ "InvokeDynamic": {
+ "Enabled": true,
+ "ReplacePercentage": 25,
+ "HeavyProtection": false,
+ "MetadataClass": "me/trouper/tuco/getOutMetadata",
+ "MassiveRandomBlank": true,
+ "Reobfuscate": false,
+ "EnhancedFlowReobf": false,
+ "BSMNativeAnnotation": false,
+ "Exclusion": []
+ },
+ "ShuffleMembers": {
+ "Enabled": true,
+ "Methods": true,
+ "Fields": true,
+ "Annotations": true,
+ "Exceptions": true,
+ "Exclusion": []
+ },
+ "Crasher": {
+ "Enabled": false,
+ "Random": false,
+ "Exclusion": []
+ },
+ "Watermark": {
+ "Enabled": true,
+ "Names": [
+ "Copyright_SentinelAntiNuke2024",
+ "obvWolf",
+ "thetrouper"
+ ],
+ "Messages": [
+ "Ah_Ah_Ah_You_Didnt_Say_The_Magic_Word",
+ "%%__USERNAME__%%",
+ "%%__USER__%%"
+ ],
+ "FieldMark": true,
+ "MethodMark": true,
+ "AnnotationMark": false,
+ "Annotations": [
+ "ProtectedByGrunt",
+ "JvavMetadata"
+ ],
+ "Versions": [
+ "1984"
+ ],
+ "InterfaceMark": false,
+ "FatherOfJava": "linus/torvalds/thegoat/",
+ "CustomTrashMethod": false,
+ "CustomMethodName": "protected by YuShengJun",
+ "CustomMethodCode": "public static String method() {\n return \"Protected by YuShengJun\";\n}",
+ "Exclusion": []
+ },
+ "PostProcess": {
+ "Enabled": true,
+ "Manifest": true,
+ "Plugin YML": true,
+ "Bungee YML": false,
+ "Fabric JSON": false,
+ "Velocity JSON": false,
+ "ManifestPrefix": [
+ "Main-Class:"
+ ]
+ }
+}
diff --git a/deps/adventure-api-4.17.0.jar b/deps/adventure-api-4.17.0.jar
deleted file mode 100644
index bae00c0..0000000
Binary files a/deps/adventure-api-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-key-4.17.0.jar b/deps/adventure-key-4.17.0.jar
deleted file mode 100644
index b58fcfa..0000000
Binary files a/deps/adventure-key-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-nbt-4.17.0.jar b/deps/adventure-nbt-4.17.0.jar
deleted file mode 100644
index a2b172c..0000000
Binary files a/deps/adventure-nbt-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-text-logger-slf4j-4.17.0.jar b/deps/adventure-text-logger-slf4j-4.17.0.jar
deleted file mode 100644
index c9d8392..0000000
Binary files a/deps/adventure-text-logger-slf4j-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-text-minimessage-4.17.0.jar b/deps/adventure-text-minimessage-4.17.0.jar
deleted file mode 100644
index 8124660..0000000
Binary files a/deps/adventure-text-minimessage-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-text-serializer-gson-4.17.0.jar b/deps/adventure-text-serializer-gson-4.17.0.jar
deleted file mode 100644
index 2b7dd71..0000000
Binary files a/deps/adventure-text-serializer-gson-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-text-serializer-json-4.17.0.jar b/deps/adventure-text-serializer-json-4.17.0.jar
deleted file mode 100644
index b76611b..0000000
Binary files a/deps/adventure-text-serializer-json-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-text-serializer-legacy-4.17.0.jar b/deps/adventure-text-serializer-legacy-4.17.0.jar
deleted file mode 100644
index 6c15c06..0000000
Binary files a/deps/adventure-text-serializer-legacy-4.17.0.jar and /dev/null differ
diff --git a/deps/adventure-text-serializer-plain-4.17.0.jar b/deps/adventure-text-serializer-plain-4.17.0.jar
deleted file mode 100644
index 85debd2..0000000
Binary files a/deps/adventure-text-serializer-plain-4.17.0.jar and /dev/null differ
diff --git a/deps/annotations-24.1.0.jar b/deps/annotations-24.1.0.jar
deleted file mode 100644
index 28d234f..0000000
Binary files a/deps/annotations-24.1.0.jar and /dev/null differ
diff --git a/deps/ant-1.10.13.jar b/deps/ant-1.10.13.jar
deleted file mode 100644
index 6dad9ad..0000000
Binary files a/deps/ant-1.10.13.jar and /dev/null differ
diff --git a/deps/ant-launcher-1.10.13.jar b/deps/ant-launcher-1.10.13.jar
deleted file mode 100644
index 8718a72..0000000
Binary files a/deps/ant-launcher-1.10.13.jar and /dev/null differ
diff --git a/deps/asm-9.4.jar b/deps/asm-9.4.jar
deleted file mode 100644
index 01cb52e..0000000
Binary files a/deps/asm-9.4.jar and /dev/null differ
diff --git a/deps/asm-9.5.jar b/deps/asm-9.5.jar
deleted file mode 100644
index f5701dc..0000000
Binary files a/deps/asm-9.5.jar and /dev/null differ
diff --git a/deps/asm-commons-9.4.jar b/deps/asm-commons-9.4.jar
deleted file mode 100644
index 593621a..0000000
Binary files a/deps/asm-commons-9.4.jar and /dev/null differ
diff --git a/deps/asm-commons-9.5.jar b/deps/asm-commons-9.5.jar
deleted file mode 100644
index 21898df..0000000
Binary files a/deps/asm-commons-9.5.jar and /dev/null differ
diff --git a/deps/asm-tree-9.4.jar b/deps/asm-tree-9.4.jar
deleted file mode 100644
index c560305..0000000
Binary files a/deps/asm-tree-9.4.jar and /dev/null differ
diff --git a/deps/asm-tree-9.5.jar b/deps/asm-tree-9.5.jar
deleted file mode 100644
index 5c6da65..0000000
Binary files a/deps/asm-tree-9.5.jar and /dev/null differ
diff --git a/deps/auto-service-annotations-1.1.1.jar b/deps/auto-service-annotations-1.1.1.jar
deleted file mode 100644
index b9ceaf7..0000000
Binary files a/deps/auto-service-annotations-1.1.1.jar and /dev/null differ
diff --git a/deps/brigadier-1.2.9.jar b/deps/brigadier-1.2.9.jar
deleted file mode 100644
index ea2f234..0000000
Binary files a/deps/brigadier-1.2.9.jar and /dev/null differ
diff --git a/deps/bungeecord-chat-1.20-R0.2-deprecated+build.18.jar b/deps/bungeecord-chat-1.20-R0.2-deprecated+build.18.jar
deleted file mode 100644
index 221c6dd..0000000
Binary files a/deps/bungeecord-chat-1.20-R0.2-deprecated+build.18.jar and /dev/null differ
diff --git a/deps/checker-qual-3.33.0.jar b/deps/checker-qual-3.33.0.jar
deleted file mode 100644
index 61761fd..0000000
Binary files a/deps/checker-qual-3.33.0.jar and /dev/null differ
diff --git a/deps/commons-io-2.11.0.jar b/deps/commons-io-2.11.0.jar
deleted file mode 100644
index be507d9..0000000
Binary files a/deps/commons-io-2.11.0.jar and /dev/null differ
diff --git a/deps/commons-lang3-3.12.0.jar b/deps/commons-lang3-3.12.0.jar
deleted file mode 100644
index 4d434a2..0000000
Binary files a/deps/commons-lang3-3.12.0.jar and /dev/null differ
diff --git a/deps/error_prone_annotations-2.18.0.jar b/deps/error_prone_annotations-2.18.0.jar
deleted file mode 100644
index e072fe0..0000000
Binary files a/deps/error_prone_annotations-2.18.0.jar and /dev/null differ
diff --git a/deps/examination-api-1.3.0.jar b/deps/examination-api-1.3.0.jar
deleted file mode 100644
index 8021db0..0000000
Binary files a/deps/examination-api-1.3.0.jar and /dev/null differ
diff --git a/deps/examination-string-1.3.0.jar b/deps/examination-string-1.3.0.jar
deleted file mode 100644
index 0d3587e..0000000
Binary files a/deps/examination-string-1.3.0.jar and /dev/null differ
diff --git a/deps/failureaccess-1.0.1.jar b/deps/failureaccess-1.0.1.jar
deleted file mode 100644
index 9b56dc7..0000000
Binary files a/deps/failureaccess-1.0.1.jar and /dev/null differ
diff --git a/deps/fastutil-8.5.6.jar b/deps/fastutil-8.5.6.jar
deleted file mode 100644
index 8ccad6a..0000000
Binary files a/deps/fastutil-8.5.6.jar and /dev/null differ
diff --git a/deps/gson-2.10.1.jar b/deps/gson-2.10.1.jar
deleted file mode 100644
index a88c5bd..0000000
Binary files a/deps/gson-2.10.1.jar and /dev/null differ
diff --git a/deps/guava-32.1.2-jre.jar b/deps/guava-32.1.2-jre.jar
deleted file mode 100644
index e71fd46..0000000
Binary files a/deps/guava-32.1.2-jre.jar and /dev/null differ
diff --git a/deps/j2objc-annotations-2.8.jar b/deps/j2objc-annotations-2.8.jar
deleted file mode 100644
index 3595c4f..0000000
Binary files a/deps/j2objc-annotations-2.8.jar and /dev/null differ
diff --git a/deps/javax.inject-1.jar b/deps/javax.inject-1.jar
deleted file mode 100644
index b2a9d0b..0000000
Binary files a/deps/javax.inject-1.jar and /dev/null differ
diff --git a/deps/jdependency-2.8.0.jar b/deps/jdependency-2.8.0.jar
deleted file mode 100644
index 49d63a1..0000000
Binary files a/deps/jdependency-2.8.0.jar and /dev/null differ
diff --git a/deps/jdom2-2.0.6.1.jar b/deps/jdom2-2.0.6.1.jar
deleted file mode 100644
index da95839..0000000
Binary files a/deps/jdom2-2.0.6.1.jar and /dev/null differ
diff --git a/deps/joml-1.10.5.jar b/deps/joml-1.10.5.jar
deleted file mode 100644
index c5fc5b9..0000000
Binary files a/deps/joml-1.10.5.jar and /dev/null differ
diff --git a/deps/json-simple-1.1.1.jar b/deps/json-simple-1.1.1.jar
deleted file mode 100644
index dfd5856..0000000
Binary files a/deps/json-simple-1.1.1.jar and /dev/null differ
diff --git a/deps/jsr305-3.0.2.jar b/deps/jsr305-3.0.2.jar
deleted file mode 100644
index 59222d9..0000000
Binary files a/deps/jsr305-3.0.2.jar and /dev/null differ
diff --git a/deps/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar b/deps/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar
deleted file mode 100644
index 45832c0..0000000
Binary files a/deps/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar and /dev/null differ
diff --git a/deps/log4j-api-2.17.1.jar b/deps/log4j-api-2.17.1.jar
deleted file mode 100644
index 605c45d..0000000
Binary files a/deps/log4j-api-2.17.1.jar and /dev/null differ
diff --git a/deps/log4j-api-2.20.0.jar b/deps/log4j-api-2.20.0.jar
deleted file mode 100644
index 29d1b52..0000000
Binary files a/deps/log4j-api-2.20.0.jar and /dev/null differ
diff --git a/deps/log4j-core-2.20.0.jar b/deps/log4j-core-2.20.0.jar
deleted file mode 100644
index 54dafcd..0000000
Binary files a/deps/log4j-core-2.20.0.jar and /dev/null differ
diff --git a/deps/maven-artifact-3.9.6.jar b/deps/maven-artifact-3.9.6.jar
deleted file mode 100644
index b695c9f..0000000
Binary files a/deps/maven-artifact-3.9.6.jar and /dev/null differ
diff --git a/deps/maven-builder-support-3.9.6.jar b/deps/maven-builder-support-3.9.6.jar
deleted file mode 100644
index 7129e8f..0000000
Binary files a/deps/maven-builder-support-3.9.6.jar and /dev/null differ
diff --git a/deps/maven-model-3.9.6.jar b/deps/maven-model-3.9.6.jar
deleted file mode 100644
index 1bbc8c8..0000000
Binary files a/deps/maven-model-3.9.6.jar and /dev/null differ
diff --git a/deps/maven-model-builder-3.9.6.jar b/deps/maven-model-builder-3.9.6.jar
deleted file mode 100644
index 49b2dde..0000000
Binary files a/deps/maven-model-builder-3.9.6.jar and /dev/null differ
diff --git a/deps/maven-repository-metadata-3.9.6.jar b/deps/maven-repository-metadata-3.9.6.jar
deleted file mode 100644
index 5ad525f..0000000
Binary files a/deps/maven-repository-metadata-3.9.6.jar and /dev/null differ
diff --git a/deps/maven-resolver-api-1.9.18.jar b/deps/maven-resolver-api-1.9.18.jar
deleted file mode 100644
index 44c03c9..0000000
Binary files a/deps/maven-resolver-api-1.9.18.jar and /dev/null differ
diff --git a/deps/maven-resolver-impl-1.9.18.jar b/deps/maven-resolver-impl-1.9.18.jar
deleted file mode 100644
index 5263984..0000000
Binary files a/deps/maven-resolver-impl-1.9.18.jar and /dev/null differ
diff --git a/deps/maven-resolver-named-locks-1.9.18.jar b/deps/maven-resolver-named-locks-1.9.18.jar
deleted file mode 100644
index e3eae74..0000000
Binary files a/deps/maven-resolver-named-locks-1.9.18.jar and /dev/null differ
diff --git a/deps/maven-resolver-provider-3.9.6.jar b/deps/maven-resolver-provider-3.9.6.jar
deleted file mode 100644
index e8024e2..0000000
Binary files a/deps/maven-resolver-provider-3.9.6.jar and /dev/null differ
diff --git a/deps/maven-resolver-spi-1.9.18.jar b/deps/maven-resolver-spi-1.9.18.jar
deleted file mode 100644
index b13e20b..0000000
Binary files a/deps/maven-resolver-spi-1.9.18.jar and /dev/null differ
diff --git a/deps/maven-resolver-util-1.9.18.jar b/deps/maven-resolver-util-1.9.18.jar
deleted file mode 100644
index d882859..0000000
Binary files a/deps/maven-resolver-util-1.9.18.jar and /dev/null differ
diff --git a/deps/option-1.0.0.jar b/deps/option-1.0.0.jar
deleted file mode 100644
index d0fc8c3..0000000
Binary files a/deps/option-1.0.0.jar and /dev/null differ
diff --git a/deps/org.eclipse.sisu.inject-0.9.0.M2.jar b/deps/org.eclipse.sisu.inject-0.9.0.M2.jar
deleted file mode 100644
index 7b309b7..0000000
Binary files a/deps/org.eclipse.sisu.inject-0.9.0.M2.jar and /dev/null differ
diff --git a/deps/packetevents-api-2.7.0.jar b/deps/packetevents-api-2.7.0.jar
deleted file mode 100644
index 90aaaa6..0000000
Binary files a/deps/packetevents-api-2.7.0.jar and /dev/null differ
diff --git a/deps/packetevents-netty-common-2.7.0.jar b/deps/packetevents-netty-common-2.7.0.jar
deleted file mode 100644
index 2f697a9..0000000
Binary files a/deps/packetevents-netty-common-2.7.0.jar and /dev/null differ
diff --git a/deps/packetevents-spigot-2.7.0.jar b/deps/packetevents-spigot-2.7.0.jar
deleted file mode 100644
index 3ffd045..0000000
Binary files a/deps/packetevents-spigot-2.7.0.jar and /dev/null differ
diff --git a/deps/paper-api-1.20.6-R0.1-SNAPSHOT.jar b/deps/paper-api-1.20.6-R0.1-SNAPSHOT.jar
deleted file mode 100644
index 49abedd..0000000
Binary files a/deps/paper-api-1.20.6-R0.1-SNAPSHOT.jar and /dev/null differ
diff --git a/deps/plexus-interpolation-1.26.jar b/deps/plexus-interpolation-1.26.jar
deleted file mode 100644
index cfcf162..0000000
Binary files a/deps/plexus-interpolation-1.26.jar and /dev/null differ
diff --git a/deps/plexus-utils-3.5.1.jar b/deps/plexus-utils-3.5.1.jar
deleted file mode 100644
index 1873c52..0000000
Binary files a/deps/plexus-utils-3.5.1.jar and /dev/null differ
diff --git a/deps/shadow-8.1.1.jar b/deps/shadow-8.1.1.jar
deleted file mode 100644
index 10f286a..0000000
Binary files a/deps/shadow-8.1.1.jar and /dev/null differ
diff --git a/deps/slf4j-api-2.0.9.jar b/deps/slf4j-api-2.0.9.jar
deleted file mode 100644
index 3796afe..0000000
Binary files a/deps/slf4j-api-2.0.9.jar and /dev/null differ
diff --git a/deps/snakeyaml-2.2.jar b/deps/snakeyaml-2.2.jar
deleted file mode 100644
index 275dd57..0000000
Binary files a/deps/snakeyaml-2.2.jar and /dev/null differ
diff --git a/gradle.properties b/gradle.properties
index fbafe19..3013070 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,7 +1,7 @@
# Plugin
group = 'me.trouper'
-version = 0.3.0
+version = 1.0.0
# Minecraft
mc_version = 1.21
diff --git a/gradlew b/gradlew
old mode 100644
new mode 100755
diff --git a/libs/NoteBlockAPI-1.6.4-SNAPSHOT.jar b/libs/NoteBlockAPI-1.6.4-SNAPSHOT.jar
new file mode 100644
index 0000000..e69de29
diff --git a/deps/PDK-1.4.0.jar b/libs/PDK-1.4.0.jar
similarity index 100%
rename from deps/PDK-1.4.0.jar
rename to libs/PDK-1.4.0.jar
diff --git a/obf/config.json b/obf/config.json
index 9c42555..beacf25 100644
--- a/obf/config.json
+++ b/obf/config.json
@@ -1,7 +1,7 @@
{
"Settings": {
- "Input": "./build/libs/Sentinel-0.3.0.jar",
- "Output": "./build/libs/Sentinel-0.3.0-obf.jar",
+ "Input": "./build/libs/Sentinel-1.0.0.jar",
+ "Output": "./build/libs/Sentinel-1.0.0-alfa.jar",
"Libraries": [
"./deps"
],
@@ -9,6 +9,8 @@
"com/",
"io/",
"me/trouper/sentinel/data/",
+ "me/trouper/sentinel/packetevents/",
+ "me/trouper/sentinel/nbtapi/",
"org/",
"net/",
"module-info"
diff --git a/obf/grunt-main.jar b/obf/grunt-main.jar
index fa7087b..3b26704 100644
Binary files a/obf/grunt-main.jar and b/obf/grunt-main.jar differ
diff --git a/run/plugins/LuckPerms-Bukkit-5.5.2.jar b/run/plugins/LuckPerms-Bukkit-5.5.2.jar
new file mode 100644
index 0000000..fb090ee
Binary files /dev/null and b/run/plugins/LuckPerms-Bukkit-5.5.2.jar differ
diff --git a/settings.gradle b/settings.gradle
index 1efd5cc..e5cc64a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,5 @@
-rootProject.name = 'Sentinel'
+plugins {
+ id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
+}
+rootProject.name = 'Sentinel'
diff --git a/src/main/java/me/trouper/sentinel/Sentinel.java b/src/main/java/me/trouper/sentinel/Sentinel.java
index c13d1cc..4d2740d 100644
--- a/src/main/java/me/trouper/sentinel/Sentinel.java
+++ b/src/main/java/me/trouper/sentinel/Sentinel.java
@@ -1,128 +1,107 @@
package me.trouper.sentinel;
import com.github.retrooper.packetevents.PacketEvents;
+import de.tr7zw.changeme.nbtapi.NBT;
import io.github.itzispyder.pdk.PDK;
-import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
-import me.trouper.sentinel.data.WhitelistStorage;
-import me.trouper.sentinel.data.config.*;
-import me.trouper.sentinel.data.config.lang.LanguageFile;
-import me.trouper.sentinel.server.events.PluginCloakingPacket;
-import me.trouper.sentinel.startup.Auth;
-import me.trouper.sentinel.startup.IndirectLaunch;
+import me.trouper.sentinel.server.Director;
import org.bukkit.Bukkit;
+import org.bukkit.NamespacedKey;
+import org.bukkit.World;
+import org.bukkit.entity.Entity;
import org.bukkit.plugin.java.JavaPlugin;
-import java.io.File;
-import java.util.logging.Logger;
+import java.util.ArrayList;
+import java.util.List;
public final class Sentinel extends JavaPlugin {
-
- public static final Logger log = Bukkit.getLogger();
+
private static Sentinel instance;
- public static LanguageFile lang;
- public static File us;
-
- private static final File dataFolder = new File("plugins/SentinelAntiNuke");
- private static final File violationcfg = new File(Sentinel .dataFolder(),"/violation-config.json");
- private static final File cfgfile = new File(Sentinel.dataFolder(),"/main-config.json");
- private static final File nbtcfg = new File(Sentinel.dataFolder(), "/nbt-config.json");
- private static final File strctcfg = new File(Sentinel.dataFolder(), "/strict.json");
- private static final File swrcfg = new File(Sentinel.dataFolder(), "/swears.json");
- private static final File fpcfg = new File(Sentinel.dataFolder(), "/false-positives.json");
- private static final File advcfg = new File(Sentinel.dataFolder(), "/advanced-config.json");
- private static final File cmdWhitelist = new File(Sentinel.dataFolder(), "/storage/whitelist.json");
-
- public static ViolationConfig violationConfig = JsonSerializable.load(violationcfg, ViolationConfig.class, new ViolationConfig());
- public static WhitelistStorage whitelist = JsonSerializable.load(cmdWhitelist, WhitelistStorage.class, new WhitelistStorage());
- public static MainConfig mainConfig = JsonSerializable.load(cfgfile, MainConfig.class, new MainConfig());
- public static FPConfig fpConfig = JsonSerializable.load(fpcfg, FPConfig.class, new FPConfig());
- public static SwearsConfig swearConfig = JsonSerializable.load(swrcfg, SwearsConfig.class, new SwearsConfig());
- public static StrictConfig strictConfig = JsonSerializable.load(strctcfg, StrictConfig.class, new StrictConfig());
- public static NBTConfig nbtConfig = JsonSerializable.load(nbtcfg, NBTConfig.class, new NBTConfig());
- public static AdvancedConfig advConfig = JsonSerializable.load(advcfg, AdvancedConfig.class, new AdvancedConfig());
-
+ private Director director;
+
public String identifier;
public String license;
public String nonce;
public String ip;
public int port;
+ public String version;
+ public String build;
+
+ /* ]=- Sentinel Startup Flow -=[
+ Make sure everything is done in sequence to avoid NullPointerException!
+ 1. onLoad
+ - PacketEvents Loading & Registration
+ 2. onEnable
+ - Init PacketEvents
+ - Init NBT-API
+ - Init PDK
+ - Instantiate Sentinel
+ - Instantiate Director
+ 3. Launch
+ - Init DRM
+ - Read Config
+ 4. Load
+ - Run DRM Checks
+ - Register Commands
+ - Register Events
+ - Register Timers
+ */
@Override
public void onLoad() {
- Sentinel.log.info("\n]======------ Pre-load started ------======[");
+ version = getPluginMeta().getVersion().split("\\-")[0];
+ build = getPluginMeta().getVersion().split("\\-")[1];
+ getLogger().info("Build ID: %s".formatted(build));
+ getLogger().info("\n]======------ Pre-load started ------======[");
- Sentinel.log.info("Setting PacketEvents API");
+ getLogger().info("Setting PacketEvents API");
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
- Sentinel.log.info("Loading PacketEvents");
+ getLogger().info("Loading PacketEvents");
PacketEvents.getAPI().load();
-
- Sentinel.log.info("Registering PacketEvents");
- PacketEvents.getAPI().getEventManager().registerListener(new PluginCloakingPacket());
}
-
+
@Override
- public void onEnable() {
- log.info("\n]======------ Loading Sentinel ------======[");
+ public void onEnable() {
+ getLogger().info("\n]======------ Loading Sentinel ------======[");
- log.info("Initializing PacketEvents");
+ getLogger().info("Initializing PacketEvents");
PacketEvents.getAPI().init();
- log.info("Initializing PDK");
+ getLogger().info("Pre-loading NBT-API");
+ if (!NBT.preloadApi()) {
+ getLogger().warning("NBT-API wasn't initialized properly. Sentinel may error out.");
+ }
+
+ getLogger().info("Initializing PDK");
PDK.init(this);
- log.info("Instantiating plugin");
+ getLogger().info("Instantiating Sentinel");
instance = this;
- us = getFile();
- IndirectLaunch.launch();
- }
+ Sentinel.getInstance().getLogger().info("Instantiating Director");
+ director = new Director();
- public void loadConfig() {
- // Init
- mainConfig = JsonSerializable.load(cfgfile,MainConfig.class,new MainConfig());
- advConfig = JsonSerializable.load(advcfg,AdvancedConfig.class,new AdvancedConfig());
- fpConfig = JsonSerializable.load(fpcfg,FPConfig.class,new FPConfig());
- strictConfig = JsonSerializable.load(strctcfg,StrictConfig.class,new StrictConfig());
- swearConfig = JsonSerializable.load(swrcfg,SwearsConfig.class,new SwearsConfig());
- nbtConfig = JsonSerializable.load(nbtcfg,NBTConfig.class,new NBTConfig());
- violationConfig = JsonSerializable.load(violationcfg,ViolationConfig.class,new ViolationConfig());
-
- // Save
- mainConfig.save();
- advConfig.save();
- fpConfig.save();
- strictConfig.save();
- swearConfig.save();
- nbtConfig.save();
- violationConfig.save();
-
- whitelist = JsonSerializable.load(cmdWhitelist, WhitelistStorage.class, new WhitelistStorage());
- whitelist.save();
-
- log.info("Loading Dictionary (%s)...".formatted(Sentinel.mainConfig.plugin.lang));
-
- lang = JsonSerializable.load(LanguageFile.PATH,LanguageFile.class,new LanguageFile());
- lang.save();
-
- log.info("Setting License Key");
- license = Auth.getLicenseKey();
+ director.launch();
}
@Override
public void onDisable() {
// Plugin shutdown logic
PacketEvents.getAPI().terminate();
- log.info("Sentinel has disabled! (%s) Your server is now no longer protected!".formatted(getDescription().getVersion()));
+ getLogger().info("Sentinel has disabled! (%s) Your server is now no longer protected!".formatted(version));
}
public static Sentinel getInstance() {
return instance;
}
+
+ public Director getDirector() {
+ return director;
+ }
- public static File dataFolder() {
- return dataFolder;
+ public NamespacedKey getNamespace(String key) {
+ return new NamespacedKey(Sentinel.getInstance(), key);
}
}
diff --git a/src/main/java/me/trouper/sentinel/data/IO.java b/src/main/java/me/trouper/sentinel/data/IO.java
new file mode 100644
index 0000000..3025c60
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/IO.java
@@ -0,0 +1,109 @@
+package me.trouper.sentinel.data;
+
+import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.config.*;
+import me.trouper.sentinel.data.config.lang.LanguageFile;
+import me.trouper.sentinel.data.config.lists.FalsePositiveList;
+import me.trouper.sentinel.data.config.lists.StrictList;
+import me.trouper.sentinel.data.config.lists.SwearList;
+import me.trouper.sentinel.data.storage.CommandBlockStorage;
+import me.trouper.sentinel.data.storage.ExtraStorage;
+import me.trouper.sentinel.data.storage.NBTStorage;
+
+import java.io.File;
+
+public class IO {
+ private final File dataFolder;
+ private final File violationFile;
+ private final File mainFile;
+ private final File nbtConfigFile;
+ private final File strictFile;
+ private final File swearFile;
+ private final File falsePositiveFile;
+ private final File advancedConfigFile;
+ private final File whitelistStorageFile;
+ private final File nbtStorageFile;
+ private final File extraStorageFile;
+
+ public LanguageFile lang;
+
+ public MainConfig mainConfig;
+ public ViolationConfig violationConfig;
+ public NBTConfig nbtConfig;
+ public AdvancedConfig advConfig;
+
+ public FalsePositiveList falsePositiveList;
+ public SwearList swearList;
+ public StrictList strictList;
+
+ public CommandBlockStorage whitelistStorage;
+ public ExtraStorage extraStorage;
+ public NBTStorage nbtStorage;
+
+ public IO() {
+ dataFolder = new File("plugins/SentinelAntiNuke");
+ violationFile = new File(dataFolder,"/violation-config.json");
+ mainFile = new File(dataFolder,"/main-config.json");
+ nbtConfigFile = new File(dataFolder, "/nbt-config.json");
+ strictFile = new File(dataFolder, "/strict.json");
+ swearFile = new File(dataFolder, "/swears.json");
+ falsePositiveFile = new File(dataFolder, "/false-positives.json");
+ advancedConfigFile = new File(dataFolder, "/advanced-config.json");
+ whitelistStorageFile = new File(dataFolder, "/storage/whitelist.json");
+ nbtStorageFile = new File(dataFolder,"/storage/nbt.json");
+ extraStorageFile = new File(dataFolder, "/storage/extra.json");
+
+ violationConfig = JsonSerializable.load(violationFile, ViolationConfig.class, new ViolationConfig());
+ whitelistStorage = JsonSerializable.load(whitelistStorageFile, CommandBlockStorage.class, new CommandBlockStorage());
+ extraStorage = JsonSerializable.load(whitelistStorageFile, ExtraStorage.class, new ExtraStorage());
+ mainConfig = JsonSerializable.load(mainFile, MainConfig.class, new MainConfig());
+ falsePositiveList = JsonSerializable.load(falsePositiveFile, FalsePositiveList.class, new FalsePositiveList());
+ swearList = JsonSerializable.load(swearFile, SwearList.class, new SwearList());
+ strictList = JsonSerializable.load(strictFile, StrictList.class, new StrictList());
+ nbtConfig = JsonSerializable.load(nbtConfigFile, NBTConfig.class, new NBTConfig());
+ advConfig = JsonSerializable.load(advancedConfigFile, AdvancedConfig.class, new AdvancedConfig());
+ nbtStorage = JsonSerializable.load(nbtStorageFile, NBTStorage.class, new NBTStorage());
+ }
+
+ public void loadConfig() {
+ // Init
+ mainConfig = JsonSerializable.load(mainFile,MainConfig.class,new MainConfig());
+ advConfig = JsonSerializable.load(advancedConfigFile,AdvancedConfig.class,new AdvancedConfig());
+ falsePositiveList = JsonSerializable.load(falsePositiveFile, FalsePositiveList.class,new FalsePositiveList());
+ strictList = JsonSerializable.load(strictFile, StrictList.class,new StrictList());
+ swearList = JsonSerializable.load(swearFile, SwearList.class,new SwearList());
+ nbtConfig = JsonSerializable.load(nbtConfigFile,NBTConfig.class,new NBTConfig());
+ violationConfig = JsonSerializable.load(violationFile,ViolationConfig.class,new ViolationConfig());
+
+
+ // Save
+ mainConfig.save();
+ advConfig.save();
+ falsePositiveList.save();
+ strictList.save();
+ swearList.save();
+ nbtConfig.save();
+ violationConfig.save();
+
+ // Storage
+
+ whitelistStorage = JsonSerializable.load(whitelistStorageFile, CommandBlockStorage.class, new CommandBlockStorage());
+ extraStorage = JsonSerializable.load(extraStorageFile, ExtraStorage.class, new ExtraStorage());
+ nbtStorage = JsonSerializable.load(nbtStorageFile,NBTStorage.class,new NBTStorage());
+
+ whitelistStorage.save();
+ extraStorage.save();
+ nbtStorage.save();
+
+
+ Sentinel.getInstance().getLogger().info("Loading Dictionary (%s)...".formatted(mainConfig.plugin.lang));
+
+ lang = JsonSerializable.load(LanguageFile.PATH,LanguageFile.class,new LanguageFile());
+ lang.save();
+ }
+
+ public File getDataFolder() {
+ return dataFolder;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/data/WhitelistStorage.java b/src/main/java/me/trouper/sentinel/data/WhitelistStorage.java
deleted file mode 100644
index 7e18029..0000000
--- a/src/main/java/me/trouper/sentinel/data/WhitelistStorage.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package me.trouper.sentinel.data;
-
-import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.types.WhitelistedBlock;
-
-import java.io.File;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-public class WhitelistStorage implements JsonSerializable {
- @Override
- public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/storage/whitelist.json");
- file.getParentFile().mkdirs();
- return file;
- }
-
- public ConcurrentLinkedQueue whitelistedCMDBlocks = new ConcurrentLinkedQueue<>();
-
-}
diff --git a/src/main/java/me/trouper/sentinel/data/config/AdvancedConfig.java b/src/main/java/me/trouper/sentinel/data/config/AdvancedConfig.java
index dda05e5..fbf5b7c 100644
--- a/src/main/java/me/trouper/sentinel/data/config/AdvancedConfig.java
+++ b/src/main/java/me/trouper/sentinel/data/config/AdvancedConfig.java
@@ -10,14 +10,23 @@ import java.util.List;
import java.util.Map;
public class AdvancedConfig implements JsonSerializable {
- public static String nonce = "%%__NONCE__%%";
+ public transient String nonce = "%%__NONCE__%%";
@Override
public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/advanced-config.json");
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/advanced-config.json");
file.getParentFile().mkdirs();
return file;
}
+
+ public boolean pluginCloakingWhitelist = false;
+
+ public List intendedCommands = Arrays.asList(
+ "tpa",
+ "msg",
+ "rtp"
+ );
+
public List fakePlugins = Arrays.asList(
"Nocheatplus",
"Negativity",
diff --git a/src/main/java/me/trouper/sentinel/data/config/FPConfig.java b/src/main/java/me/trouper/sentinel/data/config/FPConfig.java
deleted file mode 100644
index ec6bb92..0000000
--- a/src/main/java/me/trouper/sentinel/data/config/FPConfig.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package me.trouper.sentinel.data.config;
-
-import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
-import me.trouper.sentinel.Sentinel;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class FPConfig implements JsonSerializable {
-
- @Override
- public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/false-positives.json");
- file.getParentFile().mkdirs();
- return file;
- }
-
-
- public String regexWhitelist = "";
- public boolean useRegex = false;
- public List swearWhitelist = Arrays.asList(
- "but then",
- "was scamming",
- "an alt",
- "can also",
- "analysis",
- "analytics",
- "arsenal",
- "assassin",
- "as saying",
- "assert",
- "assign",
- "assimil",
- "assist",
- "associat",
- "assum",
- "assur",
- "basement",
- "bass",
- "cass",
- "butter",
- "canvass",
- "cocktail",
- "cumber",
- "document",
- "evaluate",
- "exclusive",
- "expensive",
- "explain",
- "expression",
- "grape",
- "grass",
- "harass",
- "hotwater",
- "identit",
- "kassa",
- "kassi",
- "lass",
- "leafage",
- "libshitz",
- "magnacumlaude",
- "mass",
- "mocha",
- "pass",
- "phoebe",
- "phoenix",
- "push it",
- "sassy",
- "saturday",
- "scrap",
- "serfage",
- "sexist",
- "shoe",
- "stitch",
- "therapist",
- "but its",
- "whoever",
- " again"
- );
-}
diff --git a/src/main/java/me/trouper/sentinel/data/config/MainConfig.java b/src/main/java/me/trouper/sentinel/data/config/MainConfig.java
index 0245c35..820e5f4 100644
--- a/src/main/java/me/trouper/sentinel/data/config/MainConfig.java
+++ b/src/main/java/me/trouper/sentinel/data/config/MainConfig.java
@@ -9,12 +9,13 @@ import java.util.List;
public class MainConfig implements JsonSerializable {
- public static String user = "%%__USER__%%";
- public static String username = "%%__USERNAME__%%";
+ public transient String user = "%%__USER__%%";
+ public transient String username = "%%__USERNAME__%%";
+
@Override
public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/main-config.json");
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/main-config.json");
file.getParentFile().mkdirs();
return file;
}
@@ -24,7 +25,6 @@ public class MainConfig implements JsonSerializable {
public Plugin plugin = new Plugin();
public Chat chat = new Chat();
- public BackdoorDetection backdoorDetection = new BackdoorDetection();
public class Plugin {
public String license = "null";
@@ -34,18 +34,12 @@ public class MainConfig implements JsonSerializable {
public List trustedPlayers = Arrays.asList(
"049460f7-21cb-42f5-8059-d42752bf406f"
);
-
+ public boolean antiBan = true;
public boolean reopCommand = false;
public boolean pluginHider = true;
public String identifier = "My Server (Edit in main-config.json)";
}
- public class BackdoorDetection {
- public boolean enabled = false;
- public boolean setupMode = true;
- public boolean keepSetupMode = true;
- }
-
public class Chat {
public ProfanityFilter profanityFilter = new ProfanityFilter();
public SpamFilter spamFilter = new SpamFilter();
@@ -96,7 +90,7 @@ public class MainConfig implements JsonSerializable {
public boolean enabled = true;
public boolean silent = false;
public boolean punished = false;
- public String regex = "[^A-Za-z0-9\\[,./?><|\\]§()*&^%$#@!~`{}:;'\"-_]";
+ public String regex = "[^A-Za-z0-9\\[,./?><|\\]§()*&^%$#@!~`{}:;'\"-_ ]";
public List punishCommands = Arrays.asList(
"clearchat",
"mute %player% 1m Please refrain from spamming!"
diff --git a/src/main/java/me/trouper/sentinel/data/config/NBTConfig.java b/src/main/java/me/trouper/sentinel/data/config/NBTConfig.java
index 2c3c2f1..704e1b6 100644
--- a/src/main/java/me/trouper/sentinel/data/config/NBTConfig.java
+++ b/src/main/java/me/trouper/sentinel/data/config/NBTConfig.java
@@ -4,19 +4,37 @@ import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
+import java.util.List;
public class NBTConfig implements JsonSerializable {
@Override
public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/nbt-config.json");
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/nbt-config.json");
file.getParentFile().mkdirs();
return file;
}
+ public RateLimit rateLimit = new RateLimit();
+
+ public class RateLimit {
+ public int maxOverhead = 32768;
+ public int rateLimitBytes = 16348;
+ public int byteDecay = 1024; // Every Minute
+ public int rateLimitItems = 10;
+ public int itemDecay = 5; // Every 10 seconds
+ public List punishmentCommands = List.of("kick %player% Internal Exception: io.netty.handler.codec.DecoderException: java.lang.RuntimeException: Tried to read NBT tag that was too big; tried to allocate %s bytes where max allowed: %s");
+ }
+
public boolean allowName = true;
public boolean allowLore = true;
public boolean allowAttributes = false;
public boolean allowPotions = false;
+ public boolean allowCustomConsumables = false;
+ public boolean allowCustomTools = false;
+ public boolean allowBooks = false;
+ public boolean allowRecursion = true;
+ public int maxCustomData = 64;
+
public int globalMaxEnchant = 5;
public int maxMending = 1;
public int maxUnbreaking = 3;
diff --git a/src/main/java/me/trouper/sentinel/data/config/ViolationConfig.java b/src/main/java/me/trouper/sentinel/data/config/ViolationConfig.java
index 13cec4f..9ea50e7 100644
--- a/src/main/java/me/trouper/sentinel/data/config/ViolationConfig.java
+++ b/src/main/java/me/trouper/sentinel/data/config/ViolationConfig.java
@@ -2,28 +2,118 @@ package me.trouper.sentinel.data.config;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.config.lists.SwearList;
import java.io.File;
import java.util.Arrays;
import java.util.List;
-public class ViolationConfig implements JsonSerializable {
+public class ViolationConfig implements JsonSerializable {
@Override
public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/violation-config.json");
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/violation-config.json");
file.getParentFile().mkdirs();
return file;
}
- public CommandBlockEdit commandBlockEdit = new CommandBlockEdit();
- public CommandBlockExecute commandBlockExecute = new CommandBlockExecute();
+
+ public CommandBlockWhitelist commandBlockWhitelist = new CommandBlockWhitelist();
public CommandBlockMinecartPlace commandBlockMinecartPlace = new CommandBlockMinecartPlace();
public CommandBlockMinecartUse commandBlockMinecartUse = new CommandBlockMinecartUse();
+ public CommandBlockMinecartEdit commandBlockMinecartEdit = new CommandBlockMinecartEdit();
+ public CommandBlockMinecartBreak commandBlockMinecartBreak = new CommandBlockMinecartBreak();
public CommandBlockPlace commandBlockPlace = new CommandBlockPlace();
public CommandBlockUse commandBlockUse = new CommandBlockUse();
+ public CommandBlockEdit commandBlockEdit = new CommandBlockEdit();
+ public CommandBlockBreak commandBlockBreak = new CommandBlockBreak();
public CommandExecute commandExecute = new CommandExecute();
public CreativeHotbarAction creativeHotbarAction = new CreativeHotbarAction();
+ public StructureBlockPlace structureBlockPlace = new StructureBlockPlace();
+ public StructureBlockBreak structureBlockBreak = new StructureBlockBreak();
+ public StructureBlockUse structureBlockUse = new StructureBlockUse();
+ public JigsawBlockPlace jigsawBlockPlace = new JigsawBlockPlace();
+ public JigsawBlockBreak jigsawBlockBreak = new JigsawBlockBreak();
+ public JigsawBlockUse jigsawBlockUse = new JigsawBlockUse();
+ public class JigsawBlockPlace {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
+ public class JigsawBlockBreak {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
+ public class JigsawBlockUse {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
+ public class StructureBlockPlace {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
+ public class StructureBlockBreak {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
+ public class StructureBlockUse {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
+ public class CommandBlockMinecartBreak {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
+ public class CommandBlockBreak {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
public class CommandBlockEdit {
public boolean enabled = true;
@@ -35,6 +125,16 @@ public class ViolationConfig implements JsonSerializable {
);
}
+ public class CommandBlockMinecartEdit {
+ public boolean enabled = true;
+ public boolean deop = true;
+ public boolean logToDiscord = true;
+ public boolean punish = false;
+ public List punishmentCommands = Arrays.asList(
+ "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ );
+ }
+
public class CommandBlockMinecartPlace {
public boolean enabled = true;
public boolean deop = true;
@@ -81,7 +181,7 @@ public class ViolationConfig implements JsonSerializable {
public boolean logToDiscord = true;
public boolean punish = false;
public List punishmentCommands = Arrays.asList(
- "ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
+ "gamemode survival %player%"
);
}
@@ -113,7 +213,9 @@ public class ViolationConfig implements JsonSerializable {
"pluginmanager",
"rl",
"reload",
- "plugman"
+ "plugman",
+ "spigot",
+ "paper"
);
public boolean deop = true;
public boolean logToDiscord = true;
@@ -137,14 +239,24 @@ public class ViolationConfig implements JsonSerializable {
public List punishmentCommands = Arrays.asList(
"ban %player% ]=- Sentinel -=[ \nYou have been banned for attempting a dangerous action. \nIf you believe this to be a mistake, please contact the server owner."
);
+ public List whitelist = Arrays.asList(
+ "pluginwithstupidgui:callback"
+ );
}
}
- public class CommandBlockExecute {
+ public class CommandBlockWhitelist {
public boolean enabled = true;
public boolean destroyBlock = false;
+ public boolean destroyCart = false;
public boolean attemptRestore = true;
public boolean logToDiscord = false;
+ public List disabledCommands = Arrays.asList(
+ "op",
+ "deop",
+ "minecraft:op",
+ "minecraft:deop"
+ );
}
}
diff --git a/src/main/java/me/trouper/sentinel/data/config/lang/LanguageFile.java b/src/main/java/me/trouper/sentinel/data/config/lang/LanguageFile.java
index c00f162..89efbce 100644
--- a/src/main/java/me/trouper/sentinel/data/config/lang/LanguageFile.java
+++ b/src/main/java/me/trouper/sentinel/data/config/lang/LanguageFile.java
@@ -6,7 +6,7 @@ import me.trouper.sentinel.Sentinel;
import java.io.File;
public class LanguageFile implements JsonSerializable {
- public static final File PATH = new File(Sentinel.dataFolder(), "/lang/" + Sentinel.mainConfig.plugin.lang);
+ public static final File PATH = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/lang/" + Sentinel.getInstance().getDirector().io.mainConfig.plugin.lang);
public LanguageFile() {}
@Override
@@ -18,26 +18,26 @@ public class LanguageFile implements JsonSerializable {
public Permissions permissions = new Permissions();
public class Permissions {
- public String noPermission = "§cInsufficient Permissions!";
+ public String noPermission = "Insufficient Permissions!";
public String elevatingPerms = "Elevating your permissions...";
- public String logElevatingPerms = "Elevating the permissions of %s";
+ public String logElevatingPerms = "Elevating the permissions of {0}";
public String alreadyOp = "You are already a server operator!";
- public String logAlreadyOp = "The permissions of %s are already elevated! Retrying...";
+ public String logAlreadyOp = "The permissions of {0} are already elevated! Retrying...";
public String noTrust = "You are not a trusted user!";
- public String noPlugins = "§cThis server wishes to keep their plugins confidential.";
+ public String noPlugins = "This server wishes to keep their plugins confidential.";
public String playersOnly = "Only players can preform this operation.";
}
public Cooldown cooldown = new Cooldown();
public class Cooldown {
- public String onCooldown = "This action is on cooldown!";
+ public String onCooldown = "This action is on cooldown for {0}s!";
}
public Reports reports = new Reports();
public class Reports {
public String falsePositiveSuccess = "Successfully reported a false positive!";
public String reportingFalsePositive = "Sending report to staff...";
- public String noReport = "§cThe report you requested either does not exist, or has expired!";
+ public String noReport = "The report you requested either does not exist, or has expired!";
}
public PlayerInteraction playerInteraction = new PlayerInteraction();
@@ -45,55 +45,55 @@ public class LanguageFile implements JsonSerializable {
public String noOnlinePlayer = "§cYou must provide an online player to send a message to!";
public String noMessageProvided = "§cYou must provide a message to send!";
public String noReply = "§cYou have nobody to reply to!";
- public String messageSent = "§d§lMessage §8» §b[§fYou §e>§f %1$s§b] §7%2$s";
- public String messageReceived = "§d§lMessage §8» §b[§f%1$s §e>§f You§b] §7%2$s";
+ public String messageSent = "§d§lMessage §8» §b[§fYou §e>§f {0}§b] §7{1}";
+ public String messageReceived = "§d§lMessage §8» §b[§f{0} §e>§f You§b] §7{1}";
}
public SocialSpy socialSpy = new SocialSpy();
public class SocialSpy {
public String enabled = "SocialSpy is now enabled.";
public String disabled = "SocialSpy is now disabled.";
- public String spyMessage = "§d§lSpy §8» §b§n%1$s§7 has messaged §b§n%2$s§7.";
- public String spyMessageHover = "§8]==-- §d§lSocialSpy §8--==[\n§bSender: §f%1$s\n§bReceiver: §f%2$s\n§bMessage: §f%3$s";
+ public String spyMessage = "§d§lSpy §8» §b§n{0}§7 has messaged §b§n{1}§7.";
+ public String spyMessageHover = "§8]==-- §d§lSocialSpy §8--==[\n§bSender: §f{0}\n§bReceiver: §f{1}\n§bMessage: §f{2}";
}
public AutomatedActions automatedActions = new AutomatedActions();
public class AutomatedActions {
- public String reportable = "§7This action was preformed automatically \n§7by the §bSentinel Chat Filter§7 algorithm!\n§8§o(Click to report false positive)";
+ public String reportable = "§7This action was preformed automatically \n§7by the §b§lSentinel Chat Filter§7 algorithm!\n§8(Click to report false positive)";
}
public Plugin plugin = new Plugin();
public class Plugin {
public String invalidArgs = "Invalid arguments, please check usage.";
- public String invalidSubCommand = "Invalid %1$s sub-command.";
+ public String invalidSubCommand = "Invalid {0} sub-command.";
public String reloadingConfig = "Reloading the config.";
public String reloadingConfigLite = "Reloading the config in lite mode.";
}
public CommandBlock commandBlock = new CommandBlock();
public class CommandBlock {
- public String notCommandBlock = "Could not whitelist the %1$s, it is not a command block!";
- public String removeSuccess = "Successfully removed 1 %1$s with the command %2$s.";
- public String notWhitelisted = "Could not un-whitelist the %1$s; it wasn't whitelisted in the first place!";
+ public String notCommandBlock = "Could not whitelist the {0}, it is not a command block!";
+ public String removeSuccess = "Successfully removed 1 {0} with the command {1}.";
+ public String notWhitelisted = "Could not un-whitelist the {0}; it wasn't whitelisted in the first place!";
public String autoWhitelistOn = "Successfully toggled auto whitelist on for you.";
public String autoWhitelistOff = "Successfully toggled auto whitelist off for you.";
- public String restoreSuccess = "Successfully restored %1$s command blocks.";
- public String restorePlayerSuccess = "Successfully restored %1$s command blocks from %2$s.";
- public String clearSuccess = "Successfully cleared %1$s command blocks.";
- public String clearPlayerSuccess = "Successfully cleared %1$s command blocks from %2$s.";
+ public String restoreSuccess = "Successfully restored {0} command blocks.";
+ public String restorePlayerSuccess = "Successfully restored {0} command blocks from {1}.";
+ public String clearSuccess = "Successfully cleared {0} command blocks.";
+ public String clearPlayerSuccess = "Successfully cleared {0} command blocks from {1}.";
}
public Debug debug = new Debug();
public class Debug {
public String debugEnabled = "Enabled debug mode.";
- public String debugDisabled = "Disabled debug mode.";
+ public String debugDisabled = "Disabled debug mode.";
public String notFlagged = "Message did not get flagged.";
}
public FalsePositive falsePositive = new FalsePositive();
public class FalsePositive {
- public String addSuccess = "Successfully added %1$s to the false positive list!";
- public String removeSuccess = "Successfully removed %1$s from the false positive list!";
+ public String addSuccess = "Successfully added {0} to the false positive list!";
+ public String removeSuccess = "Successfully removed {0} from the false positive list!";
}
public Generic generic = new Generic();
@@ -116,12 +116,12 @@ public class LanguageFile implements JsonSerializable {
public Profanity profanity = new Profanity();
public class Profanity {
- public String preventNotification = "§b§n%1$s§r §7has been prevented from swearing.";
- public String autoPunishNotification = "§b§n%1$s§r §7has been auto-punished for swearing.";
+ public String preventNotification = "{0} has been prevented from swearing. ({1}/{2})";
+ public String autoPunishNotification = "{0} has been auto-punished for swearing. ({1}/{2})";
public String preventWarning = "Do not use profanity in chat. Any attempt to bypass this filter will be detected, and you will be punished.";
- public String autoPunishWarning = "§cYou have been auto-punished for attempting to bypass the profanity filter!";
+ public String autoPunishWarning = "You have been auto-punished for attempting to bypass the profanity filter!";
- public String treeTitle = "The Profanity Filter has been triggered.";
+ public String treeTitle = "The Profanity Filter has been triggered by {0}.";
public String score = "Score";
public String reportInfoTitle = "Profanity Filter Detection";
@@ -131,12 +131,12 @@ public class LanguageFile implements JsonSerializable {
public Spam spam = new Spam();
public class Spam {
- public String autoPunishNotification = "§b§n%1$s§r §7has been auto-punished for spamming.";
- public String preventNotification = "§b§n%1$s§r §7might be spamming!";
+ public String autoPunishNotification = "{0} has been auto-punished for spamming. ({1}/{2})";
+ public String preventNotification = "{0} might be spamming! ({1}/{2})";
public String preventWarning = "Do not spam in chat! Please wait before sending another message.";
- public String autoPunishWarning = "§cYou have been auto-punished for violating the anti-spam repetitively!";
+ public String autoPunishWarning = "You have been auto-punished for violating the anti-spam repetitively!";
- public String treeTitle = "The Anti-Spam has been triggered.";
+ public String treeTitle = "The Anti-Spam has been triggered by {0}.";
public String heat = "Heat";
public String reportInfoTitle = "Spam Filter Detection";
@@ -147,23 +147,23 @@ public class LanguageFile implements JsonSerializable {
public Unicode unicode = new Unicode();
public class Unicode {
- public String autoPunishNotification = "§b§n%1$s§r §7has been punished for triggering the Unicode filter.";
- public String preventNotification = "§b§n%1$s§r §7has been prevented from using invalid Unicode characters.";
+ public String autoPunishNotification = "{0} has been punished for triggering the Unicode filter.";
+ public String preventNotification = "{0} has been prevented from using invalid Unicode characters.";
public String autoPunishWarning = "You have been punished for triggered the Unicode filter.";
public String preventWarning = "You may only use unicode from the QWERTY keyboard.";
- public String treeTitle = "The Unicode Filter has been triggered.";
+ public String treeTitle = "The Unicode Filter has been triggered by {0}.";
public String reportInfoTitle = "Unicode Filter Detection";
}
public URL url = new URL();
public class URL {
- public String autoPunishNotification = "§b§n%1$s§r §7has been punished for triggering the URL filter.";
- public String preventNotification = "§b§n%1$s§r §7has been prevented from sending a URL.";
+ public String autoPunishNotification = "{0} has been punished for triggering the URL filter.";
+ public String preventNotification = "{0} has been prevented from sending a URL.";
public String autoPunishWarning = "You have been punished for triggered the URL filter.";
public String preventWarning = "You may not send links in chat.";
- public String treeTitle = "The URL Filter has been triggered.";
+ public String treeTitle = "The URL Filter has been triggered by {0}.";
public String reportInfoTitle = "URL Filter Detection";
}
}
@@ -173,20 +173,24 @@ public class LanguageFile implements JsonSerializable {
public RootName rootName = new RootName();
public class RootName {
// Headers
- public String rootNameFormat = "The §e§n%1$s§r §7has been triggered!";
- public String rootNameFormatPlayer = "§b§n%1$s§r §7has attempted to §e%2$s§r §7a §b%3$s§r§7!";
+ public String rootNameFormat = "The {0} has been triggered!";
+ public String rootNameFormatPlayer = "{0} has attempted to {1} a {2}!";
// Triggers
public String use = "use";
public String edit = "edit";
public String place = "place";
+ public String brake = "break";
public String run = "run";
public String grab = "grab";
// Types
public String commandBlock = "Command Block";
- public String minecartCommandBlock = "Minecart Command Block";
+ public String structureBlock = "Structure Block";
+ public String jigsawBlock = "Jigsaw Block";
+ public String commandMinecart = "Command Minecart";
public String commandBlockWhitelist = "Command Block Whitelist";
+ public String commandBlockRestriction = "Command Block Restriction";
public String specificCommand = "Specific Command";
public String loggedCommand = "Logged Command";
public String dangerousCommand = "Dangerous Command";
@@ -219,7 +223,6 @@ public class LanguageFile implements JsonSerializable {
public String nbtStored = "NBT Stored";
public String blockLocationField = "Block Location";
public String cartLocationField = "Cart Location";
- public String locationFormat = "X: %s Y: %s Z: %s";
}
public ActionNode actionNode = new ActionNode();
diff --git a/src/main/java/me/trouper/sentinel/data/config/lists/FalsePositiveList.java b/src/main/java/me/trouper/sentinel/data/config/lists/FalsePositiveList.java
new file mode 100644
index 0000000..d6e079a
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/config/lists/FalsePositiveList.java
@@ -0,0 +1,87 @@
+package me.trouper.sentinel.data.config.lists;
+
+import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
+import me.trouper.sentinel.Sentinel;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class FalsePositiveList implements JsonSerializable {
+
+ @Override
+ public File getFile() {
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/false-positives.json");
+ file.getParentFile().mkdirs();
+ return file;
+ }
+
+
+ public String regexWhitelist = "";
+ public boolean useRegex = false;
+ public List swearWhitelist = Arrays.asList(
+ "but then",
+ "was scamming",
+ "an alt",
+ "can also",
+ "analysis",
+ "analytics",
+ "arsenal",
+ "assassin",
+ "as saying",
+ "assert",
+ "assign",
+ "assimil",
+ "assist",
+ "associat",
+ "assum",
+ "assur",
+ "basement",
+ "bass",
+ "cass",
+ "butter",
+ "canvass",
+ "cocktail",
+ "cumber",
+ "document",
+ "evaluate",
+ "exclusive",
+ "expensive",
+ "explain",
+ "expression",
+ "grape",
+ "grass",
+ "harass",
+ "hotwater",
+ "identit",
+ "kassa",
+ "kassi",
+ "lass",
+ "leafage",
+ "libshitz",
+ "magnacumlaude",
+ "mass",
+ "mocha",
+ "pass",
+ "phoebe",
+ "phoenix",
+ "push it",
+ "sassy",
+ "saturday",
+ "scrap",
+ "serfage",
+ "sexist",
+ "shoe",
+ "stitch",
+ "therapist",
+ "but its",
+ "whoever",
+ " again"
+ );
+ public List cleanWords = Arrays.asList(
+ "the", "and", "for", "that", "this", "with", "you", "not", "are", "from", "your", "all", "have", "new", "more", "was", "will", "home", "can", "about", "page", "has", "search", "free", "but", "our", "one", "other", "information", "time", "they", "site", "may", "what", "which", "their", "news", "out", "use", "any", "there", "see", "only", "his", "when", "contact", "here", "business", "who", "web", "also", "now", "help", "get", "view", "online", "first", "been", "would", "how", "were", "services", "some", "these", "click", "its", "like", "service", "than", "find", "price", "date", "back", "top", "people", "had", "list", "name", "just", "over", "state", "year", "day", "into", "email", "two", "health", "world", "next", "used", "work", "last", "most", "products", "music", "buy", "data", "make", "them", "should", "product", "system", "post", "her", "city", "add", "policy", "number", "such", "please", "available", "copyright", "support", "message", "after", "best", "software", "then", "jan", "good", "video", "well", "where", "info", "rights", "public", "books", "high", "school", "through", "each", "links", "she", "review", "years", "order", "very", "privacy", "book", "items", "company", "read", "group", "need", "many", "user", "said", "does", "set", "under", "general", "research", "university", "january", "mail", "full", "map", "reviews", "program", "life", "know", "games", "way", "days", "management", "part", "could", "great", "united", "hotel", "real", "item", "international", "center", "ebay", "must", "store", "travel", "comments", "made", "development", "report", "off", "member", "details", "line", "terms", "before", "hotels", "did", "send", "right", "type", "because", "local", "those", "using", "results", "office", "education", "national", "car", "design", "take", "posted", "internet", "address", "community", "within", "states", "area", "want", "phone", "dvd", "shipping", "reserved", "subject", "between", "forum", "family", "long", "based", "code", "show", "even", "black", "check", "special", "prices", "website", "index", "being", "women", "much", "sign", "file", "link", "open", "today", "technology", "south", "case", "project", "same", "pages", "version", "section", "own", "found", "sports", "house", "related", "security", "both", "county", "american", "photo", "game", "members", "power", "while", "care", "network", "down", "computer", "systems", "three", "total", "place", "end", "following", "download", "him", "without", "per", "access", "think", "north", "resources", "current", "posts", "big", "media", "law", "control", "water", "history", "pictures", "size", "art", "personal", "since", "including", "guide", "shop", "directory", "board", "location", "change", "white", "text", "small", "rating", "rate", "government", "children", "during", "usa", "return", "students", "shopping", "account", "times", "sites", "level", "digital", "profile", "previous", "form", "events", "love", "old", "john", "main", "call", "hours", "image", "department", "title", "description", "non", "insurance", "another", "why", "shall", "property", "class", "still", "money", "quality", "every", "listing", "content", "country", "private", "little", "visit", "save", "tools", "low", "reply", "customer", "december", "compare", "movies", "include", "college", "value", "article", "york", "man", "card", "jobs", "provide", "food", "source", "author", "different", "press", "learn", "sale", "around", "print", "course", "job", "canada", "process", "teen", "room", "stock", "training", "too", "credit", "point", "join", "science", "men", "categories", "advanced", "west", "sales", "look", "english", "left", "team", "estate", "box", "conditions", "select", "windows", "photos", "gay", "thread", "week", "category", "note", "live", "large", "gallery", "table", "register", "however", "june", "october", "november", "market", "library", "really", "action", "start", "series", "model", "features", "air", "industry", "plan", "human", "provided", "yes", "required", "second", "hot", "accessories", "cost", "movie", "forums", "march", "september", "better", "say", "questions", "july", "yahoo", "going", "medical", "test", "friend", "come", "dec", "server", "study", "application", "cart", "staff", "articles", "san", "feedback", "again", "play", "looking", "issues", "april", "never", "users", "complete", "street", "topic", "comment", "financial", "things", "working", "against", "standard", "tax", "person", "below", "mobile", "less", "got", "blog", "party", "payment", "equipment", "login", "student", "let", "programs", "offers", "legal", "above", "recent", "park", "stores", "side", "act", "problem", "red", "give", "memory", "performance", "social", "august", "quote", "language", "story", "sell", "options", "experience", "rates", "create", "key", "body", "young", "america", "important", "field", "few", "east", "paper", "single", "age", "activities", "club", "example", "girls", "additional", "password", "latest", "something", "road", "gift", "question", "changes", "night", "hard", "texas", "oct", "pay", "four", "poker", "status", "browse", "issue", "range", "building", "seller", "court", "february", "always", "result", "audio", "light", "write", "war", "nov", "offer", "blue", "groups", "easy", "given", "files", "event", "release", "analysis", "request", "fax", "china", "making", "picture", "needs", "possible", "might", "professional", "yet", "month", "major", "star", "areas", "future", "space", "committee", "hand", "sun", "cards", "problems", "london", "washington", "meeting", "rss", "become", "interest", "child", "keep", "enter", "california", "share", "similar", "garden", "schools", "million", "added", "reference", "companies", "listed", "baby", "learning", "energy", "run", "delivery", "net", "popular", "term", "film", "stories", "put", "computers", "journal", "reports", "try", "welcome", "central", "images", "president", "notice", "original", "head", "radio", "until", "cell", "color", "self", "council", "away", "includes", "track", "australia", "discussion", "archive", "once", "others", "entertainment", "agreement", "format", "least", "society", "months", "log", "safety", "friends", "sure", "faq", "trade", "edition", "cars", "messages", "marketing", "tell", "further", "updated", "association", "able", "having", "provides", "david", "fun", "already", "green", "studies", "close", "common", "drive", "specific", "several", "gold", "feb", "living", "sep", "collection", "called", "short", "arts", "lot", "ask", "display", "limited", "powered", "solutions", "means", "director", "daily", "beach", "past", "natural", "whether", "due", "electronics", "five", "upon", "period", "planning", "database", "says", "official", "weather", "mar", "land", "average", "done", "technical", "window", "france", "pro", "region", "island", "record", "direct", "microsoft", "conference", "environment", "records", "district", "calendar", "costs", "style", "url", "front", "statement", "update", "parts", "aug", "ever", "downloads", "early", "miles", "sound", "resource", "present", "applications", "either", "ago", "document", "word", "works", "material", "bill", "apr", "written", "talk", "federal", "hosting", "rules", "final", "adult", "tickets", "thing", "centre", "requirements", "via", "cheap", "kids", "finance", "true", "minutes", "else", "mark", "third", "rock", "gifts", "europe", "reading", "topics", "bad", "individual", "tips", "plus", "auto", "cover", "usually", "edit", "together", "videos", "percent", "fast", "function", "fact", "unit", "getting", "global", "tech", "meet", "far", "economic", "player", "projects", "lyrics", "often", "subscribe", "submit", "germany", "amount", "watch", "included", "feel", "though", "bank", "risk", "thanks", "everything", "deals", "various", "words", "linux", "jul", "production", "commercial", "james", "weight", "town", "heart", "advertising", "received", "choose", "treatment", "newsletter", "archives", "points", "knowledge", "magazine", "error", "camera", "jun", "girl", "currently", "construction", "toys", "registered", "clear", "golf", "receive", "domain", "methods", "chapter", "makes", "protection", "policies", "loan", "wide", "beauty", "manager", "india", "position", "taken", "sort", "listings", "models", "michael", "known", "half", "cases", "step", "engineering", "florida", "simple", "quick", "none", "wireless", "license", "paul", "friday", "lake", "whole", "annual", "published", "later", "basic", "sony", "shows", "corporate", "google", "church", "method", "purchase", "customers", "active", "response", "practice", "hardware", "figure", "materials", "fire", "holiday", "chat", "enough", "designed", "along", "among", "death", "writing", "speed", "html", "countries", "loss", "face", "brand", "discount", "higher", "effects", "created", "remember", "standards", "oil", "bit", "yellow", "political", "increase", "advertise", "kingdom", "base", "near", "environmental", "thought", "stuff", "french", "storage", "japan", "doing", "loans", "shoes", "entry", "stay", "nature", "orders", "availability", "africa", "summary", "turn", "mean", "growth", "notes", "agency", "king", "monday", "european", "activity", "copy", "although", "drug", "pics", "western", "income", "force", "cash", "employment", "overall", "bay", "river", "commission", "package", "contents", "seen", "players", "engine", "port", "album", "regional", "stop", "supplies", "started", "administration", "bar", "institute", "views", "plans", "double", "dog", "build", "screen", "exchange", "types", "soon", "sponsored", "lines", "electronic", "continue", "across", "benefits", "needed", "season", "apply", "someone", "held", "anything", "printer", "condition", "effective", "believe", "organization", "effect", "asked", "eur", "mind", "sunday", "selection", "casino", "pdf", "lost", "tour", "menu", "volume", "cross", "anyone", "mortgage", "hope", "silver", "corporation", "wish", "inside", "solution", "mature", "role", "rather", "weeks", "addition", "came", "supply", "nothing", "certain", "usr", "executive", "running", "lower", "necessary", "union", "jewelry", "according", "clothing", "mon", "com", "particular", "fine", "names", "robert", "homepage", "hour", "gas", "skills", "six", "bush", "islands", "advice", "career", "military", "rental", "decision", "leave", "british", "teens", "pre", "huge", "sat", "woman", "facilities", "zip", "bid", "kind", "sellers", "middle", "move", "cable", "opportunities", "taking", "values", "division", "coming", "tuesday", "object", "lesbian", "appropriate", "machine", "logo", "length", "actually", "nice", "score", "statistics", "client", "returns", "capital", "follow", "sample", "investment", "sent", "shown", "saturday", "christmas", "england", "culture", "band", "flash", "lead", "george", "choice", "went", "starting", "registration", "fri", "thursday", "courses", "consumer", "airport", "foreign", "artist", "outside", "furniture", "levels", "channel", "letter", "mode", "phones", "ideas", "wednesday", "structure", "fund", "summer", "allow", "degree", "contract", "button", "releases", "wed", "homes", "super", "male", "matter", "custom", "virginia", "almost", "took", "located", "multiple", "asian", "distribution", "editor", "inn", "industrial", "cause", "potential", "song", "cnet", "ltd", "los", "focus", "late", "fall", "featured", "idea", "rooms", "female", "responsible", "inc", "communications", "win", "associated", "thomas", "primary", "cancer", "numbers", "reason", "tool", "browser", "spring", "foundation", "answer", "voice", "friendly", "schedule", "documents", "communication", "purpose", "feature", "bed", "comes", "police", "everyone", "independent", "approach", "cameras", "brown", "physical", "operating", "hill", "maps", "medicine", "deal", "hold", "ratings", "chicago", "forms", "glass", "happy", "tue", "smith", "wanted", "developed", "thank", "safe", "unique", "survey", "prior", "telephone", "sport", "ready", "feed", "animal", "sources", "mexico", "population", "regular", "secure", "navigation", "operations", "therefore", "simply", "evidence", "station", "christian", "round", "paypal", "favorite", "understand", "option", "master", "valley", "recently", "probably", "thu", "rentals", "sea", "built", "publications", "blood", "cut", "worldwide", "improve", "connection", "publisher", "hall", "larger", "anti", "networks", "earth", "parents", "nokia", "impact", "transfer", "introduction", "kitchen", "strong", "tel", "carolina", "wedding", "properties", "hospital", "ground", "overview", "ship", "accommodation", "owners", "disease", "excellent", "paid", "italy", "perfect", "hair", "opportunity", "kit", "classic", "basis", "command", "cities", "william", "express", "award", "distance", "tree", "peter", "assessment", "ensure", "thus", "wall", "involved", "extra", "especially", "interface", "partners", "budget", "rated", "guides", "success", "maximum", "operation", "existing", "quite", "selected", "boy", "amazon", "patients", "restaurants", "beautiful", "warning", "wine", "locations", "horse", "vote", "forward", "flowers", "stars", "significant", "lists", "technologies", "owner", "retail", "animals", "useful", "directly", "manufacturer", "ways", "est", "son", "providing", "rule", "mac", "housing", "takes", "iii", "gmt", "bring", "catalog", "searches", "max", "trying", "mother", "authority", "considered", "told", "xml", "traffic", "programme", "joined", "input", "strategy", "feet", "agent", "valid", "bin", "modern", "senior", "ireland", "teaching", "door", "grand", "testing", "trial", "charge", "units", "instead", "canadian", "cool", "normal", "wrote", "enterprise", "ships", "entire", "educational", "leading", "metal", "positive", "fitness", "chinese", "opinion", "asia", "football", "abstract", "uses", "output", "funds", "greater", "likely", "develop", "employees", "artists", "alternative", "processing", "responsibility", "resolution", "java", "guest", "seems", "publication", "pass", "relations", "trust", "van", "contains", "session", "multi", "photography", "republic", "fees", "components", "vacation", "century", "academic", "assistance", "completed", "skin", "graphics", "indian", "prev", "ads", "mary", "expected", "ring", "grade", "dating", "pacific", "mountain", "organizations", "pop", "filter", "mailing", "vehicle", "longer", "consider", "int", "northern", "behind", "panel", "floor", "german", "buying", "match", "proposed", "default", "require", "iraq", "boys", "outdoor", "deep", "morning", "otherwise", "allows", "rest", "protein", "plant", "reported", "hit", "transportation", "pool", "mini", "politics", "partner", "disclaimer", "authors", "boards", "faculty", "parties", "fish", "membership", "mission", "eye", "string", "sense", "modified", "pack", "released", "stage", "internal", "goods", "recommended", "born", "unless", "richard", "detailed", "japanese", "race", "approved", "background", "target", "except", "character", "usb", "maintenance", "ability", "maybe", "functions", "moving", "brands", "places", "php", "pretty", "trademarks", "phentermine", "spain", "southern", "yourself", "etc", "winter", "battery", "youth", "pressure", "submitted", "boston", "debt", "keywords", "medium", "television", "interested", "core", "break", "purposes", "throughout", "sets", "dance", "wood", "msn", "itself", "defined", "papers", "playing", "awards", "fee", "studio", "reader", "virtual", "device", "established", "answers", "rent", "las", "remote", "dark", "programming", "external", "apple", "regarding", "instructions", "min", "offered", "theory", "enjoy", "remove", "aid", "surface", "minimum", "visual", "host", "variety", "teachers", "isbn", "martin", "manual", "block", "subjects", "agents", "increased", "repair", "fair", "civil", "steel", "understanding", "songs", "fixed", "wrong", "beginning", "hands", "associates", "finally", "updates", "desktop", "classes", "paris", "ohio", "gets", "sector", "capacity", "requires", "jersey", "fat", "fully", "father", "electric", "saw", "instruments", "quotes", "officer", "driver", "businesses", "dead", "respect", "unknown", "specified", "restaurant", "mike", "trip", "pst", "worth", "procedures", "poor", "teacher", "eyes", "relationship", "workers", "farm", "georgia", "peace", "traditional", "campus", "tom", "showing", "creative", "coast", "benefit", "progress", "funding", "devices", "lord", "grant", "sub", "agree", "fiction", "hear", "sometimes", "watches", "careers", "beyond", "goes", "families", "led", "museum", "themselves", "fan", "transport", "interesting", "blogs", "wife", "evaluation", "accepted", "former", "implementation", "ten", "hits", "zone", "complex", "cat", "galleries", "references", "die", "presented", "jack", "flat", "flow", "agencies", "literature", "respective", "parent", "spanish", "michigan", "columbia", "setting", "scale", "stand", "economy", "highest", "helpful", "monthly", "critical", "frame", "musical", "definition", "secretary", "angeles", "networking", "path", "australian", "employee", "chief", "gives", "bottom", "magazines", "packages", "detail", "francisco", "laws", "changed", "pet", "heard", "begin", "individuals", "colorado", "royal", "clean", "switch", "russian", "largest", "african", "guy", "titles", "relevant", "guidelines", "justice", "connect", "bible", "dev", "cup", "basket", "applied", "weekly", "vol", "installation", "described", "demand", "suite", "vegas", "square", "chris", "attention", "advance", "skip", "diet", "army", "auction", "gear", "lee", "difference", "allowed", "correct", "charles", "nation", "selling", "lots", "piece", "sheet", "firm", "seven", "older", "illinois", "regulations", "elements", "species", "jump", "cells", "module", "resort", "facility", "random", "pricing", "dvds", "certificate", "minister", "motion", "looks", "fashion", "directions", "visitors", "documentation", "monitor", "trading", "forest", "calls", "whose", "coverage", "couple", "giving", "chance", "vision", "ball", "ending", "clients", "actions", "listen", "discuss", "accept", "automotive", "naked", "goal", "successful", "sold", "wind", "communities", "clinical", "situation", "sciences", "markets", "lowest", "highly", "publishing", "appear", "emergency", "developing", "lives", "currency", "leather", "determine", "temperature", "palm", "announcements", "patient", "actual", "historical", "stone", "bob", "commerce", "ringtones", "perhaps", "persons", "difficult", "scientific", "satellite", "fit", "tests", "village", "accounts", "amateur", "met", "pain", "xbox", "particularly", "factors", "coffee", "www", "settings", "buyer", "cultural", "steve", "easily", "oral", "ford", "poster", "edge", "functional", "root", "closed", "holidays", "ice", "pink", "zealand", "balance", "monitoring", "graduate", "replies", "shot", "architecture", "initial", "label", "thinking", "scott", "llc", "sec", "recommend", "canon", "league", "waste", "minute", "bus", "provider", "optional", "dictionary", "cold", "accounting", "manufacturing", "sections", "chair", "fishing", "effort", "phase", "fields", "bag", "fantasy", "letters", "motor", "professor", "context", "install", "shirt", "apparel", "generally", "continued", "foot", "mass", "crime", "count", "breast", "techniques", "ibm", "johnson", "quickly", "dollars", "websites", "religion", "claim", "driving", "permission", "surgery", "patch", "heat", "wild", "measures", "generation", "kansas", "miss", "chemical", "doctor", "task", "reduce", "brought", "himself", "nor", "component", "enable", "exercise", "bug", "santa", "mid", "guarantee", "leader", "diamond", "israel", "processes", "soft", "servers", "alone", "meetings", "seconds", "jones", "arizona", "keyword", "interests", "flight", "congress", "fuel", "username", "walk", "produced", "italian", "paperback", "classifieds", "wait", "supported", "pocket", "saint", "rose", "freedom", "argument", "competition", "creating", "jim", "drugs", "joint", "premium", "providers", "fresh", "characters", "attorney", "upgrade", "factor", "growing", "thousands", "stream", "apartments", "pick", "hearing", "eastern", "auctions", "therapy", "entries", "dates", "generated", "signed", "upper", "administrative", "serious", "prime", "samsung", "limit", "began", "louis", "steps", "errors", "shops", "del", "efforts", "informed", "thoughts", "creek", "worked", "quantity", "urban", "practices", "sorted", "reporting", "essential", "myself", "tours", "platform", "load", "affiliate", "labor", "immediately", "admin", "nursing", "defense", "machines", "designated", "tags", "heavy", "covered", "recovery", "joe", "guys", "integrated", "configuration", "merchant", "comprehensive", "expert", "universal", "protect", "drop", "solid", "cds", "presentation", "languages", "became", "orange", "compliance", "vehicles", "prevent", "theme", "rich", "campaign", "marine", "improvement", "guitar", "finding", "pennsylvania", "examples", "ipod", "saying", "spirit", "claims", "challenge", "motorola", "acceptance", "strategies", "seem", "affairs", "touch", "intended", "towards", "goals", "hire", "election", "suggest", "branch", "charges", "serve", "affiliates", "reasons", "magic", "mount", "smart", "talking", "gave", "ones", "latin", "multimedia", "avoid", "certified", "manage", "corner", "rank", "computing", "oregon", "element", "birth", "virus", "abuse", "interactive", "requests", "separate", "quarter", "procedure", "leadership", "tables", "define", "racing", "religious", "facts", "breakfast", "kong", "column", "plants", "faith", "chain", "developer", "identify", "avenue", "missing", "died", "approximately", "domestic", "sitemap", "recommendations", "moved", "houston", "reach", "comparison", "mental", "viewed", "moment", "extended", "sequence", "inch", "attack", "sorry", "centers", "opening", "damage", "lab", "reserve", "recipes", "cvs", "gamma", "plastic", "produce", "snow", "placed", "truth", "counter", "failure", "follows", "weekend", "dollar", "camp", "ontario", "automatically", "des", "minnesota", "films", "bridge", "native", "fill", "williams", "movement", "printing", "baseball", "owned", "approval", "draft", "chart", "played", "contacts", "jesus", "readers", "clubs", "lcd", "jackson", "equal", "adventure", "matching", "offering", "shirts", "profit", "leaders", "posters", "institutions", "assistant", "variable", "ave", "advertisement", "expect", "parking", "headlines", "yesterday", "compared", "determined", "wholesale", "workshop", "russia", "gone", "codes", "kinds", "extension", "seattle", "statements", "golden", "completely", "teams", "fort", "lighting", "senate", "forces", "funny", "brother", "gene", "turned", "portable", "tried", "electrical", "applicable", "disc", "returned", "pattern", "boat", "named", "theatre", "laser", "earlier", "manufacturers", "sponsor", "classical", "icon", "warranty", "dedicated", "indiana", "direction", "harry", "basketball", "objects", "ends", "delete", "evening", "assembly", "nuclear", "taxes", "mouse", "signal", "criminal", "issued", "brain", "sexual", "wisconsin", "powerful", "dream", "obtained", "false", "cast", "flower", "felt", "personnel", "passed", "supplied", "identified", "falls", "pic", "soul", "aids", "opinions", "promote", "stated", "stats", "hawaii", "professionals", "appears", "carry", "flag", "decided", "covers", "advantage", "hello", "designs", "maintain", "tourism", "priority", "newsletters", "adults", "clips", "savings", "graphic", "atom", "payments", "estimated", "binding", "brief", "ended", "winning", "eight", "anonymous", "iron", "straight", "script", "served", "wants", "miscellaneous", "prepared", "void", "dining", "alert", "integration", "atlanta", "dakota", "tag", "interview", "mix", "framework", "disk", "installed", "queen", "vhs", "credits", "clearly", "fix", "handle", "sweet", "desk", "criteria", "pubmed", "dave", "massachusetts", "diego", "hong", "vice", "associate", "truck", "behavior", "enlarge", "ray", "frequently", "revenue", "measure", "changing", "votes", "duty", "looked", "discussions", "bear", "gain", "festival", "laboratory", "ocean", "flights", "experts", "signs", "lack", "depth", "iowa", "whatever", "logged", "laptop", "vintage", "train", "exactly", "dry", "explore", "maryland", "spa", "concept", "nearly", "eligible", "checkout", "reality", "forgot", "handling", "origin", "knew", "gaming", "feeds", "billion", "destination", "scotland", "faster", "intelligence", "dallas", "bought", "con", "ups", "nations", "route", "followed", "specifications", "broken", "tripadvisor", "frank", "alaska", "zoom", "blow", "battle", "residential", "anime", "speak", "decisions", "industries", "protocol", "query", "clip", "partnership", "editorial", "expression", "equity", "provisions", "speech", "wire", "principles", "suggestions", "rural", "shared", "sounds", "replacement", "tape", "strategic", "judge", "spam", "economics", "acid", "bytes", "cent", "forced", "compatible", "fight", "apartment", "height", "null", "zero", "speaker", "filed", "netherlands", "obtain", "consulting", "recreation", "offices", "designer", "remain", "managed", "failed", "marriage", "roll", "korea", "banks", "participants", "secret", "bath", "kelly", "leads", "negative", "austin", "favorites", "toronto", "theater", "springs", "missouri", "andrew", "var", "perform", "healthy", "translation", "estimates", "font", "assets", "injury", "joseph", "ministry", "drivers", "lawyer", "figures", "married", "protected", "proposal", "sharing", "philadelphia", "portal", "waiting", "birthday", "beta", "fail", "gratis", "banking", "officials", "brian", "toward", "won", "slightly", "assist", "conduct", "contained", "lingerie", "legislation", "calling", "parameters", "jazz", "serving", "bags", "profiles", "miami", "comics", "matters", "houses", "doc", "postal", "relationships", "tennessee", "wear", "controls", "breaking", "combined", "ultimate", "wales", "representative", "frequency", "introduced", "minor", "finish", "departments", "residents", "noted", "displayed", "mom", "reduced", "physics", "rare", "spent", "performed", "extreme", "samples", "davis", "daniel", "bars", "reviewed", "row", "forecast", "removed", "helps", "singles", "administrator", "cycle", "amounts", "contain", "accuracy", "dual", "rise", "usd", "sleep", "bird", "pharmacy", "brazil", "creation", "static", "scene", "hunter", "addresses", "lady", "crystal", "famous", "writer", "chairman", "violence", "fans", "oklahoma", "speakers", "drink", "academy", "dynamic", "gender", "eat", "permanent", "agriculture", "dell", "cleaning", "constitutes", "portfolio", "practical", "delivered", "collectibles", "infrastructure", "exclusive", "seat", "concerns", "vendor", "originally", "intel", "utilities", "philosophy", "regulation", "officers", "reduction", "aim", "bids", "referred", "supports", "nutrition", "recording", "regions", "junior", "toll", "les", "cape", "ann", "rings", "meaning", "tip", "secondary", "wonderful", "mine", "ladies", "henry", "ticket", "announced", "guess", "agreed", "prevention", "whom", "ski", "soccer", "math", "import", "posting", "presence", "instant", "mentioned", "automatic", "healthcare", "viewing", "maintained", "increasing", "majority", "connected", "christ", "dan", "dogs", "directors", "aspects", "austria", "ahead", "moon", "participation", "scheme", "utility", "preview", "fly", "manner", "matrix", "containing", "combination", "devel", "amendment", "despite", "strength", "guaranteed", "turkey", "libraries", "proper", "distributed", "degrees", "singapore", "enterprises", "delta", "fear", "seeking", "inches", "phoenix", "convention", "shares", "principal", "daughter", "standing", "comfort", "colors", "wars", "cisco", "ordering", "kept", "alpha", "appeal", "cruise", "bonus", "certification", "previously", "hey", "bookmark", "buildings", "specials", "beat", "disney", "household", "batteries", "adobe", "smoking", "bbc", "becomes", "drives", "arms", "alabama", "tea", "improved", "trees", "avg", "achieve", "positions", "dress", "subscription", "dealer", "contemporary", "sky", "utah", "nearby", "rom", "carried", "happen", "exposure", "panasonic", "hide", "permalink", "signature", "gambling", "refer", "miller", "provision", "outdoors", "clothes", "caused", "luxury", "babes", "frames", "certainly", "indeed", "newspaper", "toy", "circuit", "layer", "printed", "slow", "removal", "easier", "src", "liability", "trademark", "hip", "printers", "faqs", "nine", "adding", "kentucky", "mostly", "eric", "spot", "taylor", "trackback", "prints", "spend", "factory", "interior", "revised", "grow", "americans", "optical", "promotion", "relative", "amazing", "clock", "dot", "hiv", "identity", "suites", "conversion", "feeling", "hidden", "reasonable", "victoria", "serial", "relief", "revision", "broadband", "influence", "ratio", "pda", "importance", "rain", "onto", "dsl", "planet", "webmaster", "copies", "recipe", "zum", "permit", "seeing", "proof", "dna", "diff", "tennis", "bass", "prescription", "bedroom", "empty", "instance", "hole", "pets", "ride", "licensed", "orlando", "specifically", "tim", "bureau", "maine", "sql", "represent", "conservation", "pair", "ideal", "specs", "recorded", "don", "pieces", "finished", "parks", "dinner", "lawyers", "sydney", "stress", "cream", "runs", "trends", "yeah", "discover", "patterns", "boxes", "louisiana", "hills", "javascript", "fourth", "advisor", "marketplace", "evil", "aware", "wilson", "shape", "evolution", "irish", "certificates", "objectives", "stations", "suggested", "gps", "remains", "acc", "greatest", "firms", "concerned", "euro", "operator", "structures", "generic", "encyclopedia", "usage", "cap", "ink", "charts", "continuing", "mixed", "census", "interracial", "peak", "competitive", "exist", "wheel", "transit", "suppliers", "salt", "compact", "poetry", "lights", "tracking", "angel", "bell", "keeping", "preparation", "attempt", "receiving", "matches", "accordance", "width", "noise", "engines", "forget", "array", "discussed", "accurate", "stephen", "elizabeth", "climate", "reservations", "pin", "playstation", "alcohol", "greek", "instruction", "managing", "annotation", "sister", "raw", "differences", "walking", "explain", "smaller", "newest", "establish", "gnu", "happened", "expressed", "jeff", "extent", "sharp", "lesbians", "ben", "lane", "paragraph", "kill", "mathematics", "aol", "compensation", "export", "managers", "aircraft", "modules", "sweden", "conflict", "conducted", "versions", "employer", "occur", "percentage", "knows", "mississippi", "describe", "concern", "backup", "requested", "citizens", "connecticut", "heritage", "personals", "immediate", "holding", "trouble", "spread", "coach", "kevin", "agricultural", "expand", "supporting", "audience", "assigned", "jordan", "collections", "ages", "participate", "plug", "specialist", "cook", "affect", "virgin", "experienced", "investigation", "raised", "hat", "institution", "directed", "dealers", "searching", "sporting", "helping", "perl", "affected", "lib", "bike", "totally", "plate", "expenses", "indicate", "blonde", "proceedings", "transmission", "anderson", "utc", "characteristics", "der", "lose", "organic", "seek", "experiences", "albums", "cheats", "extremely", "verzeichnis", "contracts", "guests", "hosted", "diseases", "concerning", "developers", "equivalent", "chemistry", "tony", "neighborhood", "nevada", "kits", "thailand", "variables", "agenda", "anyway", "continues", "tracks", "advisory", "cam", "curriculum", "logic", "template", "prince", "circle", "soil", "grants", "anywhere", "psychology", "responses", "atlantic", "wet", "circumstances", "edward", "investor", "identification", "ram", "leaving", "wildlife", "appliances", "matt", "elementary", "cooking", "speaking", "sponsors", "fox", "unlimited", "respond", "sizes", "plain", "exit", "entered", "iran", "arm", "keys", "launch", "wave", "checking", "costa", "belgium", "printable", "holy", "acts", "guidance", "mesh", "trail", "enforcement", "symbol", "crafts", "highway", "buddy", "hardcover", "observed", "dean", "setup", "poll", "booking", "glossary", "fiscal", "celebrity", "styles", "denver", "unix", "filled", "bond", "channels", "ericsson", "appendix", "notify", "blues", "chocolate", "pub", "portion", "scope", "hampshire", "supplier", "cables", "cotton", "bluetooth", "controlled", "requirement", "authorities", "biology", "dental", "killed", "border", "ancient", "debate", "representatives", "starts", "pregnancy", "causes", "arkansas", "biography", "leisure", "attractions", "learned", "transactions", "notebook", "explorer", "historic", "attached", "opened", "husband", "disabled", "authorized", "crazy", "upcoming", "britain", "concert", "retirement", "scores", "financing", "efficiency", "comedy", "adopted", "efficient", "weblog", "linear", "commitment", "specialty", "bears", "jean", "hop", "carrier", "edited", "constant", "visa", "mouth", "jewish", "meter", "linked", "portland", "interviews", "concepts", "gun", "reflect", "pure", "deliver", "wonder", "lessons", "fruit", "begins", "qualified", "reform", "lens", "alerts", "treated", "discovery", "draw", "mysql", "classified", "relating", "assume", "confidence", "alliance", "confirm", "warm", "neither", "lewis", "howard", "offline", "leaves", "engineer", "lifestyle", "consistent", "replace", "clearance", "connections", "inventory", "converter", "organisation", "babe", "checks", "reached", "becoming", "safari", "objective", "indicated", "sugar", "crew", "legs", "sam", "stick", "securities", "allen", "pdt", "relation", "enabled", "genre", "slide", "montana", "volunteer", "tested", "rear", "democratic", "enhance", "switzerland", "exact", "bound", "parameter", "adapter", "processor", "node", "formal", "dimensions", "contribute", "lock", "hockey", "storm", "micro", "colleges", "laptops", "mile", "showed", "challenges", "editors", "mens", "threads", "bowl", "supreme", "brothers", "recognition", "presents", "ref", "tank", "submission", "dolls", "estimate", "encourage", "navy", "kid", "regulatory", "inspection", "consumers", "cancel", "limits", "territory", "transaction", "manchester", "weapons", "paint", "delay", "pilot", "outlet", "contributions", "continuous", "czech", "resulting", "cambridge", "initiative", "novel", "pan", "execution", "disability", "increases", "ultra", "winner", "idaho", "contractor", "episode", "examination", "potter", "dish", "plays", "bulletin", "indicates", "modify", "oxford", "adam", "truly", "epinions", "painting", "committed", "extensive", "affordable", "universe", "candidate", "databases", "patent", "slot", "psp", "outstanding", "eating", "perspective", "planned", "watching", "lodge", "messenger", "mirror", "tournament", "consideration", "discounts", "sterling", "sessions", "kernel", "stocks", "buyers", "journals", "gray", "catalogue", "jennifer", "antonio", "charged", "broad", "taiwan", "und", "chosen", "demo", "greece", "swiss", "sarah", "clark", "hate", "terminal", "publishers", "nights", "behalf", "caribbean", "liquid", "rice", "nebraska", "loop", "salary", "reservation", "foods", "gourmet", "guard", "properly", "orleans", "saving", "nfl", "remaining", "empire", "resume", "twenty", "newly", "raise", "prepare", "avatar", "gary", "depending", "illegal", "expansion", "vary", "hundreds", "rome", "arab", "lincoln", "helped", "premier", "tomorrow", "purchased", "milk", "decide", "consent", "drama", "visiting", "performing", "downtown", "keyboard", "contest", "collected", "bands", "boot", "suitable", "absolutely", "millions", "lunch", "audit", "push", "chamber", "guinea", "findings", "muscle", "featuring", "iso", "implement", "clicking", "scheduled", "polls", "typical", "tower", "yours", "sum", "misc", "calculator", "significantly", "chicken", "temporary", "attend", "shower", "alan", "sending", "jason", "tonight", "dear", "sufficient", "holdem", "shell", "province", "catholic", "oak", "vat", "awareness", "vancouver", "governor", "beer", "seemed", "contribution", "measurement", "swimming", "spyware", "formula", "constitution", "packaging", "solar", "jose", "catch", "jane", "pakistan", "reliable", "consultation", "northwest", "sir", "doubt", "earn", "finder", "unable", "periods", "classroom", "tasks", "democracy", "attacks", "kim", "wallpaper", "merchandise", "const", "resistance", "doors", "symptoms", "resorts", "biggest", "memorial", "visitor", "twin", "forth", "insert", "baltimore", "gateway", "dont", "alumni", "drawing", "candidates", "charlotte", "ordered", "biological", "fighting", "transition", "happens", "preferences", "spy", "romance", "instrument", "bruce", "split", "themes", "powers", "heaven", "bits", "pregnant", "twice", "classification", "focused", "egypt", "physician", "hollywood", "bargain", "wikipedia", "cellular", "norway", "vermont", "asking", "blocks", "normally", "spiritual", "hunting", "diabetes", "suit", "shift", "chip", "res", "sit", "bodies", "photographs", "cutting", "wow", "simon", "writers", "marks", "flexible", "loved", "mapping", "numerous", "relatively", "birds", "satisfaction", "represents", "char", "indexed", "pittsburgh", "superior", "preferred", "saved", "paying", "cartoon", "shots", "intellectual", "moore", "granted", "choices", "carbon", "spending", "comfortable", "magnetic", "interaction", "listening", "effectively", "registry", "crisis", "outlook", "massive", "denmark", "employed", "bright", "treat", "header", "poverty", "formed", "piano", "echo", "que", "grid", "sheets", "patrick", "experimental", "puerto", "revolution", "consolidation", "displays", "plasma", "allowing", "earnings", "voip", "mystery", "landscape", "dependent", "mechanical", "journey", "delaware", "bidding", "consultants", "risks", "banner", "applicant", "charter", "fig", "barbara", "cooperation", "counties", "acquisition", "ports", "implemented", "directories", "recognized", "dreams", "blogger", "notification", "licensing", "stands", "teach", "occurred", "textbooks", "rapid", "pull", "hairy", "diversity", "cleveland", "reverse", "deposit", "seminar", "investments", "latina", "nasa", "wheels", "specify", "accessibility", "dutch", "sensitive", "templates", "formats", "tab", "depends", "boots", "holds", "router", "concrete", "editing", "poland", "folder", "womens", "css", "completion", "upload", "pulse", "universities", "technique", "contractors", "voting", "courts", "notices", "subscriptions", "calculate", "detroit", "alexander", "broadcast", "converted", "metro", "toshiba", "anniversary", "improvements", "strip", "specification", "pearl", "accident", "nick", "accessible", "accessory", "resident", "plot", "qty", "possibly", "airline", "typically", "representation", "regard", "pump", "exists", "arrangements", "smooth", "conferences", "uniprotkb", "strike", "consumption", "birmingham", "flashing", "narrow", "afternoon", "threat", "surveys", "sitting", "putting", "consultant", "controller", "ownership", "committees", "legislative", "researchers", "vietnam", "trailer", "anne", "castle", "gardens", "missed", "malaysia", "unsubscribe", "antique", "labels", "willing", "bio", "molecular", "acting", "heads", "stored", "exam", "logos", "residence", "attorneys", "antiques", "density", "hundred", "ryan", "operators", "strange", "sustainable", "philippines", "statistical", "beds", "mention", "innovation", "pcs", "employers", "grey", "parallel", "honda", "amended", "operate", "bills", "bold", "bathroom", "stable", "opera", "definitions", "von", "doctors", "lesson", "cinema", "asset", "scan", "elections", "drinking", "reaction", "blank", "enhanced", "entitled", "severe", "generate", "stainless", "newspapers", "hospitals", "deluxe", "humor", "aged", "monitors", "exception", "lived", "duration", "bulk", "successfully", "indonesia", "pursuant", "sci", "fabric", "edt", "visits", "primarily", "tight", "domains", "capabilities", "pmid", "contrast", "recommendation", "flying", "recruitment", "sin", "berlin", "cute", "organized", "para", "siemens", "adoption", "improving", "expensive", "meant", "capture", "pounds", "buffalo", "organisations", "plane", "explained", "seed", "programmes", "desire", "expertise", "mechanism", "camping", "jewellery", "meets", "welfare", "peer", "caught", "eventually", "marked", "driven", "measured", "medline", "bottle", "agreements", "considering", "innovative", "marshall", "massage", "rubber", "conclusion", "closing", "tampa", "thousand", "meat", "legend", "grace", "susan", "ing", "adams", "python", "monster", "alex", "bang", "villa", "bone", "columns", "disorders", "bugs", "collaboration", "hamilton", "detection", "ftp", "cookies", "inner", "formation", "tutorial", "med", "engineers", "entity", "cruises", "gate", "holder", "proposals", "moderator", "tutorials", "settlement", "portugal", "lawrence", "roman", "duties", "valuable", "tone", "collectables", "ethics", "forever", "dragon", "busy", "captain", "fantastic", "imagine", "brings", "heating", "leg", "neck", "wing", "governments", "purchasing", "scripts", "abc", "stereo", "appointed", "taste", "dealing", "commit", "tiny", "operational", "rail", "airlines", "liberal", "livecam", "jay", "trips", "gap", "sides", "tube", "turns", "corresponding", "descriptions", "cache", "belt", "jacket", "determination", "animation", "oracle", "matthew", "lease", "productions", "aviation", "hobbies", "proud", "excess", "disaster", "console", "commands", "telecommunications", "instructor", "giant", "achieved", "injuries", "shipped", "seats", "approaches", "biz", "alarm", "voltage", "anthony", "nintendo", "usual", "loading", "stamps", "appeared", "franklin", "angle", "rob", "vinyl", "highlights", "mining", "designers", "melbourne", "ongoing", "worst", "imaging", "betting", "scientists", "liberty", "wyoming", "blackjack", "argentina", "era", "convert", "possibility", "analyst", "commissioner", "dangerous", "garage", "exciting", "reliability", "thongs", "gcc", "unfortunately", "respectively", "volunteers", "attachment", "ringtone", "finland", "morgan", "derived", "pleasure", "honor", "asp", "oriented", "eagle", "desktops", "pants", "columbus", "nurse", "prayer", "appointment", "workshops", "hurricane", "quiet", "luck", "postage", "producer", "represented", "mortgages", "dial", "responsibilities", "cheese", "comic", "carefully", "jet", "productivity", "investors", "crown", "par", "underground", "diagnosis", "maker", "crack", "principle", "picks", "vacations", "gang", "semester", "calculated", "fetish", "applies", "casinos", "appearance", "smoke", "apache", "filters", "incorporated", "craft", "cake", "notebooks", "apart", "fellow", "blind", "lounge", "mad", "algorithm", "semi", "coins", "andy", "gross", "strongly", "cafe", "valentine", "hilton", "ken", "proteins", "horror", "exp", "familiar", "capable", "douglas", "debian", "till", "involving", "pen", "investing", "christopher", "admission", "epson", "shoe", "elected", "carrying", "victory", "sand", "madison", "terrorism", "joy", "editions", "cpu", "mainly", "ethnic", "ran", "parliament", "actor", "finds", "seal", "situations", "fifth", "allocated", "citizen", "vertical", "corrections", "structural", "municipal", "describes", "prize", "occurs", "jon", "absolute", "disabilities", "consists", "anytime", "substance", "prohibited", "addressed", "lies", "pipe", "soldiers", "guardian", "lecture", "simulation", "layout", "initiatives", "ill", "concentration", "classics", "lbs", "lay", "interpretation", "horses", "lol", "dirty", "deck", "wayne", "donate", "taught", "bankruptcy", "worker", "optimization", "alive", "temple", "substances", "prove", "discovered", "wings", "breaks", "genetic", "restrictions", "participating", "waters", "promise", "thin", "exhibition", "prefer", "ridge", "cabinet", "modem", "harris", "mph", "bringing", "sick", "dose", "evaluate", "tiffany", "tropical", "collect", "bet", "composition", "toyota", "streets", "nationwide", "vector", "definitely", "shaved", "turning", "buffer", "purple", "existence", "commentary", "larry", "limousines", "developments", "def", "immigration", "destinations", "lets", "mutual", "pipeline", "necessarily", "syntax", "attribute", "prison", "skill", "chairs", "everyday", "apparently", "surrounding", "mountains", "moves", "popularity", "inquiry", "ethernet", "checked", "exhibit", "throw", "trend", "sierra", "visible", "cats", "desert", "postposted", "oldest", "rhode", "nba", "coordinator", "obviously", "mercury", "steven", "handbook", "greg", "navigate", "worse", "summit", "victims", "epa", "spaces", "fundamental", "burning", "escape", "coupons", "somewhat", "receiver", "substantial", "progressive", "cialis", "boats", "glance", "scottish", "championship", "arcade", "richmond", "sacramento", "impossible", "ron", "russell", "tells", "obvious", "fiber", "depression", "graph", "covering", "platinum", "judgment", "bedrooms", "talks", "filing", "foster", "modeling", "passing", "awarded", "testimonials", "trials", "tissue", "memorabilia", "clinton", "masters", "bonds", "cartridge", "alberta", "explanation", "folk", "org", "commons", "cincinnati", "subsection", "fraud", "electricity", "permitted", "spectrum", "arrival", "okay", "pottery", "emphasis", "roger", "aspect", "workplace", "awesome", "mexican", "confirmed", "counts", "priced", "wallpapers", "hist", "crash", "lift", "desired", "inter", "closer", "assumes", "heights", "shadow", "riding", "infection", "firefox", "lisa", "expense", "grove", "eligibility", "venture", "clinic", "korean", "healing", "princess", "mall", "entering", "packet", "spray", "studios", "involvement", "dad", "buttons", "placement", "observations", "vbulletin", "funded", "thompson", "winners", "extend", "roads", "subsequent", "pat", "dublin", "rolling", "fell", "motorcycle", "yard", "disclosure", "establishment", "memories", "nelson", "arrived", "creates", "faces", "tourist", "mayor", "murder", "sean", "adequate", "senator", "yield", "presentations", "grades", "cartoons", "pour", "digest", "reg", "lodging", "tion", "dust", "hence", "wiki", "entirely", "replaced", "radar", "rescue", "undergraduate", "losses", "combat", "reducing", "stopped", "occupation", "lakes", "donations", "associations", "citysearch", "closely", "radiation", "diary", "seriously", "kings", "shooting", "kent", "adds", "nsw", "ear", "flags", "pci", "baker", "launched", "elsewhere", "pollution", "conservative", "guestbook", "shock", "effectiveness", "walls", "abroad", "ebony", "tie", "ward", "drawn", "arthur", "ian", "visited", "roof", "walker", "demonstrate", "atmosphere", "suggests", "kiss", "beast", "operated", "experiment", "targets", "overseas", "purchases", "dodge", "counsel", "federation", "pizza", "invited", "yards", "assignment", "chemicals", "gordon", "mod", "farmers", "queries", "bmw", "rush", "ukraine", "absence", "nearest", "cluster", "vendors", "mpeg", "whereas", "yoga", "serves", "woods", "surprise", "lamp", "rico", "partial", "shoppers", "phil", "everybody", "couples", "nashville", "ranking", "jokes", "cst", "http", "ceo", "simpson", "twiki", "sublime", "counseling", "palace", "acceptable", "satisfied", "glad", "wins", "measurements", "verify", "globe", "trusted", "copper", "milwaukee", "rack", "medication", "warehouse", "shareware", "rep", "dicke", "kerry", "receipt", "supposed", "ordinary", "nobody", "ghost", "violation", "configure", "stability", "mit", "applying", "southwest", "boss", "pride", "institutional", "expectations", "independence", "knowing", "reporter", "metabolism", "keith", "champion", "cloudy", "linda", "ross", "personally", "chile", "anna", "plenty", "solo", "sentence", "throat", "ignore", "maria", "uniform", "excellence", "wealth", "tall", "somewhere", "vacuum", "dancing", "attributes", "recognize", "brass", "writes", "plaza", "pdas", "outcomes", "survival", "quest", "publish", "sri", "screening", "toe", "thumbnail", "trans", "jonathan", "whenever", "nova", "lifetime", "api", "pioneer", "booty", "forgotten", "acrobat", "plates", "acres", "venue", "athletic", "thermal", "essays", "vital", "telling", "fairly", "coastal", "config", "charity", "intelligent", "edinburgh", "excel", "modes", "obligation", "campbell", "wake", "stupid", "harbor", "hungary", "traveler", "urw", "segment", "realize", "regardless", "lan", "enemy", "puzzle", "rising", "aluminum", "wells", "wishlist", "opens", "insight", "sms", "restricted", "republican", "secrets", "lucky", "latter", "merchants", "thick", "trailers", "repeat", "syndrome", "philips", "attendance", "penalty", "drum", "glasses", "enables", "nec", "iraqi", "builder", "vista", "jessica", "chips", "terry", "flood", "foto", "ease", "arguments", "amsterdam", "arena", "adventures", "pupils", "stewart", "announcement", "tabs", "outcome", "appreciate", "expanded", "casual", "grown", "polish", "lovely", "extras", "centres", "jerry", "clause", "smile", "lands", "troops", "indoor", "bulgaria", "armed", "broker", "charger", "regularly", "believed", "pine", "cooling", "tend", "gulf", "rick", "trucks", "mechanisms", "divorce", "laura", "shopper", "tokyo", "partly", "nikon", "customize", "tradition", "candy", "pills", "tiger", "donald", "folks", "sensor", "exposed", "telecom", "hunt", "angels", "deputy", "indicators", "sealed", "thai", "emissions", "physicians", "loaded", "fred", "complaint", "scenes", "experiments", "afghanistan", "boost", "spanking", "scholarship", "governance", "mill", "founded", "supplements", "chronic", "icons", "moral", "den", "catering", "aud", "finger", "keeps", "pound", "locate", "camcorder", "trained", "burn", "implementing", "roses", "labs", "ourselves", "bread", "tobacco", "wooden", "motors", "tough", "roberts", "incident", "gonna", "dynamics", "lie", "crm", "conversation", "decrease", "chest", "pension", "billy", "revenues", "emerging", "worship", "capability", "craig", "herself", "producing", "churches", "precision", "damages", "reserves", "contributed", "solve", "shorts", "reproduction", "minority", "diverse", "amp", "ingredients", "johnny", "sole", "franchise", "recorder", "complaints", "facing", "nancy", "promotions", "tones", "passion", "rehabilitation", "maintaining", "sight", "laid", "clay", "defence", "patches", "weak", "refund", "usc", "towns", "environments", "trembl", "divided", "blvd", "reception", "amd", "wise", "emails", "cyprus", "odds", "correctly", "insider", "seminars", "consequences", "makers", "hearts", "geography", "appearing", "integrity", "worry", "discrimination", "eve", "carter", "legacy", "marc", "pleased", "danger", "vitamin", "widely", "processed", "phrase", "genuine", "raising", "implications", "functionality", "paradise", "hybrid", "reads", "roles", "intermediate", "emotional", "sons", "leaf", "pad", "glory", "platforms", "bigger", "billing", "diesel", "versus", "combine", "overnight", "geographic", "exceed", "rod", "saudi", "fault", "cuba", "hrs", "preliminary", "districts", "introduce", "silk", "promotional", "kate", "chevrolet", "babies", "karen", "compiled", "romantic", "revealed", "specialists", "generator", "albert", "examine", "jimmy", "graham", "suspension", "bristol", "margaret", "compaq", "sad", "correction", "wolf", "slowly", "authentication", "communicate", "rugby", "supplement", "showtimes", "cal", "portions", "infant", "promoting", "sectors", "samuel", "fluid", "grounds", "fits", "kick", "regards", "meal", "hurt", "machinery", "bandwidth", "unlike", "equation", "baskets", "probability", "pot", "dimension", "wright", "img", "barry", "proven", "schedules", "admissions", "cached", "warren", "slip", "studied", "reviewer", "involves", "quarterly", "rpm", "profits", "devil", "grass", "comply", "marie", "florist", "illustrated", "cherry", "continental", "alternate", "deutsch", "achievement", "limitations", "kenya", "webcam", "cuts", "funeral", "nutten", "earrings", "enjoyed", "automated", "chapters", "pee", "charlie", "quebec", "passenger", "convenient", "dennis", "mars", "francis", "tvs", "sized", "manga", "noticed", "socket", "silent", "literary", "egg", "mhz", "signals", "caps", "orientation", "pill", "theft", "childhood", "swing", "symbols", "lat", "meta", "humans", "analog", "facial", "choosing", "talent", "dated", "flexibility", "seeker", "wisdom", "shoot", "boundary", "mint", "packard", "offset", "payday", "philip", "elite", "spin", "holders", "believes", "swedish", "poems", "deadline", "jurisdiction", "robot", "displaying", "witness", "collins", "equipped", "stages", "encouraged", "sur", "winds", "powder", "broadway", "acquired", "assess", "wash", "cartridges", "stones", "entrance", "gnome", "roots", "declaration", "losing", "attempts", "gadgets", "noble", "glasgow", "automation", "impacts", "rev", "gospel", "advantages", "shore", "loves", "induced", "knight", "preparing", "loose", "aims", "recipient", "linking", "extensions", "appeals", "earned", "illness", "islamic", "athletics", "southeast", "ieee", "alternatives", "pending", "parker", "determining", "lebanon", "corp", "personalized", "kennedy", "conditioning", "teenage", "soap", "triple", "cooper", "nyc", "vincent", "jam", "secured", "unusual", "answered", "partnerships", "destruction", "slots", "increasingly", "migration", "disorder", "routine", "toolbar", "basically", "rocks", "conventional", "titans", "applicants", "wearing", "axis", "sought", "genes", "mounted", "habitat", "firewall", "median", "guns", "scanner", "herein", "occupational", "animated", "judicial", "rio", "adjustment", "hero", "integer", "treatments", "bachelor", "attitude", "camcorders", "engaged", "falling", "basics", "montreal", "carpet", "struct", "lenses", "binary", "genetics", "attended", "difficulty", "punk", "collective", "coalition", "dropped", "enrollment", "duke", "walter", "pace", "besides", "wage", "producers", "collector", "arc", "hosts", "interfaces", "advertisers", "moments", "atlas", "strings", "dawn", "representing", "observation", "feels", "torture", "carl", "deleted", "coat", "mitchell", "mrs", "rica", "restoration", "convenience", "returning", "ralph", "opposition", "container", "defendant", "warner", "confirmation", "app", "embedded", "inkjet", "supervisor", "wizard", "corps", "actors", "liver", "peripherals", "liable", "brochure", "morris", "bestsellers", "petition", "eminem", "recall", "antenna", "picked", "assumed", "departure", "minneapolis", "belief", "killing", "bikini", "memphis", "shoulder", "decor", "lookup", "texts", "harvard", "brokers", "roy", "ion", "diameter", "ottawa", "doll", "podcast", "seasons", "peru", "interactions", "refine", "bidder", "singer", "evans", "herald", "literacy", "fails", "aging", "nike", "intervention", "fed", "plugin", "attraction", "diving", "invite", "modification", "alice", "latinas", "suppose", "customized", "reed", "involve", "moderate", "terror", "younger", "thirty", "mice", "opposite", "understood", "rapidly", "dealtime", "ban", "temp", "intro", "mercedes", "zus", "assurance", "clerk", "happening", "vast", "mills", "outline", "amendments", "tramadol", "holland", "receives", "jeans", "metropolitan", "compilation", "verification", "fonts", "ent", "odd", "wrap", "refers", "mood", "favor", "veterans", "quiz", "sigma", "attractive", "xhtml", "occasion", "recordings", "jefferson", "victim", "demands", "sleeping", "careful", "ext", "beam", "gardening", "obligations", "arrive", "orchestra", "sunset", "tracked", "moreover", "minimal", "polyphonic", "lottery", "tops", "framed", "aside", "outsourcing", "licence", "adjustable", "allocation", "michelle", "essay", "discipline", "amy", "demonstrated", "dialogue", "identifying", "alphabetical", "camps", "declared", "dispatched", "aaron", "handheld", "trace", "disposal", "shut", "florists", "packs", "installing", "switches", "romania", "voluntary", "ncaa", "thou", "consult", "phd", "greatly", "blogging", "mask", "cycling", "midnight", "commonly", "photographer", "inform", "turkish", "coal", "cry", "messaging", "pentium", "quantum", "murray", "intent", "zoo", "largely", "pleasant", "announce", "constructed", "additions", "requiring", "spoke", "aka", "arrow", "engagement", "sampling", "rough", "weird", "tee", "refinance", "lion", "inspired", "holes", "weddings", "blade", "suddenly", "oxygen", "cookie", "meals", "canyon", "goto", "meters", "merely", "calendars", "arrangement", "conclusions", "passes", "bibliography", "pointer", "compatibility", "stretch", "durham", "furthermore", "permits", "cooperative", "muslim", "neil", "sleeve", "netscape", "cleaner", "cricket", "beef", "feeding", "stroke", "township", "rankings", "measuring", "cad", "hats", "robin", "robinson", "jacksonville", "strap", "headquarters", "sharon", "crowd", "tcp", "transfers", "surf", "olympic", "transformation", "remained", "attachments", "dir", "entities", "customs", "administrators", "personality", "rainbow", "hook", "roulette", "decline", "gloves", "israeli", "medicare", "cord", "skiing", "cloud", "facilitate", "subscriber", "valve", "val", "hewlett", "explains", "proceed", "flickr", "feelings", "knife", "jamaica", "priorities", "shelf", "bookstore", "timing", "liked", "parenting", "adopt", "denied", "fotos", "incredible", "britney", "freeware", "donation", "outer", "crop", "deaths", "rivers", "commonwealth", "pharmaceutical", "manhattan", "tales", "katrina", "workforce", "islam", "nodes", "thumbs", "seeds", "cited", "lite", "ghz", "hub", "targeted", "organizational", "skype", "realized", "twelve", "founder", "decade", "gamecube", "dispute", "portuguese", "tired", "titten", "adverse", "everywhere", "excerpt", "eng", "steam", "discharge", "drinks", "ace", "voices", "acute", "halloween", "climbing", "stood", "sing", "tons", "perfume", "carol", "honest", "albany", "hazardous", "restore", "stack", "methodology", "somebody", "sue", "housewares", "reputation", "resistant", "democrats", "recycling", "hang", "gbp", "curve", "creator", "amber", "qualifications", "museums", "coding", "slideshow", "tracker", "variation", "passage", "transferred", "trunk", "hiking", "pierre", "jelsoft", "headset", "photograph", "oakland", "colombia", "waves", "camel", "distributor", "lamps", "underlying", "hood", "wrestling", "suicide", "archived", "photoshop", "chi", "arabia", "gathering", "projection", "juice", "chase", "mathematical", "logical", "sauce", "fame", "extract", "specialized", "diagnostic", "panama", "indianapolis", "payable", "corporations", "courtesy", "criticism", "automobile", "confidential", "rfc", "statutory", "accommodations", "athens", "northeast", "downloaded", "judges", "seo", "retired", "isp", "remarks", "detected", "decades", "paintings", "walked", "arising", "nissan", "bracelet", "ins", "eggs", "juvenile", "injection", "yorkshire", "populations", "protective", "afraid", "acoustic", "railway", "cassette", "initially", "indicator", "pointed", "jpg", "causing", "mistake", "norton", "locked", "eliminate", "fusion", "mineral", "sunglasses", "ruby", "steering", "beads", "fortune", "preference", "canvas", "threshold", "parish", "claimed", "screens", "cemetery", "planner", "croatia", "flows", "stadium", "venezuela", "exploration", "mins", "fewer", "sequences", "coupon", "nurses", "ssl", "stem", "proxy", "astronomy", "lanka", "opt", "edwards", "drew", "contests", "flu", "translate", "announces", "mlb", "costume", "tagged", "berkeley", "voted", "killer", "bikes", "gates", "adjusted", "rap", "tune", "bishop", "pulled", "corn", "shaped", "compression", "seasonal", "establishing", "farmer", "counters", "puts", "constitutional", "grew", "perfectly", "tin", "slave", "instantly", "cultures", "norfolk", "coaching", "examined", "trek", "encoding", "litigation", "submissions", "oem", "heroes", "painted", "lycos", "zdnet", "broadcasting", "horizontal", "artwork", "cosmetic", "resulted", "portrait", "terrorist", "informational", "ethical", "carriers", "ecommerce", "mobility", "floral", "builders", "ties", "struggle", "schemes", "suffering", "neutral", "fisher", "rat", "spears", "prospective", "bedding", "ultimately", "joining", "heading", "equally", "artificial", "bearing", "spectacular", "coordination", "connector", "brad", "combo", "seniors", "worlds", "guilty", "affiliated", "activation", "naturally", "haven", "tablet", "jury", "dos", "tail", "subscribers", "charm", "lawn", "violent", "mitsubishi", "underwear", "basin", "soup", "potentially", "ranch", "constraints", "crossing", "inclusive", "dimensional", "cottage", "drunk", "considerable", "crimes", "resolved", "mozilla", "byte", "toner", "nose", "latex", "branches", "anymore", "oclc", "delhi", "holdings", "alien", "locator", "selecting", "processors", "pantyhose", "plc", "broke", "nepal", "zimbabwe", "difficulties", "juan", "complexity", "msg", "constantly", "browsing", "resolve", "barcelona", "presidential", "documentary", "cod", "territories", "melissa", "moscow", "thesis", "thru", "jews", "nylon", "palestinian", "discs", "rocky", "bargains", "frequent", "trim", "nigeria", "ceiling", "pixels", "ensuring", "hispanic", "legislature", "hospitality", "gen", "anybody", "procurement", "diamonds", "espn", "fleet", "untitled", "bunch", "totals", "marriott", "singing", "theoretical", "afford", "exercises", "starring", "referral", "nhl", "surveillance", "optimal", "quit", "distinct", "protocols", "lung", "highlight", "substitute", "inclusion", "hopefully", "brilliant", "turner", "sucking", "cents", "reuters", "gel", "todd", "spoken", "omega", "evaluated", "stayed", "civic", "assignments", "manuals", "doug", "sees", "termination", "watched", "saver", "thereof", "grill", "households", "redeem", "rogers", "grain", "aaa", "authentic", "regime", "wanna", "wishes", "bull", "montgomery", "architectural", "louisville", "depend", "differ", "macintosh", "movements", "ranging", "monica", "repairs", "breath", "amenities", "virtually", "cole", "mart", "candle", "hanging", "colored", "authorization", "tale", "verified", "lynn", "formerly", "projector", "situated", "comparative", "std", "seeks", "herbal", "loving", "strictly", "routing", "docs", "stanley", "psychological", "surprised", "retailer", "vitamins", "elegant", "gains", "renewal", "vid", "genealogy", "opposed", "deemed", "scoring", "expenditure", "brooklyn", "liverpool", "sisters", "critics", "connectivity", "spots", "algorithms", "hacker", "madrid", "similarly", "margin", "coin", "solely", "fake", "salon", "collaborative", "norman", "fda", "excluding", "turbo", "headed", "voters", "cure", "madonna", "commander", "arch", "murphy", "thinks", "thats", "suggestion", "hdtv", "soldier", "phillips", "asin", "aimed", "justin", "bomb", "harm", "interval", "mirrors", "spotlight", "tricks", "reset", "brush", "investigate", "thy", "expansys", "panels", "repeated", "assault", "connecting", "spare", "logistics", "deer", "kodak", "tongue", "bowling", "tri", "danish", "pal", "monkey", "proportion", "filename", "skirt", "florence", "invest", "honey", "analyzes", "drawings", "significance", "scenario", "lovers", "atomic", "approx", "symposium", "arabic", "gauge", "essentials", "junction", "protecting", "faced", "mat", "rachel", "solving", "transmitted", "weekends", "screenshots", "produces", "oven", "ted", "intensive", "chains", "kingston", "sixth", "engage", "deviant", "noon", "switching", "quoted", "adapters", "correspondence", "farms", "imports", "supervision", "cheat", "bronze", "expenditures", "sandy", "separation", "testimony", "suspect", "celebrities", "macro", "sender", "mandatory", "boundaries", "crucial", "syndication", "gym", "celebration", "kde", "adjacent", "filtering", "tuition", "spouse", "exotic", "viewer", "signup", "threats", "luxembourg", "puzzles", "reaching", "damaged", "cams", "receptor", "laugh", "joel", "surgical", "destroy", "citation", "pitch", "autos", "premises", "perry", "proved", "offensive", "imperial", "dozen", "benjamin", "deployment", "teeth", "cloth", "studying", "colleagues", "stamp", "lotus", "salmon", "olympus", "separated", "proc", "cargo", "tan", "directive", "salem", "mate", "starter", "upgrades", "likes", "butter", "pepper", "weapon", "luggage", "burden", "chef", "tapes", "zones", "races", "isle", "stylish", "slim", "maple", "luke", "grocery", "offshore", "governing", "retailers", "depot", "kenneth", "comp", "alt", "pie", "blend", "harrison", "julie", "occasionally", "cbs", "attending", "emission", "pete", "spec", "finest", "realty", "janet", "bow", "penn", "recruiting", "apparent", "instructional", "phpbb", "autumn", "traveling", "probe", "midi", "permissions", "biotechnology", "toilet", "ranked", "jackets", "routes", "packed", "excited", "outreach", "helen", "mounting", "recover", "tied", "lopez", "balanced", "prescribed", "catherine", "timely", "talked", "debug", "delayed", "chuck", "reproduced", "hon", "dale", "explicit", "calculation", "villas", "ebook", "consolidated", "exclude", "peeing", "occasions", "brooks", "equations", "newton", "oils", "sept", "exceptional", "anxiety", "bingo", "whilst", "spatial", "respondents", "unto", "ceramic", "prompt", "precious", "minds", "annually", "considerations", "scanners", "atm", "xanax", "pays", "fingers", "sunny", "ebooks", "delivers", "queensland", "necklace", "musicians", "leeds", "composite", "unavailable", "cedar", "arranged", "lang", "theaters", "advocacy", "raleigh", "stud", "fold", "essentially", "designing", "threaded", "qualify", "blair", "hopes", "assessments", "cms", "mason", "diagram", "burns", "pumps", "footwear", "vic", "beijing", "peoples", "victor", "mario", "pos", "attach", "licenses", "utils", "removing", "advised", "brunswick", "spider", "phys", "ranges", "pairs", "sensitivity", "trails", "preservation", "hudson", "isolated", "calgary", "interim", "assisted", "divine", "streaming", "approve", "chose", "compound", "intensity", "technological", "syndicate", "abortion", "dialog", "venues", "blast", "wellness", "calcium", "newport", "antivirus", "addressing", "pole", "discounted", "indians", "shield", "harvest", "membrane", "prague", "previews", "bangladesh", "constitute", "locally", "concluded", "pickup", "desperate", "mothers", "nascar", "iceland", "demonstration", "governmental", "manufactured", "candles", "graduation", "mega", "bend", "sailing", "variations", "moms", "sacred", "addiction", "morocco", "chrome", "tommy", "springfield", "refused", "brake", "exterior", "greeting", "ecology", "oliver", "congo", "glen", "botswana", "nav", "delays", "synthesis", "olive", "undefined", "unemployment", "cyber", "verizon", "scored", "enhancement", "newcastle", "clone", "velocity", "lambda", "relay", "composed", "tears", "performances", "oasis", "baseline", "cab", "angry", "societies", "silicon", "brazilian", "identical", "petroleum", "compete", "ist", "norwegian", "lover", "belong", "honolulu", "beatles", "lips", "retention", "exchanges", "pond", "rolls", "thomson", "barnes", "soundtrack", "wondering", "malta", "daddy", "ferry", "rabbit", "profession", "seating", "dam", "cnn", "separately", "physiology", "lil", "collecting", "das", "exports", "omaha", "tire", "participant", "scholarships", "recreational", "dominican", "chad", "electron", "loads", "friendship", "heather", "passport", "motel", "unions", "treasury", "warrant", "sys", "solaris", "frozen", "occupied", "josh", "royalty", "scales", "rally", "observer", "sunshine", "strain", "drag", "ceremony", "somehow", "arrested", "expanding", "provincial", "investigations", "icq", "ripe", "yamaha", "rely", "medications", "hebrew", "gained", "rochester", "dying", "laundry", "stuck", "solomon", "placing", "stops", "homework", "adjust", "assessed", "advertiser", "enabling", "encryption", "filling", "downloadable", "sophisticated", "imposed", "silence", "scsi", "focuses", "soviet", "possession", "laboratories", "treaty", "vocal", "trainer", "organ", "stronger", "volumes", "advances", "vegetables", "lemon", "toxic", "dns", "thumbnails", "darkness", "pty", "nuts", "nail", "bizrate", "vienna", "implied", "span", "stanford", "sox", "stockings", "joke", "respondent", "packing", "statute", "rejected", "satisfy", "destroyed", "shelter", "chapel", "gamespot", "manufacture", "layers", "wordpress", "guided", "vulnerability", "accountability", "celebrate", "accredited", "appliance", "compressed", "bahamas", "powell", "mixture", "bench", "univ", "tub", "rider", "scheduling", "radius", "perspectives", "mortality", "logging", "hampton", "christians", "borders", "therapeutic", "pads", "butts", "inns", "bobby", "impressive", "sheep", "accordingly", "architect", "railroad", "lectures", "challenging", "wines", "nursery", "harder", "cups", "ash", "microwave", "cheapest", "accidents", "travesti", "relocation", "stuart", "contributors", "salvador", "ali", "salad", "monroe", "tender", "violations", "foam", "temperatures", "paste", "clouds", "competitions", "discretion", "tft", "tanzania", "preserve", "jvc", "poem", "unsigned", "staying", "cosmetics", "easter", "theories", "repository", "praise", "jeremy", "venice", "concentrations", "estonia", "christianity", "veteran", "streams", "landing", "signing", "executed", "katie", "negotiations", "realistic", "cgi", "showcase", "integral", "asks", "relax", "namibia", "generating", "christina", "congressional", "synopsis", "hardly", "prairie", "reunion", "composer", "bean", "sword", "absent", "photographic", "sells", "ecuador", "hoping", "accessed", "spirits", "modifications", "coral", "pixel", "float", "colin", "bias", "imported", "paths", "bubble", "por", "acquire", "contrary", "millennium", "tribune", "vessel", "acids", "focusing", "viruses", "cheaper", "admitted", "dairy", "admit", "mem", "fancy", "equality", "samoa", "achieving", "tap", "stickers", "fisheries", "exceptions", "reactions", "leasing", "lauren", "beliefs", "macromedia", "companion", "squad", "analyze", "ashley", "scroll", "relate", "divisions", "swim", "wages", "additionally", "suffer", "forests", "fellowship", "nano", "invalid", "concerts", "martial", "males", "victorian", "retain", "execute", "tunnel", "genres", "cambodia", "patents", "copyrights", "chaos", "lithuania", "mastercard", "wheat", "chronicles", "obtaining", "beaver", "updating", "distribute", "readings", "decorative", "kijiji", "confused", "compiler", "enlargement", "eagles", "bases", "vii", "accused", "bee", "campaigns", "unity", "loud", "conjunction", "bride", "rats", "defines", "airports", "instances", "indigenous", "begun", "cfr", "brunette", "packets", "anchor", "socks", "validation", "parade", "corruption", "stat", "trigger", "incentives", "cholesterol", "gathered", "essex", "slovenia", "notified", "differential", "beaches", "folders", "dramatic", "surfaces", "terrible", "routers", "cruz", "pendant", "dresses", "baptist", "scientist", "starsmerchant", "hiring", "clocks", "arthritis", "bios", "females", "wallace", "nevertheless", "reflects", "taxation", "fever", "pmc", "cuisine", "surely", "practitioners", "transcript", "myspace", "theorem", "inflation", "thee", "ruth", "pray", "stylus", "compounds", "pope", "drums", "contracting", "arnold", "structured", "reasonably", "jeep", "chicks", "bare", "hung", "cattle", "mba", "radical", "graduates", "rover", "recommends", "controlling", "treasure", "reload", "distributors", "flame", "levitra", "tanks", "assuming", "monetary", "elderly", "pit", "arlington", "mono", "particles", "floating", "extraordinary", "tile", "indicating", "bolivia", "spell", "hottest", "stevens", "coordinate", "kuwait", "exclusively", "emily", "alleged", "limitation", "widescreen", "compile", "webster", "struck", "illustration", "plymouth", "warnings", "construct", "apps", "inquiries", "bridal", "annex", "mag", "gsm", "inspiration", "tribal", "curious", "affecting", "freight", "rebate", "meetup", "eclipse", "sudan", "ddr", "downloading", "rec", "shuttle", "aggregate", "stunning", "cycles", "affects", "forecasts", "detect", "actively", "ciao", "ampland", "knee", "prep", "complicated", "chem", "fastest", "butler", "shopzilla", "injured", "decorating", "payroll", "cookbook", "expressions", "ton", "courier", "uploaded", "shakespeare", "hints", "collapse", "americas", "connectors", "unlikely", "gif", "pros", "conflicts", "techno", "beverage", "tribute", "wired", "elvis", "immune", "latvia", "travelers", "forestry", "barriers", "cant", "rarely", "gpl", "infected", "offerings", "martha", "genesis", "barrier", "argue", "incorrect", "trains", "metals", "bicycle", "furnishings", "letting", "arise", "guatemala", "celtic", "thereby", "irc", "jamie", "particle", "perception", "minerals", "advise", "humidity", "bottles", "boxing", "bangkok", "renaissance", "pathology", "sara", "bra", "ordinance", "hughes", "photographers", "infections", "jeffrey", "chess", "operates", "brisbane", "configured", "survive", "oscar", "festivals", "menus", "joan", "possibilities", "duck", "reveal", "canal", "amino", "phi", "contributing", "herbs", "clinics", "mls", "cow", "manitoba", "analytical", "missions", "watson", "lying", "costumes", "strict", "dive", "saddam", "circulation", "drill", "offense", "bryan", "cet", "protest", "assumption", "jerusalem", "hobby", "tries", "transexuales", "invention", "nickname", "fiji", "technician", "inline", "executives", "enquiries", "washing", "audi", "staffing", "cognitive", "exploring", "trick", "enquiry", "closure", "raid", "ppc", "timber", "volt", "intense", "div", "playlist", "registrar", "showers", "supporters", "ruling", "steady", "dirt", "statutes", "withdrawal", "myers", "drops", "predicted", "wider", "saskatchewan", "cancellation", "plugins", "enrolled", "sensors", "screw", "ministers", "publicly", "hourly", "blame", "geneva", "freebsd", "veterinary", "acer", "prostores", "reseller", "dist", "handed", "suffered", "intake", "informal", "relevance", "incentive", "butterfly", "tucson", "mechanics", "heavily", "swingers", "fifty", "headers", "mistakes", "numerical", "ons", "geek", "uncle", "defining", "counting", "reflection", "sink", "accompanied", "assure", "invitation", "devoted", "princeton", "jacob", "sodium", "randy", "spirituality", "hormone", "meanwhile", "proprietary", "timothy", "childrens", "brick", "grip", "naval", "thumbzilla", "medieval", "porcelain", "avi", "bridges", "pichunter", "captured", "watt", "thehun", "decent", "casting", "dayton", "translated", "shortly", "cameron", "columnists", "pins", "carlos", "reno", "donna", "andreas", "warrior", "diploma", "cabin", "innocent", "scanning", "ide", "consensus", "polo", "valium", "copying", "rpg", "delivering", "cordless", "patricia", "horn", "eddie", "uganda", "fired", "journalism", "prot", "trivia", "adidas", "perth", "frog", "grammar", "intention", "syria", "disagree", "klein", "harvey", "tires", "logs", "undertaken", "tgp", "hazard", "retro", "leo", "statewide", "semiconductor", "gregory", "episodes", "boolean", "circular", "anger", "diy", "mainland", "illustrations", "suits", "chances", "interact", "snap", "happiness", "arg", "substantially", "bizarre", "glenn", "auckland", "olympics", "fruits", "identifier", "geo", "ribbon", "calculations", "doe", "jpeg", "conducting", "startup", "suzuki", "trinidad", "ati", "kissing", "wal", "handy", "swap", "exempt", "crops", "reduces", "accomplished", "calculators", "geometry", "impression", "abs", "slovakia", "flip", "guild", "correlation", "gorgeous", "capitol", "sim", "dishes", "rna", "barbados", "chrysler", "nervous", "refuse", "extends", "fragrance", "mcdonald", "replica", "plumbing", "brussels", "tribe", "neighbors", "trades", "superb", "buzz", "transparent", "nuke", "rid", "trinity", "charleston", "handled", "legends", "boom", "calm", "champions", "floors", "selections", "projectors", "inappropriate", "exhaust", "comparing", "shanghai", "speaks", "burton", "vocational", "davidson", "copied", "scotia", "farming", "gibson", "pharmacies", "fork", "troy", "roller", "introducing", "batch", "organize", "appreciated", "alter", "nicole", "latino", "ghana", "edges", "mixing", "handles", "skilled", "fitted", "albuquerque", "harmony", "distinguished", "asthma", "projected", "assumptions", "shareholders", "twins", "developmental", "rip", "zope", "regulated", "triangle", "amend", "anticipated", "oriental", "reward", "windsor", "zambia", "completing", "gmbh", "buf", "hydrogen", "webshots", "sprint", "comparable", "chick", "advocate", "sims", "confusion", "copyrighted", "tray", "inputs", "warranties", "genome", "escorts", "documented", "thong", "medal", "paperbacks", "coaches", "vessels", "walks", "sol", "keyboards", "sage", "knives", "eco", "vulnerable", "arrange", "artistic", "bat", "honors", "booth", "indie", "reflected", "unified", "bones", "breed", "detector", "ignored", "polar", "fallen", "precise", "sussex", "respiratory", "notifications", "msgid", "transexual", "mainstream", "invoice", "evaluating", "lip", "subcommittee", "sap", "gather", "suse", "maternity", "backed", "alfred", "colonial", "carey", "motels", "forming", "embassy", "cave", "journalists", "danny", "rebecca", "slight", "proceeds", "indirect", "amongst", "wool", "foundations", "msgstr", "arrest", "volleyball", "adipex", "horizon", "deeply", "toolbox", "ict", "marina", "liabilities", "prizes", "bosnia", "browsers", "decreased", "patio", "tolerance", "surfing", "creativity", "lloyd", "describing", "optics", "pursue", "lightning", "overcome", "eyed", "quotations", "grab", "inspector", "attract", "brighton", "beans", "bookmarks", "ellis", "disable", "snake", "succeed", "leonard", "lending", "oops", "reminder", "searched", "behavioral", "riverside", "bathrooms", "plains", "sku", "raymond", "insights", "abilities", "initiated", "sullivan", "midwest", "karaoke", "trap", "lonely", "fool", "nonprofit", "lancaster", "suspended", "hereby", "observe", "julia", "containers", "attitudes", "karl", "berry", "collar", "simultaneously", "racial", "integrate", "bermuda", "amanda", "sociology", "mobiles", "screenshot", "exhibitions", "kelkoo", "confident", "retrieved", "exhibits", "officially", "consortium", "dies", "terrace", "bacteria", "pts", "replied", "seafood", "novels", "rrp", "recipients", "ought", "delicious", "traditions", "jail", "safely", "finite", "kidney", "periodically", "fixes", "sends", "durable", "mazda", "allied", "throws", "moisture", "hungarian", "roster", "referring", "symantec", "spencer", "wichita", "nasdaq", "uruguay", "ooo", "transform", "timer", "tablets", "tuning", "gotten", "educators", "tyler", "futures", "vegetable", "verse", "highs", "humanities", "independently", "wanting", "custody", "scratch", "launches", "ipaq", "alignment", "henderson", "britannica", "comm", "ellen", "competitors", "nhs", "rocket", "aye", "bullet", "towers", "racks", "lace", "nasty", "visibility", "latitude", "consciousness", "ste", "tumor", "ugly", "deposits", "beverly", "mistress", "encounter", "trustees", "watts", "duncan", "reprints", "hart", "bernard", "resolutions", "ment", "accessing", "forty", "tubes", "attempted", "col", "midlands", "priest", "floyd", "ronald", "analysts", "queue", "trance", "locale", "nicholas", "biol", "bundle", "hammer", "invasion", "witnesses", "runner", "rows", "administered", "notion", "skins", "mailed", "fujitsu", "spelling", "arctic", "exams", "rewards", "beneath", "strengthen", "defend", "frederick"
+ );
+}
diff --git a/src/main/java/me/trouper/sentinel/data/config/StrictConfig.java b/src/main/java/me/trouper/sentinel/data/config/lists/StrictList.java
similarity index 72%
rename from src/main/java/me/trouper/sentinel/data/config/StrictConfig.java
rename to src/main/java/me/trouper/sentinel/data/config/lists/StrictList.java
index 7c00cab..ef5d800 100644
--- a/src/main/java/me/trouper/sentinel/data/config/StrictConfig.java
+++ b/src/main/java/me/trouper/sentinel/data/config/lists/StrictList.java
@@ -1,17 +1,16 @@
-package me.trouper.sentinel.data.config;
+package me.trouper.sentinel.data.config.lists;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
import java.io.File;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-public class StrictConfig implements JsonSerializable {
+public class StrictList implements JsonSerializable {
@Override
public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/strict.json");
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/strict.json");
file.getParentFile().mkdirs();
return file;
}
diff --git a/src/main/java/me/trouper/sentinel/data/config/SwearsConfig.java b/src/main/java/me/trouper/sentinel/data/config/lists/SwearList.java
similarity index 92%
rename from src/main/java/me/trouper/sentinel/data/config/SwearsConfig.java
rename to src/main/java/me/trouper/sentinel/data/config/lists/SwearList.java
index 99ec70f..3cbf7cd 100644
--- a/src/main/java/me/trouper/sentinel/data/config/SwearsConfig.java
+++ b/src/main/java/me/trouper/sentinel/data/config/lists/SwearList.java
@@ -1,4 +1,4 @@
-package me.trouper.sentinel.data.config;
+package me.trouper.sentinel.data.config.lists;
import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
import me.trouper.sentinel.Sentinel;
@@ -7,10 +7,10 @@ import java.io.File;
import java.util.Arrays;
import java.util.List;
-public class SwearsConfig implements JsonSerializable {
+public class SwearList implements JsonSerializable {
@Override
public File getFile() {
- File file = new File(Sentinel.dataFolder(), "/swears.json");
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/swears.json");
file.getParentFile().mkdirs();
return file;
}
diff --git a/src/main/java/me/trouper/sentinel/data/storage/CommandBlockStorage.java b/src/main/java/me/trouper/sentinel/data/storage/CommandBlockStorage.java
new file mode 100644
index 0000000..fa94ebe
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/storage/CommandBlockStorage.java
@@ -0,0 +1,30 @@
+package me.trouper.sentinel.data.storage;
+
+import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CommandBlockStorage implements JsonSerializable {
+ @Override
+ public File getFile() {
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/storage/whitelist.json");
+ file.getParentFile().mkdirs();
+ return file;
+ }
+
+
+ public List holders = new ArrayList<>();
+
+ public synchronized boolean remove(CommandBlockHolder holder) {
+ return holders.removeIf(existing -> existing.loc().isSameLocation(holder.loc()));
+ }
+ public synchronized boolean add(CommandBlockHolder holder) {
+ holders.removeIf(existing -> existing.loc().isSameLocation(holder.loc()));
+ return holders.add(holder);
+ }
+
+}
diff --git a/src/main/java/me/trouper/sentinel/data/storage/ExtraStorage.java b/src/main/java/me/trouper/sentinel/data/storage/ExtraStorage.java
new file mode 100644
index 0000000..f543b90
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/storage/ExtraStorage.java
@@ -0,0 +1,22 @@
+package me.trouper.sentinel.data.storage;
+
+import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.types.SerialLocation;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class ExtraStorage implements JsonSerializable {
+ @Override
+ public File getFile() {
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "/storage/extra.json");
+ file.getParentFile().mkdirs();
+ return file;
+ }
+
+ public Map shadowRealm = new HashMap<>();
+
+}
diff --git a/src/main/java/me/trouper/sentinel/data/storage/NBTStorage.java b/src/main/java/me/trouper/sentinel/data/storage/NBTStorage.java
new file mode 100644
index 0000000..0e3f1c2
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/storage/NBTStorage.java
@@ -0,0 +1,114 @@
+package me.trouper.sentinel.data.storage;
+
+import io.github.itzispyder.pdk.utils.misc.config.JsonSerializable;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.types.NBTHolder;
+import me.trouper.sentinel.utils.ItemBuilder;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class NBTStorage implements JsonSerializable {
+
+ /**
+ * A lightweight, serializable class to hold item metadata in memory.
+ * This is what gets stored in the main nbt.json file.
+ */
+ public static class Metadata {
+ public final UUID owner;
+ public final long timestamp;
+ public final int byteSize;
+
+ // Private no-arg constructor for JSON deserialization
+ private Metadata() {
+ this(null, 0, 0);
+ }
+
+ public Metadata(UUID owner, long timestamp, int byteSize) {
+ this.owner = owner;
+ this.timestamp = timestamp;
+ this.byteSize = byteSize;
+ }
+ }
+
+ // The map stores a filename key and the lightweight Metadata object.
+ // The large item data is NOT stored in memory.
+ public Map caughtItems = new HashMap<>();
+
+ public void storeItem(ItemStack item, UUID owner) {
+ // Use NBTHolder as a temporary tool to get the serialized data and metadata.
+ NBTHolder holder = new NBTHolder(item, owner);
+ String nbt = holder.getBase64Item();
+
+ if (nbt == null) {
+ System.err.println("Failed to serialize item for NBT storage.");
+ return;
+ }
+
+ File storageDir = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "storage/nbt");
+ String fileName = UUID.randomUUID().toString() + ".nbt";
+ File file = new File(storageDir, fileName);
+
+ try (FileOutputStream fos = new FileOutputStream(file);
+ OutputStreamWriter writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
+ writer.write(nbt);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return; // Do not save metadata if file write fails.
+ }
+
+ // Create the lightweight metadata object and store it in the map.
+ Metadata metadata = new Metadata(holder.getOwner(), holder.getTimestamp(), holder.getByteSize());
+ caughtItems.put(fileName, metadata);
+ save();
+ }
+
+ public boolean deleteItem(String fileName) {
+ File storageDir = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "storage/nbt");
+ File file = new File(storageDir, fileName);
+ caughtItems.remove(fileName);
+ save();
+ return file.delete();
+ }
+
+ public static ItemStack getItem(String fileName) {
+ File storageDir = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "storage/nbt");
+ File file = new File(storageDir, fileName);
+ try (FileInputStream fis = new FileInputStream(file)) {
+ String b64 = new String(fis.readAllBytes(), StandardCharsets.UTF_8);
+ // Use the static decoder from NBTHolder to avoid duplicate code.
+ return NBTHolder.decodeItem(b64);
+ } catch (FileNotFoundException e) {
+ // Cleanup the metadata entry if the corresponding file is missing.
+ Sentinel.getInstance().getDirector().io.nbtStorage.caughtItems.remove(fileName);
+ Sentinel.getInstance().getDirector().io.nbtStorage.save();
+ return new ItemBuilder().material(Material.STRUCTURE_VOID)
+ .displayName(Component.text("File not found.", NamedTextColor.RED).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(Component.text("This item no longer exists and has been removed from the list.",NamedTextColor.GRAY))
+ .build();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return new ItemBuilder().material(Material.STRUCTURE_VOID)
+ .displayName(Component.text("Unknown IO Exception.", NamedTextColor.RED).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(Component.text("Check console for details.",NamedTextColor.DARK_RED))
+ .build();
+ }
+ }
+
+ @Override
+ public File getFile() {
+ File file = new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "storage/nbt.json");
+ // Ensure the directory for individual .nbt files exists.
+ new File(Sentinel.getInstance().getDirector().io.getDataFolder(), "storage/nbt").mkdirs();
+ file.getParentFile().mkdirs();
+ return file;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/data/types/CMDBlockType.java b/src/main/java/me/trouper/sentinel/data/types/CMDBlockType.java
deleted file mode 100644
index 3fcd6ca..0000000
--- a/src/main/java/me/trouper/sentinel/data/types/CMDBlockType.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package me.trouper.sentinel.data.types;
-
-public enum CMDBlockType {
- CHAIN,
- REPEAT,
- IMPULSE,
-}
diff --git a/src/main/java/me/trouper/sentinel/data/types/CommandBlockHolder.java b/src/main/java/me/trouper/sentinel/data/types/CommandBlockHolder.java
new file mode 100644
index 0000000..b8156a1
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/types/CommandBlockHolder.java
@@ -0,0 +1,374 @@
+package me.trouper.sentinel.data.types;
+
+import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientUpdateCommandBlock;
+import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientUpdateCommandBlockMinecart;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.Main;
+import me.trouper.sentinel.utils.*;
+import me.trouper.sentinel.utils.display.BlockDisplayRaytracer;
+import me.trouper.sentinel.utils.display.DisplayUtils;
+import org.bukkit.*;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.persistence.PersistentDataType;
+
+import java.util.List;
+
+public class CommandBlockHolder implements Main {
+
+ private String owner;
+ private SerialLocation loc;
+ private String facing;
+ private String type;
+ private boolean auto;
+ private boolean conditional;
+ private String command;
+ private boolean whitelisted;
+
+ public CommandBlockHolder(String owner, SerialLocation loc, String facing, String type, boolean auto, boolean conditional, String command) {
+ this.owner = owner;
+ this.loc = loc;
+ this.facing = facing;
+ this.type = type;
+ this.auto = auto;
+ this.conditional = conditional;
+ this.command = command;
+ this.whitelisted = false;
+ }
+
+ public String owner() {
+ return owner;
+ }
+
+ public CommandBlockHolder setOwner(String owner) {
+ this.owner = owner;
+ main.dir().io.whitelistStorage.save();
+ return this;
+ }
+
+ public SerialLocation loc() {
+ return this.loc;
+ }
+
+ public String facing() {
+ return this.facing;
+ }
+
+ public String type() {
+ return this.type;
+ }
+
+ public boolean isAuto() {
+ return this.auto;
+ }
+
+ public boolean isConditional() {
+ return this.conditional;
+ }
+
+ public String command() {
+ return this.command;
+ }
+
+ public boolean present() {
+ try {
+ if (this.loc.isUUID()) {
+ Entity cart = Bukkit.getEntity(this.loc.toUIID());
+ if (!(cart instanceof CommandMinecart cm)) return false;
+ return this.command.equals(cm.getCommand());
+ } else {
+ Location where = loc.translate();
+ boolean preLoaded = where.isChunkLoaded();
+
+ if (!where.isChunkLoaded()) where.getChunk().load(false);
+
+
+ Block b = where.getBlock();
+ if (!(b.getState() instanceof CommandBlock c) || !(b.getBlockData() instanceof org.bukkit.block.data.type.CommandBlock cb)) {
+ ServerUtils.verbose(1,"Block is not present due to not being a command block. Whitelisted: %s",this.isWhitelisted());
+ if (!this.isWhitelisted()) this.delete();
+ return false;
+ }
+ if (!this.getDirection().equals(cb.getFacing())) {
+ ServerUtils.verbose("Block is not present due to facing mismatch. Should be '%s', is '%s'",this.facing(),cb.getFacing());
+ if (!this.isWhitelisted()) this.delete();
+ return false;
+ }
+ if (!this.getType().equals(c.getType())) {
+ ServerUtils.verbose("Block is not present due to type mismatch. Should be '%s', is '%s'",this.type(),c.getType());
+ if (!this.isWhitelisted()) this.delete();
+ return false;
+ }
+ if (!this.command().equals(c.getCommand())) {
+ ServerUtils.verbose("Block is not present due to command mismatch. Should be '%s', is '%s'",this.command(),c.getCommand());
+ if (!this.isWhitelisted()) this.delete();
+ return false;
+ }
+ if (this.isConditional() != cb.isConditional()) {
+ ServerUtils.verbose("Block is not present due to conditional mismatch.");
+ if (!this.isWhitelisted()) this.delete();
+ return false;
+ }
+ if (this.isAuto() != (c.getPersistentDataContainer().getOrDefault(Sentinel.getInstance().getNamespace("auto"), PersistentDataType.BYTE,(byte) 0) == (byte) 1)) {
+ ServerUtils.verbose("Block is not present due to auto mismatch.");
+ if (!this.isWhitelisted()) this.delete();
+ return false;
+ }
+ if (!preLoaded) where.getChunk().unload();
+ return true;
+ }
+ } catch (IllegalStateException ex) {
+ ServerUtils.verbose("Do not check present command blocks asynchronously. Bukkit has something to say about this.");
+ ex.printStackTrace();
+ ServerUtils.verbose("Not present because the command block is not loaded. I really should make this not call async, and just have a variable that I update every so often...");
+ return false;
+ }
+ }
+
+ public boolean isWhitelisted() {
+ return this.whitelisted;
+ }
+
+ public CommandBlockHolder setWhitelisted(boolean whitelisted) {
+ this.whitelisted = whitelisted;
+ main.dir().io.whitelistStorage.save();
+ return this;
+ }
+
+ public CommandBlockHolder addAndWhitelist() {
+ return setWhitelisted(true).add();
+ }
+
+ public BlockFace getDirection() {
+ return BlockFace.valueOf(facing().toUpperCase());
+ }
+
+ public Material getType() {
+ return Material.valueOf(type().toUpperCase());
+ }
+
+ public void destroy() {
+ ServerUtils.verbose(1,"Destroying command block...");
+ SerialLocation.translate(this.loc).getBlock().setType(Material.AIR);
+ if (!this.isWhitelisted()) delete();
+ }
+
+ public boolean restore() {
+ if (Material.COMMAND_BLOCK_MINECART.equals(this.getType())) {
+ ServerUtils.verbose(1,"Cannot restore minecarts yet.");
+ return false;
+ }
+
+ if (this.present() || !this.isWhitelisted()) return false;
+
+ Block block = SerialLocation.translate(this.loc).getBlock();
+ block.setType(this.getType());
+ if (!ServerUtils.isCommandBlock(block)) {
+ ServerUtils.verbose(1,"Block at the location was not a command block (You shouldn't be seeing this. Report it).");
+ return false;
+ }
+
+ CommandBlock cb = (CommandBlock) block.getState();
+
+ cb.setCommand(this.command());
+ block.setType(this.getType());
+ block.getState().update(true, false);
+
+ org.bukkit.block.data.type.CommandBlock conditional = (org.bukkit.block.data.type.CommandBlock) cb.getBlock().getBlockData();
+ //ServerUtils.verbose("Direction is " + this.getDirection());
+ //ServerUtils.verbose("Conditional is " + this.conditional);
+
+ conditional.setFacing(this.getDirection());
+ conditional.setConditional(this.conditional);
+
+ cb.setBlockData(conditional);
+
+ cb.getPersistentDataContainer().set(
+ Sentinel.getInstance().getNamespace("auto"),
+ PersistentDataType.BYTE,
+ this.auto ? (byte) 1 : (byte) 0
+ );
+
+ cb.update(true,true);
+ ServerUtils.verbose("Command block at " + this.loc.toString() + " has been restored.");
+ return true;
+ }
+
+ public boolean isCart() {
+ return loc.isUUID();
+ }
+
+ public CommandBlockHolder add() {
+ ServerUtils.verbose(1,"Adding command block...");
+ main.dir().io.whitelistStorage.add(this);
+ main.dir().io.whitelistStorage.save();
+ return this;
+ }
+
+ public void delete() {
+ ServerUtils.verbose(1,"Deleting & Destroying command block...");
+ if (this.loc.isUUID() && Bukkit.getEntity(this.loc.toUIID()) != null) Bukkit.getEntity(this.loc.toUIID()).remove();
+ else SerialLocation.translate(this.loc).getBlock().setType(Material.AIR);
+ main.dir().io.whitelistStorage.remove(this);
+ main.dir().io.whitelistStorage.save();
+ }
+
+ public void highlight(Player viewer, Material color) {
+ if (this.loc.isUUID()) {
+ Color c = switch (color) {
+ case RED_CONCRETE_POWDER -> Color.RED;
+ case LIME_CONCRETE_POWDER -> Color.LIME;
+ case MAGENTA_CONCRETE_POWDER, PURPLE_CONCRETE_POWDER -> Color.FUCHSIA;
+ default -> Color.BLACK;
+ };
+ Entity cart = Bukkit.getEntity(this.loc.toUIID());
+ if (cart == null) return;
+ for (int i = 0; i < 5; i++) {
+ DisplayUtils.ring(cart.getLocation().clone().add(0, (double) i /5,0),0.6, (location) -> {
+ DisplayUtils.PLAYER_DUST_PARTICLE_FACTORY.apply(c,1F).accept(viewer,location);
+ },((location, integer) -> {
+ return integer % 36 == 0;
+ }));
+ }
+ } else {
+ BlockDisplayRaytracer.outline(color, this.loc.translate(), 0.05, 2, List.of(viewer));
+ }
+ }
+
+ public boolean update(Player updater) {
+ ServerUtils.verbose(1,"Processing update requested by %s",updater.getName());
+ if (this.isWhitelisted()) return false;
+ boolean changesMade = false;
+ if (!this.owner().equals(updater.getUniqueId().toString())) {
+ this.owner = updater.getUniqueId().toString();
+ changesMade = true;
+ }
+ if (this.loc.isUUID()) {
+ Entity cart = Bukkit.getEntity(this.loc.toUIID());
+ if (!(cart instanceof CommandMinecart cm)) return false;
+ if (!cm.getCommand().equals(this.command())) {
+ this.command = cm.getCommand();
+ changesMade = true;
+ }
+ } else {
+ Location where = loc.translate();
+ boolean preLoaded = where.isChunkLoaded();
+ where.getChunk().load(false);
+ Block b = where.getBlock();
+ if (!(b.getState() instanceof CommandBlock c) || !(b.getBlockData() instanceof org.bukkit.block.data.type.CommandBlock cb)) {
+ ServerUtils.verbose(1,"Block cannot be updated due to not being a command block. It will be deleted if it is not whitelisted. Whitelisted: %s",this.isWhitelisted());
+ if (!this.isWhitelisted()) this.delete();
+ return false;
+ }
+ if (!this.getDirection().equals(cb.getFacing())) {
+ ServerUtils.verbose("Block needs update due to facing mismatch. Should be '%s', is '%s'",this.facing(),cb.getFacing());
+ this.facing = cb.getFacing().toString();
+ changesMade = true;
+ }
+ if (!this.getType().equals(c.getType())) {
+ ServerUtils.verbose("Block needs update due to type mismatch. Should be '%s', is '%s'",this.type(),c.getType());
+ this.type = c.getType().toString();
+ changesMade = true;
+
+ }
+ if (!this.command().equals(c.getCommand())) {
+ ServerUtils.verbose("Block needs update due to command mismatch. Should be '%s', is '%s'",this.command(),c.getCommand());
+ this.command = c.getCommand();
+ changesMade = true;
+
+ }
+ if (this.isConditional() != cb.isConditional()) {
+ ServerUtils.verbose("Block needs update due to conditional mismatch.");
+ this.conditional = cb.isConditional();
+ changesMade = true;
+
+ }
+ if (this.isAuto() != (c.getPersistentDataContainer().getOrDefault(Sentinel.getInstance().getNamespace("auto"), PersistentDataType.BYTE,(byte) 0) == (byte) 1)) {
+ ServerUtils.verbose("Block needs update due to auto mismatch.");
+ this.auto = (c.getPersistentDataContainer().getOrDefault(Sentinel.getInstance().getNamespace("auto"), PersistentDataType.BYTE,(byte) 0) == (byte) 1);
+ changesMade = true;
+ }
+ if (!preLoaded) where.getChunk().unload();
+ }
+
+ if (changesMade) Text.messageAny(Text.Pallet.SUCCESS,updater, "Successfully updated a {0}.", FormatUtils.formatType(this.type));
+ return changesMade;
+ }
+
+ public boolean update(Player updater, WrapperPlayClientUpdateCommandBlockMinecart packet) {
+ ServerUtils.verbose(1,"Processing packet update requested by %s",updater.getName());
+ if (this.isWhitelisted()) return false;
+ boolean changesMade = false;
+ if (!this.owner().equals(updater.getUniqueId().toString())) {
+ this.owner = updater.getUniqueId().toString();
+ changesMade = true;
+ }
+
+ if (!this.loc.isUUID()) {
+ throw new IllegalArgumentException("Cannot update block commands with this packet.");
+ }
+
+ if (!this.command().equals(packet.getCommand())) {
+ ServerUtils.verbose("Block needs update due to command mismatch. Should be '%s', is '%s'",this.command(),packet.getCommand());
+ this.command = packet.getCommand();
+ changesMade = true;
+
+ }
+
+ if (changesMade) Text.messageAny(Text.Pallet.SUCCESS,updater,"Successfully updated a {0}.", FormatUtils.formatType(this.type()));
+
+ return changesMade;
+ }
+
+ public boolean update(Player updater, WrapperPlayClientUpdateCommandBlock packet) {
+ ServerUtils.verbose(1,"Processing packet update requested by %s",updater.getName());
+ if (this.isWhitelisted()) return false;
+ boolean changesMade = false;
+ if (!this.owner().equals(updater.getUniqueId().toString())) {
+ this.owner = updater.getUniqueId().toString();
+ changesMade = true;
+ }
+
+ if (this.loc.isUUID()) {
+ throw new IllegalArgumentException("Cannot update UUID command blocks with this packet.");
+ }
+
+ Material t = switch (packet.getMode()) {
+ case AUTO -> Material.REPEATING_COMMAND_BLOCK;
+ case REDSTONE -> Material.COMMAND_BLOCK;
+ case SEQUENCE -> Material.CHAIN_COMMAND_BLOCK;
+ };
+
+ if (!this.getType().equals(t)) {
+ ServerUtils.verbose("Block needs update due to type mismatch. Should be '%s', is '%s'",this.type(),t.toString());
+ this.type = t.toString();
+ changesMade = true;
+
+ }
+ if (!this.command().equals(packet.getCommand())) {
+ ServerUtils.verbose("Block needs update due to command mismatch. Should be '%s', is '%s'",this.command(),packet.getCommand());
+ this.command = packet.getCommand();
+ changesMade = true;
+
+ }
+ if (this.isConditional() != packet.isConditional()) {
+ ServerUtils.verbose("Block needs update due to conditional mismatch.");
+ this.conditional = packet.isConditional();
+ changesMade = true;
+
+ }
+ if (this.isAuto() != packet.isAutomatic()) {
+ ServerUtils.verbose("Block needs update due to auto mismatch.");
+ this.auto = packet.isAutomatic();
+ changesMade = true;
+ }
+
+ if (changesMade) Text.messageAny(Text.Pallet.SUCCESS,updater,"Successfully updated a {0}.", FormatUtils.formatType(this.type()));
+
+ return changesMade;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/data/Emojis.java b/src/main/java/me/trouper/sentinel/data/types/Emojis.java
similarity index 98%
rename from src/main/java/me/trouper/sentinel/data/Emojis.java
rename to src/main/java/me/trouper/sentinel/data/types/Emojis.java
index 13a1d0c..bab6afd 100644
--- a/src/main/java/me/trouper/sentinel/data/Emojis.java
+++ b/src/main/java/me/trouper/sentinel/data/types/Emojis.java
@@ -1,4 +1,4 @@
-package me.trouper.sentinel.data;
+package me.trouper.sentinel.data.types;
public class Emojis {
public static String space = "<:space:1210008300515762238>";
diff --git a/src/main/java/me/trouper/sentinel/data/types/IPLocation.java b/src/main/java/me/trouper/sentinel/data/types/IPLocation.java
new file mode 100644
index 0000000..c69f12e
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/types/IPLocation.java
@@ -0,0 +1,180 @@
+package me.trouper.sentinel.data.types;
+
+public class IPLocation {
+ private String country;
+ private String countryCode;
+ private String region;
+ private String regionCode;
+ private String city;
+ private String district;
+ private String zip;
+ private String lat;
+ private String lon;
+ private String timezone;
+ private String isp;
+ private String org;
+ private String as;
+ private String reverse;
+ private boolean isMobile;
+ private boolean isProxied;
+ private boolean isHosted;
+
+
+ public IPLocation(String country, String countryCode, String region, String regionCode, String city, String district, String zip, String lat, String lon, String timezone, String isp, String org, String as, String reverse, boolean isMobile, boolean isProxied, boolean isHosted) {
+ this.country = country;
+ this.countryCode = countryCode;
+ this.region = region;
+ this.regionCode = regionCode;
+ this.city = city;
+ this.district = district;
+ this.zip = zip;
+ this.lat = lat;
+ this.lon = lon;
+ this.timezone = timezone;
+ this.isp = isp;
+ this.org = org;
+ this.as = as;
+ this.reverse = reverse;
+ this.isMobile = isMobile;
+ this.isProxied = isProxied;
+ this.isHosted = isHosted;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getCountryCode() {
+ return countryCode;
+ }
+
+ public void setCountryCode(String countryCode) {
+ this.countryCode = countryCode;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public void setRegion(String region) {
+ this.region = region;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public void setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getDistrict() {
+ return district;
+ }
+
+ public void setDistrict(String district) {
+ this.district = district;
+ }
+
+ public String getZip() {
+ return zip;
+ }
+
+ public void setZip(String zip) {
+ this.zip = zip;
+ }
+
+ public String getLat() {
+ return lat;
+ }
+
+ public void setLat(String lat) {
+ this.lat = lat;
+ }
+
+ public String getLon() {
+ return lon;
+ }
+
+ public void setLon(String lon) {
+ this.lon = lon;
+ }
+
+ public String getTimezone() {
+ return timezone;
+ }
+
+ public void setTimezone(String timezone) {
+ this.timezone = timezone;
+ }
+
+ public String getIsp() {
+ return isp;
+ }
+
+ public void setIsp(String isp) {
+ this.isp = isp;
+ }
+
+ public String getOrg() {
+ return org;
+ }
+
+ public void setOrg(String org) {
+ this.org = org;
+ }
+
+ public String getAs() {
+ return as;
+ }
+
+ public void setAs(String as) {
+ this.as = as;
+ }
+
+ public String getReverse() {
+ return reverse;
+ }
+
+ public void setReverse(String reverse) {
+ this.reverse = reverse;
+ }
+
+ public boolean isMobile() {
+ return isMobile;
+ }
+
+ public void setMobile(boolean mobile) {
+ isMobile = mobile;
+ }
+
+ public boolean isProxied() {
+ return isProxied;
+ }
+
+ public void setProxied(boolean proxied) {
+ isProxied = proxied;
+ }
+
+ public boolean isHosted() {
+ return isHosted;
+ }
+
+ public void setHosted(boolean hosted) {
+ isHosted = hosted;
+ }
+}
+
+
diff --git a/src/main/java/me/trouper/sentinel/data/types/Location.java b/src/main/java/me/trouper/sentinel/data/types/Location.java
deleted file mode 100644
index cbf4c81..0000000
--- a/src/main/java/me/trouper/sentinel/data/types/Location.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package me.trouper.sentinel.data.types;
-
-public record Location(String world, double x, double y,double z) {
-}
diff --git a/src/main/java/me/trouper/sentinel/data/types/NBTHolder.java b/src/main/java/me/trouper/sentinel/data/types/NBTHolder.java
new file mode 100644
index 0000000..9cd7245
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/types/NBTHolder.java
@@ -0,0 +1,73 @@
+package me.trouper.sentinel.data.types;
+
+import org.bukkit.inventory.ItemStack;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.UUID;
+
+public class NBTHolder {
+
+ private final String base64Item;
+ private final UUID owner;
+ private final long timestamp;
+ private final int byteSize;
+
+ public NBTHolder(ItemStack item, UUID owner) {
+ this.base64Item = encodeItem(item);
+ this.owner = owner;
+ this.timestamp = System.currentTimeMillis();
+ this.byteSize = base64Item != null ? base64Item.getBytes(StandardCharsets.UTF_8).length : 0;
+ }
+
+ public UUID getOwner() {
+ return owner;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public int getByteSize() {
+ return byteSize;
+ }
+
+ public ItemStack getItem() {
+ return decodeItem(base64Item);
+ }
+
+ public String getBase64Item() {
+ return base64Item;
+ }
+
+ /**
+ * Encodes an ItemStack into a Base64 string using the modern, robust byte array serialization.
+ * @param item The item to encode.
+ * @return A Base64 string representing the item.
+ */
+ public static String encodeItem(ItemStack item) {
+ if (item == null) return null;
+ try {
+ byte[] itemBytes = item.serializeAsBytes();
+ return Base64.getEncoder().encodeToString(itemBytes);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Decodes a Base64 string back into an ItemStack using byte array deserialization.
+ * @param base64 The Base64 string to decode.
+ * @return The deserialized ItemStack.
+ */
+ public static ItemStack decodeItem(String base64) {
+ if (base64 == null || base64.isEmpty()) return null;
+ try {
+ byte[] itemBytes = Base64.getDecoder().decode(base64);
+ return ItemStack.deserializeBytes(itemBytes);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/data/types/Selection.java b/src/main/java/me/trouper/sentinel/data/types/Selection.java
new file mode 100644
index 0000000..7d2f63c
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/types/Selection.java
@@ -0,0 +1,68 @@
+package me.trouper.sentinel.data.types;
+
+import me.trouper.sentinel.utils.display.BlockDisplayRaytracer;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+public class Selection {
+
+ private Location pos1;
+ private Location pos2;
+
+ public void setPos1(Location loc) { this.pos1 = loc; }
+ public void setPos2(Location loc) { this.pos2 = loc; }
+
+ public Location getPos1() { return pos1; }
+ public Location getPos2() { return pos2; }
+
+ public boolean isComplete() {
+ return pos1 != null && pos2 != null;
+ }
+
+ public void forEachBlock(Consumer action) {
+ for (Block block : getBlocks()) {
+ action.accept(block);
+ }
+ }
+
+ public Set getBlocks() {
+ Location pos1 = this.getPos1();
+ Location pos2 = this.getPos2();
+
+ World world = pos1.getWorld();
+ int minX = Math.min(pos1.getBlockX(), pos2.getBlockX());
+ int minY = Math.min(pos1.getBlockY(), pos2.getBlockY());
+ int minZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ());
+ int maxX = Math.max(pos1.getBlockX(), pos2.getBlockX());
+ int maxY = Math.max(pos1.getBlockY(), pos2.getBlockY());
+ int maxZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ());
+
+ Set blocks = new HashSet<>();
+
+ for (int x = minX; x <= maxX; x++) {
+ for (int y = minY; y <= maxY; y++) {
+ for (int z = minZ; z <= maxZ; z++) {
+ blocks.add(world.getBlockAt(x,y,z));
+ }
+ }
+ }
+
+ return blocks;
+ }
+
+ public void display(Player beholder) {
+ if (!beholder.isOnline()
+ || this.pos1 == null
+ || this.pos2 == null
+ || (beholder.getLocation().distance(this.pos1) > 64 && beholder.getLocation().distance(this.pos2) > 64)) return;
+ BlockDisplayRaytracer.outline(Material.LIGHT_BLUE_STAINED_GLASS,this.getPos1(),this.getPos2(),0.1,2, List.of(beholder));
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/data/types/SerialLocation.java b/src/main/java/me/trouper/sentinel/data/types/SerialLocation.java
new file mode 100644
index 0000000..f7a17a0
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/data/types/SerialLocation.java
@@ -0,0 +1,62 @@
+package me.trouper.sentinel.data.types;
+
+import me.trouper.sentinel.utils.MathUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+
+import java.util.UUID;
+
+public record SerialLocation(String world, double x, double y, double z) {
+ public static Location translate(SerialLocation loc) {
+ World w = Bukkit.getWorld(loc.world());
+ return new Location(w,loc.x(),loc.y(),loc.z());
+ }
+
+ public static SerialLocation translate(Location loc) {
+ return new SerialLocation(loc.getWorld().getName(),loc.x(),loc.y(),loc.z());
+ }
+
+ public Location translate() {
+ return translate(this);
+ }
+
+ public UUID toUIID() {
+ return toUUID(this);
+ }
+
+ public boolean isUUID() {
+ return this.world.equals("./Sentinel/ UUID$");
+ }
+
+ public boolean isSameLocation(Location loc) {
+ if (this.isUUID()) return false;
+ Location thisLoc = this.translate();
+ return thisLoc.getWorld().equals(loc.getWorld()) &&
+ thisLoc.getBlockX() == loc.getBlockX() &&
+ thisLoc.getBlockY() == loc.getBlockY() &&
+ thisLoc.getBlockZ() == loc.getBlockZ();
+ }
+
+ public boolean isSameLocation(SerialLocation loc) {
+ if (this.isUUID() && loc.isUUID()) {
+ return loc.toUIID().equals(this.toUIID());
+ } else if (this.isUUID() ^ loc.isUUID()) {
+ return false;
+ }
+ return this.world.equals(loc.world) &&
+ (int) this.x == (int) loc.x &&
+ (int) this.y == (int) loc.y &&
+ (int) this.z == (int) loc.z;
+ }
+
+ public static UUID toUUID(SerialLocation loc) {
+ if (!loc.world.equals("./Sentinel/ UUID$")) throw new IllegalArgumentException("You can only get UUIDs from locations which hold them.");
+ return MathUtils.doublesToUuid(new double[]{loc.x,loc.y,loc.z});
+ }
+
+ public static SerialLocation uuidToLocation(UUID uuid) {
+ double[] doubles = MathUtils.uuidToDoubles(uuid);
+ return new SerialLocation("./Sentinel/ UUID$",doubles[0],doubles[1],doubles[2]);
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/data/types/WhitelistedBlock.java b/src/main/java/me/trouper/sentinel/data/types/WhitelistedBlock.java
deleted file mode 100644
index 46b272a..0000000
--- a/src/main/java/me/trouper/sentinel/data/types/WhitelistedBlock.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package me.trouper.sentinel.data.types;
-
-import org.bukkit.Bukkit;
-import org.bukkit.World;
-
-public record WhitelistedBlock(String owner, Location loc, String type, boolean active, String command) {
-
- public static org.bukkit.Location fromSerialized(Location loc) {
- World w = Bukkit.getWorld(loc.world());
- return new org.bukkit.Location(w,loc.x(),loc.y(),loc.z());
- }
- public static Location serialize(org.bukkit.Location loc) {
- return new Location(loc.getWorld().getName(),loc.x(),loc.y(),loc.z());
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/Director.java b/src/main/java/me/trouper/sentinel/server/Director.java
new file mode 100644
index 0000000..dc78a1b
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/Director.java
@@ -0,0 +1,55 @@
+package me.trouper.sentinel.server;
+
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.IO;
+import me.trouper.sentinel.server.functions.helpers.CBWhitelistManager;
+import me.trouper.sentinel.server.functions.helpers.MessageHandler;
+import me.trouper.sentinel.server.functions.helpers.ReportHandler;
+import me.trouper.sentinel.startup.Telemetry;
+import me.trouper.sentinel.startup.drm.Auth;
+import me.trouper.sentinel.startup.drm.Loader;
+import me.trouper.sentinel.utils.ServerUtils;
+
+public final class Director {
+
+ public Loader loader;
+ public Auth auth;
+ public Telemetry telemetry;
+ public IO io;
+ public CBWhitelistManager whitelistManager;
+ public MessageHandler messageHandler;
+ public ReportHandler reportHandler;
+
+ public Director() {
+ Sentinel.getInstance().getLogger().info("Instantiating Systems");
+ telemetry = new Telemetry();
+ auth = new Auth();
+ loader = new Loader();
+ io = new IO();
+ whitelistManager = new CBWhitelistManager();
+ messageHandler = new MessageHandler();
+ reportHandler = new ReportHandler();
+ }
+
+ public void launch() {
+ Sentinel.getInstance().getLogger().info("Launching Sentinel");
+ Sentinel.getInstance().ip = ServerUtils.getPublicIPAddress();
+ Sentinel.getInstance().port = ServerUtils.getPort();
+ Sentinel.getInstance().nonce = auth.getNonce();
+
+ Sentinel.getInstance().getLogger().info("Getting plugin file");
+
+ Sentinel.getInstance().getLogger().info("Reading Persistent files...");
+
+ io.loadConfig();
+
+ Sentinel.getInstance().getLogger().info("Language Status: (%s)".formatted(io.lang.brokenLang));
+
+ Sentinel.getInstance().getLogger().info("Initializing Auth Identifier");
+
+ Sentinel.getInstance().license = auth.getLicenseKey();
+ Sentinel.getInstance().identifier = auth.getServerID();
+
+ loader.load(Sentinel.getInstance().license,Sentinel.getInstance().identifier, true);
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/Main.java b/src/main/java/me/trouper/sentinel/server/Main.java
new file mode 100644
index 0000000..976c64a
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/Main.java
@@ -0,0 +1,93 @@
+package me.trouper.sentinel.server;
+
+import io.papermc.paper.registry.RegistryAccess;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.IO;
+import me.trouper.sentinel.data.config.lang.LanguageFile;
+import me.trouper.sentinel.utils.Text;
+import net.kyori.adventure.audience.Audience;
+import net.kyori.adventure.text.Component;
+
+import java.util.Random;
+import java.util.function.BooleanSupplier;
+import java.util.logging.Logger;
+
+public interface Main {
+ Main main = new Main() {};
+
+ Random random = new Random();
+
+ default RegistryAccess getRegistryAccess() {
+ return RegistryAccess.registryAccess();
+ }
+
+ default Sentinel getPlugin() {
+ return Sentinel.getInstance();
+ }
+
+ default Logger getLogger() {
+ return getPlugin().getLogger();
+ }
+
+ default Director dir() {
+ return getPlugin().getDirector();
+ }
+
+ default IO io() {
+ return dir().io;
+ };
+
+ default LanguageFile lang() {
+ return io().lang;
+ }
+
+ default void infoAny(Audience player, String message, Object... args) {
+ Text.messageAny(Text.Pallet.INFO, player, message, args);
+ }
+
+ default void errorAny(Audience player, String message, Object... args) {
+ Text.messageAny(Text.Pallet.ERROR,player, message, args);
+ }
+
+ default void warningAny(Audience player, String message, Object... args) {
+ Text.messageAny(Text.Pallet.WARNING, player, message, args);
+ }
+
+ default void successAny(Audience player, String message, Object... args) {
+ Text.messageAny(Text.Pallet.SUCCESS, player, message, args);
+ }
+
+ default void messageAny(Audience player, String message, Object... args) {
+ Text.messageAny(Text.Pallet.NEUTRAL, player, message, args);
+ }
+
+ default void info(Audience player, Component message, Component... args) {
+ Text.message(Text.Pallet.INFO, player, message, args);
+ }
+
+ default void error(Audience player, Component message, Component... args) {
+ Text.message(Text.Pallet.ERROR,player, message, args);
+ }
+
+ default void warning(Audience player, Component message, Component... args) {
+ Text.message(Text.Pallet.WARNING, player, message, args);
+ }
+
+ default void success(Audience player, Component message, Component... args) {
+ Text.message(Text.Pallet.SUCCESS, player, message, args);
+ }
+
+ default void message(Audience player, Component message, Component... args) {
+ Text.message(Text.Pallet.NEUTRAL, player, message, args);
+ }
+
+ default void checkPre(boolean check, String msg, Object... args) {
+ if (!check) {
+ throw new IllegalArgumentException(msg.formatted(args));
+ }
+ }
+
+ default void checkPre(BooleanSupplier check, String msg, Object... args) {
+ checkPre(check.getAsBoolean(), msg, args);
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/CallbackCommand.java b/src/main/java/me/trouper/sentinel/server/commands/CallbackCommand.java
index d2f822f..b858ded 100644
--- a/src/main/java/me/trouper/sentinel/server/commands/CallbackCommand.java
+++ b/src/main/java/me/trouper/sentinel/server/commands/CallbackCommand.java
@@ -2,15 +2,11 @@ package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
-import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import io.github.itzispyder.pdk.utils.misc.Cooldown;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.FalsePositiveReporting;
import me.trouper.sentinel.server.functions.helpers.Report;
import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.Text;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -18,7 +14,7 @@ import org.bukkit.entity.Player;
import java.util.UUID;
@CommandRegistry(value = "sentinelcallback", permission = @Permission("sentinel.callbacks"), printStackTrace = true)
-public class CallbackCommand implements CustomCommand {
+public class CallbackCommand implements QuickCommand {
Cooldown fpReportCooldown = new Cooldown<>();
@@ -29,18 +25,18 @@ public class CallbackCommand implements CustomCommand {
case "fpreport" -> {
if (!PlayerUtils.checkPermission(sender,"sentinel.callbacks.fpreport")) return;
if (fpReportCooldown.isOnCooldown(p.getUniqueId()) && !p.isOp()) {
- p.sendMessage(Text.prefix(Sentinel.lang.cooldown.onCooldown + fpReportCooldown.getCooldown(p.getUniqueId())));
+ warningAny(sender,main.lang().cooldown.onCooldown,fpReportCooldown.getCooldownSec(p.getUniqueId()));
return;
}
long id = args.get(1).toLong();
- Report report = FalsePositiveReporting.reports.get(id);
+ Report report = main.dir().reportHandler.reports.get(id);
if (report == null) {
- p.sendMessage(Text.prefix(Sentinel.lang.reports.noReport));
+ errorAny(sender,main.lang().reports.noReport);
return;
}
- p.sendMessage(Text.prefix(Sentinel.lang.reports.reportingFalsePositive));
- FalsePositiveReporting.sendReport(p,report);
- p.sendMessage(Text.prefix(Sentinel.lang.reports.falsePositiveSuccess));
+ infoAny(sender,main.lang().reports.reportingFalsePositive);
+ main.dir().reportHandler.sendReport(p,report);
+ successAny(sender,main.lang().reports.falsePositiveSuccess);
}
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/ExtraCommand.java b/src/main/java/me/trouper/sentinel/server/commands/ExtraCommand.java
new file mode 100644
index 0000000..9bef0e2
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/ExtraCommand.java
@@ -0,0 +1,107 @@
+package me.trouper.sentinel.server.commands;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.util.Vector3d;
+import com.github.retrooper.packetevents.wrapper.play.server.*;
+//import com.xxmicloxx.NoteBlockAPI.model.Song;
+//import com.xxmicloxx.NoteBlockAPI.model.SoundCategory;
+//import com.xxmicloxx.NoteBlockAPI.songplayer.RadioSongPlayer;
+//import com.xxmicloxx.NoteBlockAPI.songplayer.SongPlayer;
+//import com.xxmicloxx.NoteBlockAPI.utils.NBSDecoder;
+import io.github.itzispyder.pdk.commands.Args;
+import io.github.itzispyder.pdk.commands.CommandRegistry;
+import io.github.itzispyder.pdk.commands.Permission;
+import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.types.IPLocation;
+import me.trouper.sentinel.data.types.SerialLocation;
+import me.trouper.sentinel.server.commands.extras.AbstractExtra;
+import me.trouper.sentinel.server.events.extras.ShadowRealmEvents;
+import me.trouper.sentinel.utils.*;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.Style;
+import net.kyori.adventure.text.format.TextDecoration;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerKickEvent;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@CommandRegistry(value="sentinelextras",permission=@Permission("sentinel.extras"),printStackTrace = true)
+public class ExtraCommand implements QuickCommand {
+
+ public final List extraRegistry = new ArrayList<>();
+
+ public ExtraCommand(List enabledExtras) {
+ extraRegistry.addAll(enabledExtras);
+ }
+
+ @Override
+ public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
+ if (!PlayerUtils.isTrusted(sender)) {
+ warningAny(sender,main.dir().io.lang.permissions.noTrust);
+ return;
+ }
+ if (args.getSize() < 2) {
+ Component helpMessage = Component.empty()
+ .append(Component.text("Extra's Guide",NamedTextColor.GOLD)).appendNewline()
+ .append(Component.text("All Features are packet based. \nThey do not effect other players.",NamedTextColor.GRAY)).appendNewline()
+ .append(Component.text("Syntax",NamedTextColor.AQUA)
+ .append(Component.text(": ",NamedTextColor.WHITE)
+ .append(Component.text("/sentinelextras [free]",NamedTextColor.GRAY)))).appendNewline()
+ .append(Component.text("Features",NamedTextColor.AQUA)
+ .append(Component.text(":",NamedTextColor.WHITE))).appendNewline();
+
+ for (AbstractExtra extra : extraRegistry) {
+ helpMessage = helpMessage.append(Text.format(Text.Pallet.NEUTRAL," - {0}: {1}",extra.getName(),extra.getDescription())).appendNewline();
+ }
+
+ message(sender,helpMessage);
+ return;
+ }
+
+ String target = args.get(1).toString();
+ Player victim = Bukkit.getPlayer(target);
+ if (victim == null || !victim.isOnline()) {
+ errorAny(sender,"You must pick an online player. {0} is not online!",target);
+ return;
+ }
+
+ String choice = args.get(0).toString();
+ AbstractExtra extra = null;
+
+ for (AbstractExtra abstractExtra : extraRegistry) {
+ if (!abstractExtra.getName().equals(choice)) continue;
+ extra = abstractExtra;
+ break;
+ }
+
+ if (extra == null) {
+ errorAny(sender,"You must pick a valid extra. {0} does not exist!",choice);
+ return;
+ }
+
+ if (args.getSize() >= 3 && Objects.equals("free",args.get(2).toString())) {
+ extra.stop(sender,victim);
+ return;
+ }
+
+ extra.execute(sender,victim);
+ }
+
+ @Override
+ public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
+ b.then(b.arg("info"));
+ List extras = new ArrayList<>();
+ extraRegistry.forEach(extra -> extras.add(extra.getName()));
+ b.then(b.arg(extras).then(
+ b.argOnlinePlayers().then(b.arg("free"))
+ ));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/commands/MessageCommand.java b/src/main/java/me/trouper/sentinel/server/commands/MessageCommand.java
index 9b79f42..1ffc395 100644
--- a/src/main/java/me/trouper/sentinel/server/commands/MessageCommand.java
+++ b/src/main/java/me/trouper/sentinel/server/commands/MessageCommand.java
@@ -2,13 +2,9 @@ package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
-import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.Message;
import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.Text;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@@ -18,17 +14,17 @@ import java.util.ArrayList;
import java.util.List;
@CommandRegistry(value = "sentinelmessage",permission = @Permission("sentinel.message"),printStackTrace = true)
-public class MessageCommand implements CustomCommand {
+public class MessageCommand implements QuickCommand {
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
Player p = (Player) sender;
Player r = null;
if (args.getSize() == 0) {
- p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noOnlinePlayer));
+ errorAny(sender,main.dir().io.lang.playerInteraction.noOnlinePlayer);
return;
}
if (args.getSize() == 1) {
- p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noMessageProvided));
+ errorAny(sender,main.dir().io.lang.playerInteraction.noMessageProvided);
return;
}
r = Bukkit.getPlayer(args.get(0).toString());
@@ -36,8 +32,8 @@ public class MessageCommand implements CustomCommand {
String msg = args.getAll(1).toString().trim();
if (PlayerUtils.checkPermission(sender,"sentinel.message") && r != null) {
- Message.messagePlayer(p,r,msg);
- } else if (r == null) p.sendMessage(Text.prefix((Sentinel.lang.playerInteraction.noOnlinePlayer)));
+ main.dir().messageHandler.messagePlayer(p,r,msg);
+ } else if (r == null) errorAny(sender,main.dir().io.lang.playerInteraction.noOnlinePlayer);
}
@Override
diff --git a/src/main/java/me/trouper/sentinel/server/commands/QuickCommand.java b/src/main/java/me/trouper/sentinel/server/commands/QuickCommand.java
new file mode 100644
index 0000000..bac312e
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/QuickCommand.java
@@ -0,0 +1,101 @@
+package me.trouper.sentinel.server.commands;
+
+import io.github.itzispyder.pdk.commands.Args;
+import io.github.itzispyder.pdk.commands.CommandRegistry;
+import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
+import io.github.itzispyder.pdk.commands.completions.CompletionNode;
+import io.github.itzispyder.pdk.utils.misc.Voidable;
+import me.trouper.sentinel.server.Main;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.command.TabExecutor;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public interface QuickCommand extends TabExecutor, Main {
+
+ void dispatchCommand(CommandSender sender, Command command, String label, Args args);
+
+ void dispatchCompletions(CommandSender sender, Command command, String label, CompletionBuilder b);
+
+ default void register() {
+ CommandRegistry registry = this.getClass().getAnnotation(CommandRegistry.class);
+ PluginCommand command = getPlugin().getCommand(registry.value());
+
+ if (command != null) {
+ command.setExecutor(this);
+ command.setTabCompleter(this);
+ }
+ }
+
+ @Override
+ default boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ CommandRegistry registry = this.getClass().getAnnotation(CommandRegistry.class);
+ if (registry == null) {
+ return true;
+ }
+ if (!(sender instanceof Player) && registry.playersOnly()) {
+ infoAny(sender, "This command is for players only!");
+ return true;
+ }
+
+ try {
+ String perm = registry.permission().value();
+ if (perm != null && !perm.isEmpty() && !sender.hasPermission(perm)) {
+ errorAny(sender, registry.permission().message());
+ return true;
+ }
+ dispatchCommand(sender, command, label, new Args(args));
+ }
+ catch (Exception ex) {
+ if (registry.printStackTrace()) {
+ ex.printStackTrace();
+ }
+ infoAny(sender, "&cCorrect Usage: &7" + registry.usage());
+ }
+ return true;
+ }
+
+ @Override
+ default List onTabComplete(CommandSender sender, Command command, String label, String[] args) {
+ try {
+ CompletionBuilder b = new CompletionBuilder(label);
+ dispatchCompletions(sender, command, label, b);
+ CompletionNode node = b.getRootNode();
+
+ if (args.length == 0) {
+ return node.getOptions();
+ }
+ for (int i = 0; i < args.length - 1; i++) {
+ node = node.next(args[i]);
+ }
+
+ String end = args[args.length - 1];
+ List a = new ArrayList<>(node.getOptions());
+
+ if (node.isOptionsRegex()) {
+ List regexResult = new ArrayList<>();
+ for (CompletionNode option : node.getNextOptions()) {
+ boolean regexMatches = CompletionNode.containsRegex(option, end) || end.isEmpty();
+ for (String s : option.getValues())
+ regexResult.add((regexMatches ? "§d" : "§c") + s + "§r");
+ }
+ return regexResult;
+ }
+ else {
+ a.removeIf(s -> !s.toLowerCase().contains(end.toLowerCase()));
+ return a;
+ }
+ }
+ catch (Exception ex) {
+ return new ArrayList<>();
+ }
+ }
+
+ default Voidable getRegistry() {
+ return Voidable.of(this.getClass().getAnnotation(CommandRegistry.class));
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/ReopCommand.java b/src/main/java/me/trouper/sentinel/server/commands/ReopCommand.java
index c8d2586..1bab3a1 100644
--- a/src/main/java/me/trouper/sentinel/server/commands/ReopCommand.java
+++ b/src/main/java/me/trouper/sentinel/server/commands/ReopCommand.java
@@ -2,32 +2,30 @@ package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
-import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.Text;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandRegistry(value = "reop")
-public class ReopCommand implements CustomCommand {
+public class ReopCommand implements QuickCommand {
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
Player p = (Player) sender;
- if (PlayerUtils.isTrusted(p) && Sentinel.mainConfig.plugin.reopCommand) {
+ if (PlayerUtils.isTrusted(p) && main.dir().io.mainConfig.plugin.reopCommand) {
if (!p.isOp()) {
- p.sendMessage(Text.prefix(Sentinel.lang.permissions.elevatingPerms));
- Sentinel.log.info(Sentinel.lang.permissions.logElevatingPerms.formatted(p.getName()));
+ successAny(sender,main.dir().io.lang.permissions.elevatingPerms);
+ Sentinel.getInstance().getLogger().info(main.dir().io.lang.permissions.logElevatingPerms.formatted(p.getName()));
p.setOp(true);
} else {
- p.sendMessage(Text.prefix(Sentinel.lang.permissions.alreadyOp));
- Sentinel.log.info(Sentinel.lang.permissions.logAlreadyOp.formatted(p.getName()));
+ infoAny(sender,main.dir().io.lang.permissions.alreadyOp);
+ Sentinel.getInstance().getLogger().info(main.dir().io.lang.permissions.logAlreadyOp.formatted(p.getName()));
p.setOp(true);
}
} else {
- p.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
+ errorAny(sender,main.dir().io.lang.permissions.noTrust);
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/ReplyCommand.java b/src/main/java/me/trouper/sentinel/server/commands/ReplyCommand.java
index 8eeaf32..f2b0672 100644
--- a/src/main/java/me/trouper/sentinel/server/commands/ReplyCommand.java
+++ b/src/main/java/me/trouper/sentinel/server/commands/ReplyCommand.java
@@ -2,13 +2,9 @@ package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
-import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.Message;
import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.Text;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -17,9 +13,9 @@ import java.util.Map;
import java.util.UUID;
@CommandRegistry(value = "reply", permission = @Permission("sentinel.reply"),printStackTrace = true)
-public class ReplyCommand implements CustomCommand {
+public class ReplyCommand implements QuickCommand {
- public static Map replyMap = Message.replyMap;
+ public static Map replyMap = main.dir().messageHandler.replyMap;
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
@@ -27,16 +23,16 @@ public class ReplyCommand implements CustomCommand {
Player p = sender.getServer().getPlayer(name);
UUID senderID = p.getUniqueId();
if (replyMap.get(senderID) == null) {
- p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noReply));
+ errorAny(sender,main.dir().io.lang.playerInteraction.noReply);
}
Player r = sender.getServer().getPlayer(replyMap.get(senderID));
UUID reciverID = r.getUniqueId();
if (args.get(0).toString() == null) {
- p.sendMessage(Text.prefix(Sentinel.lang.playerInteraction.noMessageProvided));
+ errorAny(sender,main.dir().io.lang.playerInteraction.noMessageProvided);
}
String msg = args.getAll().toString();
if (PlayerUtils.checkPermission(sender,"sentinel.message")) {
- Message.messagePlayer(p,r,msg);
+ main.dir().messageHandler.messagePlayer(p,r,msg);
replyMap.put(senderID,reciverID);
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/SentinelCommand.java b/src/main/java/me/trouper/sentinel/server/commands/SentinelCommand.java
index e31c13a..0752564 100644
--- a/src/main/java/me/trouper/sentinel/server/commands/SentinelCommand.java
+++ b/src/main/java/me/trouper/sentinel/server/commands/SentinelCommand.java
@@ -2,22 +2,25 @@ package me.trouper.sentinel.server.commands;
import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.commands.CommandRegistry;
-import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.Permission;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import io.papermc.paper.chat.ChatRenderer;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.types.WhitelistedBlock;
-import me.trouper.sentinel.server.functions.helpers.CBWhitelistManager;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.data.types.NBTHolder;
+import me.trouper.sentinel.data.types.Selection;
+import me.trouper.sentinel.data.types.SerialLocation;
+import me.trouper.sentinel.server.events.admin.WandEvents;
+import me.trouper.sentinel.server.events.violations.players.CreativeHotbar;
import me.trouper.sentinel.server.functions.chatfilter.profanity.ProfanityFilter;
import me.trouper.sentinel.server.functions.chatfilter.spam.SpamFilter;
import me.trouper.sentinel.server.functions.chatfilter.unicode.UnicodeFilter;
import me.trouper.sentinel.server.functions.chatfilter.url.UrlFilter;
+import me.trouper.sentinel.server.functions.hotbar.items.ItemCheck;
+import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.startup.Load;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.startup.drm.Loader;
+import me.trouper.sentinel.utils.*;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.Node;
@@ -30,290 +33,466 @@ import org.bukkit.block.CommandBlock;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.inventory.InventoryCreativeEvent;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-@CommandRegistry(value = "sentinel",permission = @Permission("sentinel.staff"),printStackTrace = true)
-public class SentinelCommand implements CustomCommand {
+@CommandRegistry(value = "sentinel", permission = @Permission("sentinel.staff"), printStackTrace = true)
+public class SentinelCommand implements QuickCommand {
+
+ // Constants for usage messages
+ private static final String USAGE_SENTINEL = "Usage: /sentinel ";
+ private static final String USAGE_COMMANDBLOCK = "Usage: /sentinel commandblock ";
+ private static final String USAGE_SELECTION = "Usage: /sentinel commandblock selection ";
+ private static final String USAGE_RESTORE = "Usage: /sentinel commandblock restore ";
+ private static final String USAGE_CLEAR = "Usage: /sentinel commandblock clear ";
public static Map spyMap = new HashMap<>();
@Override
public void dispatchCommand(CommandSender sender, Command command, String s, Args args) {
try {
- safety(sender,command,s,args);
+ processCommand(sender, command, s, args);
} catch (IllegalArgumentException e) {
- sender.sendMessage(Text.prefix(Sentinel.lang.plugin.invalidArgs));
+ e.printStackTrace();
+ errorAny(sender, main.lang().plugin.invalidArgs);
}
}
@Override
- public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
+ public void dispatchCompletions(CommandSender sender, Command command, String s, CompletionBuilder b) {
b.then(b.arg("socialspy"));
b.then(b.arg("config"));
+ b.then(b.arg("wand"));
b.then(b.arg("reload"));
- b.then(b.arg("false-positive").then(b.arg("add","remove")));
- b.then(b.arg("debug").then(
- b.arg("lang","toggle","chat")));
- b.then(b.arg("commandblock","cb").then(b.arg("add","remove","auto"))
- .then(b.arg("restore")
- .then(b.arg("","all")))
- .then(b.arg("clear")
- .then(b.arg("","all"))));
+
+ b.then(
+ b.arg("false-positive")
+ .then(b.arg("add", "remove"))
+ );
+
+ b.then(
+
+ b.arg("debug")
+ .then(b.arg("lang", "toggle", "chat"))
+ .then(b.arg("nbt")
+ .then(b.arg("system","store","filter")))
+ );
+
+ b.then(
+ b.arg("commandblock", "cb")
+ .then(b.arg("add", "remove", "auto"))
+ .then(
+ b.arg("selection")
+ .then(b.arg("add", "remove", "delete", "deselect", "pos1", "pos2"))
+ )
+ .then(
+ b.arg("restore")
+ .then(b.arg("", "all"))
+ )
+ .then(
+ b.arg("clear")
+ .then(b.arg("", "all"))
+ )
+ );
}
-
- private void safety(CommandSender sender, Command command, String label, Args args) {
- if (Load.lite) {
+ /* Main Command Processing */
+ private void processCommand(CommandSender sender, Command command, String label, Args args) {
+ // Lite mode check
+ if (main.dir().loader.isLite()) {
handleLiteMessage(sender, args);
return;
}
+
if (args.isEmpty()) {
- sender.sendMessage(Text.prefix("Usage: /sentinel "));
+ infoAny(sender, USAGE_SENTINEL);
return;
}
String subCommand = args.get(0).toString().toLowerCase();
switch (subCommand) {
case "reload" -> handleReload(sender);
+ case "wand" -> handleWand(sender);
case "config" -> handleConfig(sender);
case "commandblock", "cb" -> handleCommandBlock(sender, args);
case "debug" -> handleDebugCommand(sender, args);
case "false-positive" -> handleFalsePositive(sender, args);
case "socialspy" -> handleSocialSpy(sender);
- default -> sender.sendMessage(Text.prefix("Invalid sub-command. Usage: /sentinel "));
+ default -> errorAny(sender, "Invalid sub-command. %s", USAGE_SENTINEL);
}
}
-
- private void handleReload(CommandSender sender) {
+ private Player getPlayer(CommandSender sender) {
if (sender instanceof Player p) {
- if (!PlayerUtils.checkPermission(sender, "sentinel.reload") || !PlayerUtils.isTrusted(p)) {
- p.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
- return;
- }
+ return p;
}
- Sentinel.log.info("Sentinel is now reloading the config.");
- sender.sendMessage(Text.prefix(Sentinel.lang.plugin.reloadingConfig));
- Sentinel.getInstance().loadConfig();
+ errorAny(sender, "Only players can execute this command.");
+ return null;
}
- private void handleConfig(CommandSender sender) {
- if (!PlayerUtils.playerCheck(sender))
+ /* =======================
+ Subcommand: RELOAD
+ ======================= */
+ private void handleReload(CommandSender sender) {
+ if (!PlayerUtils.isTrusted(sender)) {
+ errorAny(sender, main.lang().permissions.noTrust);
return;
+ }
+ main.getLogger().info("Sentinel is now reloading the config.");
+ infoAny(sender, main.lang().plugin.reloadingConfig);
+ main.dir().io.loadConfig();
+ }
+
+ /* =======================
+ Subcommand: WAND
+ ======================= */
+ private void handleWand(CommandSender sender) {
+ if (PlayerUtils.isConsoleCheck(sender)) return;
+ if (!PlayerUtils.isTrusted(sender)) return;
Player p = (Player) sender;
- if (!PlayerUtils.checkPermission(sender, "sentinel.config") || !PlayerUtils.isTrusted(p))
- return;
- if (!MainGUI.verify(p))
- return;
+ p.give(WandEvents.SELECTION_WAND);
+ successAny(sender, "Given you a selection wand.");
+ }
+
+ /* =======================
+ Subcommand: CONFIG
+ ======================= */
+ private void handleConfig(CommandSender sender) {
+ Player p = getPlayer(sender);
+ if (p == null) return;
+ if (!PlayerUtils.isTrusted(p)) return;
+ if (!MainGUI.verify(p)) return;
+
p.openInventory(new MainGUI().home.getInventory());
}
+ /* =======================
+ Subcommand: COMMANDBLOCK
+ ======================= */
private void handleCommandBlock(CommandSender sender, Args args) {
- if (!PlayerUtils.isTrusted(sender))
- return;
+ if (!PlayerUtils.isTrusted(sender)) return;
if (args.getSize() < 2) {
- sender.sendMessage(Text.prefix("Usage: /sentinel commandblock "));
+ infoAny(sender, USAGE_COMMANDBLOCK);
return;
}
+
String sub = args.get(1).toString().toLowerCase();
switch (sub) {
- case "add" -> {
- if (!PlayerUtils.playerCheck(sender))
- return;
- Player p = (Player) sender;
- Block target = p.getTargetBlock(Set.of(Material.AIR), 10);
- if (target.getType() == Material.COMMAND_BLOCK ||
- target.getType() == Material.REPEATING_COMMAND_BLOCK ||
- target.getType() == Material.CHAIN_COMMAND_BLOCK) {
- CommandBlock cb = (CommandBlock) target.getState();
- CBWhitelistManager.add(cb, p.getUniqueId());
- } else {
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.notCommandBlock.formatted(Text.cleanName(target.getType().toString()))));
- }
- }
- case "remove" -> {
- if (!PlayerUtils.playerCheck(sender))
- return;
- Player p = (Player) sender;
- Block target = p.getTargetBlock(Set.of(Material.AIR), 10);
- WhitelistedBlock wb = CBWhitelistManager.get(target.getLocation());
- if (wb != null) {
- CBWhitelistManager.remove(target.getLocation());
- String cleanedType = Text.cleanName(WhitelistedBlock.fromSerialized(wb.loc()).getBlock().getType().toString());
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.removeSuccess.formatted(cleanedType, wb.command())));
- } else {
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.notWhitelisted.formatted(Text.cleanName(target.getType().toString()))));
- }
- }
- case "auto" -> {
- if (!PlayerUtils.playerCheck(sender))
- return;
- Player p = (Player) sender;
- if (CBWhitelistManager.autoWhitelist.contains(p.getUniqueId())) {
- CBWhitelistManager.autoWhitelist.remove(p.getUniqueId());
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.autoWhitelistOn));
- } else {
- CBWhitelistManager.autoWhitelist.add(p.getUniqueId());
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.autoWhitelistOff));
- }
- }
- case "restore" -> {
- if (args.getSize() < 3) {
- sender.sendMessage(Text.prefix("Usage: /sentinel commandblock restore "));
- return;
- }
- String targetPlayer = args.get(2).toString();
- if (targetPlayer.equalsIgnoreCase("all")) {
- int result = CBWhitelistManager.restoreAll();
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.restoreSuccess.formatted(result)));
- } else {
- UUID id = Bukkit.getOfflinePlayer(targetPlayer).getUniqueId();
- int result = CBWhitelistManager.restoreAll(id);
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.restorePlayerSuccess.formatted(result,targetPlayer)));
- }
- }
- case "clear" -> {
- if (args.getSize() < 3) {
- sender.sendMessage(Text.prefix("Usage: /sentinel commandblock clear "));
- return;
- }
- String targetPlayer = args.get(2).toString();
- if (targetPlayer.equalsIgnoreCase("all")) {
- int result = CBWhitelistManager.clearAll();
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.clearSuccess.formatted(result)));
- } else {
- UUID id = Bukkit.getOfflinePlayer(targetPlayer).getUniqueId();
- int result = CBWhitelistManager.clearAll(id);
- sender.sendMessage(Text.prefix(Sentinel.lang.commandBlock.clearPlayerSuccess.formatted(result,targetPlayer)));
- }
- }
- default -> sender.sendMessage(Text.prefix(Sentinel.lang.plugin.invalidSubCommand.formatted("commandblock")));
+ case "selection" -> handleCommandBlockSelection(sender, args);
+ case "add" -> handleCommandBlockAdd(sender);
+ case "remove" -> handleCommandBlockRemove(sender);
+ case "auto" -> handleCommandBlockAuto(sender);
+ case "restore" -> handleCommandBlockRestore(sender, args);
+ case "clear" -> handleCommandBlockClear(sender, args);
+ default -> errorAny(sender, main.lang().plugin.invalidSubCommand, "commandblock");
}
}
+ // --- CommandBlock -> SELECTION ---
+ private void handleCommandBlockSelection(CommandSender sender, Args args) {
+ if (args.getSize() < 3) {
+ infoAny(sender, USAGE_SELECTION);
+ return;
+ }
+ Player p = getPlayer(sender);
+ if (p == null) return;
+
+ String action = args.get(2).toString().toLowerCase();
+ switch (action) {
+ case "add" -> main.dir().whitelistManager.addSelectionToWhitelist(p);
+ case "remove" -> main.dir().whitelistManager.removeSelectionFromWhitelist(p);
+ case "delete" -> main.dir().whitelistManager.deleteSelection(p);
+ case "deselect", "desel" -> WandEvents.selections.remove(p.getUniqueId());
+ case "pos1" -> {
+ Selection selection = WandEvents.selections.computeIfAbsent(p.getUniqueId(), k -> new Selection());
+ selection.setPos1(p.getLocation());
+ success(p, Component.text("Position 1 set at {0}."), FormatUtils.formatLoc(p.getLocation()));
+ }
+ case "pos2" -> {
+ Selection selection = WandEvents.selections.computeIfAbsent(p.getUniqueId(), k -> new Selection());
+ selection.setPos2(p.getLocation());
+ success(p, Component.text("Position 2 set at {0}."), FormatUtils.formatLoc(p.getLocation()));
+ }
+ default -> errorAny(p, "Invalid selection action. %s", USAGE_SELECTION);
+ }
+ }
+
+ // --- CommandBlock -> ADD ---
+ private void handleCommandBlockAdd(CommandSender sender) {
+ Player p = getPlayer(sender);
+ if (p == null) return;
+
+ if (p.getTargetEntity(10) instanceof CommandMinecart cm) {
+ main.dir().whitelistManager
+ .generateHolder(p.getUniqueId(), cm).addAndWhitelist();
+ return;
+ }
+ Block target = p.getTargetBlock(Set.of(Material.AIR), 10);
+ if (ServerUtils.isCommandBlock(target)) {
+ CommandBlock cb = (CommandBlock) target.getState();
+ main.dir().whitelistManager
+ .generateHolder(p.getUniqueId(), cb).addAndWhitelist();
+ } else {
+ errorAny(sender, main.lang().commandBlock.notCommandBlock, FormatUtils.formatType(target.getType().toString()));
+ }
+ }
+
+ // --- CommandBlock -> REMOVE ---
+ private void handleCommandBlockRemove(CommandSender sender) {
+ Player p = getPlayer(sender);
+ if (p == null) return;
+
+ if (p.getTargetEntity(10) instanceof CommandMinecart cm) {
+ CommandBlockHolder wb = main.dir().whitelistManager
+ .getFromList(cm.getUniqueId());
+ if (wb != null) {
+ wb.setWhitelisted(false);
+ String cleanedType = FormatUtils.formatType(SerialLocation.translate(wb.loc()).getBlock().getType().toString());
+ successAny(sender, main.lang().commandBlock.removeSuccess, cleanedType, wb.command());
+ } else {
+ errorAny(sender, main.lang().commandBlock.notWhitelisted, FormatUtils.formatType(cm.getType().toString()));
+ }
+ return;
+ }
+
+ Block target = p.getTargetBlock(Set.of(Material.AIR), 10);
+ CommandBlockHolder wb = main.dir().whitelistManager
+ .getFromList(target.getLocation());
+ if (wb != null) {
+ wb.setWhitelisted(false);
+ String cleanedType = FormatUtils.formatType(SerialLocation.translate(wb.loc()).getBlock().getType().toString());
+ successAny(sender, main.lang().commandBlock.removeSuccess, cleanedType, wb.command());
+ } else {
+ errorAny(sender, main.lang().commandBlock.notWhitelisted, FormatUtils.formatType(target.getType().toString()));
+ }
+ }
+
+ // --- CommandBlock -> AUTO ---
+ private void handleCommandBlockAuto(CommandSender sender) {
+ Player p = getPlayer(sender);
+ if (p == null) return;
+
+ var whitelistManager = main.dir().whitelistManager;
+ if (whitelistManager.autoWhitelist.contains(p.getUniqueId())) {
+ whitelistManager.autoWhitelist.remove(p.getUniqueId());
+ infoAny(sender, main.lang().commandBlock.autoWhitelistOff);
+ } else {
+ whitelistManager.autoWhitelist.add(p.getUniqueId());
+ infoAny(sender, main.lang().commandBlock.autoWhitelistOn);
+ }
+ }
+
+ // --- CommandBlock -> RESTORE ---
+ private void handleCommandBlockRestore(CommandSender sender, Args args) {
+ if (args.getSize() < 3) {
+ infoAny(sender, USAGE_RESTORE);
+ return;
+ }
+ String targetPlayer = args.get(2).toString();
+ if (targetPlayer.equalsIgnoreCase("all")) {
+ int result = main.dir().whitelistManager.restoreAll();
+ successAny(sender, main.lang().commandBlock.restoreSuccess, result);
+ } else {
+ UUID id = Bukkit.getOfflinePlayer(targetPlayer).getUniqueId();
+ int result = main.dir().whitelistManager.restoreAll(id);
+ successAny(sender, main.lang().commandBlock.restorePlayerSuccess, result, targetPlayer);
+ }
+ }
+
+ // --- CommandBlock -> CLEAR ---
+ private void handleCommandBlockClear(CommandSender sender, Args args) {
+ if (args.getSize() < 3) {
+ infoAny(sender, USAGE_CLEAR);
+ return;
+ }
+ String targetPlayer = args.get(2).toString();
+ if (targetPlayer.equalsIgnoreCase("all")) {
+ int result = main.dir().whitelistManager.clearAll();
+ successAny(sender, main.lang().commandBlock.clearSuccess, result);
+ } else {
+ UUID id = Bukkit.getOfflinePlayer(targetPlayer).getUniqueId();
+ int result = main.dir().whitelistManager.clearAll(id);
+ successAny(sender, main.lang().commandBlock.clearPlayerSuccess, result, targetPlayer);
+ }
+ }
+
+ /* =======================
+ Subcommand: DEBUG
+ ======================= */
private void handleDebugCommand(CommandSender sender, Args args) {
- if (!PlayerUtils.checkPermission(sender, "sentinel.debug"))
- return;
+ if (!PlayerUtils.checkPermission(sender, "sentinel.debug")) return;
if (args.getSize() < 2) {
- sender.sendMessage(Text.prefix("Usage: /sentinel debug "));
+ infoAny(sender, "Usage: /sentinel debug ");
return;
}
String sub = args.get(1).toString().toLowerCase();
switch (sub) {
- case "lang" -> sender.sendMessage(Sentinel.lang.brokenLang);
+ case "lang" -> errorAny(sender, main.lang().brokenLang);
case "toggle" -> {
- Sentinel.mainConfig.debugMode = !Sentinel.mainConfig.debugMode;
- String message = Sentinel.mainConfig.debugMode
- ? Sentinel.lang.debug.debugEnabled
- : Sentinel.lang.debug.debugDisabled;
- sender.sendMessage(Text.prefix(message));
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.debugMode = !main.dir().io.mainConfig.debugMode;
+ String message = main.dir().io.mainConfig.debugMode
+ ? main.lang().debug.debugEnabled
+ : main.lang().debug.debugDisabled;
+ infoAny(sender, message);
+ main.dir().io.mainConfig.save();
}
- case "chat" -> {
- if (!PlayerUtils.playerCheck(sender))
- return;
- if (args.getSize() < 3) {
- sender.sendMessage(Text.prefix("Usage: /sentinel debug chat "));
- return;
- }
- Player p = (Player) sender;
- String messageText = args.getAll(2).toString();
- AsyncChatEvent message = new AsyncChatEvent(true,
- p,
- Set.of(p),
- ChatRenderer.defaultRenderer(),
- Component.text(messageText),
- Component.text(messageText),
- SignedMessage.system(messageText, Component.text(messageText))
- );
- UnicodeFilter.handleUnicodeFilter(message);
- UrlFilter.handleUrlFilter(message);
- SpamFilter.handleSpamFilter(message);
- ProfanityFilter.handleProfanityFilter(message);
- if (!message.isCancelled()) {
- sender.sendMessage(Text.prefix(Sentinel.lang.debug.notFlagged));
+ case "chat" -> handleDebugChat(sender, args);
+ case "nbt" -> handleDebugNbt(sender, args);
+ default -> errorAny(sender, main.lang().plugin.invalidSubCommand, "debug");
+ }
+ }
+
+ private void handleDebugNbt(CommandSender sender, Args args) {
+ if (PlayerUtils.isConsoleCheck(sender)) return;
+ if (args.getSize() < 3) {
+ infoAny(sender, "Usage: /sentinel debug nbt ");
+ return;
+ }
+
+ Player p = (Player) sender;
+ String sub = args.get(2).toString().toLowerCase();
+ switch (sub) {
+ case "filter" -> {
+ boolean passes = new ItemCheck().passes(p.getInventory().getItemInMainHand());
+ if (passes) {
+ success(sender,Component.text("Item passes filter."));
+ } else {
+ warning(sender,Component.text("Item flags filter."));
}
}
- default -> sender.sendMessage(Text.prefix(Sentinel.lang.plugin.invalidSubCommand.formatted("debug")));
+ case "store" -> {
+ if (p.getInventory().getItemInMainHand().isEmpty()) {
+ error(sender,Component.text("You must hold the item you wish to store."));
+ return;
+ }
+ main.dir().io.nbtStorage.storeItem(p.getInventory().getItemInMainHand(),p.getUniqueId());
+ success(sender,Component.text("Your item is now visible in the NBT Honeypot."));
+ }
+ case "system" -> {
+ ItemStack i = p.getInventory().getItemInMainHand();
+ if (i == null || i.isEmpty()) {
+ error(sender,Component.text("You must hold an item to test it."));
+ return;
+ }
+ new CreativeHotbar().scan(new InventoryCreativeEvent(p.openInventory(p.getInventory()), InventoryType.SlotType.QUICKBAR,p.getInventory().getHeldItemSlot(),i),p,i);
+ p.closeInventory();
+ success(sender,Component.text("Scanned your item."));
+ }
+ }
+ }
+
+ private void handleDebugChat(CommandSender sender, Args args) {
+ if (PlayerUtils.isConsoleCheck(sender)) return;
+ if (args.getSize() < 3) {
+ infoAny(sender, "Usage: /sentinel debug chat ");
+ return;
+ }
+ Player p = (Player) sender;
+ String messageText = args.getAll(2).toString();
+ AsyncChatEvent chatEvent = new AsyncChatEvent(true,
+ p,
+ Set.of(p),
+ ChatRenderer.defaultRenderer(),
+ Component.text(messageText),
+ Component.text(messageText),
+ SignedMessage.system(messageText, Component.text(messageText))
+ );
+ UnicodeFilter.handleUnicodeFilter(chatEvent);
+ UrlFilter.handleUrlFilter(chatEvent);
+ SpamFilter.handleSpamFilter(chatEvent);
+ ProfanityFilter.handleProfanityFilter(chatEvent);
+ if (!chatEvent.isCancelled()) {
+ successAny(sender, main.lang().debug.notFlagged);
}
}
+ /* =======================
+ Subcommand: FALSE-POSITIVE
+ ======================= */
private void handleFalsePositive(CommandSender sender, Args args) {
if (args.getSize() < 2) {
- sender.sendMessage(Text.prefix("Usage: /sentinel false-positive "));
+ infoAny(sender, "Usage: /sentinel false-positive ");
return;
}
- if (!PlayerUtils.checkPermission(sender, "sentinel.false-positive"))
- return;
+ if (!PlayerUtils.checkPermission(sender, "sentinel.false-positive")) return;
String sub = args.get(1).toString().toLowerCase();
String falsePositive = args.getAll(2).toString();
+
Node root = new Node("Sentinel");
root.addTextLine("False Positive Management Log");
Node info = new Node("Info");
info.addKeyValue("User", sender.getName());
+
switch (sub) {
case "add" -> {
- if (!PlayerUtils.checkPermission(sender,"sentinel.false-positive.add")) return;
- Sentinel.fpConfig.swearWhitelist.add(falsePositive);
- sender.sendMessage(Text.prefix(Sentinel.lang.falsePositive.addSuccess.formatted(falsePositive)));
+ if (!PlayerUtils.checkPermission(sender, "sentinel.false-positive.add")) return;
+ main.dir().io.falsePositiveList.swearWhitelist.add(falsePositive);
+ successAny(sender, main.lang().falsePositive.addSuccess, falsePositive);
info.addKeyValue("Action", "Add");
}
case "remove" -> {
- if (!PlayerUtils.checkPermission(sender,"sentinel.false-positive.remove")) return;
- Sentinel.fpConfig.swearWhitelist.remove(falsePositive);
- sender.sendMessage(Text.prefix(Sentinel.lang.falsePositive.removeSuccess.formatted(falsePositive)));
+ if (!PlayerUtils.checkPermission(sender, "sentinel.false-positive.remove")) return;
+ main.dir().io.falsePositiveList.swearWhitelist.remove(falsePositive);
+ successAny(sender, main.lang().falsePositive.removeSuccess, falsePositive);
info.addKeyValue("Action", "Remove");
}
default -> {
- sender.sendMessage(Text.prefix(Sentinel.lang.plugin.invalidSubCommand.formatted("false-positive")));
+ errorAny(sender, main.lang().plugin.invalidSubCommand, "false-positive");
return;
}
}
info.addKeyValue("False Positive Edited", falsePositive);
root.addChild(info);
- Sentinel.fpConfig.save();
- Sentinel.log.info(ConsoleFormatter.format(root));
+ main.dir().io.falsePositiveList.save();
+ main.getLogger().info(ConsoleFormatter.format(root));
EmbedFormatter.sendEmbed(EmbedFormatter.format(root));
}
+ /* =======================
+ Subcommand: SOCIALSPY
+ ======================= */
private void handleSocialSpy(CommandSender sender) {
- if (!PlayerUtils.playerCheck(sender))
- return;
- if (!PlayerUtils.checkPermission(sender, "sentinel.socialspy"))
- return;
+ if (PlayerUtils.isConsoleCheck(sender)) return;
+ if (!PlayerUtils.checkPermission(sender, "sentinel.socialspy")) return;
Player p = (Player) sender;
UUID senderID = p.getUniqueId();
boolean enabled = spyMap.getOrDefault(senderID, false);
if (!enabled) {
- sender.sendMessage(Text.prefix(Sentinel.lang.socialSpy.enabled));
+ infoAny(sender, main.lang().socialSpy.enabled);
spyMap.put(senderID, true);
} else {
- sender.sendMessage(Text.prefix(Sentinel.lang.socialSpy.disabled));
+ infoAny(sender, main.lang().socialSpy.disabled);
spyMap.put(senderID, false);
}
}
+ /* =======================
+ Lite Mode Handler
+ ======================= */
private void handleLiteMessage(CommandSender sender, Args args) {
if (!args.isEmpty() && args.get(0).toString().equalsIgnoreCase("reload")) {
- if (sender instanceof Player p && !PlayerUtils.isTrusted(p)) {
- sender.sendMessage(Text.prefix(Sentinel.lang.permissions.noTrust));
+ if (!PlayerUtils.isTrusted(sender)) {
+ errorAny(sender, main.lang().permissions.noTrust);
return;
}
- Sentinel.log.info("Sentinel is now reloading the config in lite mode.");
- sender.sendMessage(Text.prefix(Sentinel.lang.plugin.reloadingConfigLite));
- Sentinel.getInstance().loadConfig();
+ main.getLogger().info("Sentinel is now reloading the config in lite mode.");
+ infoAny(sender, main.lang().plugin.reloadingConfigLite);
+ main.dir().io.loadConfig();
- if (Load.load(Sentinel.getInstance().license, Sentinel.getInstance().identifier, false)) {
+ if (main.dir().loader.load(main.getPlugin().license, main.getPlugin().identifier, false)) {
return;
}
- Sentinel.log.info("Re-authentication Failed.");
+ main.getLogger().info("Re-authentication Failed.");
} else {
- sender.sendMessage(Load.liteMode);
+ warningAny(sender, Loader.LITE_MODE);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/commands/TrapCommand.java b/src/main/java/me/trouper/sentinel/server/commands/TrapCommand.java
index 196c584..9218db3 100644
--- a/src/main/java/me/trouper/sentinel/server/commands/TrapCommand.java
+++ b/src/main/java/me/trouper/sentinel/server/commands/TrapCommand.java
@@ -5,25 +5,23 @@ import io.github.itzispyder.pdk.commands.CommandRegistry;
import io.github.itzispyder.pdk.commands.CustomCommand;
import io.github.itzispyder.pdk.commands.completions.CompletionBuilder;
import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.utils.OldTXT;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@CommandRegistry(value = "sentineltab")
-public class TrapCommand implements CustomCommand {
+public class TrapCommand implements QuickCommand {
@Override
public void dispatchCommand(CommandSender commandSender, Command command, String s, Args args) {
- commandSender.sendMessage(Component.text(Text.prefix("https://www.youtube.com/watch?v=4F4qzPbcFiA")).clickEvent(ClickEvent.openUrl("https://www.youtube.com/watch?v=4F4qzPbcFiA")));
+ message(commandSender,Component.text("https://www.youtube.com/watch?v=4F4qzPbcFiA").clickEvent(ClickEvent.openUrl("https://www.youtube.com/watch?v=4F4qzPbcFiA")));
}
@Override
public void dispatchCompletions(CommandSender commandSender, Command command, String s, CompletionBuilder b) {
- ServerUtils.verbose("Listing the fake plugins: %s".formatted(Sentinel.advConfig.fakePlugins));
- b.then(b.arg(Sentinel.advConfig.fakePlugins));
+ b.then(b.arg(main.dir().io.advConfig.fakePlugins));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/AbstractExtra.java b/src/main/java/me/trouper/sentinel/server/commands/extras/AbstractExtra.java
new file mode 100644
index 0000000..3e65a3b
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/AbstractExtra.java
@@ -0,0 +1,26 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import me.trouper.sentinel.server.Main;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public abstract class AbstractExtra implements Main {
+ private final String name;
+ private final String description;
+
+ public AbstractExtra(String name, String description) {
+ this.name = name;
+ this.description = description;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public abstract void execute(CommandSender sender, Player target);
+ public abstract void stop(CommandSender sender, Player target);
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/BlockShuffler.java b/src/main/java/me/trouper/sentinel/server/commands/extras/BlockShuffler.java
new file mode 100644
index 0000000..4c8c7d1
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/BlockShuffler.java
@@ -0,0 +1,69 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.protocol.player.User;
+import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
+import com.github.retrooper.packetevents.util.Vector3i;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBlockChange;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class BlockShuffler extends AbstractExtra {
+ public BlockShuffler() {
+ super("blocks","Cube of random");
+ }
+
+ private final List scrambleBlocks = new ArrayList<>();
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ scrambleBlocks.add(target.getUniqueId());
+ User user = PacketEvents.getAPI().getPlayerManager().getUser(target);
+
+ int x = target.getLocation().getBlockX();
+ int y = target.getLocation().getBlockY();
+ int z = target.getLocation().getBlockZ();
+
+ List blockMaterials = new ArrayList<>(Arrays.stream(Material.values())
+ .filter(Material::isBlock)
+ .toList());
+ Collections.shuffle(blockMaterials);
+ ConcurrentLinkedQueue stateQueue = new ConcurrentLinkedQueue<>();
+
+ blockMaterials.forEach(material -> stateQueue.add(SpigotConversionUtil.fromBukkitBlockData(Bukkit.createBlockData(material))));
+
+ int radius = 8;
+ Bukkit.getScheduler().runTaskTimerAsynchronously(main.getPlugin(),task -> {
+ for (int xValue = x - radius; xValue < x + radius; xValue++) {
+ for (int yValue = y - radius; yValue < y + radius; yValue++) {
+ for (int zValue = z - radius; zValue < z + radius; zValue++) {
+ if (!scrambleBlocks.contains(target.getUniqueId())) {
+ task.cancel();
+ return;
+ }
+ var blockState = stateQueue.poll();
+ stateQueue.offer(blockState);
+
+ WrapperPlayServerBlockChange blockChange = new WrapperPlayServerBlockChange(new Vector3i(xValue,yValue,zValue),blockState.getGlobalId());
+ blockChange.setBlockState(blockState);
+ user.sendPacket(blockChange);
+ }
+ }
+ }
+ },0,5);
+
+ successAny(sender,"Scrambling {0}'s blocks.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ scrambleBlocks.remove(target.getUniqueId());
+ errorAny(sender,"Stopped scrambling {0}'s blocks.",target.getUniqueId());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/BookExtra.java b/src/main/java/me/trouper/sentinel/server/commands/extras/BookExtra.java
new file mode 100644
index 0000000..45d97f1
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/BookExtra.java
@@ -0,0 +1,57 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
+import com.github.retrooper.packetevents.protocol.player.InteractionHand;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenBook;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetSlot;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTitle;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
+import me.trouper.sentinel.utils.ImageUtils;
+import net.kyori.adventure.inventory.Book;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.BookMeta;
+import org.bukkit.inventory.meta.ItemMeta;
+
+public class BookExtra extends AbstractExtra {
+
+ public BookExtra() {
+ super("book", "Sends the player a book :3");
+ }
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ ItemStack bookItem = new ItemStack(Material.WRITTEN_BOOK);
+ ItemMeta bookItemMeta = bookItem.getItemMeta();
+ BookMeta bookMeta = (BookMeta) bookItemMeta;
+
+ bookMeta.author(Component.text("The Boykisser"));
+ bookMeta.title(Component.text("Book :3"));
+ bookMeta.addPages(Component.text("""
+ You like kissing boys don't you?
+ ⢸⠂⠀⠀⠀⠘⣧⠀⠀⣟⠛⠲⢤⡀⠀⠀⣰⠏⠀⠀⠀⠀⠀⢹⡀
+ ⠀⡿⠀⠀⠀⠀⠀⠈⢷⡀⢻⡀⠀⠀⠙⢦⣰⠏⠀⠀⠀⠀⠀⠀⢸⠀
+ ⠀⡇⠀⠀⠀⠀⠀⠀⢀⣻⠞⠛⠀⠀⠀⠀⠻⠀⠀⠀⠀⠀⠀⠀⢸⠀
+ ⠀⡇⠀⠀⠀⠀⠀⠀⠛⠓⠒⠓⠓⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀
+ ⠀⢿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣀⣀⠀⠀⢀⡟⠀
+ ⠀⠘⣇⠀⠘⣿⠋⢹⠛⣿⡇⠀⠀⠀⠀⣿⣿⡇⠀⢳⠉⠀⣠⡾⠁⠀
+ ⣦⣤⣽⣆⢀⡇⠀⢸⡇⣾⡇⠀⠀⠀⠀⣿⣿⡷⠀⢸⡇⠐⠛⠛⣿⠀
+ ⠹⣦⠀⠀⠸⡇⠀⠸⣿⡿⠁⢀⡀⠀⠀⠿⠿⠃⠀⢸⠇⠀⢀⡾⠁⠀
+ ⠀⠈⡿⢠⢶⣡⡄⠀⠀⠀⠀⠉⠁⠀⠀⠀⠀⠀⣴⣧⠆⠀⢻⡄⠀⠀
+ ⠀⢸⠃⠀⠘⠉⠀⠀⠀⠠⣄⡴⠲⠶⠴⠃⠀⠀⠀⠉⡀⠀⠀⢻⡄⠀
+ ⠀⠘⠒⠒⠻⢦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⠞⠛⠒⠛⠋⠁⠀
+ ⠀⠀⠀⠀⠀⠀⠸⣟⠓⠒⠂⠀⠀⠀⠀⠀⠈⢷⡀⠀⠀⠀⠀⠀⠀⠀
+ """));
+
+ target.openBook(bookItem);
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ infoAny(sender,"You can't un-read something...");
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/CorruptChunks.java b/src/main/java/me/trouper/sentinel/server/commands/extras/CorruptChunks.java
new file mode 100644
index 0000000..d3a75d0
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/CorruptChunks.java
@@ -0,0 +1,48 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUnloadChunk;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import me.trouper.sentinel.Sentinel;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+public class CorruptChunks extends AbstractExtra {
+
+ public CorruptChunks() {
+ super("corrupt","Unload chunks around player");
+ }
+
+ private final List corrupted = new ArrayList<>();
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ corrupted.add(target.getUniqueId());
+ Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(), (t) -> {
+ if (!target.isOnline() || !corrupted.contains(target.getUniqueId())) {
+ t.cancel();
+ return;
+ }
+ for (int i = 0; i < 50; i++) {
+ int chunkX = (target.getLocation().getBlockX() >> 4) + i;
+ int chunkZ = (target.getLocation().getBlockZ() >> 4) + i;
+ player.sendPacket(new WrapperPlayServerUnloadChunk(chunkX, chunkZ));
+ }
+ }, 1, 1);
+ successAny(sender,"Corrupting {0}'s chunks.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ corrupted.remove(player.getUUID());
+ player.sendPacket(new WrapperPlayServerUpdateViewDistance(Bukkit.getViewDistance()));
+ successAny(sender,"Attempting to save {0}.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/DeletePlayer.java b/src/main/java/me/trouper/sentinel/server/commands/extras/DeletePlayer.java
new file mode 100644
index 0000000..bf64ffa
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/DeletePlayer.java
@@ -0,0 +1,74 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.protocol.player.GameMode;
+import com.github.retrooper.packetevents.protocol.world.Difficulty;
+import com.github.retrooper.packetevents.protocol.world.WorldBlockPosition;
+import com.github.retrooper.packetevents.protocol.world.dimension.DimensionType;
+import com.github.retrooper.packetevents.resources.ResourceLocation;
+import com.github.retrooper.packetevents.util.Vector3d;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import io.github.retrooper.packetevents.util.SpigotConversionUtil;
+import org.apache.commons.lang3.builder.Diff;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.Optional;
+
+public class DeletePlayer extends AbstractExtra {
+
+ public DeletePlayer() {
+ super("delete","Tell player's client to self delete");
+ }
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ player.sendPacket(new WrapperPlayServerDestroyEntities(target.getEntityId()));
+ successAny(sender,"Deleting {0}.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ var playerSpawn = new WrapperPlayServerSpawnEntity(
+ target.getEntityId(),
+ Optional.of(target.getUniqueId()),
+ EntityTypes.PLAYER,
+ new Vector3d(),
+ target.getLocation().getYaw(),
+ target.getLocation().getPitch(),
+ target.getLocation().getYaw(),
+ 0,
+ Optional.of(new Vector3d(0,0,0)
+ )
+ );
+ String world = target.getWorld().getName();
+ Difficulty difficulty = Difficulty.valueOf(target.getWorld().getDifficulty().toString());
+ GameMode gameMode = GameMode.valueOf(target.getGameMode().toString());
+ ResourceLocation location = new ResourceLocation(player.getDimension().getDimensionName());
+ WorldBlockPosition position = new WorldBlockPosition(location,target.getLocation().getBlockX(),target.getLocation().getBlockY(),target.getLocation().getBlockZ());
+ WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(
+ player.getDimensionType(),
+ world,
+ difficulty,
+ 0L,
+ gameMode,
+ gameMode,
+ false,
+ false,
+ true,
+ location,
+ position,
+ 0
+ );
+ player.sendPacket(respawn);
+ successAny(sender,"Attempting to restore {0}. If it does not work just kick them or tell them to leave.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/DemoScreenCrash.java b/src/main/java/me/trouper/sentinel/server/commands/extras/DemoScreenCrash.java
new file mode 100644
index 0000000..c41c430
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/DemoScreenCrash.java
@@ -0,0 +1,46 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChangeGameState;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerCloseWindow;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import me.trouper.sentinel.Sentinel;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+public class DemoScreenCrash extends AbstractExtra {
+
+ public DemoScreenCrash() {
+ super("demo","Lock player's mouse and crash them");
+ }
+
+ private final List demoCrash = new ArrayList<>();
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ demoCrash.add(target.getUniqueId());
+ Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(), (t) -> {
+ if (!target.isOnline() || !demoCrash.contains(target.getUniqueId())) {
+ t.cancel();
+ return;
+ }
+ for (int i = 0; i < 35 * 9; i++) {
+ player.sendPacket(new WrapperPlayServerCloseWindow());
+ player.sendPacket(new WrapperPlayServerChangeGameState(WrapperPlayServerChangeGameState.Reason.DEMO_EVENT, 0));
+ }
+ }, 1, 1);
+ successAny(sender,"Freezing {0}.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ demoCrash.remove(target.getUniqueId());
+ successAny(sender,"Attempting to save {0}.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/EntitySpamCrash.java b/src/main/java/me/trouper/sentinel/server/commands/extras/EntitySpamCrash.java
new file mode 100644
index 0000000..eba0139
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/EntitySpamCrash.java
@@ -0,0 +1,96 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
+import com.github.retrooper.packetevents.util.Vector3d;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
+import me.trouper.sentinel.Sentinel;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+
+public class EntitySpamCrash extends AbstractExtra {
+
+ public EntitySpamCrash() {
+ super("entity","Spam player with bogus entities");
+ }
+
+ private final Map entityCrash = new HashMap<>();
+
+ public class EntityCache {
+ private final int startingId;
+ private int highestId;
+
+ public EntityCache(int startingId) {
+ this.highestId = startingId;
+ this.startingId = startingId;
+ }
+
+ public int getStartingId() {
+ return startingId;
+ }
+
+ public int getHighestId() {
+ return highestId;
+ }
+
+ public void setHighestId(int highestId) {
+ this.highestId = highestId;
+ }
+
+ public void incrementHighest() {
+ this.highestId = this.highestId + 1;
+ }
+ }
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ EntityCache cache = new EntityCache(target.getWorld().getEntityCount());
+ Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(), (t) -> {
+ if (!target.isOnline() || !entityCrash.containsKey(target.getUniqueId())) {
+ t.cancel();
+ }
+ for (int i = 0; i < 100; i++) {
+ cache.incrementHighest();
+ WrapperPlayServerSpawnEntity packet = new WrapperPlayServerSpawnEntity(
+ cache.getHighestId(),
+ Optional.of(UUID.randomUUID()),
+ EntityTypes.ENDER_DRAGON,
+ new Vector3d(target.getLocation().getX(), target.getLocation().getY(), target.getLocation().getZ()),
+ 0F,
+ 0F,
+ 0F,
+ 0,
+ Optional.of(new Vector3d(0, 0, 0))
+ );
+ player.sendPacket(packet);
+ }
+ }, 1, 1);
+ successAny(sender,"Summoning entities on {0}.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ if (!entityCrash.containsKey(player.getUUID())) {
+ errorAny(sender,"{0} is not being crashed.",target.getName());
+ return;
+ }
+ EntityCache cache = entityCrash.get(player.getUUID());
+ int lowest = cache.getStartingId();
+ int highest = cache.getHighestId();
+
+ int[] entities = new int[highest - lowest];
+ for (int i = lowest; i < highest; i++) {
+ entities[i - lowest] = i;
+ }
+
+ player.sendPacket(new WrapperPlayServerDestroyEntities(entities));
+ entityCrash.remove(player.getUUID());
+ successAny(sender,"Attempting to save {0}.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/KickTroll.java b/src/main/java/me/trouper/sentinel/server/commands/extras/KickTroll.java
new file mode 100644
index 0000000..5c8a561
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/KickTroll.java
@@ -0,0 +1,56 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import me.trouper.sentinel.data.types.IPLocation;
+import me.trouper.sentinel.utils.IPUtils;
+import me.trouper.sentinel.utils.ImageUtils;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerKickEvent;
+
+public class KickTroll extends AbstractExtra {
+
+ public KickTroll() {
+ super("kick","Kick the player with no back button");
+ }
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ String beforeLines = "\n".repeat(15 * 100 + 3);
+ String afterLines = "\n".repeat(15 * 100);
+
+ Component image = Component.text("\n");
+ for (Component component : ImageUtils.makeImage("https://r2.e-z.host/d440b58a-ba90-4839-8df6-8bba298cf817/x1ksxaas.png")) {
+ image = image.appendNewline().append(component);
+ }
+ String header = "Sorry %1$s!\nLooks like you're a griefer... \n...and this is a decoy server\nYour presence has been recorded. \n\nHow's the weather in %2$s, %3$s? \n";
+ String footer = "\n\nWant to try again?\n Nope. No back to server list for you.\n\nCopyright © 2025 Sentinel Anti Nuke. All rights reserved.\n";
+ String name = target.getName();
+ String ip = IPUtils.extractIp(target.getAddress().getAddress());
+ IPLocation location = IPUtils.getLocation(ip);
+ String region = location.getRegion();
+ String city = location.getCity();
+ target.kick(Component.text(beforeLines)
+ .append(Component.text(
+ header.formatted(
+ name,
+ city,
+ region
+ )))
+ .append(image)
+ .append(Component.text(
+ footer + afterLines
+ )
+ ),
+ PlayerKickEvent.Cause.ILLEGAL_ACTION);
+ successAny(sender,"Kicked {0} and removed the back to server list button. Their IP was {1} ({2}, {3})",target.getName(), ip, city, region);
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ errorAny(sender,"You cannot un-kick someone!");
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/MessageSpamCrash.java b/src/main/java/me/trouper/sentinel/server/commands/extras/MessageSpamCrash.java
new file mode 100644
index 0000000..d2b6551
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/MessageSpamCrash.java
@@ -0,0 +1,43 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChatMessage;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import me.trouper.sentinel.Sentinel;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+public class MessageSpamCrash extends AbstractExtra {
+
+ public MessageSpamCrash() {
+ super("spam","Crash player by spamming chat message");
+ }
+
+ private final List chatCrash = new ArrayList<>();
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ chatCrash.add(target.getUniqueId());
+ Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(), (t) -> {
+ if (!target.isOnline() || !chatCrash.contains(target.getUniqueId())) {
+ t.cancel();
+ return;
+ }
+ for (int i = 0; i < 4000; i++) {
+ target.sendMessage(":3 Baiiiiii!!!!"); // This "sendMessage" can stay
+ }
+ }, 1, 1);
+ successAny(sender,"Filling the logs of {0}.",target);
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ chatCrash.remove(target.getUniqueId());
+ successAny(sender,"Attempting to save {0}.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/ShadowRealm.java b/src/main/java/me/trouper/sentinel/server/commands/extras/ShadowRealm.java
new file mode 100644
index 0000000..9971877
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/ShadowRealm.java
@@ -0,0 +1,36 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import me.trouper.sentinel.data.types.SerialLocation;
+import me.trouper.sentinel.server.events.extras.ShadowRealmEvents;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class ShadowRealm extends AbstractExtra {
+
+ public ShadowRealm() {
+ super("shadow","Send player to the shadow realm");
+ }
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ main.dir().io.extraStorage.shadowRealm.put(target.getUniqueId(), SerialLocation.translate(target.getLocation()));
+ main.dir().io.extraStorage.save();
+ ShadowRealmEvents.enforce(target);
+ successAny(sender,"Sending {0} to the shadow realm.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ if (main.dir().io.extraStorage.shadowRealm.containsKey(target.getUniqueId())) {
+ Location to = SerialLocation.translate(main.dir().io.extraStorage.shadowRealm.get(target.getUniqueId()));
+ main.dir().io.extraStorage.shadowRealm.remove(target.getUniqueId());
+ main.dir().io.extraStorage.save();
+ target.teleport(to);
+ }
+ successAny(sender,"Released {0}.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/SleepyPlayer.java b/src/main/java/me/trouper/sentinel/server/commands/extras/SleepyPlayer.java
new file mode 100644
index 0000000..2c57cf6
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/SleepyPlayer.java
@@ -0,0 +1,39 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import me.trouper.sentinel.Sentinel;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+public class SleepyPlayer extends AbstractExtra {
+
+ public SleepyPlayer() {
+ super("eepy","Make player's screen dim rapidly");
+ }
+
+ private final List eepyPlayers = new ArrayList<>();
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ eepyPlayers.add(target.getUniqueId());
+ Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(), (t) -> {
+ if (!eepyPlayers.contains(target.getUniqueId())) t.cancel();
+ player.sendPacket(new WrapperPlayServerEntityAnimation(target.getEntityId(), WrapperPlayServerEntityAnimation.EntityAnimationType.WAKE_UP));
+ }, 1, 1);
+ successAny(sender,"{0} is getting very eepy.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ eepyPlayers.remove(target.getUniqueId());
+ successAny(sender,"Gave {0} some coffee, and they are waking up now.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/commands/extras/ViewDistanceCrash.java b/src/main/java/me/trouper/sentinel/server/commands/extras/ViewDistanceCrash.java
new file mode 100644
index 0000000..6ff8ca1
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/commands/extras/ViewDistanceCrash.java
@@ -0,0 +1,28 @@
+package me.trouper.sentinel.server.commands.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateViewDistance;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class ViewDistanceCrash extends AbstractExtra {
+
+ public ViewDistanceCrash() {
+ super("view","A reliable player crash");
+ }
+
+ @Override
+ public void execute(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ player.sendPacket(new WrapperPlayServerUpdateViewDistance(32000));
+ successAny(sender,"Crashing {0}.",target.getName());
+ }
+
+ @Override
+ public void stop(CommandSender sender, Player target) {
+ var player = PacketEvents.getAPI().getPlayerManager().getUser(target);
+ player.sendPacket(new WrapperPlayServerUpdateViewDistance(Bukkit.getViewDistance()));
+ successAny(sender,"Attempting to save {0}.",target.getName());
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/ChatEvent.java b/src/main/java/me/trouper/sentinel/server/events/ChatEvent.java
deleted file mode 100644
index 9cb6b7a..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/ChatEvent.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import io.github.itzispyder.pdk.utils.SchedulerUtils;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.chatfilter.profanity.ProfanityFilter;
-import me.trouper.sentinel.server.functions.chatfilter.spam.SpamFilter;
-import me.trouper.sentinel.server.functions.chatfilter.unicode.UnicodeFilter;
-import me.trouper.sentinel.server.functions.chatfilter.url.UrlFilter;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.chat.ProfanityFilterGUI;
-import me.trouper.sentinel.server.gui.config.chat.SpamFilterGUI;
-import me.trouper.sentinel.server.gui.config.chat.UnicodeFilterGUI;
-import me.trouper.sentinel.server.gui.config.chat.UrlFilterGUI;
-import me.trouper.sentinel.server.gui.config.nuke.checks.*;
-import me.trouper.sentinel.server.gui.config.nuke.checks.command.DangerousCMDGUI;
-import me.trouper.sentinel.server.gui.config.nuke.checks.command.LoggedCMDGUI;
-import me.trouper.sentinel.server.gui.config.nuke.checks.command.SpecificCMDGUI;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-
-import java.util.function.Consumer;
-
-public class ChatEvent implements CustomListener {
-
- @EventHandler
- private void onChat(AsyncChatEvent e) {
- ServerUtils.verbose("Chat event sanity check:\n Canceled %s".formatted(e.isCancelled()));
- handleEvent(e);
- }
-
- public void handleEvent(AsyncChatEvent e) {
- if (e.isCancelled()) return;
- if (PlayerUtils.isTrusted(e.getPlayer().getUniqueId().toString())) {
- if (MainGUI.awaitingCallback.contains(e.getPlayer().getUniqueId())) {
- ServerUtils.verbose("Attempting to cancel events for callback!");
- e.setCancelled(true);
- MainGUI.awaitingCallback.remove(e.getPlayer().getUniqueId());
- ServerUtils.verbose("Handling Chat Event for callbacks");
- SchedulerUtils.later(0,()->{
- UnicodeFilterGUI.updater.invokeCallbacks(e);
- UrlFilterGUI.updater.invokeCallbacks(e);
- ProfanityFilterGUI.updater.invokeCallbacks(e);
- SpamFilterGUI.updater.invokeCallbacks(e);
- DangerousCMDGUI.updater.invokeCallbacks(e);
- LoggedCMDGUI.updater.invokeCallbacks(e);
- SpecificCMDGUI.updater.invokeCallbacks(e);
- CBEditGUI.updater.invokeCallbacks(e);
- CBMCPlaceGUI.updater.invokeCallbacks(e);
- CBMCUseGUI.updater.invokeCallbacks(e);
- CBPlaceGUI.updater.invokeCallbacks(e);
- CBUseGUI.updater.invokeCallbacks(e);
- HotbarActionGUI.updater.invokeCallbacks(e);
- });
- }
- return;
- }
-
- Player p = e.getPlayer();
-
- ServerUtils.verbose("Chat event start after trust check:\n Canceled %s".formatted(e.isCancelled()));
-
- handle(p,
- "sentinel.chatfilter.unicode.bypass",
- Sentinel.mainConfig.chat.unicodeFilter.enabled, "unicode",
- e,
- UnicodeFilter::handleUnicodeFilter);
-
- ServerUtils.verbose("Chat event middle after unicode:\n Canceled %s".formatted(e.isCancelled()));
-
- handle(p,
- "sentinel.chatfilter.url.bypass",
- Sentinel.mainConfig.chat.urlFilter.enabled, "url",
- e,
- UrlFilter::handleUrlFilter);
-
- ServerUtils.verbose("Chat event middle after URL:\n Canceled %s".formatted(e.isCancelled()));
-
- handle(p,
- "sentinel.chatfilter.spam.bypass",
- Sentinel.mainConfig.chat.spamFilter.enabled,
- "spam",
- e,
- SpamFilter::handleSpamFilter);
-
- ServerUtils.verbose("Chat event middle after spam:\n Canceled %s".formatted(e.isCancelled()));
-
- handle(p,
- "sentinel.chatfilter.swear.bypass",
- Sentinel.mainConfig.chat.profanityFilter.enabled,
- "swear",
- e,
- ProfanityFilter::handleProfanityFilter);
-
- ServerUtils.verbose("Chat event ending after swear:\n Canceled %s".formatted(e.isCancelled()));
- }
-
- private static void handle(Player p, String permission, boolean isEnabled, String eventType, AsyncChatEvent e, Consumer handler) {
- ServerUtils.verbose("Handeling a chat filter:\n Canceled %s\nType: %s".formatted(e.isCancelled(),eventType));
- if (e.isCancelled()) return;
- if (p.hasPermission(permission)) return;
- ServerUtils.verbose("ChatEvent: Permission bypass failed, checking for " + eventType);
- if (!isEnabled) return;
- ServerUtils.verbose("ChatEvent: " + eventType + " check enabled, continuing!");
- handler.accept(e);
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/events/CommandBlockEdit.java b/src/main/java/me/trouper/sentinel/server/events/CommandBlockEdit.java
deleted file mode 100644
index d30bb1a..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CommandBlockEdit.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.server.functions.helpers.CBWhitelistManager;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.trees.Node;
-import org.bukkit.Material;
-import org.bukkit.block.Block;
-import org.bukkit.block.BlockState;
-import org.bukkit.block.CommandBlock;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.entity.EntityChangeBlockEvent;
-
-public class CommandBlockEdit extends AbstractViolation {
-
- @EventHandler
- private void onCMDBlockChange(EntityChangeBlockEvent e) {
- //ServerUtils.verbose("CommandBlockChange: Detected the event");
- if (!Sentinel.violationConfig.commandBlockEdit.enabled) return;
- //ServerUtils.verbose("CommandBlockChange: Enabled");
- if (!(e.getEntity() instanceof Player p)) return;
- //ServerUtils.verbose("CommandBlockChange: Changer is a player");
- Block b = e.getBlock();
- if (!(b.getType() == Material.COMMAND_BLOCK || b.getType() == Material.REPEATING_COMMAND_BLOCK || b.getType() == Material.CHAIN_COMMAND_BLOCK))
- return;
- ServerUtils.verbose("CommandBlockChange: Block is a command block");
- CommandBlock cb = (CommandBlock) b.getState();
- if (PlayerUtils.isTrusted(p)) {
- if (!CBWhitelistManager.autoWhitelist.contains(p.getUniqueId())) return;
- CBWhitelistManager.add(cb, p.getUniqueId());
- return;
- }
- ServerUtils.verbose("CommandBlockChange: Not trusted, performing action");
-
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .deop(Sentinel.violationConfig.commandBlockEdit.deop)
- .cancel(true)
- .punish(Sentinel.violationConfig.commandBlockEdit.punish)
- .setPunishmentCommands(Sentinel.violationConfig.commandBlockEdit.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.commandBlockEdit.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.edit, Sentinel.lang.violations.protections.rootName.commandBlock),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.edit, Sentinel.lang.violations.protections.rootName.commandBlock),
- generateCommandBlockInfo(cb),
- config
- );
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/events/CommandBlockExecute.java b/src/main/java/me/trouper/sentinel/server/events/CommandBlockExecute.java
deleted file mode 100644
index 5d4a391..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CommandBlockExecute.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.server.functions.helpers.CBWhitelistManager;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import org.bukkit.Material;
-import org.bukkit.block.Block;
-import org.bukkit.block.CommandBlock;
-import org.bukkit.command.BlockCommandSender;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.server.ServerCommandEvent;
-
-public class CommandBlockExecute extends AbstractViolation {
-
- @EventHandler
- private void commandBlockExecute(ServerCommandEvent e) {
- //ServerUtils.verbose("Handling command block event: " + e.getCommand());
- if (!Sentinel.violationConfig.commandBlockExecute.enabled) return;
- //ServerUtils.verbose("Whitelist not disabled ");
- if (!(e.getSender() instanceof BlockCommandSender s)) return;
- //ServerUtils.verbose("Sender is command block");
- Block cmdBlock = s.getBlock();
- if (CBWhitelistManager.canRun(cmdBlock)) return;
- ServerUtils.verbose("Command block can't run.");
-
- CommandBlock cb = (CommandBlock) cmdBlock.getState();
-
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setBlock(cmdBlock)
- .cancel(true)
- .destroyBlock(Sentinel.violationConfig.commandBlockExecute.destroyBlock)
- .restoreBlock(Sentinel.violationConfig.commandBlockExecute.attemptRestore)
- .logToDiscord(Sentinel.violationConfig.commandBlockExecute.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormat.formatted(Sentinel.lang.violations.protections.rootName.commandBlockWhitelist),
- Sentinel.lang.violations.protections.rootName.rootNameFormat.formatted( Sentinel.lang.violations.protections.rootName.commandBlockWhitelist),
- generateCommandBlockInfo(cb),
- config
- );
- }
-}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/CommandBlockMinecartPlace.java b/src/main/java/me/trouper/sentinel/server/events/CommandBlockMinecartPlace.java
deleted file mode 100644
index 35dc6f9..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CommandBlockMinecartPlace.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import org.bukkit.Material;
-import org.bukkit.block.Block;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.player.PlayerInteractEvent;
-
-public class CommandBlockMinecartPlace extends AbstractViolation {
-
- @EventHandler
- private void onCMDMinecartPlace(PlayerInteractEvent e) {
- //ServerUtils.verbose("MinecartCommandPlace: Detected interaction");
- if (!Sentinel.violationConfig.commandBlockMinecartPlace.enabled) return;
- //ServerUtils.verbose("MinecartCommandPlace: Check is enabled");
- Player p = e.getPlayer();
- if (!p.isOp()) return;
- //ServerUtils.verbose("MinecartCommandPlace: Player is op");
- if (e.getItem() == null) return;
- ServerUtils.verbose("MinecartCommandPlace: Item isn't null");
- if (e.getClickedBlock() == null) return;
- ServerUtils.verbose("MinecartCommandPlace: Clicked block isn't null");
- if (!e.getItem().getType().equals(Material.COMMAND_BLOCK_MINECART)) return;
- ServerUtils.verbose("MinecartCommandPlace: Item is a minecart command");
- if (!(e.getClickedBlock().getType() == Material.RAIL || e.getClickedBlock().getType() == Material.POWERED_RAIL || e.getClickedBlock().getType() == Material.ACTIVATOR_RAIL || e.getClickedBlock().getType() == Material.DETECTOR_RAIL)) return;
- ServerUtils.verbose("MinecartCommandPlace: Clicked block is a rail");
- if (PlayerUtils.isTrusted(p)) return;
- ServerUtils.verbose("MinecartCommandPlace: Not trusted, performing action");
-
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .cancel(true)
- .punish(Sentinel.violationConfig.commandBlockMinecartPlace.punish)
- .deop(Sentinel.violationConfig.commandBlockMinecartPlace.deop)
- .setPunishmentCommands(Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord);
-
- // Remove the command block minecart from the player's inventory
- p.getInventory().remove(Material.COMMAND_BLOCK_MINECART);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.place, Sentinel.lang.violations.protections.rootName.minecartCommandBlock),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.place, Sentinel.lang.violations.protections.rootName.minecartCommandBlock),
- generateBlockInfo(e.getClickedBlock()),
- config
- );
- }
-}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/CommandBlockMinecartUse.java b/src/main/java/me/trouper/sentinel/server/events/CommandBlockMinecartUse.java
deleted file mode 100644
index 182f596..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CommandBlockMinecartUse.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.EntityType;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.player.PlayerInteractEntityEvent;
-
-public class CommandBlockMinecartUse extends AbstractViolation {
-
- @EventHandler
- private void onCMDBlockMinecartUse(PlayerInteractEntityEvent e) {
- //ServerUtils.verbose("MinecartCommandUse: Detected Interaction with entity");
- if (!Sentinel.violationConfig.commandBlockMinecartUse.enabled) return;
- //ServerUtils.verbose("MinecartCommandUse: Enabled");
- Player p = e.getPlayer();
- if (!p.isOp()) return;
- ServerUtils.verbose("MinecartCommandUse: Player op");
- if (e.getRightClicked().getType() != EntityType.COMMAND_BLOCK_MINECART) return;
- ServerUtils.verbose("MinecartCommandUse: Entity is minecart command");
- if (PlayerUtils.isTrusted(p)) return;
- ServerUtils.verbose("MinecartCommandUse: Not trusted, performing action");
-
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .cancel(true)
- .punish(Sentinel.violationConfig.commandBlockMinecartUse.punish)
- .deop(Sentinel.violationConfig.commandBlockMinecartUse.deop)
- .setPunishmentCommands(Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.use, Sentinel.lang.violations.protections.rootName.minecartCommandBlock),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.use, Sentinel.lang.violations.protections.rootName.minecartCommandBlock),
- generateMinecartInfo(e.getRightClicked()),
- config
- );
- }
-}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/CommandBlockPlace.java b/src/main/java/me/trouper/sentinel/server/events/CommandBlockPlace.java
deleted file mode 100644
index 12a2f1c..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CommandBlockPlace.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import org.bukkit.Material;
-import org.bukkit.block.Block;
-import org.bukkit.block.CommandBlock;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.block.BlockPlaceEvent;
-
-public class CommandBlockPlace extends AbstractViolation {
-
- @EventHandler
- public void listen(BlockPlaceEvent e) {
- //ServerUtils.verbose("CommandBlockPlace: Detected block place");
- if (!Sentinel.violationConfig.commandBlockPlace.enabled) return;
- //ServerUtils.verbose("CommandBlockPlace: Enabled");
- Player p = e.getPlayer();
- if (!p.isOp()) return;
- //ServerUtils.verbose("CommandBlockPlace: Player is operator");
- Block b = e.getBlockPlaced();
- if (!(b.getType().equals(Material.COMMAND_BLOCK) ||
- b.getType().equals(Material.REPEATING_COMMAND_BLOCK) ||
- b.getType().equals(Material.CHAIN_COMMAND_BLOCK))) return;
- ServerUtils.verbose("CommandBlockPlace: Block is a command block");
- CommandBlock cb = (CommandBlock) b.getState();
- if (PlayerUtils.isTrusted(p)) return;
- ServerUtils.verbose("CommandBlockPlace: Not trusted, performing action");
-
-
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .deop(Sentinel.violationConfig.commandBlockPlace.deop)
- .cancel(true)
- .setEvent(e)
- .punish(true)
- .setPunishmentCommands(Sentinel.violationConfig.commandBlockPlace.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.commandBlockPlace.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.place, Sentinel.lang.violations.protections.rootName.commandBlock),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.place, Sentinel.lang.violations.protections.rootName.commandBlock),
- generateCommandBlockInfo(cb),
- config
- );
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/events/CommandBlockUse.java b/src/main/java/me/trouper/sentinel/server/events/CommandBlockUse.java
deleted file mode 100644
index 978e3fe..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CommandBlockUse.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.server.functions.helpers.CBWhitelistManager;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import org.bukkit.Material;
-import org.bukkit.block.Block;
-import org.bukkit.block.CommandBlock;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.player.PlayerInteractEvent;
-
-public class CommandBlockUse extends AbstractViolation {
-
- @EventHandler
- private void onCMDBlockUse(PlayerInteractEvent e) {
- //ServerUtils.verbose("CommandBlockUse: Detected Interaction");
- if (!Sentinel.violationConfig.commandBlockUse.enabled) return;
- //ServerUtils.verbose("CommandBlockUse: Enabled");
- Player p = e.getPlayer();
- if (!p.isOp()) return;
- //ServerUtils.verbose("CommandBlockUse: Player is op");
- if (e.getClickedBlock() == null) return;
- //ServerUtils.verbose("CommandBlockUse: Block isn't null");
- Block b = e.getClickedBlock();
- if (!(b.getType() == Material.COMMAND_BLOCK || b.getType() == Material.REPEATING_COMMAND_BLOCK || b.getType() == Material.CHAIN_COMMAND_BLOCK)) return;
- CommandBlock cb = (CommandBlock) b.getState();
- ServerUtils.verbose("CommandBlockUse: Block is a command block");
- if (PlayerUtils.isTrusted(p)) {
- if (!CBWhitelistManager.autoWhitelist.contains(p.getUniqueId())) return;
- if (CBWhitelistManager.canRun(cb.getBlock())) return;
- e.setCancelled(true);
- CBWhitelistManager.add(cb, p.getUniqueId());
- return;
- }
- ServerUtils.verbose("CommandBlockUse: Not trusted, performing action");
-
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .deop(Sentinel.violationConfig.commandBlockUse.deop)
- .cancel(true)
- .punish(Sentinel.violationConfig.commandBlockUse.punish)
- .setPunishmentCommands(Sentinel.violationConfig.commandBlockUse.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.commandBlockUse.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.use, Sentinel.lang.violations.protections.rootName.commandBlock),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.use, Sentinel.lang.violations.protections.rootName.commandBlock),
- generateCommandBlockInfo(cb),
- config
- );
- }
-}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/CommandExecute.java b/src/main/java/me/trouper/sentinel/server/events/CommandExecute.java
deleted file mode 100644
index c7ac7ad..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CommandExecute.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.utils.PlayerUtils;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.player.PlayerCommandPreprocessEvent;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class CommandExecute extends AbstractViolation {
-
- @EventHandler
- private void onCommand(PlayerCommandPreprocessEvent e) {
- Player p = e.getPlayer();
- if (PlayerUtils.isTrusted(p)) return;
- String label = e.getMessage().substring(1).split(" ")[0];
- String args = e.getMessage();
-
- Set status = getCommandStatus(label);
-
- if (status.contains("SPECIFIC") && Sentinel.violationConfig.commandExecute.specific.enabled) {
- e.setCancelled(true);
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .cancel(true)
- .punish(Sentinel.violationConfig.commandExecute.specific.punish)
- .setPunishmentCommands(Sentinel.violationConfig.commandExecute.specific.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.commandExecute.specific.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.run, Sentinel.lang.violations.protections.rootName.specificCommand),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.run, Sentinel.lang.violations.protections.rootName.specificCommand),
- generateCommandInfo(args, p),
- config
- );
- return;
- }
-
- if (status.contains("DANGEROUS") && Sentinel.violationConfig.commandExecute.dangerous.enabled) {
- e.setCancelled(true);
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .deop(Sentinel.violationConfig.commandExecute.dangerous.deop)
- .cancel(true)
- .punish(Sentinel.violationConfig.commandExecute.dangerous.punish)
- .setPunishmentCommands(Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.commandExecute.dangerous.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.run, Sentinel.lang.violations.protections.rootName.dangerousCommand),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.run, Sentinel.lang.violations.protections.rootName.dangerousCommand),
- generateCommandInfo(args, p),
- config
- );
- return;
- }
-
- if (status.contains("LOGGED") && Sentinel.violationConfig.commandExecute.logged.enabled) {
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setPlayer(p)
- .logToDiscord(Sentinel.violationConfig.commandExecute.logged.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.run, Sentinel.lang.violations.protections.rootName.loggedCommand),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.run, Sentinel.lang.violations.protections.rootName.loggedCommand),
- generateCommandInfo(args, p),
- config
- );
- return;
- }
- }
-
- public static Set getCommandStatus(String label) {
- Set commandTypes = new HashSet<>();
-
- if (label.startsWith("/")) {
- label = label.substring(1);
- }
-
- if (label.contains(":")) {
- commandTypes.add("SPECIFIC");
- }
-
- for (String loggedCommand : Sentinel.violationConfig.commandExecute.logged.commands) {
- if (loggedCommand.equals(label)) commandTypes.add("LOGGED");
- }
-
- for (String dangerousCommand : Sentinel.violationConfig.commandExecute.dangerous.commands) {
- if (dangerousCommand.equals(label)) commandTypes.add("DANGEROUS");
- }
-
- return commandTypes;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/CreativeHotbar.java b/src/main/java/me/trouper/sentinel/server/events/CreativeHotbar.java
deleted file mode 100644
index edfd979..0000000
--- a/src/main/java/me/trouper/sentinel/server/events/CreativeHotbar.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package me.trouper.sentinel.server.events;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.AbstractViolation;
-import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
-import me.trouper.sentinel.utils.ItemUtils;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.inventory.InventoryCreativeEvent;
-import org.bukkit.inventory.ItemStack;
-
-public class CreativeHotbar extends AbstractViolation {
-
- @EventHandler
- private void onNBTPull(InventoryCreativeEvent e) {
- //ServerUtils.verbose("NBT: Detected creative mode action");
- if (!Sentinel.violationConfig.creativeHotbarAction.enabled) return;
- ServerUtils.verbose("NBT: Enabled");
- if (!(e.getWhoClicked() instanceof Player p)) return;
- ServerUtils.verbose("NBT: Clicker is a player");
- if (e.getCursor() == null) return; // Well it threw an exception during testing, so it isn't always false!
- ServerUtils.verbose("NBT: Cursor isn't null");
- ItemStack i = e.getCursor();
- if (PlayerUtils.isTrusted(p)) return;
- ServerUtils.verbose("NBT: Not trusted");
- if (e.getCursor().getItemMeta() == null) return;
- ServerUtils.verbose("NBT: Cursor has meta");
- if (!(i.hasItemMeta() && i.getItemMeta() != null)) return;
- ServerUtils.verbose("NBT: Item has meta");
- if (ItemUtils.itemPasses(i)) return;
- ServerUtils.verbose("NBT: Item doesn't pass, performing action");
-
- ActionConfiguration.Builder config = new ActionConfiguration.Builder()
- .setEvent(e)
- .setPlayer(p)
- .cancel(true)
- .punish(Sentinel.violationConfig.creativeHotbarAction.punish)
- .deop(Sentinel.violationConfig.creativeHotbarAction.deop)
- .setPunishmentCommands(Sentinel.violationConfig.creativeHotbarAction.punishmentCommands)
- .logToDiscord(Sentinel.violationConfig.creativeHotbarAction.logToDiscord);
-
- runActions(
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.grab, Sentinel.lang.violations.protections.rootName.nbtItem),
- Sentinel.lang.violations.protections.rootName.rootNameFormatPlayer.formatted(p.getName(), Sentinel.lang.violations.protections.rootName.grab, Sentinel.lang.violations.protections.rootName.nbtItem),
- generateItemInfo(i),
- config
- );
- }
-}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/QuickListener.java b/src/main/java/me/trouper/sentinel/server/events/QuickListener.java
new file mode 100644
index 0000000..75041f8
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/QuickListener.java
@@ -0,0 +1,12 @@
+package me.trouper.sentinel.server.events;
+
+import me.trouper.sentinel.server.Main;
+import org.bukkit.Bukkit;
+import org.bukkit.event.Listener;
+
+public interface QuickListener extends Listener, Main {
+ default QuickListener register() {
+ Bukkit.getPluginManager().registerEvents(this, this.getPlugin());
+ return this;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/admin/AntiBanEvents.java b/src/main/java/me/trouper/sentinel/server/events/admin/AntiBanEvents.java
new file mode 100644
index 0000000..d2dccc2
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/admin/AntiBanEvents.java
@@ -0,0 +1,30 @@
+package me.trouper.sentinel.server.events.admin;
+
+import io.github.itzispyder.pdk.events.CustomListener;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.QuickListener;
+import me.trouper.sentinel.utils.PlayerUtils;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
+import org.bukkit.event.player.PlayerKickEvent;
+import org.bukkit.event.player.PlayerLoginEvent;
+
+public class AntiBanEvents implements QuickListener {
+
+ // Well. I hope that no banning plugins use the highest priority as well, that would be embarrassing.
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onKick(PlayerKickEvent e) {
+ if (PlayerUtils.isTrusted(e.getPlayer()) && main.dir().io.mainConfig.plugin.antiBan) e.setCancelled(true);
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onLogin(PlayerLoginEvent e) {
+ if (PlayerUtils.isTrusted(e.getPlayer()) && main.dir().io.mainConfig.plugin.antiBan) e.allow();
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void beforeLogin(AsyncPlayerPreLoginEvent e) {
+ if (PlayerUtils.isTrusted(e.getUniqueId()) && main.dir().io.mainConfig.plugin.antiBan) e.allow();
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/admin/BlockDisplayHideEvent.java b/src/main/java/me/trouper/sentinel/server/events/admin/BlockDisplayHideEvent.java
new file mode 100644
index 0000000..5e2531b
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/admin/BlockDisplayHideEvent.java
@@ -0,0 +1,24 @@
+package me.trouper.sentinel.server.events.admin;
+
+import io.github.itzispyder.pdk.events.CustomListener;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.QuickListener;
+import org.bukkit.entity.BlockDisplay;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.player.PlayerJoinEvent;
+
+public class BlockDisplayHideEvent implements QuickListener {
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+
+ for (Entity entity : player.getWorld().getEntities()) {
+ if (entity instanceof BlockDisplay && entity.getScoreboardTags().contains("./Sentinel/ Block Display")) {
+ player.hideEntity(Sentinel.getInstance(), entity);
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/admin/WandEvents.java b/src/main/java/me/trouper/sentinel/server/events/admin/WandEvents.java
new file mode 100644
index 0000000..33271db
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/admin/WandEvents.java
@@ -0,0 +1,200 @@
+package me.trouper.sentinel.server.events.admin;
+
+import io.github.itzispyder.pdk.utils.misc.SoundPlayer;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.data.types.Selection;
+import me.trouper.sentinel.server.events.QuickListener;
+import me.trouper.sentinel.utils.*;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.vehicle.VehicleDamageEvent;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.*;
+
+public class WandEvents implements QuickListener {
+ public static final ItemStack SELECTION_WAND = ItemBuilder.of(Material.BLAZE_ROD)
+ .displayName(Component.text("Command Block Wand", NamedTextColor.LIGHT_PURPLE).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(
+ Text.color("&7Use this wand to manage command blocks."),
+ Text.color("&7It can scan up to 10 blocks away."),
+ Text.color("&7Selections are visible up to 64 blocks away."),
+ Text.color("&8&l➥&r &7Left Click&8:&f Set Position 1"),
+ Text.color("&8&l➥&r &7Right Click&8:&f Set Position 2"),
+ Text.color("&8&l➥&r &7Break CMD Block&8:&f Remove from whitelist"),
+ Text.color("&8&l➥&r &7Click CMD Block&8:&f Add to whitelist"),
+ Text.color("&8&l➥&r &7Sneak&8:&f Force Position Setting"),
+ Text.color("&7Blocks close to you will get highlighted when holding."),
+ Text.color(" &fHighlight Color Key&8:"),
+ Text.color(" &8- &cRed &7: &fNot whitelisted."),
+ Text.color(" &8- &aGreen &7: &fWhitelisted."),
+ Text.color(" &8- &9Blue &7: &fYour selection."),
+ Text.color(" &8- &dPurple &7: &fMissing Command Block"),
+ Text.color(" &8- &fBlack &7: &fUnknown Command Block (Auto-Correcting)")
+ )
+ .customModelData(1984)
+ .build();
+
+ public static final Map selections = new HashMap<>();
+
+ @EventHandler
+ public void onClickEntity(PlayerInteractEntityEvent e) {
+ Player p = e.getPlayer();
+ ItemStack i = p.getInventory().getItemInMainHand();
+
+ if (!i.isSimilar(SELECTION_WAND)) return;
+ if (!PlayerUtils.isTrusted(p)) return;
+
+ SoundPlayer add = new SoundPlayer(p.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 100, 1);
+ if (!(e.getRightClicked() instanceof CommandMinecart cm)) return;
+
+ e.setCancelled(true);
+
+ main.dir().whitelistManager.getFromList(cm.getUniqueId()).setWhitelisted(true);
+ add.play(p);
+ }
+
+ @EventHandler
+ public void onDamage(VehicleDamageEvent e) {
+ if (!(e.getAttacker() instanceof Player p)) return;
+ ItemStack i = p.getInventory().getItemInMainHand();
+
+ if (!i.isSimilar(SELECTION_WAND)) return;
+ if (!PlayerUtils.isTrusted(p)) return;
+
+ SoundPlayer remove = new SoundPlayer(p.getLocation(), Sound.BLOCK_GLASS_BREAK, 100, 1);
+
+ if (!(e.getVehicle() instanceof CommandMinecart cm)) return;
+ e.setCancelled(true);
+
+ main.dir().whitelistManager.getFromList(cm.getUniqueId()).setWhitelisted(false);
+ remove.play(p);
+ }
+
+ @EventHandler
+ public void onClick(PlayerInteractEvent e) {
+ Player p = e.getPlayer();
+ ItemStack i = p.getInventory().getItemInMainHand();
+
+ if (!i.isSimilar(SELECTION_WAND)) return;
+ if (!PlayerUtils.isTrusted(p)) return;
+
+ SoundPlayer add = new SoundPlayer(p.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 100, 1);
+ SoundPlayer remove = new SoundPlayer(p.getLocation(), Sound.BLOCK_GLASS_BREAK, 100, 1);
+ SoundPlayer set1 = new SoundPlayer(p.getLocation(), Sound.UI_BUTTON_CLICK, 100, 1);
+ SoundPlayer set2 = new SoundPlayer(p.getLocation(), Sound.UI_BUTTON_CLICK, 100, 0.8F);
+
+ Selection selection = selections.computeIfAbsent(p.getUniqueId(), k -> new Selection());
+ if (p.getTargetBlockExact(10) == null) return;
+ Location loc = p.getTargetBlockExact(10).getLocation();
+
+ if (e.getAction() == Action.LEFT_CLICK_BLOCK) {
+ e.setCancelled(true);
+ if (p.isSneaking() && ServerUtils.isCommandBlock(loc.getBlock())) {
+ set1.play(p);
+ setPos1(p, selection, loc);
+ } else if (ServerUtils.isCommandBlock(loc.getBlock())) {
+ remove.play(p);
+ main.dir().whitelistManager.getFromList(loc).setWhitelisted(false);
+ } else {
+ set1.play(p);
+ setPos1(p, selection, loc);
+ }
+ } else if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
+ if (p.isSneaking() && ServerUtils.isCommandBlock(loc.getBlock())) {
+ e.setCancelled(true);
+ set2.play(p);
+ setPos2(p, selection, loc);
+ } else if (ServerUtils.isCommandBlock(loc.getBlock())) {
+ add.play(p);
+ main.dir().whitelistManager.generateHolder(p.getUniqueId(),(CommandBlock) loc.getBlock().getState()).addAndWhitelist();
+ e.setCancelled(true);
+ } else {
+ e.setCancelled(true);
+ set2.play(p);
+ setPos2(p, selection, loc);
+ }
+ }
+ }
+
+ private static void sortNear(Player p) {
+ ItemStack i = p.getInventory().getItemInMainHand();
+
+ if (!i.isSimilar(SELECTION_WAND) || !PlayerUtils.isTrusted(p)) {
+ return;
+ }
+
+ Selection around = new Selection();
+ around.setPos1(p.getLocation().add(-10, -10, -10));
+ around.setPos2(p.getLocation().add(10, 10, 10));
+ around.getBlocks().stream()
+ .filter(block -> ServerUtils.isCommandBlock(block) && block.getLocation().distance(p.getLocation()) <= 10)
+ .forEach(block -> {
+ if (!(block.getState() instanceof CommandBlock cb)) return;
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(block.getLocation());
+ Material color = Material.BLACK_CONCRETE_POWDER;
+ if (holder == null) {
+ holder = main.dir().whitelistManager.generateHolder(p.getUniqueId(), cb);
+ holder.add();
+ } else {
+ color = holder.isWhitelisted() ? Material.LIME_CONCRETE_POWDER : Material.RED_CONCRETE_POWDER;
+ }
+ holder.highlight(p, color);
+ });
+
+ p.getNearbyEntities(10, 10, 10).stream()
+ .filter(entity -> entity instanceof CommandMinecart)
+ .forEach(entity -> {
+ CommandMinecart cm = (CommandMinecart) entity;
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(cm.getUniqueId());
+ Material color = Material.BLACK_CONCRETE_POWDER;
+ if (holder == null) {
+ holder = main.dir().whitelistManager.generateHolder(p.getUniqueId(), cm);
+ holder.add();
+ } else {
+ color = holder.isWhitelisted() ? Material.LIME_CONCRETE_POWDER : Material.RED_CONCRETE_POWDER;
+ }
+ holder.highlight(p, color);
+ });
+
+ List holdersCopy = new ArrayList<>(main.dir().io.whitelistStorage.holders);
+ holdersCopy.forEach(holder -> {
+ if (!holder.present() && holder.isWhitelisted()) holder.highlight(p,Material.MAGENTA_CONCRETE_POWDER);
+ });
+ }
+
+ public static void handleDisplay() {
+ PlayerUtils.forEachTrusted(WandEvents::sortNear);
+
+ selections.forEach((uuid, selection) -> {
+ Player p = Bukkit.getPlayer(uuid);
+ if (p == null || !p.isOnline() || !p.getInventory().getItemInMainHand().isSimilar(SELECTION_WAND)) return;
+ selection.display(p);
+ });
+ }
+
+ private void setPos2(Player p, Selection selection, Location loc) {
+ if (selection.getPos2() != null && selection.getPos2().distance(loc) < 0.1) return;
+ selection.setPos2(loc);
+ info(p,Component.text("Position 2 set to {0}"),FormatUtils.formatLoc(loc));
+ }
+
+ private void setPos1(Player p, Selection selection, Location loc) {
+ if (selection.getPos1() != null && selection.getPos1().distance(loc) < 0.1) return;
+ selection.setPos1(loc);
+ info(p, Component.text("Position 1 set to {0}"),FormatUtils.formatLoc(loc));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/extras/ShadowRealmEvents.java b/src/main/java/me/trouper/sentinel/server/events/extras/ShadowRealmEvents.java
new file mode 100644
index 0000000..5bf9e9d
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/extras/ShadowRealmEvents.java
@@ -0,0 +1,77 @@
+package me.trouper.sentinel.server.events.extras;
+
+import com.github.retrooper.packetevents.PacketEvents;
+import com.github.retrooper.packetevents.event.PacketListener;
+import com.github.retrooper.packetevents.event.PacketReceiveEvent;
+import com.github.retrooper.packetevents.event.PacketSendEvent;
+import com.github.retrooper.packetevents.protocol.packettype.PacketType;
+import com.github.retrooper.packetevents.protocol.player.GameMode;
+import com.github.retrooper.packetevents.protocol.teleport.RelativeFlag;
+import com.github.retrooper.packetevents.protocol.world.Difficulty;
+import com.github.retrooper.packetevents.protocol.world.dimension.DimensionTypes;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerCloseWindow;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerPositionAndLook;
+import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
+import io.github.itzispyder.pdk.events.CustomListener;
+import io.github.itzispyder.pdk.utils.SchedulerUtils;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.QuickListener;
+import me.trouper.sentinel.utils.PacketUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.player.PlayerJoinEvent;
+
+public class ShadowRealmEvents implements QuickListener, PacketListener {
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent e) {
+ Player p = e.getPlayer();
+ if (!main.dir().io.extraStorage.shadowRealm.containsKey(p.getUniqueId())) return;
+ SchedulerUtils.later(20,()->{
+ enforce(p);
+ });
+ }
+
+ @Override
+ public void onPacketReceive(PacketReceiveEvent e) {
+ if (e.getPacketType() == PacketType.Play.Client.KEEP_ALIVE) return;
+ if (e.getPacketType() == PacketType.Play.Client.TELEPORT_CONFIRM) return;
+ if (e.getPacketType() == PacketType.Play.Client.CLIENT_SETTINGS) return;
+ if (e.getPacketType() == PacketType.Play.Client.PLAYER_FLYING) return;
+ Player player = e.getPlayer();
+ if (player == null) return;
+ if (!main.dir().io.extraStorage.shadowRealm.containsKey(player.getUniqueId())) return;
+ e.setCancelled(true);
+ }
+
+ @Override
+ public void onPacketSend(PacketSendEvent e) {
+ if (e.getPacketType() == PacketType.Play.Server.KEEP_ALIVE) return;
+ if (e.getPacketType() == PacketType.Play.Server.PLAYER_POSITION_AND_LOOK) return;
+ if (e.getPacketType() == PacketType.Play.Server.RESPAWN) return;
+ if (e.getPacketType() == PacketType.Play.Server.DISCONNECT) return;
+ if (e.getPacketType() == PacketType.Play.Server.CLOSE_WINDOW) return;
+ if (e.getPacketType() == PacketType.Play.Server.CHUNK_DATA) return;
+ if (e.getPacketType() == PacketType.Play.Server.CHUNK_BATCH_BEGIN) return;
+ if (e.getPacketType() == PacketType.Play.Server.CHUNK_BATCH_END) return;
+ if (e.getPacketType() == PacketType.Play.Server.CHUNK_BIOMES) return;
+ if (e.getPacketType() == PacketType.Play.Server.UNLOAD_CHUNK) return;
+ if (e.getPacketType() == PacketType.Play.Server.MAP_CHUNK_BULK) return;
+
+ Player player = e.getPlayer();
+ if (player == null) return;
+ if (!main.dir().io.extraStorage.shadowRealm.containsKey(player.getUniqueId())) return;
+ e.setCancelled(true);
+ }
+
+ public static void enforce(Player p) {
+ if (p == null || !main.dir().io.extraStorage.shadowRealm.containsKey(p.getUniqueId())) return;
+ PacketUtils.sendFakeRespawn(p,"minecraft:the_end",Difficulty.PEACEFUL, GameMode.SPECTATOR);
+ Bukkit.getScheduler().runTaskTimerAsynchronously(Sentinel.getInstance(),(t)->{
+ if (p == null || !p.isOnline() || !main.dir().io.extraStorage.shadowRealm.containsKey(p.getUniqueId())) t.cancel();
+ PacketUtils.sendFakePosition(p,0,32767,0);
+ PacketUtils.sendCloseScreen(p);
+ },1,1);
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/AbstractViolation.java b/src/main/java/me/trouper/sentinel/server/events/violations/AbstractViolation.java
new file mode 100644
index 0000000..719d757
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/AbstractViolation.java
@@ -0,0 +1,166 @@
+package me.trouper.sentinel.server.events.violations;
+
+import io.github.itzispyder.pdk.commands.Args;
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
+import io.papermc.paper.event.player.AsyncChatEvent;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.config.ViolationConfig;
+import me.trouper.sentinel.server.events.QuickListener;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.utils.*;
+import me.trouper.sentinel.utils.trees.ConsoleFormatter;
+import me.trouper.sentinel.utils.trees.EmbedFormatter;
+import me.trouper.sentinel.utils.trees.HoverFormatter;
+import me.trouper.sentinel.utils.trees.Node;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.event.ClickEvent;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import org.bukkit.Bukkit;
+import org.bukkit.block.Block;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.command.Command;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.text.Format;
+import java.util.function.BiConsumer;
+
+public abstract class AbstractViolation implements QuickListener {
+
+ public abstract CustomGui getConfigGui();
+ public abstract void getMainPage(Inventory inv);
+ public abstract void onClick(InventoryClickEvent e);
+
+ public static ConfigUpdater updater = new ConfigUpdater<>(main.dir().io.violationConfig);
+
+ protected void queuePlayer(Player player, BiConsumer action, String currentValue) {
+ MainGUI.awaitingCallback.add(player.getUniqueId());
+ player.closeInventory();
+ updater.queuePlayer(player, 20*60, (e)->{
+ e.setCancelled(true);
+ return LegacyComponentSerializer.legacySection().serialize(e.message());
+ }, (cfg, newValue) -> {
+ action.accept(cfg,new Args(newValue.split("\\s+")));
+ cfg.save();
+ successAny(player,"Value updated successfully");
+ player.openInventory(getConfigGui().getInventory());
+ });
+ message(player,Component.text("Enter the new value in chat. The value is currently set to {0}. (Click to insert)").clickEvent(ClickEvent.suggestCommand(currentValue)),Component.text(currentValue));
+ }
+
+ public void runActions(Component rootName, Node violationInfo, ActionConfiguration.Builder configuration) {
+ ActionConfiguration config = configuration.build();
+
+ Node root = new Node("Sentinel");
+ root.addTextLine(rootName);
+
+ if (config.getPlayer() != null) root.addChild(generatePlayerInfo(config.getPlayer()));
+
+ root.addChild(violationInfo);
+
+ root.addChild(configuration.getActionNode());
+
+ notifyTrusted(root, rootName);
+ if (configuration.isLoggedToDiscord()) EmbedFormatter.sendEmbed(EmbedFormatter.format(root));
+ Sentinel.getInstance().getLogger().info(ConsoleFormatter.format(root));
+ }
+
+ public void notifyTrusted(Node root, Component rootNamePlayer) {
+ PlayerUtils.forEachTrusted(trusted -> {
+ message(trusted,rootNamePlayer.hoverEvent(HoverFormatter.format(root).asHoverEvent()));
+ });
+ }
+
+ public Node generatePlayerInfo(Player p) {
+ Node playerInfo = new Node(main.dir().io.lang.violations.protections.infoNode.playerInfo);
+ playerInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.name, p.getName());
+ playerInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.uuid, p.getUniqueId().toString());
+ playerInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.operator, p.isOp() ? main.dir().io.lang.generic.yes : main.dir().io.lang.generic.no);
+ playerInfo.addField(Component.text(main.dir().io.lang.violations.protections.infoNode.locationField), FormatUtils.formatLoc(p.getLocation()));
+
+ return playerInfo;
+ }
+
+ public static Node generateBlockInfo(Block block) {
+ Node blockInfo = new Node(main.dir().io.lang.violations.protections.infoNode.blockInfo);
+ blockInfo.addTextLine(FormatUtils.formatType(block.getType().toString()));
+ blockInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.worldField,block.getWorld().getName());
+ blockInfo.addField(Component.text(main.dir().io.lang.violations.protections.infoNode.blockLocationField),FormatUtils.formatLoc(block.getLocation()));
+
+ return blockInfo;
+ }
+
+ public Node generateCommandBlockInfo(CommandBlock commandBlock) {
+ Node commandBlockInfo = new Node(main.dir().io.lang.violations.protections.infoNode.blockInfo);
+ commandBlockInfo.addTextLine(FormatUtils.formatType(commandBlock.getType().toString()));
+ commandBlockInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.worldField,commandBlock.getWorld().getName());
+ commandBlockInfo.addField(Component.text(main.dir().io.lang.violations.protections.infoNode.blockLocationField), FormatUtils.formatLoc(commandBlock.getLocation()));
+
+ String command = commandBlock.getCommand();
+ if (command == null || command.isBlank()) {
+ return commandBlockInfo;
+ } else if (command.length() <= 128) {
+ commandBlockInfo.addField(main.dir().io.lang.violations.protections.infoNode.commandField, command);
+ } else {
+ commandBlockInfo.addField(main.dir().io.lang.violations.protections.infoNode.commandTooLargeField, FileUtils.createCommandLog(command));
+ }
+
+ return commandBlockInfo;
+ }
+
+ public Node generateMinecartInfo(CommandMinecart entity) {
+ Node minecartInfo = new Node(main.dir().io.lang.violations.protections.infoNode.minecartInfo);
+ minecartInfo.addTextLine(FormatUtils.formatType(entity.getType().toString()));
+ minecartInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.worldField,entity.getWorld().getName());
+ minecartInfo.addField(Component.text(main.dir().io.lang.violations.protections.infoNode.cartLocationField),FormatUtils.formatLoc(entity.getLocation()));
+
+ String command = entity.getCommand();
+ if (command == null || command.isBlank()) {
+ return minecartInfo;
+ } else if (command.length() <= 128) {
+ minecartInfo.addField(main.dir().io.lang.violations.protections.infoNode.commandField, command);
+ } else {
+ minecartInfo.addField(main.dir().io.lang.violations.protections.infoNode.commandTooLargeField, FileUtils.createCommandLog(command));
+ }
+
+ return minecartInfo;
+ }
+
+ public Node generateItemInfo(ItemStack item) {
+ Node itemInfo = new Node(main.dir().io.lang.violations.protections.infoNode.itemInfo);
+ itemInfo.addTextLine(FormatUtils.formatType(item.getType().toString()));
+ itemInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.hasMeta,item.hasItemMeta() ? main.dir().io.lang.generic.yes : main.dir().io.lang.generic.no);
+ if (item.hasItemMeta()) {
+ itemInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.hasName,item.getItemMeta().hasCustomName() ? main.dir().io.lang.generic.yes : main.dir().io.lang.generic.no);
+ itemInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.hasLore,item.getItemMeta().hasLore() ? main.dir().io.lang.generic.yes : main.dir().io.lang.generic.no);
+ itemInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.hasAttributes,item.getItemMeta().hasAttributeModifiers() ? main.dir().io.lang.generic.yes : main.dir().io.lang.generic.no);
+ itemInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.hasEnchants,item.getItemMeta().hasEnchants() ? main.dir().io.lang.generic.yes : main.dir().io.lang.generic.no);
+ }
+
+ return itemInfo;
+ }
+
+ public Node generateCommandInfo(String command, Player executor) {
+ Node commandInfo = new Node(main.dir().io.lang.violations.protections.infoNode.commandInfo);
+ String name = command.split(" ")[0].substring(1);
+ ServerUtils.verbose("Command Name: " + name);
+ Command executed = Bukkit.getServer().getCommandMap().getCommand(name);
+
+ commandInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.name,name);
+ if (command.length() <= 128) {
+ commandInfo.addField(main.dir().io.lang.violations.protections.infoNode.commandField, command);
+ } else {
+ commandInfo.addField(main.dir().io.lang.violations.protections.infoNode.commandTooLargeField, FileUtils.createCommandLog(command));
+ }
+ if (executed == null || executed.getPermission() == null) return commandInfo;
+ commandInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.permissionRequired,executed.getPermission());
+ commandInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.permissionSatisfied,executor.hasPermission(executed.getPermission()) ? main.dir().io.lang.generic.yes : main.dir().io.lang.generic.no);
+
+ return commandInfo;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockBreak.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockBreak.java
new file mode 100644
index 0000000..a06aa52
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockBreak.java
@@ -0,0 +1,144 @@
+package me.trouper.sentinel.server.events.violations.blocks.command;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.*;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class CommandBlockBreak extends AbstractViolation {
+
+ @EventHandler
+ public void onBreak(BlockBreakEvent e) {
+ Block b = e.getBlock();
+ if (!(ServerUtils.isCommandBlock(b))) return;
+ ServerUtils.verbose("CommandBlockBreak: Block is a command block");
+ Player p = e.getPlayer();
+ CommandBlock cb = (CommandBlock) b.getState();
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(cb.getLocation());
+ if (PlayerUtils.isTrusted(e.getPlayer())) {
+ if (main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) {
+ ServerUtils.verbose("Auto Whitelist is on, un-whitelisting the command block.");
+ holder.setWhitelisted(false);
+ holder.delete();
+ }
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockBreak.enabled) {
+ ServerUtils.verbose("Not enabled, deletion allowed.");
+ if (!holder.isWhitelisted()) holder.delete();
+ return;
+ }
+
+ ServerUtils.verbose("CommandBlockBreak: is enabled, performing action");
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.commandBlockBreak.deop)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.commandBlockBreak.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockBreak.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockBreak.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.brake, main.dir().io.lang.violations.protections.rootName.commandBlock),
+ generateCommandBlockInfo(cb),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Block Break"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockBreak.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockBreak.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockBreak.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockBreak.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockBreak.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockBreak.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockBreak.enabled = !main.dir().io.violationConfig.commandBlockBreak.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockBreak.deop = !main.dir().io.violationConfig.commandBlockBreak.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockBreak.logToDiscord = !main.dir().io.violationConfig.commandBlockBreak.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockBreak.punish = !main.dir().io.violationConfig.commandBlockBreak.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockBreak.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockBreak.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockBreak.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockEdit.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockEdit.java
new file mode 100644
index 0000000..9d84062
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockEdit.java
@@ -0,0 +1,156 @@
+package me.trouper.sentinel.server.events.violations.blocks.command;
+
+import com.github.retrooper.packetevents.event.PacketListener;
+import com.github.retrooper.packetevents.event.PacketReceiveEvent;
+import com.github.retrooper.packetevents.protocol.packettype.PacketType;
+import com.github.retrooper.packetevents.protocol.player.User;
+import com.github.retrooper.packetevents.util.Vector3i;
+import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientUpdateCommandBlock;
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class CommandBlockEdit extends AbstractViolation implements PacketListener {
+
+ @Override
+ public void onPacketReceive(PacketReceiveEvent event) {
+ if (event.getPacketType() != PacketType.Play.Client.UPDATE_COMMAND_BLOCK) return;
+ ServerUtils.verbose("Packet is a command block update packet");
+
+ WrapperPlayClientUpdateCommandBlock wrapper = new WrapperPlayClientUpdateCommandBlock(event);
+ User user = event.getUser();
+ Player p = Bukkit.getPlayer(user.getUUID());
+ if (p == null) return;
+
+ Vector3i pos = wrapper.getPosition();
+ Location loc = new Location(p.getWorld(), pos.x, pos.y, pos.z);
+
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(loc);
+ if (PlayerUtils.isTrusted(p)) {
+ if (main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) holder.setWhitelisted(true);
+ holder.update(p,wrapper);
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockEdit.enabled) {
+ holder.update(p,wrapper);
+ return;
+ }
+
+ ServerUtils.verbose("Enabled, performing action");
+
+ event.setCancelled(true);
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.commandBlockEdit.deop)
+ .punish(main.dir().io.violationConfig.commandBlockEdit.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockEdit.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockEdit.logToDiscord);
+
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.edit, main.dir().io.lang.violations.protections.rootName.commandBlock),
+ generateCommandBlockInfo((CommandBlock) holder.loc().translate().getBlock().getState()),
+ config
+ );
+ }
+
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Block Edit"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockEdit.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockEdit.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockEdit.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockEdit.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockEdit.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockEdit.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockEdit.enabled = !main.dir().io.violationConfig.commandBlockEdit.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockEdit.deop = !main.dir().io.violationConfig.commandBlockEdit.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockEdit.logToDiscord = !main.dir().io.violationConfig.commandBlockEdit.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockEdit.punish = !main.dir().io.violationConfig.commandBlockEdit.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockEdit.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockEdit.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockEdit.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockPlace.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockPlace.java
new file mode 100644
index 0000000..ea993dc
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockPlace.java
@@ -0,0 +1,143 @@
+package me.trouper.sentinel.server.events.violations.blocks.command;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class CommandBlockPlace extends AbstractViolation {
+
+ @EventHandler
+ public void listen(BlockPlaceEvent e) {
+ Player p = e.getPlayer();
+ Block b = e.getBlockPlaced();
+ if (!ServerUtils.isCommandBlock(b)) return;
+ CommandBlock cb = (CommandBlock) b.getState();
+ CommandBlockHolder holder = main.dir().whitelistManager.generateHolder(p.getUniqueId(),cb);
+ if (PlayerUtils.isTrusted(p)) {
+ if (main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) holder.addAndWhitelist();
+ holder.add();
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockPlace.enabled) {
+ holder.add();
+ return;
+ }
+
+ ServerUtils.verbose("CommandBlockPlace: Enabled, performing action");
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.commandBlockPlace.deop)
+ .cancel(true)
+ .setEvent(e)
+ .punish(main.dir().io.violationConfig.commandBlockPlace.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockPlace.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockPlace.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.place, main.dir().io.lang.violations.protections.rootName.commandBlock),
+ generateCommandBlockInfo(cb),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Block Place"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockPlace.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockPlace.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockPlace.enabled = !main.dir().io.violationConfig.commandBlockPlace.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockPlace.deop = !main.dir().io.violationConfig.commandBlockPlace.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockPlace.logToDiscord = !main.dir().io.violationConfig.commandBlockPlace.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockPlace.punish = !main.dir().io.violationConfig.commandBlockPlace.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockPlace.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockPlace.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockPlace.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockUse.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockUse.java
new file mode 100644
index 0000000..2ce6d75
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/command/CommandBlockUse.java
@@ -0,0 +1,149 @@
+package me.trouper.sentinel.server.events.violations.blocks.command;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class CommandBlockUse extends AbstractViolation {
+
+ @EventHandler
+ private void onCMDBlockUse(PlayerInteractEvent e) {
+ Player p = e.getPlayer();
+ if (e.getClickedBlock() == null) return;
+ //ServerUtils.verbose("CommandBlockUse: Block isn't null");
+ Block b = e.getClickedBlock();
+ if (!(ServerUtils.isCommandBlock(b))) return;
+ CommandBlock cb = (CommandBlock) b.getState();
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(cb.getLocation());
+ if (holder == null) {
+ holder = main.dir().whitelistManager.generateHolder(p.getUniqueId(),cb);
+ holder.add();
+ }
+ if (PlayerUtils.isTrusted(p)) {
+ if (main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) holder.setWhitelisted(true);
+
+ holder.update(p);
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockUse.enabled) {
+ holder.update(p);
+ return;
+ }
+
+ ServerUtils.verbose("CommandBlockUse: Not trusted, performing action");
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.commandBlockUse.deop)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.commandBlockUse.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockUse.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockUse.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.use, main.dir().io.lang.violations.protections.rootName.commandBlock),
+ generateCommandBlockInfo(cb),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Block Use"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockUse.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockUse.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockUse.enabled = !main.dir().io.violationConfig.commandBlockUse.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockUse.deop = !main.dir().io.violationConfig.commandBlockUse.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockUse.logToDiscord = !main.dir().io.violationConfig.commandBlockUse.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockUse.punish = !main.dir().io.violationConfig.commandBlockUse.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockUse.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockUse.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockUse.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockBreak.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockBreak.java
new file mode 100644
index 0000000..4f6712e
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockBreak.java
@@ -0,0 +1,133 @@
+package me.trouper.sentinel.server.events.violations.blocks.jigsaw;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class JigsawBlockBreak extends AbstractViolation {
+
+ @EventHandler
+ public void onPlace(BlockBreakEvent e) {
+ if (!main.dir().io.violationConfig.commandBlockPlace.enabled) return;
+ Player p = e.getPlayer();
+ Block b = e.getBlock();
+ if (b == null) return;
+ if (!Material.JIGSAW.equals(b.getType())) return;
+ ServerUtils.verbose("StructureBlockBreak: Block is a Structure block");
+ if (PlayerUtils.isTrusted(p)) return;
+ ServerUtils.verbose("StructureBlockBreak: Not trusted, performing action");
+
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.jigsawBlockBreak.deop)
+ .cancel(true)
+ .setEvent(e)
+ .punish(main.dir().io.violationConfig.jigsawBlockBreak.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.jigsawBlockBreak.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.jigsawBlockBreak.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.brake, main.dir().io.lang.violations.protections.rootName.jigsawBlock),
+ generateBlockInfo(b),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Jigsaw Block Break"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.jigsawBlockBreak.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockBreak.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockBreak.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockBreak.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockBreak.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.jigsawBlockBreak.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.jigsawBlockBreak.enabled = !main.dir().io.violationConfig.jigsawBlockBreak.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.jigsawBlockBreak.deop = !main.dir().io.violationConfig.jigsawBlockBreak.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.jigsawBlockBreak.logToDiscord = !main.dir().io.violationConfig.jigsawBlockBreak.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.jigsawBlockBreak.punish = !main.dir().io.violationConfig.jigsawBlockBreak.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.jigsawBlockBreak.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.jigsawBlockBreak.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.jigsawBlockBreak.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockPlace.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockPlace.java
new file mode 100644
index 0000000..bded2c5
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockPlace.java
@@ -0,0 +1,134 @@
+package me.trouper.sentinel.server.events.violations.blocks.jigsaw;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class JigsawBlockPlace extends AbstractViolation {
+
+ @EventHandler
+ public void onPlace(BlockPlaceEvent e) {
+ if (!main.dir().io.violationConfig.commandBlockPlace.enabled) return;
+ Player p = e.getPlayer();
+ Block b = e.getBlockPlaced();
+ if (b == null) return;
+ if (!b.getType().equals(Material.JIGSAW)) return;
+ ServerUtils.verbose("StructureBlockPlace: Block is a Structure block");
+ if (PlayerUtils.isTrusted(p)) return;
+ ServerUtils.verbose("StructureBlockPlace: Not trusted, performing action");
+
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.jigsawBlockPlace.deop)
+ .cancel(true)
+ .setEvent(e)
+ .punish(main.dir().io.violationConfig.jigsawBlockPlace.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.jigsawBlockPlace.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.jigsawBlockPlace.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.place, main.dir().io.lang.violations.protections.rootName.jigsawBlock),
+ generateBlockInfo(b),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Jigsaw Block Place"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.jigsawBlockPlace.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockPlace.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.jigsawBlockPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.jigsawBlockPlace.enabled = !main.dir().io.violationConfig.jigsawBlockPlace.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.jigsawBlockPlace.deop = !main.dir().io.violationConfig.jigsawBlockPlace.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.jigsawBlockPlace.logToDiscord = !main.dir().io.violationConfig.jigsawBlockPlace.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.jigsawBlockPlace.punish = !main.dir().io.violationConfig.jigsawBlockPlace.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.jigsawBlockPlace.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.jigsawBlockPlace.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.jigsawBlockPlace.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockUse.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockUse.java
new file mode 100644
index 0000000..681eeee
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/jigsaw/JigsawBlockUse.java
@@ -0,0 +1,133 @@
+package me.trouper.sentinel.server.events.violations.blocks.jigsaw;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class JigsawBlockUse extends AbstractViolation {
+ @EventHandler
+ public void onPlace(PlayerInteractEvent e) {
+ if (!main.dir().io.violationConfig.commandBlockPlace.enabled) return;
+ Player p = e.getPlayer();
+ Block b = e.getClickedBlock();
+ if (b == null) return;
+ if (!Material.JIGSAW.equals(b.getType())) return;
+ ServerUtils.verbose("StructureBlockUse: Block is a Structure block");
+ if (PlayerUtils.isTrusted(p)) return;
+ ServerUtils.verbose("StructureBlockUse: Not trusted, performing action");
+
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.jigsawBlockUse.deop)
+ .cancel(true)
+ .setEvent(e)
+ .punish(main.dir().io.violationConfig.jigsawBlockUse.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.jigsawBlockUse.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.jigsawBlockUse.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.use, main.dir().io.lang.violations.protections.rootName.jigsawBlock),
+ generateBlockInfo(b),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Jigsaw Block Use"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.jigsawBlockUse.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockUse.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.jigsawBlockUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.jigsawBlockUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.jigsawBlockUse.enabled = !main.dir().io.violationConfig.jigsawBlockUse.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.jigsawBlockUse.deop = !main.dir().io.violationConfig.jigsawBlockUse.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.jigsawBlockUse.logToDiscord = !main.dir().io.violationConfig.jigsawBlockUse.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.jigsawBlockUse.punish = !main.dir().io.violationConfig.jigsawBlockUse.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.jigsawBlockUse.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.jigsawBlockUse.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.jigsawBlockUse.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockBreak.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockBreak.java
new file mode 100644
index 0000000..475c00c
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockBreak.java
@@ -0,0 +1,134 @@
+package me.trouper.sentinel.server.events.violations.blocks.structure;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class StructureBlockBreak extends AbstractViolation {
+
+ @EventHandler
+ public void onPlace(BlockBreakEvent e) {
+ if (!main.dir().io.violationConfig.commandBlockPlace.enabled) return;
+ Player p = e.getPlayer();
+ Block b = e.getBlock();
+ if (b == null) return;
+ if (!Material.STRUCTURE_BLOCK.equals(b.getType())) return;
+ ServerUtils.verbose("StructureBlockBreak: Block is a Structure block");
+ if (PlayerUtils.isTrusted(p)) return;
+ ServerUtils.verbose("StructureBlockBreak: Not trusted, performing action");
+
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.structureBlockBreak.deop)
+ .cancel(true)
+ .setEvent(e)
+ .punish(main.dir().io.violationConfig.structureBlockBreak.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.structureBlockBreak.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.structureBlockBreak.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.brake, main.dir().io.lang.violations.protections.rootName.structureBlock),
+ generateBlockInfo(b),
+ config
+ );
+ }
+
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Structure Block Break"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.structureBlockBreak.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.structureBlockBreak.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.structureBlockBreak.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.structureBlockBreak.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.structureBlockBreak.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.structureBlockBreak.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.structureBlockBreak.enabled = !main.dir().io.violationConfig.structureBlockBreak.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.structureBlockBreak.deop = !main.dir().io.violationConfig.structureBlockBreak.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.structureBlockBreak.logToDiscord = !main.dir().io.violationConfig.structureBlockBreak.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.structureBlockBreak.punish = !main.dir().io.violationConfig.structureBlockBreak.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.structureBlockBreak.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.structureBlockBreak.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.structureBlockBreak.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockPlace.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockPlace.java
new file mode 100644
index 0000000..5e2083a
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockPlace.java
@@ -0,0 +1,132 @@
+package me.trouper.sentinel.server.events.violations.blocks.structure;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class StructureBlockPlace extends AbstractViolation {
+ @EventHandler
+ public void onPlace(BlockPlaceEvent e) {
+ if (!main.dir().io.violationConfig.commandBlockPlace.enabled) return;
+ Player p = e.getPlayer();
+ Block b = e.getBlockPlaced();
+ if (b == null) return;
+ if (!b.getType().equals(Material.STRUCTURE_BLOCK)) return;
+ ServerUtils.verbose("StructureBlockPlace: Block is a Structure block");
+ if (PlayerUtils.isTrusted(p)) return;
+ ServerUtils.verbose("StructureBlockPlace: Not trusted, performing action");
+
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.structureBlockPlace.deop)
+ .cancel(true)
+ .setEvent(e)
+ .punish(main.dir().io.violationConfig.structureBlockPlace.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.structureBlockPlace.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.structureBlockPlace.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.place, main.dir().io.lang.violations.protections.rootName.structureBlock),
+ generateBlockInfo(b),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Structure Block Place"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.structureBlockPlace.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.structureBlockPlace.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.structureBlockPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.structureBlockPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.structureBlockPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.structureBlockPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.structureBlockPlace.enabled = !main.dir().io.violationConfig.structureBlockPlace.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.structureBlockPlace.deop = !main.dir().io.violationConfig.structureBlockPlace.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.structureBlockPlace.logToDiscord = !main.dir().io.violationConfig.structureBlockPlace.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.structureBlockPlace.punish = !main.dir().io.violationConfig.structureBlockPlace.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.structureBlockPlace.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.structureBlockPlace.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.structureBlockPlace.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockUse.java b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockUse.java
new file mode 100644
index 0000000..e47b7b2
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/blocks/structure/StructureBlockUse.java
@@ -0,0 +1,133 @@
+package me.trouper.sentinel.server.events.violations.blocks.structure;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class StructureBlockUse extends AbstractViolation {
+ @EventHandler
+ public void onPlace(PlayerInteractEvent e) {
+ if (!main.dir().io.violationConfig.commandBlockPlace.enabled) return;
+ Player p = e.getPlayer();
+ Block b = e.getClickedBlock();
+ if (b == null) return;
+ if (!Material.STRUCTURE_BLOCK.equals(b.getType())) return;
+ ServerUtils.verbose("StructureBlockUse: Block is a Structure block");
+ if (PlayerUtils.isTrusted(p)) return;
+
+ ServerUtils.verbose("StructureBlockUse: Not trusted, performing action");
+
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.structureBlockUse.deop)
+ .cancel(true)
+ .setEvent(e)
+ .punish(main.dir().io.violationConfig.structureBlockUse.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.structureBlockUse.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.structureBlockUse.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.use, main.dir().io.lang.violations.protections.rootName.structureBlock),
+ generateBlockInfo(b),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Structure Block Use"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.structureBlockUse.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.structureBlockUse.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.structureBlockUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.structureBlockUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.structureBlockUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.structureBlockUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.structureBlockUse.enabled = !main.dir().io.violationConfig.structureBlockUse.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.structureBlockUse.deop = !main.dir().io.violationConfig.structureBlockUse.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.structureBlockUse.logToDiscord = !main.dir().io.violationConfig.structureBlockUse.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.structureBlockUse.punish = !main.dir().io.violationConfig.structureBlockUse.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.structureBlockUse.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.structureBlockUse.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.structureBlockUse.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/command/DangerousCommand.java b/src/main/java/me/trouper/sentinel/server/events/violations/command/DangerousCommand.java
new file mode 100644
index 0000000..5da3076
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/command/DangerousCommand.java
@@ -0,0 +1,140 @@
+package me.trouper.sentinel.server.events.violations.command;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class DangerousCommand extends AbstractViolation {
+ @EventHandler
+ private void onCommand(PlayerCommandPreprocessEvent e) {
+ Player p = e.getPlayer();
+ if (PlayerUtils.isTrusted(p)) return;
+ String label = e.getMessage().substring(1).split(" ")[0];
+ String args = e.getMessage();
+
+ if (main.dir().io.violationConfig.commandExecute.dangerous.commands.contains(label) && main.dir().io.violationConfig.commandExecute.dangerous.enabled) {
+ e.setCancelled(true);
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.commandExecute.dangerous.deop)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.commandExecute.dangerous.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandExecute.dangerous.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandExecute.dangerous.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.run, main.dir().io.lang.violations.protections.rootName.dangerousCommand),
+ generateCommandInfo(args, p),
+ config
+ );
+ }
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Dangerous Command Check"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i, Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandExecute.dangerous.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandExecute.dangerous.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandExecute.dangerous.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandExecute.dangerous.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandExecute.dangerous.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandExecute.dangerous.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ inv.setItem(22,Items.stringListItem(main.dir().io.violationConfig.commandExecute.dangerous.commands,Material.CRIMSON_HANGING_SIGN,"Commands","Commands that will flag this check."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandExecute.dangerous.enabled = !main.dir().io.violationConfig.commandExecute.dangerous.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandExecute.dangerous.deop = !main.dir().io.violationConfig.commandExecute.dangerous.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandExecute.dangerous.logToDiscord = !main.dir().io.violationConfig.commandExecute.dangerous.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandExecute.dangerous.punish = !main.dir().io.violationConfig.commandExecute.dangerous.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
+ cfg.commandExecute.dangerous.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandExecute.dangerous.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandExecute.dangerous.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 22 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
+ cfg.commandExecute.dangerous.commands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandExecute.dangerous.commands);
+ return;
+ }
+ main.dir().io.violationConfig.commandExecute.dangerous.commands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/command/LoggedCommand.java b/src/main/java/me/trouper/sentinel/server/events/violations/command/LoggedCommand.java
new file mode 100644
index 0000000..c062e04
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/command/LoggedCommand.java
@@ -0,0 +1,110 @@
+package me.trouper.sentinel.server.events.violations.command;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class LoggedCommand extends AbstractViolation {
+
+ @EventHandler
+ public void onCommand(PlayerCommandPreprocessEvent e) {
+ Player p = e.getPlayer();
+ if (PlayerUtils.isTrusted(p)) return;
+ String label = e.getMessage().substring(1).split(" ")[0];
+ String args = e.getMessage();
+
+ if (main.dir().io.violationConfig.commandExecute.logged.commands.contains(label) && main.dir().io.violationConfig.commandExecute.logged.enabled) {
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setPlayer(p)
+ .logToDiscord(main.dir().io.violationConfig.commandExecute.logged.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.run, main.dir().io.lang.violations.protections.rootName.loggedCommand),
+ generateCommandInfo(args, p),
+ config
+ );
+ }
+ }
+
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Logged Command Check"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandExecute.logged.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandExecute.logged.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(11,Items.booleanItem(main.dir().io.violationConfig.commandExecute.logged.logToDiscord,Items.configItem("Log to Discord",Material.OAK_LOG,"If this check will log to discord")));
+ inv.setItem(15,Items.stringListItem(main.dir().io.violationConfig.commandExecute.logged.commands,Material.CRIMSON_HANGING_SIGN,"Commands","Commands that will flag this check"));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandExecute.logged.enabled = !main.dir().io.violationConfig.commandExecute.logged.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 11 -> {
+ main.dir().io.violationConfig.commandExecute.logged.logToDiscord = !main.dir().io.violationConfig.commandExecute.logged.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 15 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
+ cfg.commandExecute.logged.commands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandExecute.logged.commands);
+ return;
+ }
+ main.dir().io.violationConfig.commandExecute.logged.commands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/command/SpecificCommand.java b/src/main/java/me/trouper/sentinel/server/events/violations/command/SpecificCommand.java
new file mode 100644
index 0000000..40e4354
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/command/SpecificCommand.java
@@ -0,0 +1,117 @@
+package me.trouper.sentinel.server.events.violations.command;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+public class SpecificCommand extends AbstractViolation {
+
+ @EventHandler
+ private void onCommand(PlayerCommandPreprocessEvent e) {
+ Player p = e.getPlayer();
+ if (PlayerUtils.isTrusted(p)) return;
+ String label = e.getMessage().substring(1).split(" ")[0];
+ String args = e.getMessage();
+
+ if (label.contains(":") && main.dir().io.violationConfig.commandExecute.specific.enabled) {
+ e.setCancelled(true);
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.commandExecute.specific.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandExecute.specific.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandExecute.specific.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.run, main.dir().io.lang.violations.protections.rootName.specificCommand),
+ generateCommandInfo(args, p),
+ config
+ );
+ }
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Specific Command Check"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack top = Items.RED;
+ if (main.dir().io.violationConfig.commandExecute.specific.enabled) {
+ top = Items.GREEN;
+ }
+
+ for (int i = 0; i < 9; i++) {
+ inv.setItem(i,top);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(4,Items.booleanItem(main.dir().io.violationConfig.commandExecute.specific.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(11,Items.booleanItem(main.dir().io.violationConfig.commandExecute.specific.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"If this check will run the punishment commands")));
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandExecute.specific.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(15,Items.stringListItem(main.dir().io.violationConfig.commandExecute.specific.punishmentCommands,Material.DIAMOND_AXE,"Commands","Commands that will flag this check"));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 4 -> {
+ main.dir().io.violationConfig.commandExecute.specific.enabled = !main.dir().io.violationConfig.commandExecute.specific.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 13 -> {
+ main.dir().io.violationConfig.commandExecute.specific.logToDiscord = !main.dir().io.violationConfig.commandExecute.specific.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 11 -> {
+ main.dir().io.violationConfig.commandExecute.specific.punish = !main.dir().io.violationConfig.commandExecute.specific.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 15 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandExecute.specific.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandExecute.specific.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandExecute.specific.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartBreak.java b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartBreak.java
new file mode 100644
index 0000000..68ed3c4
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartBreak.java
@@ -0,0 +1,151 @@
+package me.trouper.sentinel.server.events.violations.entities;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.vehicle.VehicleDamageEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class CommandMinecartBreak extends AbstractViolation {
+ @EventHandler
+ public void onBreak(VehicleDamageEvent e) {
+ if (!(e.getVehicle() instanceof CommandMinecart cm)) return;
+ if (e.getAttacker() == null) {
+ e.setCancelled(true);
+ return;
+ }
+ if (!(e.getAttacker() instanceof Player p)) {
+ e.setCancelled(true);
+ return;
+ }
+
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(cm.getUniqueId());
+ if (PlayerUtils.isTrusted(p)) {
+ if (main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) {
+ ServerUtils.verbose("Auto Whitelist is on, un-whitelisting the command minecart.");
+ holder.setWhitelisted(false);
+ holder.delete();
+ }
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockMinecartBreak.enabled) {
+ ServerUtils.verbose("Not enabled, deletion allowed.");
+ if (!holder.isWhitelisted()) holder.delete();
+ return;
+ }
+
+
+ ServerUtils.verbose("Not trusted, performing action");
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setEntity(cm)
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.commandBlockBreak.deop)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.commandBlockBreak.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockBreak.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockBreak.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.brake, main.dir().io.lang.violations.protections.rootName.commandMinecart),
+ generateMinecartInfo(cm),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Cart Break"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockMinecartBreak.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartBreak.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartBreak.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartBreak.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartBreak.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockMinecartBreak.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockMinecartBreak.enabled = !main.dir().io.violationConfig.commandBlockMinecartBreak.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockMinecartBreak.deop = !main.dir().io.violationConfig.commandBlockMinecartBreak.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockMinecartBreak.logToDiscord = !main.dir().io.violationConfig.commandBlockMinecartBreak.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockMinecartBreak.punish = !main.dir().io.violationConfig.commandBlockMinecartBreak.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockMinecartBreak.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockMinecartBreak.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockMinecartBreak.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartEdit.java b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartEdit.java
new file mode 100644
index 0000000..d51e369
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartEdit.java
@@ -0,0 +1,166 @@
+package me.trouper.sentinel.server.events.violations.entities;
+
+import com.github.retrooper.packetevents.event.PacketListener;
+import com.github.retrooper.packetevents.event.PacketReceiveEvent;
+import com.github.retrooper.packetevents.protocol.packettype.PacketType;
+import com.github.retrooper.packetevents.protocol.player.User;
+import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientUpdateCommandBlockMinecart;
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class CommandMinecartEdit extends AbstractViolation implements PacketListener {
+ @Override
+ public void onPacketReceive(PacketReceiveEvent event) {
+ if (event.getPacketType() != PacketType.Play.Client.UPDATE_COMMAND_BLOCK_MINECART) return;
+ ServerUtils.verbose("Packet is a command block update packet");
+
+ WrapperPlayClientUpdateCommandBlockMinecart wrapper = new WrapperPlayClientUpdateCommandBlockMinecart(event);
+ User user = event.getUser();
+ Player p = Bukkit.getPlayer(user.getUUID());
+ if (p == null) return;
+
+ if (!(getEntityById(p.getWorld(),wrapper.getEntityId()) instanceof CommandMinecart cart)) {
+ ServerUtils.verbose("Packet is a canceled due to bad entity UUID");
+ event.setCancelled(true);
+ return;
+ }
+
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(cart.getUniqueId());
+ if (PlayerUtils.isTrusted(p)) {
+ if (main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) holder.setWhitelisted(true);
+ holder.update(p,wrapper);
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockMinecartEdit.enabled) {
+ holder.update(p,wrapper);
+ return;
+ }
+
+ ServerUtils.verbose("Enabled, performing action");
+
+ event.setCancelled(true);
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setPlayer(p)
+ .deop(main.dir().io.violationConfig.commandBlockMinecartEdit.deop)
+ .punish(main.dir().io.violationConfig.commandBlockMinecartEdit.punish)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockMinecartEdit.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockMinecartEdit.logToDiscord);
+
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.edit, main.dir().io.lang.violations.protections.rootName.commandBlock),
+ generateMinecartInfo(cart),
+ config
+ );
+ }
+
+ private Entity getEntityById(World world, int entityId) {
+ for (Entity entity : world.getEntities()) {
+ if (entity.getEntityId() == entityId) {
+ return entity;
+ }
+ }
+ return null; // Entity with the given ID not found
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Block Edit"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockMinecartEdit.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartEdit.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartEdit.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartEdit.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartEdit.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockMinecartEdit.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockMinecartEdit.enabled = !main.dir().io.violationConfig.commandBlockMinecartEdit.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockMinecartEdit.deop = !main.dir().io.violationConfig.commandBlockMinecartEdit.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockMinecartEdit.logToDiscord = !main.dir().io.violationConfig.commandBlockMinecartEdit.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockMinecartEdit.punish = !main.dir().io.violationConfig.commandBlockMinecartEdit.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockMinecartEdit.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockMinecartEdit.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockMinecartEdit.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartPlace.java b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartPlace.java
new file mode 100644
index 0000000..ee10736
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartPlace.java
@@ -0,0 +1,198 @@
+package me.trouper.sentinel.server.events.violations.entities;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.vehicle.VehicleCreateEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class CommandMinecartPlace extends AbstractViolation {
+
+ private final ConcurrentHashMap queuedInteractions = new ConcurrentHashMap<>();
+
+ private UUID getPlayer(Location loc) {
+ ServerUtils.verbose("Getting responsible player for a location");
+ AtomicReference player = new AtomicReference<>();
+
+ queuedInteractions.forEach((location,uuid)->{
+ if (player.get() == null) {
+ ServerUtils.verbose("Loop is running");
+ if (loc.distance(location) < 1) {
+ ServerUtils.verbose("Found a matching minecart");
+ player.set(uuid);
+ queuedInteractions.remove(location);
+ }
+ }
+ });
+ return player.get();
+ }
+
+ @EventHandler
+ private void onVehicleCreate(VehicleCreateEvent e) {
+ //ServerUtils.verbose("Vehicle Creation Event");
+ if (!(e.getVehicle() instanceof CommandMinecart cm)) return;
+ if (queuedInteractions.isEmpty() ) {
+ ServerUtils.verbose("Queue is empty, preventing");
+ e.setCancelled(true);
+ return;
+ }
+ UUID uuid = getPlayer(e.getVehicle().getLocation());
+ if (uuid == null) {
+ ServerUtils.verbose("UUID is null, preventing");
+ e.setCancelled(true);
+ return;
+ }
+ Player p = Bukkit.getPlayer(uuid);
+ if (p == null) {
+ ServerUtils.verbose("Player is null, preventing");
+ e.setCancelled(true);
+ return;
+ }
+ CommandBlockHolder holder = main.dir().whitelistManager.generateHolder(p.getUniqueId(),cm);
+ if (PlayerUtils.isTrusted(p)) {
+ if (!main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) holder.addAndWhitelist();
+ holder.add();
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockMinecartPlace.enabled) {
+ holder.add();
+ return;
+ }
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.commandBlockMinecartPlace.punish)
+ .deop(main.dir().io.violationConfig.commandBlockMinecartPlace.deop)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockMinecartPlace.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockMinecartPlace.logToDiscord);
+
+ // Remove the command block minecart from the player's inventory
+ p.getInventory().remove(Material.COMMAND_BLOCK_MINECART);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.place, main.dir().io.lang.violations.protections.rootName.commandMinecart),
+ generateMinecartInfo(cm),
+ config
+ );
+ }
+
+ @EventHandler
+ private void onIneteract(PlayerInteractEvent e) {
+ //ServerUtils.verbose("Player Interaction Event");
+ //ServerUtils.verbose("MinecartCommandPlace: Check is enabled");
+ Player p = e.getPlayer();
+ if (e.getItem() == null) return;
+ //ServerUtils.verbose("MinecartCommandPlace: Item isn't null");
+ if (e.getClickedBlock() == null) return;
+ //ServerUtils.verbose("MinecartCommandPlace: Clicked block isn't null");
+ if (!e.getItem().getType().equals(Material.COMMAND_BLOCK_MINECART)) return;
+ ServerUtils.verbose("Item is a minecart command");
+ if (!(e.getClickedBlock().getType() == Material.RAIL || e.getClickedBlock().getType() == Material.POWERED_RAIL || e.getClickedBlock().getType() == Material.ACTIVATOR_RAIL || e.getClickedBlock().getType() == Material.DETECTOR_RAIL)) return;
+ ServerUtils.verbose("Clicked block is a rail, adding to list");
+
+ queuedInteractions.put(e.getClickedBlock().getLocation(),p.getUniqueId());
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Cart Place"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockMinecartPlace.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartPlace.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockMinecartPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockMinecartPlace.enabled = !main.dir().io.violationConfig.commandBlockMinecartPlace.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockMinecartPlace.deop = !main.dir().io.violationConfig.commandBlockMinecartPlace.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockMinecartPlace.logToDiscord = !main.dir().io.violationConfig.commandBlockMinecartPlace.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockMinecartPlace.punish = !main.dir().io.violationConfig.commandBlockMinecartPlace.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockMinecartPlace.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockMinecartPlace.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockMinecartPlace.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartUse.java b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartUse.java
new file mode 100644
index 0000000..4c72985
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/entities/CommandMinecartUse.java
@@ -0,0 +1,140 @@
+package me.trouper.sentinel.server.events.violations.entities;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.List;
+
+public class CommandMinecartUse extends AbstractViolation {
+
+ @EventHandler
+ private void onCMDBlockMinecartUse(PlayerInteractEntityEvent e) {
+ Player p = e.getPlayer();
+ if (!(e.getRightClicked() instanceof CommandMinecart cm)) return;
+ ServerUtils.verbose("MinecartCommandUse: Entity is minecart command");
+
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(cm.getUniqueId());
+ if (PlayerUtils.isTrusted(p)) {
+ if (main.dir().whitelistManager.autoWhitelist.contains(p.getUniqueId())) holder.setWhitelisted(true);
+ holder.update(p);
+ e.setCancelled(true);
+ return;
+ }
+
+ if (!main.dir().io.violationConfig.commandBlockUse.enabled) {
+ holder.update(p);
+ return;
+ }
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .setEntity(cm)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.commandBlockMinecartUse.punish)
+ .deop(main.dir().io.violationConfig.commandBlockMinecartUse.deop)
+ .setPunishmentCommands(main.dir().io.violationConfig.commandBlockMinecartUse.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockMinecartUse.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.use, main.dir().io.lang.violations.protections.rootName.commandMinecart),
+ generateMinecartInfo(cm),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Cart Use"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockMinecartUse.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartUse.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.commandBlockMinecartUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.commandBlockMinecartUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockMinecartUse.enabled = !main.dir().io.violationConfig.commandBlockMinecartUse.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.commandBlockMinecartUse.deop = !main.dir().io.violationConfig.commandBlockMinecartUse.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.commandBlockMinecartUse.logToDiscord = !main.dir().io.violationConfig.commandBlockMinecartUse.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.commandBlockMinecartUse.punish = !main.dir().io.violationConfig.commandBlockMinecartUse.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.commandBlockMinecartUse.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockMinecartUse.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockMinecartUse.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/players/ChatEvent.java b/src/main/java/me/trouper/sentinel/server/events/violations/players/ChatEvent.java
new file mode 100644
index 0000000..9dd8277
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/players/ChatEvent.java
@@ -0,0 +1,145 @@
+package me.trouper.sentinel.server.events.violations.players;
+
+import io.github.itzispyder.pdk.events.CustomListener;
+import io.github.itzispyder.pdk.utils.SchedulerUtils;
+import io.papermc.paper.event.player.AsyncChatEvent;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.QuickListener;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockBreak;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockEdit;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockPlace;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockUse;
+import me.trouper.sentinel.server.events.violations.blocks.jigsaw.JigsawBlockBreak;
+import me.trouper.sentinel.server.events.violations.blocks.jigsaw.JigsawBlockPlace;
+import me.trouper.sentinel.server.events.violations.blocks.jigsaw.JigsawBlockUse;
+import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockBreak;
+import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockPlace;
+import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockUse;
+import me.trouper.sentinel.server.events.violations.command.DangerousCommand;
+import me.trouper.sentinel.server.events.violations.command.LoggedCommand;
+import me.trouper.sentinel.server.events.violations.command.SpecificCommand;
+import me.trouper.sentinel.server.events.violations.entities.CommandMinecartBreak;
+import me.trouper.sentinel.server.events.violations.entities.CommandMinecartPlace;
+import me.trouper.sentinel.server.events.violations.entities.CommandMinecartUse;
+import me.trouper.sentinel.server.events.violations.whitelist.CommandBlockExecute;
+import me.trouper.sentinel.server.events.violations.whitelist.CommandMinecartExecute;
+import me.trouper.sentinel.server.functions.chatfilter.profanity.ProfanityFilter;
+import me.trouper.sentinel.server.functions.chatfilter.spam.SpamFilter;
+import me.trouper.sentinel.server.functions.chatfilter.unicode.UnicodeFilter;
+import me.trouper.sentinel.server.functions.chatfilter.url.UrlFilter;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.chat.ProfanityFilterGUI;
+import me.trouper.sentinel.server.gui.config.chat.SpamFilterGUI;
+import me.trouper.sentinel.server.gui.config.chat.UnicodeFilterGUI;
+import me.trouper.sentinel.server.gui.config.chat.UrlFilterGUI;
+import me.trouper.sentinel.server.gui.nbt.NBTGui;
+import me.trouper.sentinel.server.gui.whitelist.WhitelistGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+
+import java.util.function.Consumer;
+
+public class ChatEvent implements QuickListener {
+
+ @EventHandler
+ private void onChat(AsyncChatEvent e) {
+ ServerUtils.verbose("Chat event sanity check:\n Canceled %s", e.isCancelled()
+);
+ handleEvent(e);
+ }
+
+ public void handleEvent(AsyncChatEvent e) {
+ if (e.isCancelled()) return;
+ if (PlayerUtils.isTrusted(e.getPlayer().getUniqueId().toString())) {
+ if (MainGUI.awaitingCallback.contains(e.getPlayer().getUniqueId())) {
+ ServerUtils.verbose("Attempting to cancel events for callback!");
+ e.setCancelled(true);
+ MainGUI.awaitingCallback.remove(e.getPlayer().getUniqueId());
+ ServerUtils.verbose("Handling Chat Event for callbacks");
+ SchedulerUtils.later(0,()->{
+ UnicodeFilterGUI.updater.invokeCallbacks(e);
+ UrlFilterGUI.updater.invokeCallbacks(e);
+ ProfanityFilterGUI.updater.invokeCallbacks(e);
+ SpamFilterGUI.updater.invokeCallbacks(e);
+ WhitelistGUI.updater.invokeCallbacks(e);
+ NBTGui.updater.invokeCallbacks(e);
+ DangerousCommand.updater.invokeCallbacks(e);
+ LoggedCommand.updater.invokeCallbacks(e);
+ SpecificCommand.updater.invokeCallbacks(e);
+ CommandBlockBreak.updater.invokeCallbacks(e);
+ CommandBlockEdit.updater.invokeCallbacks(e);
+ CommandBlockPlace.updater.invokeCallbacks(e);
+ CommandBlockUse.updater.invokeCallbacks(e);
+ JigsawBlockBreak.updater.invokeCallbacks(e);
+ JigsawBlockPlace.updater.invokeCallbacks(e);
+ JigsawBlockUse.updater.invokeCallbacks(e);
+ StructureBlockBreak.updater.invokeCallbacks(e);
+ StructureBlockPlace.updater.invokeCallbacks(e);
+ StructureBlockUse.updater.invokeCallbacks(e);
+ CommandMinecartBreak.updater.invokeCallbacks(e);
+ CommandMinecartPlace.updater.invokeCallbacks(e);
+ CommandMinecartUse.updater.invokeCallbacks(e);
+ CommandBlockExecute.updater.invokeCallbacks(e);
+ CommandMinecartExecute.updater.invokeCallbacks(e);
+ CreativeHotbar.updater.invokeCallbacks(e);
+ });
+ }
+ return;
+ }
+
+ Player p = e.getPlayer();
+
+ ServerUtils.verbose("Chat event start after trust check:\n Canceled %s", e.isCancelled()
+);
+
+ handle(p,
+ "sentinel.chatfilter.unicode.bypass",
+ main.dir().io.mainConfig.chat.unicodeFilter.enabled, "unicode",
+ e,
+ UnicodeFilter::handleUnicodeFilter);
+
+ ServerUtils.verbose("Chat event middle after unicode:\n Canceled %s", e.isCancelled()
+);
+
+ handle(p,
+ "sentinel.chatfilter.url.bypass",
+ main.dir().io.mainConfig.chat.urlFilter.enabled, "url",
+ e,
+ UrlFilter::handleUrlFilter);
+
+ ServerUtils.verbose("Chat event middle after URL:\n Canceled %s", e.isCancelled()
+);
+
+ handle(p,
+ "sentinel.chatfilter.spam.bypass",
+ main.dir().io.mainConfig.chat.spamFilter.enabled,
+ "spam",
+ e,
+ SpamFilter::handleSpamFilter);
+
+ ServerUtils.verbose("Chat event middle after spam:\n Canceled %s", e.isCancelled()
+);
+
+ handle(p,
+ "sentinel.chatfilter.profanity.bypass",
+ main.dir().io.mainConfig.chat.profanityFilter.enabled,
+ "swear",
+ e,
+ ProfanityFilter::handleProfanityFilter);
+
+ ServerUtils.verbose("Chat event ending after swear:\n Canceled %s", e.isCancelled()
+);
+ }
+
+ private static void handle(Player p, String permission, boolean isEnabled, String eventType, AsyncChatEvent e, Consumer handler) {
+ ServerUtils.verbose("Handeling a chat filter:\n Canceled %s\nType: %s".formatted(e.isCancelled(),eventType));
+ if (e.isCancelled()) return;
+ if (p.hasPermission(permission)) return;
+ ServerUtils.verbose("ChatEvent: Permission bypass failed, checking for " + eventType);
+ if (!isEnabled) return;
+ ServerUtils.verbose("ChatEvent: " + eventType + " check enabled, continuing!");
+ handler.accept(e);
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/players/CreativeHotbar.java b/src/main/java/me/trouper/sentinel/server/events/violations/players/CreativeHotbar.java
new file mode 100644
index 0000000..a343782
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/players/CreativeHotbar.java
@@ -0,0 +1,176 @@
+package me.trouper.sentinel.server.events.violations.players;
+
+import com.github.retrooper.packetevents.protocol.packettype.PacketType;
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import io.github.itzispyder.pdk.utils.misc.Pair;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.functions.hotbar.items.ItemCheck;
+import me.trouper.sentinel.server.functions.hotbar.items.RateLimitCheck;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCreativeEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CreativeHotbar extends AbstractViolation {
+
+ @EventHandler
+ private void onNBTPull(InventoryCreativeEvent e) {
+ //ServerUtils.verbose("NBT: Detected creative mode action");
+ if (!main.dir().io.violationConfig.creativeHotbarAction.enabled) return;
+ //ServerUtils.verbose("NBT: Enabled");
+ if (!(e.getWhoClicked() instanceof Player p)) return;
+ //ServerUtils.verbose("NBT: Clicker is a player");
+ if (e.getCursor() == null) return; // Well it threw an exception during testing, so it isn't always false!
+ //ServerUtils.verbose("NBT: Cursor isn't null");
+ ItemStack i = e.getCursor();
+ if (PlayerUtils.isTrusted(p)) return;
+ //ServerUtils.verbose("NBT: Not trusted");
+ scan(e,p,i);
+ }
+
+ public void scan(InventoryCreativeEvent e, Player p, ItemStack i) {
+ if (e.getCursor().getItemMeta() == null) return;
+ //ServerUtils.verbose("NBT: Cursor has meta");
+ if (!(i.hasItemMeta() && i.getItemMeta() != null)) return;
+ if (!new RateLimitCheck().passes(new Pair<>(p,i))) {
+ List punishmentCommands = new ArrayList<>();
+ for (String punishmentCommand : main.dir().io.nbtConfig.rateLimit.punishmentCommands) {
+ try {
+ punishmentCommand = punishmentCommand.formatted(RateLimitCheck.dataUsed.get(p.getUniqueId()),main.dir().io.nbtConfig.rateLimit.rateLimitBytes);
+ } catch (Exception ignored) {}
+ punishmentCommands.add(punishmentCommand);
+ }
+
+ ServerUtils.verbose("Player flags rate limit, performing action");
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .cancel(true)
+ .punish(true)
+ .deop(main.dir().io.violationConfig.creativeHotbarAction.deop)
+ .setPunishmentCommands(punishmentCommands);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.grab, main.dir().io.lang.violations.protections.rootName.nbtItem),
+ generatePlayerInfo(p),
+ config
+ );
+
+ return;
+ }
+ if (new ItemCheck().passes(i)) return;
+ ServerUtils.verbose("NBT: Item doesn't pass, performing action");
+
+ main.dir().io.nbtStorage.storeItem(i, p.getUniqueId());
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setPlayer(p)
+ .cancel(true)
+ .punish(main.dir().io.violationConfig.creativeHotbarAction.punish)
+ .deop(main.dir().io.violationConfig.creativeHotbarAction.deop)
+ .setPunishmentCommands(main.dir().io.violationConfig.creativeHotbarAction.punishmentCommands)
+ .logToDiscord(main.dir().io.violationConfig.creativeHotbarAction.logToDiscord);
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormatPlayer,p.getName(), main.dir().io.lang.violations.protections.rootName.grab, main.dir().io.lang.violations.protections.rootName.nbtItem),
+ generateItemInfo(i),
+ config
+ );
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Creative Hotbar Check"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i, Items.BLANK);
+ }
+
+ ItemStack ring = Items.RED;
+ if (main.dir().io.violationConfig.creativeHotbarAction.enabled) {
+ ring = Items.GREEN;
+ }
+
+ List ringList = List.of(3,4,5,12,14,21,22,23);
+
+ for (Integer i : ringList) {
+ inv.setItem(i,ring);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.creativeHotbarAction.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(2,Items.booleanItem(main.dir().io.violationConfig.creativeHotbarAction.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.violationConfig.creativeHotbarAction.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(6,Items.booleanItem(main.dir().io.violationConfig.creativeHotbarAction.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.violationConfig.creativeHotbarAction.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+
+ switch (e.getSlot()) {
+ case 13 -> {
+ main.dir().io.violationConfig.creativeHotbarAction.enabled = !main.dir().io.violationConfig.creativeHotbarAction.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 2 -> {
+ main.dir().io.violationConfig.creativeHotbarAction.deop = !main.dir().io.violationConfig.creativeHotbarAction.deop;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 20 -> {
+ main.dir().io.violationConfig.creativeHotbarAction.logToDiscord = !main.dir().io.violationConfig.creativeHotbarAction.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 6 -> {
+ main.dir().io.violationConfig.creativeHotbarAction.punish = !main.dir().io.violationConfig.creativeHotbarAction.punish;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ case 24 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
+ cfg.creativeHotbarAction.punishmentCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.creativeHotbarAction.punishmentCommands);
+ return;
+ }
+ main.dir().io.violationConfig.creativeHotbarAction.punishmentCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/players/EthanolPacket.java b/src/main/java/me/trouper/sentinel/server/events/violations/players/EthanolPacket.java
new file mode 100644
index 0000000..3c94c12
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/players/EthanolPacket.java
@@ -0,0 +1,40 @@
+package me.trouper.sentinel.server.events.violations.players;
+
+import com.github.retrooper.packetevents.event.PacketListener;
+import com.github.retrooper.packetevents.event.PacketReceiveEvent;
+import com.github.retrooper.packetevents.protocol.packettype.PacketType;
+import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPluginMessage;
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+
+public class EthanolPacket extends AbstractViolation implements PacketListener {
+
+
+ @Override
+ public void onPacketReceive(PacketReceiveEvent event) {
+ if (!event.getPacketType().equals(PacketType.Play.Client.PLUGIN_MESSAGE)) return;
+ WrapperPlayClientPluginMessage packet = new WrapperPlayClientPluginMessage(event);
+ String channel = packet.getChannelName();
+ if (channel.equals("auth_res")) {
+ // TODO: Finish Ethanol Detection
+ System.out.println("Detected ethanol, but I haven't coded the way to stop it yet.");
+ }
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return null;
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/events/PluginCloakingEvent.java b/src/main/java/me/trouper/sentinel/server/events/violations/players/PluginCloakingEvents.java
similarity index 56%
rename from src/main/java/me/trouper/sentinel/server/events/PluginCloakingEvent.java
rename to src/main/java/me/trouper/sentinel/server/events/violations/players/PluginCloakingEvents.java
index 549ed74..f98b745 100644
--- a/src/main/java/me/trouper/sentinel/server/events/PluginCloakingEvent.java
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/players/PluginCloakingEvents.java
@@ -1,9 +1,10 @@
-package me.trouper.sentinel.server.events;
+package me.trouper.sentinel.server.events.violations.players;
import io.github.itzispyder.pdk.events.CustomListener;
import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.events.QuickListener;
import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
import me.trouper.sentinel.utils.Text;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -13,17 +14,17 @@ import org.bukkit.event.player.PlayerQuitEvent;
import java.util.List;
-public class PluginCloakingEvent implements CustomListener {
+public class PluginCloakingEvents implements QuickListener {
@EventHandler
public void onQuit(PlayerQuitEvent e) {
- PluginCloakingPacket.tabReplaceQueue.remove(e.getPlayer());
+ PluginCloakingPacket.tabReplaceQueue.remove(e.getPlayer().getUniqueId());
}
@EventHandler
public void onCommand(PlayerCommandPreprocessEvent e) {
- if (!Sentinel.mainConfig.plugin.pluginHider) return;
+ if (!main.dir().io.mainConfig.plugin.pluginHider) return;
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) return;
@@ -33,16 +34,16 @@ public class PluginCloakingEvent implements CustomListener {
message = message.substring(1);
}
- for (String alias : Sentinel.advConfig.commandsWithPluginAccess) {
- if (!message.startsWith(alias)) continue;
+ for (String alias : main.dir().io.advConfig.commandsWithPluginAccess) {
+ if (!message.equals(alias)) continue;
e.setCancelled(true);
- p.sendMessage(Text.color(Sentinel.lang.permissions.noPlugins));
+ p.sendMessage(Text.color(main.dir().io.lang.permissions.noPlugins)); // This Player.sendMessage() call is ALLOWED. We want to let the owner set the sendMessage to whatever they want.
}
}
@EventHandler
public void onTabComplete(PlayerCommandSendEvent e) {
- if (!Sentinel.mainConfig.plugin.pluginHider) return;
+ if (!main.dir().io.mainConfig.plugin.pluginHider) return;
Player p = e.getPlayer();
if (PlayerUtils.isTrusted(p)) return;
@@ -52,15 +53,15 @@ public class PluginCloakingEvent implements CustomListener {
e.getCommands().remove(command);
continue;
}
- if (Sentinel.advConfig.commandsWithPluginAccess.contains(command)) {
+ if (main.dir().io.advConfig.commandsWithPluginAccess.contains(command)) {
e.getCommands().remove(command);
continue;
}
}
- ServerUtils.verbose("Removed all the plugin specific commands form the listing. It now contains %s".formatted(e.getCommands().stream().toList().toString()));
- for (String fakePlugin : Sentinel.advConfig.fakePlugins) {
+ //ServerUtils.verbose("Removed all the plugin specific commands form the listing. It now contains %s".formatted(e.getCommands().stream().toList().toString()));
+ for (String fakePlugin : main.dir().io.advConfig.fakePlugins) {
e.getCommands().add(fakePlugin + ":" + fakePlugin);
}
- ServerUtils.verbose("Added the fake plugins, now it contains this: %s".formatted(e.getCommands().stream().toList().toString()));
+ //ServerUtils.verbose("Added the fake plugins, now it contains this: %s".formatted(e.getCommands().stream().toList().toString()));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/events/PluginCloakingPacket.java b/src/main/java/me/trouper/sentinel/server/events/violations/players/PluginCloakingPacket.java
similarity index 50%
rename from src/main/java/me/trouper/sentinel/server/events/PluginCloakingPacket.java
rename to src/main/java/me/trouper/sentinel/server/events/violations/players/PluginCloakingPacket.java
index 3b6a440..ed81f56 100644
--- a/src/main/java/me/trouper/sentinel/server/events/PluginCloakingPacket.java
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/players/PluginCloakingPacket.java
@@ -1,7 +1,6 @@
-package me.trouper.sentinel.server.events;
+package me.trouper.sentinel.server.events.violations.players;
-import com.github.retrooper.packetevents.event.PacketListenerAbstract;
-import com.github.retrooper.packetevents.event.PacketListenerPriority;
+import com.github.retrooper.packetevents.event.PacketListener;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.chat.Node;
@@ -10,6 +9,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTa
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDeclareCommands;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTabComplete;
import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import org.bukkit.entity.Player;
@@ -18,39 +18,63 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
+import java.util.concurrent.ConcurrentLinkedQueue;
-public class PluginCloakingPacket extends PacketListenerAbstract {
-
- public static final List tabReplaceQueue = new ArrayList<>();
-
- public PluginCloakingPacket() {
- super(PacketListenerPriority.NORMAL);
- }
+public class PluginCloakingPacket implements Main, PacketListener {
+ public static final ConcurrentLinkedQueue tabReplaceQueue = new ConcurrentLinkedQueue<>();
+
@Override
public void onPacketReceive(PacketReceiveEvent event) {
- if (!Sentinel.mainConfig.plugin.pluginHider) return;
- if (event.getPacketType() != PacketType.Play.Client.TAB_COMPLETE) return;
+ if (!main.dir().io.mainConfig.plugin.pluginHider) return;
+ switch (event.getPacketType()) {
+ case PacketType.Play.Client.TAB_COMPLETE -> {
+ WrapperPlayClientTabComplete wrapper = new WrapperPlayClientTabComplete(event);
+ Player player = (Player) event.getPlayer();
+ if (player == null) return;
+ if (PlayerUtils.isTrusted(player)) return;
- WrapperPlayClientTabComplete wrapper = new WrapperPlayClientTabComplete(event);
- Player player = (Player) event.getPlayer();
- if (player == null) return;
- if (PlayerUtils.isTrusted(player)) return;
+ String text = wrapper.getText();
+ if (text.startsWith("/")) text = text.substring(1);
+ text = text.split(" ")[0];
- String text = wrapper.getText();
- for (String versionAlias : Sentinel.advConfig.pluginTabCompletions) {
- if (!text.contains(versionAlias)) continue;
- ServerUtils.verbose("Caught a version command tab completion. (%s -> %s)".formatted(text,versionAlias));
- tabReplaceQueue.add(player.getUniqueId());
- break;
+ List intendedCommands = main.dir().io.advConfig.intendedCommands;
+ List pluginTabCompletions = main.dir().io.advConfig.pluginTabCompletions;
+
+ if (main.dir().io.advConfig.pluginCloakingWhitelist) {
+ boolean whitelisted = false;
+ for (String pattern : intendedCommands) {
+ if (text.matches(pattern)) {
+ whitelisted = true;
+ break;
+ }
+ }
+ if (!whitelisted) {
+ ServerUtils.verbose("Caught a non-whitelisted tab completion. (%s)", text)
+;
+ tabReplaceQueue.add(player.getUniqueId());
+ }
+ }
+
+ for (String pattern : pluginTabCompletions) {
+ if (text.matches(pattern)) {
+ ServerUtils.verbose("Caught a plugin listing command tab completion. (%s -> %s)", text, pattern)
+;
+ tabReplaceQueue.add(player.getUniqueId());
+ break;
+ }
+ }
+ }
+ default -> {}
}
}
+
@Override
public void onPacketSend(PacketSendEvent event) {
- if (!Sentinel.mainConfig.plugin.pluginHider) return;
+ if (!main.dir().io.mainConfig.plugin.pluginHider) return;
Player player = (Player) event.getPlayer();
if (player == null) return;
@@ -63,7 +87,7 @@ public class PluginCloakingPacket extends PacketListenerAbstract {
ServerUtils.verbose("Player was queued for replacement, setting tab completions.");
WrapperPlayServerTabComplete wrapper = new WrapperPlayServerTabComplete(event);
List matches = new ArrayList<>();
- for (String fakePlugin : Sentinel.advConfig.fakePlugins) {
+ for (String fakePlugin : main.dir().io.advConfig.fakePlugins) {
matches.add(new WrapperPlayServerTabComplete.CommandMatch(fakePlugin));
}
wrapper.setCommandMatches(matches);
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/whitelist/CommandBlockExecute.java b/src/main/java/me/trouper/sentinel/server/events/violations/whitelist/CommandBlockExecute.java
new file mode 100644
index 0000000..533314c
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/whitelist/CommandBlockExecute.java
@@ -0,0 +1,157 @@
+package me.trouper.sentinel.server.events.violations.whitelist;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.CommandBlock;
+import org.bukkit.command.BlockCommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.server.ServerCommandEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.UUID;
+
+public class CommandBlockExecute extends AbstractViolation {
+
+ @EventHandler
+ private void commandBlockExecute(ServerCommandEvent e) {
+ //ServerUtils.verbose("Handling command block event: " + e.getCommand());
+ if (!main.dir().io.violationConfig.commandBlockWhitelist.enabled) return;
+ //ServerUtils.verbose("Whitelist not disabled");
+ if (!(e.getSender() instanceof BlockCommandSender s)) return;
+ //ServerUtils.verbose("Sender is command block");
+
+ Block block = s.getBlock();
+ CommandBlock cb = (CommandBlock) block.getState();
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(cb.getLocation());
+
+ String label = cb.getCommand();
+ ServerUtils.verbose("Command block is set to %s.", label)
+;
+ label = label.split(" ")[0];
+ if (label.startsWith("/")) label = label.substring(1);
+ ServerUtils.verbose("It's label is %s.", label)
+;
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setBlock(block)
+ .cancel(true)
+ .destroyBlock(main.dir().io.violationConfig.commandBlockWhitelist.destroyBlock)
+ .restoreBlock(main.dir().io.violationConfig.commandBlockWhitelist.attemptRestore)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockWhitelist.logToDiscord);
+
+ if (main.dir().io.violationConfig.commandBlockWhitelist.disabledCommands.contains(label)) {
+ ServerUtils.verbose("Command block is using a restricted command.");
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormat,main.dir().io.lang.violations.protections.rootName.commandBlockRestriction),
+ generateCommandBlockInfo(cb),
+ config
+ );
+ } else if (holder == null || !holder.isWhitelisted() || !holder.present()|| !PlayerUtils.isTrusted(UUID.fromString(holder.owner()))) {
+ ServerUtils.verbose("Command block can't run. Not whitelisted and/or trusted.");
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormat,main.dir().io.lang.violations.protections.rootName.commandBlockWhitelist),
+ generateCommandBlockInfo(cb),
+ config
+ );
+ }
+ }
+
+
+ @Override
+ public CustomGui getConfigGui() {
+ return CustomGui.create()
+ .title(OldTXT.color("&6&lSentinel &8»&0 Command Block Whitelist"))
+ .size(27)
+ .onDefine(this::getMainPage)
+ .defineMain(this::onClick)
+ .define(26, Items.BACK, e->{
+ e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
+ })
+ .build();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ for (int i = 0; i < inv.getSize(); i++) {
+ inv.setItem(i,Items.BLANK);
+ }
+
+ ItemStack top = Items.RED;
+ if (main.dir().io.violationConfig.commandBlockWhitelist.enabled) {
+ top = Items.GREEN;
+ }
+
+ for (int i = 0; i < 9; i++) {
+ inv.setItem(i,top);
+ }
+
+ inv.setItem(26,Items.BACK);
+ inv.setItem(4,Items.booleanItem(main.dir().io.violationConfig.commandBlockWhitelist.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
+ inv.setItem(11,Items.booleanItem(main.dir().io.violationConfig.commandBlockWhitelist.destroyBlock,Items.configItem("Destroy",Material.NETHERITE_PICKAXE,"Destroy the offending command-block")));
+ inv.setItem(12,Items.booleanItem(main.dir().io.violationConfig.commandBlockWhitelist.destroyCart,Items.configItem("Destroy",Material.TNT_MINECART,"Destroy the offending command-cart")));
+ inv.setItem(13,Items.booleanItem(main.dir().io.violationConfig.commandBlockWhitelist.attemptRestore,Items.configItem("Restore",Material.COMMAND_BLOCK,"Attempt to restore the block if a \nwhitelisted one exists at the location")));
+ inv.setItem(14,Items.booleanItem(main.dir().io.violationConfig.commandBlockWhitelist.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
+ inv.setItem(15,Items.stringListItem(main.dir().io.violationConfig.commandBlockWhitelist.disabledCommands,Material.CRIMSON_HANGING_SIGN,"Commands","Commands no command blocks can run. \nWorks even if whitelist is disabled. \nYou must add plugin specific versions yourself."));
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ e.setCancelled(true);
+ if (!MainGUI.verify((Player) e.getWhoClicked())) return;
+ switch (e.getSlot()) {
+ case 4 -> {
+ main.dir().io.violationConfig.commandBlockWhitelist.enabled = !main.dir().io.violationConfig.commandBlockWhitelist.enabled;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 11 -> {
+ main.dir().io.violationConfig.commandBlockWhitelist.destroyBlock = !main.dir().io.violationConfig.commandBlockWhitelist.destroyBlock;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 12 -> {
+ main.dir().io.violationConfig.commandBlockWhitelist.destroyCart = !main.dir().io.violationConfig.commandBlockWhitelist.destroyCart;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 13 -> {
+ main.dir().io.violationConfig.commandBlockWhitelist.attemptRestore = !main.dir().io.violationConfig.commandBlockWhitelist.attemptRestore;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 14 -> {
+ main.dir().io.violationConfig.commandBlockWhitelist.logToDiscord = !main.dir().io.violationConfig.commandBlockWhitelist.logToDiscord;
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ case 15 -> {
+ if (e.isLeftClick()) {
+ queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
+ cfg.commandBlockWhitelist.disabledCommands.add(args.getAll().toString());
+ },"" + main.dir().io.violationConfig.commandBlockWhitelist.disabledCommands);
+ return;
+ }
+ main.dir().io.violationConfig.commandBlockWhitelist.disabledCommands.clear();
+ getMainPage(e.getInventory());
+ main.dir().io.violationConfig.save();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/events/violations/whitelist/CommandMinecartExecute.java b/src/main/java/me/trouper/sentinel/server/events/violations/whitelist/CommandMinecartExecute.java
new file mode 100644
index 0000000..4438a35
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/events/violations/whitelist/CommandMinecartExecute.java
@@ -0,0 +1,76 @@
+package me.trouper.sentinel.server.events.violations.whitelist;
+
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.events.violations.AbstractViolation;
+import me.trouper.sentinel.server.functions.helpers.ActionConfiguration;
+import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.Text;
+import org.bukkit.entity.minecart.CommandMinecart;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.server.ServerCommandEvent;
+import org.bukkit.inventory.Inventory;
+
+import java.util.UUID;
+
+public class CommandMinecartExecute extends AbstractViolation {
+
+ @EventHandler
+ public void onExecute(ServerCommandEvent e) {
+ //ServerUtils.verbose("Handling command block event: " + e.getCommand());
+ if (!main.dir().io.violationConfig.commandBlockWhitelist.enabled) return;
+ //ServerUtils.verbose("Whitelist not disabled");
+ if (!(e.getSender() instanceof CommandMinecart s)) return;
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(s.getUniqueId());
+
+ String label = s.getCommand();
+ ServerUtils.verbose("Command block is set to %s.", label)
+;
+ label = label.split(" ")[0];
+ if (label.startsWith("/")) label = label.substring(1);
+ ServerUtils.verbose("It's label is %s.", label)
+;
+
+ ActionConfiguration.Builder config = new ActionConfiguration.Builder()
+ .setEvent(e)
+ .setEntity(s)
+ .cancel(true)
+ .removeEntity(main.dir().io.violationConfig.commandBlockWhitelist.destroyCart)
+ .logToDiscord(main.dir().io.violationConfig.commandBlockWhitelist.logToDiscord);
+
+ if (main.dir().io.violationConfig.commandBlockWhitelist.disabledCommands.contains(label)) {
+ ServerUtils.verbose("Command cart is using a restricted command.");
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormat,main.dir().io.lang.violations.protections.rootName.commandBlockRestriction),
+ generateMinecartInfo(s),
+ config
+ );
+ } else if (holder == null || !holder.isWhitelisted() || !holder.present() || !PlayerUtils.isTrusted(UUID.fromString(holder.owner()))) {
+ ServerUtils.verbose("Command cart can't run. Block is not whitelisted, and/or not trusted.");
+
+ runActions(
+ Text.format(Text.Pallet.WARNING,main.dir().io.lang.violations.protections.rootName.rootNameFormat,main.dir().io.lang.violations.protections.rootName.commandBlockWhitelist),
+ generateMinecartInfo(s),
+ config
+ );
+ }
+ }
+
+ @Override
+ public CustomGui getConfigGui() {
+ return new CommandBlockExecute().getConfigGui();
+ }
+
+ @Override
+ public void getMainPage(Inventory inv) {
+ new CommandBlockExecute().getMainPage(inv);
+ }
+
+ @Override
+ public void onClick(InventoryClickEvent e) {
+ new CommandBlockExecute().onClick(e);
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/AbstractActionHandler.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/AbstractActionHandler.java
index 8c70761..2745f72 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/AbstractActionHandler.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/AbstractActionHandler.java
@@ -1,21 +1,21 @@
package me.trouper.sentinel.server.functions.chatfilter;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
+import io.papermc.paper.event.player.AsyncChatEvent;
import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.FalsePositiveReporting;
-import me.trouper.sentinel.server.functions.helpers.FilterHelpers;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.utils.trees.ConsoleFormatter;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import me.trouper.sentinel.utils.trees.Node;
-public abstract class AbstractActionHandler {
+public abstract class AbstractActionHandler implements Main {
public void run(T response) {
- FalsePositiveReporting.reports.put(response.getReport().getId(), response.getReport());
+ main.dir().reportHandler.reports.put(response.getReport().getId(), response.getReport());
Node tree = buildTree(response);
if (response.isBlocked()) {
- FilterHelpers.restrictMessage(response.getEvent(),!shouldWarnPlayer(response));
+ restrictMessage(response.getEvent(),!shouldWarnPlayer(response));
}
if (response.isPunished()) {
punish(response);
@@ -36,11 +36,20 @@ public abstract class AbstractActionHandler {
protected abstract boolean shouldWarnPlayer(T response);
protected void consoleLog(Node tree) {
- Sentinel.log.info(ConsoleFormatter.format(tree));
+ Sentinel.getInstance().getLogger().info(ConsoleFormatter.format(tree));
}
protected void discordNotification(Node tree) {
DiscordEmbed embed = EmbedFormatter.format(tree);
EmbedFormatter.sendEmbed(embed);
}
+
+ protected void restrictMessage(AsyncChatEvent event, boolean silent) {
+ if (silent) {
+ event.viewers().clear();
+ event.viewers().add(event.getPlayer());
+ } else {
+ event.setCancelled(true);
+ }
+ }
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/FilterResponse.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/FilterResponse.java
index ef075f8..aec097a 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/FilterResponse.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/FilterResponse.java
@@ -1,10 +1,11 @@
package me.trouper.sentinel.server.functions.chatfilter;
import io.papermc.paper.event.player.AsyncChatEvent;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.server.functions.helpers.Report;
import org.bukkit.entity.Player;
-public interface FilterResponse {
+public interface FilterResponse extends Main {
AsyncChatEvent getEvent();
Player getPlayer();
Report getReport();
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.java
index 1c803de..031b775 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityAction.java
@@ -1,7 +1,7 @@
package me.trouper.sentinel.server.functions.chatfilter.profanity;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.AbstractActionHandler;
+import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import me.trouper.sentinel.utils.trees.HoverFormatter;
@@ -14,59 +14,66 @@ public class ProfanityAction extends AbstractActionHandler {
@Override
public void punish(ProfanityResponse response) {
if (response.getSeverity().equals(Severity.SLUR)) {
- for (String slurCommand : Sentinel.mainConfig.chat.profanityFilter.strictPunishCommands) {
+ for (String slurCommand : main.dir().io.mainConfig.chat.profanityFilter.strictPunishCommands) {
ServerUtils.sendCommand(slurCommand.replaceAll("%player%", response.getPlayer().getName()));
}
}
- for (String swearCommand : Sentinel.mainConfig.chat.profanityFilter.profanityPunishCommands) {
+ for (String swearCommand : main.dir().io.mainConfig.chat.profanityFilter.profanityPunishCommands) {
ServerUtils.sendCommand(swearCommand.replaceAll("%player%", response.getPlayer().getName()));
}
}
@Override
public void staffWarning(ProfanityResponse response, Node tree) {
- String messageText = Text.prefix("&b&n%s&r &7%s &8(&4%s&7/&c%s&8)".formatted(
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,response.isPunished() ?
+ main.dir().io.lang.violations.chat.profanity.autoPunishNotification :
+ main.dir().io.lang.violations.chat.profanity.preventNotification,
response.getPlayer().getName(),
- response.isPunished() ? Sentinel.lang.violations.chat.profanity.autoPunishNotification : Sentinel.lang.violations.chat.profanity.preventNotification,
ProfanityFilter.scoreMap.getOrDefault(response.getPlayer().getUniqueId(), 0),
- Sentinel.mainConfig.chat.profanityFilter.punishScore
- ));
- String hoverText = HoverFormatter.format(tree);
+ main.dir().io.mainConfig.chat.profanityFilter.punishScore
+ );
- ServerUtils.forEachPlayer(player -> {
- if (player.hasPermission("sentinel.chatfilter.profanity.view")) player.sendMessage(Component.text(messageText).hoverEvent(Component.text(hoverText).asHoverEvent()));
+ PlayerUtils.forEachPlayer(player -> {
+ if (!player.hasPermission("sentinel.chatfilter.profanity.view")) return;
+ Text.message(Text.Pallet.INFO,player,message.hoverEvent(HoverFormatter.format(tree).asHoverEvent()));
});
}
@Override
public void playerWarning(ProfanityResponse response) {
- String message = Text.prefix(response.isPunished() ? Sentinel.lang.violations.chat.profanity.autoPunishWarning : Sentinel.lang.violations.chat.profanity.preventWarning);
- String hoverText = Sentinel.lang.automatedActions.reportable;
- String command = "/sentinelcallback fpreport %s".formatted(response.getReport().getId());
- response.getPlayer().sendMessage(Component.text(message)
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,
+ response.isPunished() ? main.dir().io.lang.violations.chat.profanity.autoPunishWarning :
+ main.dir().io.lang.violations.chat.profanity.preventWarning
+ );
+ String hoverText = main.dir().io.lang.automatedActions.reportable;
+ String command = "/sentinelcallback fpreport " + response.getReport().getId();
+ Text.message(Text.Pallet.INFO,response.getPlayer(),message
.hoverEvent(Component.text(hoverText).asHoverEvent())
- .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command)));
+ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command))
+ );
}
@Override
public Node buildTree(ProfanityResponse response) {
- Node root = new Node("Sentinel");
- root.addTextLine(Sentinel.lang.violations.chat.profanity.treeTitle);
+ Node root = new Node();
+ root.addTextLine(Text.format(Text.Pallet.NEUTRAL,main.dir().io.lang.violations.chat.profanity.treeTitle,response.getPlayer().name()));
- Node playerInfo = new Node(Sentinel.lang.violations.protections.infoNode.playerInfo.formatted(response.getPlayer().getName()));
- playerInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.uuid, response.getPlayer().getUniqueId().toString());
- playerInfo.addKeyValue(Sentinel.lang.violations.chat.profanity.score, "%s/%s".formatted(ProfanityFilter.scoreMap.getOrDefault(response.getPlayer().getUniqueId(),0),Sentinel.mainConfig.chat.profanityFilter.punishScore));
+ Node playerInfo = new Node(main.dir().io.lang.violations.protections.infoNode.playerInfo.formatted(response.getPlayer().getName()));
+ playerInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.uuid, response.getPlayer().getUniqueId().toString());
+ playerInfo.addKeyValue(main.dir().io.lang.violations.chat.profanity.score, "%s/%s".formatted(ProfanityFilter.scoreMap.getOrDefault(response.getPlayer().getUniqueId(),0),main.dir().io.mainConfig.chat.profanityFilter.punishScore));
root.addChild(playerInfo);
- Node reportInfo = new Node(Sentinel.lang.violations.chat.profanity.reportInfoTitle);
- reportInfo.addField(Sentinel.lang.violations.chat.originalMessage, response.getOriginalMessage());
- reportInfo.addField(Sentinel.lang.violations.chat.profanity.processedMessage, response.getProcessedMessage());
- reportInfo.addKeyValue(Sentinel.lang.violations.chat.profanity.severity, response.getSeverity().toString());
+ Node reportInfo = new Node(main.dir().io.lang.violations.chat.profanity.reportInfoTitle);
+ reportInfo.addField(main.dir().io.lang.violations.chat.originalMessage, response.getOriginalMessage());
+ reportInfo.addField(Component.text(main.dir().io.lang.violations.chat.profanity.processedMessage), Node.parseLegacyText(response.getProcessedMessage()));
+ reportInfo.addKeyValue(main.dir().io.lang.violations.chat.profanity.severity, response.getSeverity().toString());
root.addChild(reportInfo);
- Node actions = new Node(Sentinel.lang.violations.protections.actionNode.actionNodeTitle);
- actions.addTextLine(Sentinel.lang.violations.chat.denyMessage);
- if (response.isPunished()) actions.addTextLine(Sentinel.lang.violations.protections.actionNode.punishmentCommandsExecuted);
+ Node actions = new Node(main.dir().io.lang.violations.protections.actionNode.actionNodeTitle);
+ actions.addTextLine(main.dir().io.lang.violations.chat.denyMessage);
+ if (response.isPunished()) actions.addTextLine(main.dir().io.lang.violations.protections.actionNode.punishmentCommandsExecuted);
root.addChild(actions);
return root;
@@ -74,6 +81,6 @@ public class ProfanityAction extends AbstractActionHandler {
@Override
protected boolean shouldWarnPlayer(ProfanityResponse response) {
- return !Sentinel.mainConfig.chat.profanityFilter.silent;
+ return !main.dir().io.mainConfig.chat.profanityFilter.silent;
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityFilter.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityFilter.java
index c07ddb1..b08104c 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityFilter.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityFilter.java
@@ -2,15 +2,15 @@ package me.trouper.sentinel.server.functions.chatfilter.profanity;
import io.papermc.paper.event.player.AsyncChatEvent;
import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.utils.ServerUtils;
import org.bukkit.entity.Player;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-public class ProfanityFilter {
+public class ProfanityFilter implements Main {
public static Map scoreMap = new HashMap<>();
public static void handleProfanityFilter(AsyncChatEvent event) {
@@ -33,7 +33,7 @@ public class ProfanityFilter {
int newScore = previousScore + severity.getScore();
scoreMap.put(player.getUniqueId(), newScore);
- if (newScore > Sentinel.mainConfig.chat.profanityFilter.punishScore || Severity.SLUR.equals(severity)) {
+ if (newScore > main.dir().io.mainConfig.chat.profanityFilter.punishScore || Severity.SLUR.equals(severity)) {
response.setPunished(true);
new ProfanityAction().run(response);
return;
@@ -46,7 +46,7 @@ public class ProfanityFilter {
for (UUID uuid : scoreMap.keySet()) {
int score = scoreMap.get(uuid);
if (score > 0) {
- score = score - Sentinel.mainConfig.chat.profanityFilter.scoreDecay;
+ score = score - main.dir().io.mainConfig.chat.profanityFilter.scoreDecay;
scoreMap.put(uuid, Math.max(0, score));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.java
index b40737e..6de24a2 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/ProfanityResponse.java
@@ -1,22 +1,26 @@
package me.trouper.sentinel.server.functions.chatfilter.profanity;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.data.Emojis;
-import me.trouper.sentinel.server.functions.helpers.FalsePositiveReporting;
-import me.trouper.sentinel.server.functions.helpers.FilterHelpers;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.types.Emojis;
import me.trouper.sentinel.server.functions.chatfilter.FilterResponse;
import me.trouper.sentinel.server.functions.helpers.Report;
+import me.trouper.sentinel.utils.FormatUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.entity.Player;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
public class ProfanityResponse implements FilterResponse {
- private AsyncChatEvent event;
+ private final AsyncChatEvent event;
private String originalMessage;
private String processedMessage;
- private Report report;
+ private final Report report;
private Severity severity;
private boolean blocked;
private boolean punished;
@@ -35,23 +39,15 @@ public class ProfanityResponse implements FilterResponse {
public Player getPlayer() {
return event.getPlayer();
}
-
+
public AsyncChatEvent getEvent() {
return event;
}
- public void setEvent(AsyncChatEvent event) {
- this.event = event;
- }
-
public String getOriginalMessage() {
return originalMessage;
}
- public void setOriginalMessage(String originalMessage) {
- this.originalMessage = originalMessage;
- }
-
public String getProcessedMessage() {
return processedMessage;
}
@@ -64,10 +60,6 @@ public class ProfanityResponse implements FilterResponse {
return report;
}
- public void setReport(Report report) {
- this.report = report;
- }
-
public Severity getSeverity() {
return severity;
}
@@ -91,101 +83,157 @@ public class ProfanityResponse implements FilterResponse {
public void setPunished(boolean punished) {
this.punished = punished;
}
-
+
public static ProfanityResponse generate(AsyncChatEvent e) {
if (e.isCancelled()) {
- ServerUtils.verbose("Profanity response opening: Event is canceled.");
+ ServerUtils.verbose("Profanity response: Event is already cancelled.");
}
- String message = LegacyComponentSerializer.legacySection().serialize(e.message());
- Report report = FalsePositiveReporting.initializeReport(message);
- Severity severity = Severity.SAFE;
+ String message = PlainTextComponentSerializer.plainText().serialize(e.message());
+ Report report = main.dir().reportHandler.initializeReport(message);
+ ProfanityResponse response = new ProfanityResponse(e, message, message, report, Severity.SAFE, false, false);
+ Severity currentSeverity;
- ProfanityResponse response = new ProfanityResponse(e,message,null,report,severity,false,false);
+ // Stage 1: Basic check on lowercased text
+ String processedText = Text.removeColors(message).toLowerCase();
+ report.getStepsTaken().put("Lowercased", processedText);
+ ServerUtils.verbose("ProfanityFilter: Lowercased: " + processedText);
+ currentSeverity = checkProfanity(processedText, Severity.LOW);
+ if (currentSeverity != Severity.SAFE) return finalizeResponse(response, processedText, "Lowercased", currentSeverity);
- String text = Text.removeFirstColor(message);
- response.setOriginalMessage(text);
-
- // 1:
- String lowercasedText = text.toLowerCase();
- response.getReport().getStepsTaken().put("Lowercased", lowercasedText);
- response.setProcessedMessage(FilterHelpers.highlightProfanity(lowercasedText,"", ""));
- ServerUtils.verbose("ProfanityFilter: Lowercased: " + lowercasedText);
+ // Stage 2: Mask allowed words
+ processedText = maskValidWords(processedText);
+ report.getStepsTaken().put("Masked Valid Words", processedText);
+ ServerUtils.verbose("ProfanityFilter: Masked Valid Words: " + processedText);
- // 2:
- String cleanedText = FilterHelpers.removeFalsePositives(lowercasedText);
- response.getReport().getStepsTaken().put("Remove False Positives", cleanedText);
- response.setProcessedMessage(FilterHelpers.highlightProfanity(cleanedText,"", ""));
- ServerUtils.verbose(("ProfanityFilter: Removed False positives: " + cleanedText));
+ // Stage 3: Convert LeetSpeak (e.g., @ -> a, 3 -> e)
+ processedText = convertLeetSpeakCharacters(processedText);
+ report.getStepsTaken().put("Convert LeetSpeak", processedText);
+ ServerUtils.verbose("ProfanityFilter: Leet Converted: " + processedText);
+ currentSeverity = checkProfanity(processedText, Severity.MEDIUM_LOW);
+ if (currentSeverity != Severity.SAFE) return finalizeResponse(response, processedText, "Convert LeetSpeak", currentSeverity);
- response.setSeverity(FilterHelpers.checkSlur(cleanedText, Severity.LOW));
- if (response.getSeverity() != Severity.SAFE) {
- response.getReport().getStepsTaken().replace("Remove False Positives", "%s %s".formatted(
- FilterHelpers.highlightProfanity(cleanedText,"||","||"),
- Emojis.alarm));
- return response;
- }
+ // Stage 4: Strip special characters
+ processedText = stripSpecialCharacters(processedText);
+ report.getStepsTaken().put("Remove Special Characters", processedText);
+ ServerUtils.verbose("ProfanityFilter: Specials Removed: " + processedText);
+ currentSeverity = checkProfanity(processedText, Severity.MEDIUM);
+ if (currentSeverity != Severity.SAFE) return finalizeResponse(response, processedText, "Remove Special Characters", currentSeverity);
- // 4:
- String convertedText = FilterHelpers.convertLeetSpeakCharacters(cleanedText);
- response.getReport().getStepsTaken().put("Convert LeetSpeak", convertedText);
- response.setProcessedMessage(FilterHelpers.highlightProfanity(convertedText,"", ""));
- ServerUtils.verbose(("ProfanityFilter: Leet Converted: " + convertedText));
+ // Stage 5: Simplify repeating letters (e.g., heeeello -> helo)
+ processedText = simplifyRepeatingLetters(processedText);
+ report.getStepsTaken().put("Remove Repeats", processedText);
+ ServerUtils.verbose("ProfanityFilter: Removed Repeating: " + processedText);
+ currentSeverity = checkProfanity(processedText, Severity.MEDIUM_HIGH);
+ if (currentSeverity != Severity.SAFE) return finalizeResponse(response, processedText, "Remove Repeats", currentSeverity);
- response.setSeverity(FilterHelpers.checkSlur(convertedText, Severity.MEDIUM_LOW));
- if (response.getSeverity() != Severity.SAFE) {
- response.getReport().getStepsTaken().replace("Convert LeetSpeak", "%s %s".formatted(
- FilterHelpers.highlightProfanity(cleanedText,"||","||"),
- Emojis.alarm));
- return response;
- }
+ // Stage 6: Remove all spaces and remaining punctuation
+ processedText = removePunctuation(processedText);
+ report.getStepsTaken().put("Remove Punctuation", processedText);
+ ServerUtils.verbose("ProfanityFilter: Remove Punctuation: " + processedText);
+ currentSeverity = checkProfanity(processedText, Severity.HIGH);
+ if (currentSeverity != Severity.SAFE) return finalizeResponse(response, processedText, "Remove Punctuation", currentSeverity);
- // 6:
- String strippedText = FilterHelpers.stripSpecialCharacters(convertedText);
- response.getReport().getStepsTaken().put("Remove Special Characters", strippedText);
- response.setProcessedMessage(FilterHelpers.highlightProfanity(strippedText,"", ""));
- ServerUtils.verbose(("ProfanityFilter: Specials Removed: " + strippedText));
-
- response.setSeverity(FilterHelpers.checkSlur(strippedText, Severity.MEDIUM));
- if (response.getSeverity() != Severity.SAFE) {
- response.getReport().getStepsTaken().replace("Remove Special Characters", "%s %s".formatted(
- FilterHelpers.highlightProfanity(cleanedText,"||","||"),
- Emojis.alarm));
- return response;
- }
-
- // 8:
- String simplifiedText = FilterHelpers.simplifyRepeatingLetters(strippedText);
- response.getReport().getStepsTaken().put("Remove Repeats", simplifiedText);
- response.setProcessedMessage(FilterHelpers.highlightProfanity(simplifiedText,"", ""));
- ServerUtils.verbose(("ProfanityFilter: Removed Repeating: " + simplifiedText));
-
- response.setSeverity(FilterHelpers.checkSlur(simplifiedText, Severity.MEDIUM_HIGH));
- if (response.getSeverity() != Severity.SAFE) {
- response.getReport().getStepsTaken().replace("Remove Repeats", "%s %s".formatted(
- FilterHelpers.highlightProfanity(cleanedText,"||","||"),
- Emojis.alarm));
- return response;
- }
-
- // 10:
- String finalText = FilterHelpers.removePeriodsAndSpaces(simplifiedText);
- response.getReport().getStepsTaken().put("Remove Punctuation", finalText);
- response.setProcessedMessage(FilterHelpers.highlightProfanity(finalText,"", ""));
- ServerUtils.verbose(("ProfanityFilter: Remove Punctuation: " + finalText));
-
- response.setSeverity(FilterHelpers.checkSlur(finalText, Severity.HIGH));
- if (response.getSeverity() != Severity.SAFE) {
- response.getReport().getStepsTaken().replace("Remove Punctuation", "%s %s".formatted(
- FilterHelpers.highlightProfanity(cleanedText,"||","||"),
- Emojis.alarm));
- }
-
- ServerUtils.verbose(("ProfanityFilter: Finished " + finalText));
- if (e.isCancelled()) {
- ServerUtils.verbose("Profanity response closing: Event is canceled.");
- }
+ ServerUtils.verbose("ProfanityFilter: Finished. No profanity detected.");
return response;
}
+
+ private static ProfanityResponse finalizeResponse(ProfanityResponse response, String text, String stage, Severity severity) {
+ response.setSeverity(severity);
+ String highlightedText = highlightAllProfanity(text, "||", "||");
+ response.getReport().getStepsTaken().replace(stage, "%s %s".formatted(highlightedText, Emojis.alarm));
+ response.setProcessedMessage(highlightAllProfanity(text,"█HS█","█HE█"));
+ ServerUtils.verbose("ProfanityFilter: Flagged at stage '%s' with severity '%s'", stage, severity)
+;
+ return response;
+ }
+
+ private static Severity checkProfanity(String text, Severity current) {
+ if (containsSlurs(text)) return Severity.SLUR;
+ if (containsSwears(text)) return current;
+ return Severity.SAFE;
+ }
+
+ private static boolean containsSwears(String text) {
+ ServerUtils.verbose("ProfanityFilter: Checking for swears in: " + text);
+ for (String swear : main.dir().io.swearList.swears) {
+ if (text.contains(swear)) return true;
+ }
+ if (main.dir().io.swearList.useRegex) {
+ Pattern pattern = Pattern.compile(main.dir().io.swearList.regexSwears, Pattern.CASE_INSENSITIVE);
+ return pattern.matcher(text).find();
+ }
+ return false;
+ }
+
+ private static boolean containsSlurs(String text) {
+ ServerUtils.verbose("ProfanityFilter: Checking for slurs in: " + text);
+ for (String slur : main.dir().io.strictList.strict) {
+ if (text.contains(slur)) return true;
+ }
+ if (main.dir().io.strictList.useRegex) {
+ Pattern pattern = Pattern.compile(main.dir().io.strictList.regexStrict, Pattern.CASE_INSENSITIVE);
+ return pattern.matcher(text).find();
+ }
+ return false;
+ }
+
+ private static String maskValidWords(String text) {
+ String result = text;
+ for (String falsePositive : main.dir().io.falsePositiveList.swearWhitelist) {
+ result = result.replace(falsePositive, "█SW█");
+ }
+ if (main.dir().io.falsePositiveList.useRegex) {
+ result = result.replaceAll(main.dir().io.falsePositiveList.regexWhitelist, "█RW█");
+ }
+ for (String falsePositive : main.dir().io.falsePositiveList.cleanWords) {
+ result = result.replace(falsePositive, "█CW█");
+ }
+ return result;
+ }
+
+ private static String convertLeetSpeakCharacters(String text) {
+ Map dictionary = Sentinel.getInstance().getDirector().io.advConfig.leetPatterns;
+
+ for (String key : dictionary.keySet()) {
+ if (!text.contains(key)) continue;
+ try {
+ if (key.equals("$")) {
+ text = text.replaceAll("\\$", "s");
+ }
+ else {
+ text = text.replaceAll(key, dictionary.get(key));
+ }
+ } catch (PatternSyntaxException ex) {
+ String regex = "[" + key + "]";
+ text = text.replaceAll(regex, dictionary.get(key));
+ }
+ }
+ return text;
+ }
+
+ private static String stripSpecialCharacters(String text) {
+ return text.replaceAll("(?!█[A-Z]{2}█)[^a-zA-Z0-9\\s,.?!█]", "");
+ }
+
+ private static String simplifyRepeatingLetters(String text) {
+ return FormatUtils.replaceRepeatingLetters(text);
+ }
+
+ private static String removePunctuation(String text) {
+ return text.replaceAll("[.,!?\\s]", "");
+ }
+
+ private static String highlightAllProfanity(String text, String start, String end) {
+ String result = text;
+ for (String slur : main.dir().io.strictList.strict) {
+ result = result.replace(slur, start + slur + end);
+ }
+
+ for (String swear : main.dir().io.swearList.swears) {
+ result = result.replace(swear, start + swear + end);
+ }
+ return Text.legacyColor(result);
+ }
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.java
index dbe2b2b..64d1e6e 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/profanity/Severity.java
@@ -1,15 +1,16 @@
package me.trouper.sentinel.server.functions.chatfilter.profanity;
import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.Main;
-public enum Severity {
- LOW(Sentinel.mainConfig.chat.profanityFilter.lowScore),
- MEDIUM_LOW(Sentinel.mainConfig.chat.profanityFilter.mediumLowScore),
- MEDIUM(Sentinel.mainConfig.chat.profanityFilter.mediumScore),
- MEDIUM_HIGH(Sentinel.mainConfig.chat.profanityFilter.mediumHighScore),
- HIGH(Sentinel.mainConfig.chat.profanityFilter.highScore),
- REGEX(Sentinel.mainConfig.chat.profanityFilter.regexScore),
- SLUR(Sentinel.mainConfig.chat.profanityFilter.highScore),
+public enum Severity implements Main {
+ LOW(main.dir().io.mainConfig.chat.profanityFilter.lowScore),
+ MEDIUM_LOW(main.dir().io.mainConfig.chat.profanityFilter.mediumLowScore),
+ MEDIUM(main.dir().io.mainConfig.chat.profanityFilter.mediumScore),
+ MEDIUM_HIGH(main.dir().io.mainConfig.chat.profanityFilter.mediumHighScore),
+ HIGH(main.dir().io.mainConfig.chat.profanityFilter.highScore),
+ REGEX(main.dir().io.mainConfig.chat.profanityFilter.regexScore),
+ SLUR(main.dir().io.mainConfig.chat.profanityFilter.highScore),
SAFE(0);
private final int score;
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.java
index c6a4792..9437cb7 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamAction.java
@@ -1,7 +1,7 @@
package me.trouper.sentinel.server.functions.chatfilter.spam;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.AbstractActionHandler;
+import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import me.trouper.sentinel.utils.trees.HoverFormatter;
@@ -13,55 +13,63 @@ public class SpamAction extends AbstractActionHandler {
@Override
public void punish(SpamResponse response) {
- for (String spamPunishCommand : Sentinel.mainConfig.chat.spamFilter.punishCommands) {
+ for (String spamPunishCommand : main.dir().io.mainConfig.chat.spamFilter.punishCommands) {
ServerUtils.sendCommand(spamPunishCommand.replaceAll("%player%", response.getEvent().getPlayer().getName()));
}
}
@Override
- public void staffWarning(SpamResponse report, Node tree) {
- String messageText = Text.prefix("&b&n%s&r &7%s &8(&4%s&7/&c%s&8)".formatted(
- report.getEvent().getPlayer().getName(),
- report.isPunished() ? Sentinel.lang.violations.chat.spam.autoPunishNotification : Sentinel.lang.violations.chat.spam.preventNotification,
- SpamFilter.heatMap.get(report.getEvent().getPlayer().getUniqueId()),
- Sentinel.mainConfig.chat.spamFilter.punishHeat
- ));
- String hoverText = HoverFormatter.format(tree);
+ public void staffWarning(SpamResponse response, Node tree) {
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,
+ response.isPunished() ?
+ main.dir().io.lang.violations.chat.spam.autoPunishNotification :
+ main.dir().io.lang.violations.chat.spam.preventNotification,
+ response.getEvent().getPlayer().getName(),
+ SpamFilter.heatMap.get(response.getEvent().getPlayer().getUniqueId()),
+ main.dir().io.mainConfig.chat.spamFilter.punishHeat
+ );
- ServerUtils.forEachPlayer(player -> {
- if (player.hasPermission("sentinel.chatfilter.spam.view")) player.sendMessage(Component.text(messageText).hoverEvent(Component.text(hoverText).asHoverEvent()));
+ PlayerUtils.forEachPlayer(player -> {
+ if (!player.hasPermission("sentinel.chatfilter.spam.view")) return;
+ Text.message(Text.Pallet.INFO, player, message.hoverEvent(HoverFormatter.format(tree).asHoverEvent()));
});
}
@Override
public void playerWarning(SpamResponse response) {
- String message = Text.prefix(response.isPunished() ? Sentinel.lang.violations.chat.spam.autoPunishWarning : Sentinel.lang.violations.chat.spam.preventWarning) ;
- String hoverText = Sentinel.lang.automatedActions.reportable;
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,
+ response.isPunished() ? main.dir().io.lang.violations.chat.spam.autoPunishWarning :
+ main.dir().io.lang.violations.chat.spam.preventWarning
+ );
+ String hoverText = main.dir().io.lang.automatedActions.reportable;
String command = "/sentinelcallback fpreport %s".formatted(response.getReport().getId());
- response.getEvent().getPlayer().sendMessage(Component.text(message)
- .hoverEvent(Component.text(hoverText).asHoverEvent())
- .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command)));
+ Text.message(Text.Pallet.INFO, response.getEvent().getPlayer(), message
+ .hoverEvent(Component.text(hoverText).asHoverEvent())
+ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, command))
+ );
}
@Override
public Node buildTree(SpamResponse response) {
Node root = new Node("Sentinel");
- root.addTextLine(Sentinel.lang.violations.chat.spam.treeTitle);
+ root.addTextLine(Text.format(Text.Pallet.NEUTRAL, Component.text(main.dir().io.lang.violations.chat.spam.treeTitle),response.getPlayer().name()));
- Node playerInfo = new Node(Sentinel.lang.violations.protections.infoNode.playerInfo.formatted(response.getEvent().getPlayer().getName()));
- playerInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.uuid, response.getEvent().getPlayer().getUniqueId().toString());
- playerInfo.addKeyValue(Sentinel.lang.violations.chat.spam.heat, "%s/%s".formatted(SpamFilter.heatMap.get(response.getEvent().getPlayer().getUniqueId()),Sentinel.mainConfig.chat.spamFilter.punishHeat));
+ Node playerInfo = new Node(main.dir().io.lang.violations.protections.infoNode.playerInfo);
+ playerInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.uuid, response.getEvent().getPlayer().getUniqueId().toString());
+ playerInfo.addKeyValue(main.dir().io.lang.violations.chat.spam.heat, "%s/%s".formatted(SpamFilter.heatMap.get(response.getEvent().getPlayer().getUniqueId()),main.dir().io.mainConfig.chat.spamFilter.punishHeat));
root.addChild(playerInfo);
- Node reportInfo = new Node(Sentinel.lang.violations.chat.spam.reportInfoTitle);
- reportInfo.addField(Sentinel.lang.violations.chat.spam.previousMessage, response.getPreviousMessage());
- reportInfo.addField(Sentinel.lang.violations.chat.spam.currentMessage, response.getCurrentMessage());
- reportInfo.addKeyValue(Sentinel.lang.violations.chat.spam.similarity, "%s/%s".formatted((int) Math.round(response.getSimilarity()),Sentinel.mainConfig.chat.spamFilter.blockSimilarity));
+ Node reportInfo = new Node(main.dir().io.lang.violations.chat.spam.reportInfoTitle);
+ reportInfo.addField(main.dir().io.lang.violations.chat.spam.previousMessage, response.getPreviousMessage());
+ reportInfo.addField(main.dir().io.lang.violations.chat.spam.currentMessage, response.getCurrentMessage());
+ reportInfo.addKeyValue(main.dir().io.lang.violations.chat.spam.similarity, "%s/%s".formatted((int) Math.round(response.getSimilarity()),main.dir().io.mainConfig.chat.spamFilter.blockSimilarity));
root.addChild(reportInfo);
- Node actions = new Node(Sentinel.lang.violations.protections.actionNode.actionNodeTitle);
- actions.addTextLine(Sentinel.lang.violations.chat.denyMessage);
- if (response.isPunished()) actions.addTextLine(Sentinel.lang.violations.protections.actionNode.punishmentCommandsExecuted);
+ Node actions = new Node(main.dir().io.lang.violations.protections.actionNode.actionNodeTitle);
+ actions.addTextLine(main.dir().io.lang.violations.chat.denyMessage);
+ if (response.isPunished()) actions.addTextLine(main.dir().io.lang.violations.protections.actionNode.punishmentCommandsExecuted);
root.addChild(actions);
return root;
@@ -69,6 +77,6 @@ public class SpamAction extends AbstractActionHandler {
@Override
protected boolean shouldWarnPlayer(SpamResponse response) {
- return !Sentinel.mainConfig.chat.spamFilter.silent;
+ return !main.dir().io.mainConfig.chat.spamFilter.silent;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamFilter.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamFilter.java
index 7967bc0..f9f79a0 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamFilter.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamFilter.java
@@ -1,17 +1,19 @@
package me.trouper.sentinel.server.functions.chatfilter.spam;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.Main;
+import me.trouper.sentinel.utils.FormatUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-public class SpamFilter {
+public class SpamFilter implements Main {
public static Map heatMap = new HashMap<>();
public static Map lastMessageMap = new HashMap<>();
@@ -20,8 +22,8 @@ public class SpamFilter {
ServerUtils.verbose("Anti Spam Opening: Event is canceled.");
}
Player p = e.getPlayer();
- String message = Text.removeFirstColor(LegacyComponentSerializer.legacySection().serialize(e.message()));
- for (String whitelistedMessage : Sentinel.mainConfig.chat.spamFilter.whitelist) {
+ String message = PlainTextComponentSerializer.plainText().serialize(e.message());
+ for (String whitelistedMessage : main.dir().io.mainConfig.chat.spamFilter.whitelist) {
if (whitelistedMessage.equalsIgnoreCase(message)) return;
}
int currentHeat = heatMap.getOrDefault(p.getUniqueId(),0);
@@ -34,7 +36,7 @@ public class SpamFilter {
ServerUtils.verbose("AntiSpam responded");
response.getReport().getStepsTaken().put("Response came back", "Heat to add: %s".formatted(addHeat));
- if (currentHeat > Sentinel.mainConfig.chat.spamFilter.punishHeat) {
+ if (currentHeat > main.dir().io.mainConfig.chat.spamFilter.punishHeat) {
response.setBlocked(true);
response.getReport().getStepsTaken().put("Punished user", "Their final heat was %s".formatted(currentHeat));
response.setPunished(true);
@@ -43,7 +45,7 @@ public class SpamFilter {
return;
}
- if (currentHeat > Sentinel.mainConfig.chat.spamFilter.blockHeat) {
+ if (currentHeat > main.dir().io.mainConfig.chat.spamFilter.blockHeat) {
response.setBlocked(true);
response.getReport().getStepsTaken().put("Blocked message", "Their heat is %s".formatted(currentHeat));
new SpamAction().run(response);
@@ -51,7 +53,7 @@ public class SpamFilter {
return;
}
- if (response.getSimilarity() > Sentinel.mainConfig.chat.spamFilter.blockSimilarity) {
+ if (response.getSimilarity() > main.dir().io.mainConfig.chat.spamFilter.blockSimilarity) {
response.setBlocked(true);
response.getReport().getStepsTaken().put("Blocked message", "The similarity was too high! %s".formatted(response.getSimilarity()));
new SpamAction().run(response);
@@ -69,7 +71,7 @@ public class SpamFilter {
for (UUID p : heatMap.keySet()) {
int heat = heatMap.getOrDefault(p,0);
if (heat > 0) {
- heat = heat - Sentinel.mainConfig.chat.spamFilter.heatDecay;
+ heat = heat - main.dir().io.mainConfig.chat.spamFilter.heatDecay;
heatMap.put(p, Math.max(0, heat));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.java
index 96098e3..fe72137 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/spam/SpamResponse.java
@@ -2,10 +2,9 @@ package me.trouper.sentinel.server.functions.chatfilter.spam;
import io.github.retrooper.packetevents.adventure.serializer.legacy.LegacyComponentSerializer;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.helpers.FalsePositiveReporting;
import me.trouper.sentinel.server.functions.chatfilter.FilterResponse;
import me.trouper.sentinel.server.functions.helpers.Report;
+import me.trouper.sentinel.utils.FormatUtils;
import me.trouper.sentinel.utils.MathUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
@@ -40,9 +39,9 @@ public class SpamResponse implements FilterResponse {
}
String message = LegacyComponentSerializer.legacySection().serialize(e.message());
- Report report = FalsePositiveReporting.initializeReport(message);
+ Report report = main.dir().reportHandler.initializeReport(message);
- message = Text.removeFirstColor(message);
+ message = Text.removeColors(message);
String previousMessage = lastMessageMap.getOrDefault(e.getPlayer().getUniqueId(),"/* Placeholder Message from Sentinel */");
SpamResponse response = new SpamResponse(e,message,previousMessage,0,0,report,false,false);
@@ -52,25 +51,25 @@ public class SpamResponse implements FilterResponse {
response.setSimilarity(similarity);
report.getStepsTaken().put("Calculated Similarity: ","%s".formatted(similarity));
- int addHeat = Sentinel.mainConfig.chat.spamFilter.defaultGain;
- if (similarity > Sentinel.mainConfig.chat.spamFilter.blockSimilarity) {
- addHeat = Sentinel.mainConfig.chat.spamFilter.highGain;
- response.getReport().getStepsTaken().put("Similarity is greater than %s%%".formatted(Sentinel.mainConfig.chat.spamFilter.blockSimilarity), "That is %s heat. (Auto-Block due to configured value)".formatted(addHeat));
+ int addHeat = main.dir().io.mainConfig.chat.spamFilter.defaultGain;
+ if (similarity > main.dir().io.mainConfig.chat.spamFilter.blockSimilarity) {
+ addHeat = main.dir().io.mainConfig.chat.spamFilter.highGain;
+ response.getReport().getStepsTaken().put("Similarity is greater than %s%%".formatted(main.dir().io.mainConfig.chat.spamFilter.blockSimilarity), "That is %s heat. (Auto-Block due to configured value)".formatted(addHeat));
response.setHeatAdded(addHeat);
return response;
} else if (similarity > 90) {
- addHeat = Sentinel.mainConfig.chat.spamFilter.highGain;
+ addHeat = main.dir().io.mainConfig.chat.spamFilter.highGain;
response.getReport().getStepsTaken().put("Similarity is greater than 90%", "That is %s heat.".formatted(addHeat));
response.setHeatAdded(addHeat);
return response;
} else if (similarity > 50) {
- addHeat = Sentinel.mainConfig.chat.spamFilter.mediumGain;
+ addHeat = main.dir().io.mainConfig.chat.spamFilter.mediumGain;
response.getReport().getStepsTaken().put("Similarity is greater than 50%", "That is %s heat.".formatted(addHeat));
response.setHeatAdded(addHeat);
return response;
} else if (similarity > 25) {
response.getReport().getStepsTaken().put("Similarity is greater than 25%", "That is %s heat.".formatted(addHeat));
- addHeat = Sentinel.mainConfig.chat.spamFilter.lowGain;
+ addHeat = main.dir().io.mainConfig.chat.spamFilter.lowGain;
response.setHeatAdded(addHeat);
return response;
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeAction.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeAction.java
index a5c5243..dd04036 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeAction.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeAction.java
@@ -1,7 +1,7 @@
package me.trouper.sentinel.server.functions.chatfilter.unicode;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.AbstractActionHandler;
+import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import me.trouper.sentinel.utils.trees.HoverFormatter;
@@ -12,51 +12,59 @@ import net.kyori.adventure.text.event.ClickEvent;
public class UnicodeAction extends AbstractActionHandler {
@Override
protected void punish(UnicodeResponse response) {
- for (String punishCommand : Sentinel.mainConfig.chat.unicodeFilter.punishCommands) {
- ServerUtils.sendCommand(punishCommand.replaceAll("%player%",response.getPlayer().getName()));
+ for (String punishCommand : main.dir().io.mainConfig.chat.unicodeFilter.punishCommands) {
+ ServerUtils.sendCommand(punishCommand.replaceAll("%player%", response.getPlayer().getName()));
}
}
@Override
protected void staffWarning(UnicodeResponse response, Node tree) {
- String messageText = Text.prefix("&b&n%s&r &7%s".formatted(
- response.getPlayer().getName(),
- response.isPunished() ? Sentinel.lang.violations.chat.unicode.autoPunishNotification : Sentinel.lang.violations.chat.unicode.preventNotification
- ));
- String hoverText = HoverFormatter.format(tree);
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,
+ response.isPunished() ?
+ main.dir().io.lang.violations.chat.unicode.autoPunishNotification :
+ main.dir().io.lang.violations.chat.unicode.preventNotification,
+ response.getPlayer().getName()
+ );
- ServerUtils.forEachPlayer(player -> {
- if (player.hasPermission("sentinel.chatfilter.unicode.view")) player.sendMessage(Component.text(messageText).hoverEvent(Component.text(hoverText).asHoverEvent()));
+ PlayerUtils.forEachPlayer(player -> {
+ if (!player.hasPermission("sentinel.chatfilter.unicode.view")) return;
+ Text.message(Text.Pallet.INFO, player, message.hoverEvent(HoverFormatter.format(tree).asHoverEvent()));
});
}
@Override
protected void playerWarning(UnicodeResponse response) {
- String message = Text.prefix(response.isPunished() ? Sentinel.lang.violations.chat.unicode.autoPunishWarning : Sentinel.lang.violations.chat.unicode.preventWarning);
- String hoverText = Sentinel.lang.automatedActions.reportable;
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,
+ response.isPunished() ? main.dir().io.lang.violations.chat.unicode.autoPunishWarning :
+ main.dir().io.lang.violations.chat.unicode.preventWarning
+ );
+ String hoverText = main.dir().io.lang.automatedActions.reportable;
String command = "/sentinelcallback fpreport %s".formatted(response.getReport().getId());
- response.getPlayer().sendMessage(Component.text(message)
+ Text.message(Text.Pallet.INFO, response.getPlayer(), message
.hoverEvent(Component.text(hoverText).asHoverEvent())
- .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command)));
+ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, command))
+ );
}
@Override
protected Node buildTree(UnicodeResponse response) {
Node root = new Node("Sentinel");
- root.addTextLine(Sentinel.lang.violations.chat.unicode.treeTitle);
+ root.addTextLine(Text.format(Text.Pallet.NEUTRAL,Component.text(main.dir().io.lang.violations.chat.unicode.treeTitle),response.getPlayer().name()));
- Node playerInfo = new Node(Sentinel.lang.violations.protections.infoNode.playerInfo.formatted(response.getPlayer().getName()));
- playerInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.uuid, response.getPlayer().getUniqueId().toString());
+ Node playerInfo = new Node(main.dir().io.lang.violations.protections.infoNode.playerInfo.formatted(response.getPlayer().getName()));
+ playerInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.uuid, response.getPlayer().getUniqueId().toString());
root.addChild(playerInfo);
- Node reportInfo = new Node(Sentinel.lang.violations.chat.unicode.reportInfoTitle);
- reportInfo.addField(Sentinel.lang.violations.chat.originalMessage, response.getOriginalMessage());
- reportInfo.addField(Sentinel.lang.violations.chat.highlightedMessage, response.getHighlightedMessage());
+ Node reportInfo = new Node(main.dir().io.lang.violations.chat.unicode.reportInfoTitle);
+ reportInfo.addField(main.dir().io.lang.violations.chat.originalMessage, response.getOriginalMessage());
+ reportInfo.addField(Component.text(main.dir().io.lang.violations.chat.highlightedMessage), Node.parseLegacyText(response.getHighlightedMessage()));
root.addChild(reportInfo);
- Node actions = new Node(Sentinel.lang.violations.protections.actionNode.actionNodeTitle);
- actions.addTextLine(Sentinel.lang.violations.chat.denyMessage);
- if (response.isPunished()) actions.addTextLine(Sentinel.lang.violations.protections.actionNode.punishmentCommandsExecuted);
+ Node actions = new Node(main.dir().io.lang.violations.protections.actionNode.actionNodeTitle);
+ actions.addTextLine(main.dir().io.lang.violations.chat.denyMessage);
+ if (response.isPunished()) actions.addTextLine(main.dir().io.lang.violations.protections.actionNode.punishmentCommandsExecuted);
root.addChild(actions);
return root;
@@ -64,6 +72,6 @@ public class UnicodeAction extends AbstractActionHandler {
@Override
protected boolean shouldWarnPlayer(UnicodeResponse response) {
- return !Sentinel.mainConfig.chat.unicodeFilter.silent;
+ return !main.dir().io.mainConfig.chat.unicodeFilter.silent;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeResponse.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeResponse.java
index 419350d..583691c 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeResponse.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/unicode/UnicodeResponse.java
@@ -2,11 +2,10 @@ package me.trouper.sentinel.server.functions.chatfilter.unicode;
import io.github.retrooper.packetevents.adventure.serializer.legacy.LegacyComponentSerializer;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.Emojis;
-import me.trouper.sentinel.server.functions.helpers.FalsePositiveReporting;
+import me.trouper.sentinel.data.types.Emojis;
import me.trouper.sentinel.server.functions.chatfilter.FilterResponse;
import me.trouper.sentinel.server.functions.helpers.Report;
+import me.trouper.sentinel.utils.FormatUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import org.bukkit.entity.Player;
@@ -38,29 +37,31 @@ public class UnicodeResponse implements FilterResponse {
}
String message = LegacyComponentSerializer.legacySection().serialize(e.message());
- message = Text.removeFirstColor(message);
- Report report = FalsePositiveReporting.initializeReport(message);
+ message = Text.removeColors(message);
+ Report report = main.dir().reportHandler.initializeReport(message);
- UnicodeResponse response = new UnicodeResponse(e,message,message,report,false,false);
-
- String disallowedRegex = Sentinel.mainConfig.chat.unicodeFilter.regex;
- ServerUtils.verbose("Regex: %s\nMessage: %s".formatted(disallowedRegex,message));
+ UnicodeResponse response = new UnicodeResponse(e, message, message, report, false, false);
+ String disallowedRegex = main.dir().io.mainConfig.chat.unicodeFilter.regex;
Pattern pattern = Pattern.compile(disallowedRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(message);
- ServerUtils.verbose("Matcher result %s\nGroup 1: %s".formatted(matcher.find(),matcher.find() ? matcher.group() : ""));
+
+ boolean found = matcher.find();
- response.getReport().getStepsTaken().put("Anti-URL", "`%s`".formatted(
- message
- ));
+ ServerUtils.verbose("Matcher result: %s",found);
+ if (found) {
+ ServerUtils.verbose("Group 1: %s",matcher.group());
+ }
- if (matcher.find()) {
- ServerUtils.verbose("Unicode Filter: Caught Unicode: " + disallowedRegex);
+ response.getReport().getStepsTaken().put("Anti-Unicode", "`" + message + "`");
+
+ if (found) {
+ ServerUtils.verbose("Unicode Filter: Caught Unicode using regex: " + disallowedRegex);
response.getReport().getStepsTaken().replace("Anti-Unicode", "`%s` %s".formatted(message, Emojis.alarm));
response.setBlocked(true);
- response.setPunished(Sentinel.mainConfig.chat.unicodeFilter.punished);
- response.setHighlightedMessage(Text.regexHighlighter(message,Sentinel.mainConfig.chat.unicodeFilter.regex," > ", " < "));
+ response.setPunished(main.dir().io.mainConfig.chat.unicodeFilter.punished);
+ response.setHighlightedMessage(FormatUtils.regexHighlighter(message, disallowedRegex, "█HS█", "█HE█"));
}
return response;
@@ -118,4 +119,4 @@ public class UnicodeResponse implements FilterResponse {
public void setPunished(boolean punished) {
this.punished = punished;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlAction.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlAction.java
index 9d71d10..548b52e 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlAction.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlAction.java
@@ -1,7 +1,7 @@
package me.trouper.sentinel.server.functions.chatfilter.url;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.server.functions.chatfilter.AbstractActionHandler;
+import me.trouper.sentinel.utils.PlayerUtils;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.Text;
import me.trouper.sentinel.utils.trees.HoverFormatter;
@@ -12,51 +12,59 @@ import net.kyori.adventure.text.event.ClickEvent;
public class UrlAction extends AbstractActionHandler {
@Override
protected void punish(UrlResponse response) {
- for (String punishCommand : Sentinel.mainConfig.chat.urlFilter.punishCommands) {
- ServerUtils.sendCommand(punishCommand.replaceAll("%player%",response.getPlayer().getName()));
+ for (String punishCommand : main.dir().io.mainConfig.chat.urlFilter.punishCommands) {
+ ServerUtils.sendCommand(punishCommand.replaceAll("%player%", response.getPlayer().getName()));
}
}
@Override
protected void staffWarning(UrlResponse response, Node tree) {
- String messageText = Text.prefix("&b&n%s&r &7%s".formatted(
- response.getPlayer().getName(),
- response.isPunished() ? Sentinel.lang.violations.chat.url.autoPunishNotification : Sentinel.lang.violations.chat.url.preventNotification
- ));
- String hoverText = HoverFormatter.format(tree);
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,
+ response.isPunished() ?
+ main.dir().io.lang.violations.chat.url.autoPunishNotification :
+ main.dir().io.lang.violations.chat.url.preventNotification,
+ response.getPlayer().getName()
+ );
- ServerUtils.forEachPlayer(player -> {
- if (player.hasPermission("sentinel.chatfilter.url.view")) player.sendMessage(Component.text(messageText).hoverEvent(Component.text(hoverText).asHoverEvent()));
+ PlayerUtils.forEachPlayer(player -> {
+ if (!player.hasPermission("sentinel.chatfilter.url.view")) return;
+ Text.message(Text.Pallet.INFO, player, message.hoverEvent(HoverFormatter.format(tree).asHoverEvent()));
});
}
@Override
protected void playerWarning(UrlResponse response) {
- String message = Text.prefix(response.isPunished() ? Sentinel.lang.violations.chat.url.autoPunishWarning : Sentinel.lang.violations.chat.url.preventWarning);
- String hoverText = Sentinel.lang.automatedActions.reportable;
+ Component message = Text.getMessageAny(
+ Text.Pallet.INFO,
+ response.isPunished() ? main.dir().io.lang.violations.chat.url.autoPunishWarning :
+ main.dir().io.lang.violations.chat.url.preventWarning
+ );
+ String hoverText = main.dir().io.lang.automatedActions.reportable;
String command = "/sentinelcallback fpreport %s".formatted(response.getReport().getId());
- response.getPlayer().sendMessage(Component.text(message)
+ Text.message(Text.Pallet.INFO, response.getPlayer(), message
.hoverEvent(Component.text(hoverText).asHoverEvent())
- .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND,command)));
+ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, command))
+ );
}
@Override
protected Node buildTree(UrlResponse response) {
Node root = new Node("Sentinel");
- root.addTextLine(Sentinel.lang.violations.chat.url.treeTitle);
+ root.addTextLine(Text.format(Text.Pallet.NEUTRAL,Component.text(main.dir().io.lang.violations.chat.url.treeTitle),response.getPlayer().name()));
- Node playerInfo = new Node(Sentinel.lang.violations.protections.infoNode.playerInfo.formatted(response.getPlayer().getName()));
- playerInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.uuid, response.getPlayer().getUniqueId().toString());
+ Node playerInfo = new Node(main.dir().io.lang.violations.protections.infoNode.playerInfo.formatted(response.getPlayer().getName()));
+ playerInfo.addKeyValue(main.dir().io.lang.violations.protections.infoNode.uuid, response.getPlayer().getUniqueId().toString());
root.addChild(playerInfo);
- Node reportInfo = new Node(Sentinel.lang.violations.chat.url.reportInfoTitle);
- reportInfo.addField(Sentinel.lang.violations.chat.originalMessage, response.getOriginalMessage());
- reportInfo.addField(Sentinel.lang.violations.chat.highlightedMessage, response.getHighlightedMessage());
+ Node reportInfo = new Node(main.dir().io.lang.violations.chat.url.reportInfoTitle);
+ reportInfo.addField(main.dir().io.lang.violations.chat.originalMessage, response.getOriginalMessage());
+ reportInfo.addField(Component.text(main.dir().io.lang.violations.chat.highlightedMessage), Node.parseLegacyText(response.getHighlightedMessage()));
root.addChild(reportInfo);
- Node actions = new Node(Sentinel.lang.violations.protections.actionNode.actionNodeTitle);
- actions.addTextLine(Sentinel.lang.violations.chat.denyMessage);
- if (response.isPunished()) actions.addTextLine(Sentinel.lang.violations.protections.actionNode.punishmentCommandsExecuted);
+ Node actions = new Node(main.dir().io.lang.violations.protections.actionNode.actionNodeTitle);
+ actions.addTextLine(main.dir().io.lang.violations.chat.denyMessage);
+ if (response.isPunished()) actions.addTextLine(main.dir().io.lang.violations.protections.actionNode.punishmentCommandsExecuted);
root.addChild(actions);
return root;
@@ -64,6 +72,6 @@ public class UrlAction extends AbstractActionHandler {
@Override
protected boolean shouldWarnPlayer(UrlResponse response) {
- return !Sentinel.mainConfig.chat.urlFilter.silent;
+ return !main.dir().io.mainConfig.chat.urlFilter.silent;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlResponse.java b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlResponse.java
index 10c4c64..c6e357b 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlResponse.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/chatfilter/url/UrlResponse.java
@@ -2,13 +2,11 @@ package me.trouper.sentinel.server.functions.chatfilter.url;
import io.github.retrooper.packetevents.adventure.serializer.legacy.LegacyComponentSerializer;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.Emojis;
-import me.trouper.sentinel.server.functions.helpers.FalsePositiveReporting;
+import me.trouper.sentinel.data.types.Emojis;
import me.trouper.sentinel.server.functions.chatfilter.FilterResponse;
import me.trouper.sentinel.server.functions.helpers.Report;
+import me.trouper.sentinel.utils.FormatUtils;
import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
import org.bukkit.entity.Player;
import java.util.regex.Matcher;
@@ -36,9 +34,9 @@ public class UrlResponse implements FilterResponse {
}
String message = LegacyComponentSerializer.legacySection().serialize(e.message());
- Report report = FalsePositiveReporting.initializeReport(message);
+ Report report = main.dir().reportHandler.initializeReport(message);
UrlResponse response = new UrlResponse(e,message,message,report,false,false);
- for (String allowed : Sentinel.mainConfig.chat.urlFilter.whitelist) {
+ for (String allowed : main.dir().io.mainConfig.chat.urlFilter.whitelist) {
message = message.replaceAll(allowed,"");
}
@@ -46,7 +44,7 @@ public class UrlResponse implements FilterResponse {
message
));
- String urlRegex = Sentinel.mainConfig.chat.urlFilter.regex;
+ String urlRegex = main.dir().io.mainConfig.chat.urlFilter.regex;
Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(message);
@@ -56,12 +54,12 @@ public class UrlResponse implements FilterResponse {
));
if (matcher.find()) {
- String highlighted = Text.regexHighlighter(message,Sentinel.mainConfig.chat.urlFilter.regex," > "," < ");
+ String highlighted = FormatUtils.regexHighlighter(message,main.dir().io.mainConfig.chat.urlFilter.regex,"█HS█","█HE█");
ServerUtils.verbose("Caught URL: " + highlighted);
response.getReport().getStepsTaken().replace("Anti-URL", "`%s` %s".formatted(highlighted, Emojis.alarm));
response.setBlocked(true);
- response.setPunished(Sentinel.mainConfig.chat.urlFilter.punished);
+ response.setPunished(main.dir().io.mainConfig.chat.urlFilter.punished);
response.setHighlightedMessage(highlighted);
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/helpers/AbstractViolation.java b/src/main/java/me/trouper/sentinel/server/functions/helpers/AbstractViolation.java
deleted file mode 100644
index 65979a4..0000000
--- a/src/main/java/me/trouper/sentinel/server/functions/helpers/AbstractViolation.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package me.trouper.sentinel.server.functions.helpers;
-
-import io.github.itzispyder.pdk.events.CustomListener;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.utils.FileUtils;
-import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import me.trouper.sentinel.utils.trees.ConsoleFormatter;
-import me.trouper.sentinel.utils.trees.EmbedFormatter;
-import me.trouper.sentinel.utils.trees.HoverFormatter;
-import me.trouper.sentinel.utils.trees.Node;
-import net.kyori.adventure.text.Component;
-import org.bukkit.Bukkit;
-import org.bukkit.block.Block;
-import org.bukkit.block.CommandBlock;
-import org.bukkit.command.Command;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.plugin.Plugin;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicReference;
-
-public abstract class AbstractViolation implements CustomListener {
-
- public void runActions(String rootName, String rootNamePlayer, Node violationInfo, ActionConfiguration.Builder configuration) {
- ActionConfiguration config = configuration.build();
-
- Node root = new Node("Sentinel");
- root.addTextLine(rootName);
-
- if (config.getPlayer() != null) root.addChild(generatePlayerInfo(config.getPlayer()));
-
- root.addChild(violationInfo);
-
- root.addChild(configuration.getActionNode());
-
- notifyTrusted(root,(rootNamePlayer == null || rootNamePlayer.isBlank()) ? rootName : rootNamePlayer);
- if (configuration.isLoggedToDiscord()) EmbedFormatter.sendEmbed(EmbedFormatter.format(root));
- Sentinel.log.info(ConsoleFormatter.format(root));
- }
-
- public void notifyTrusted(Node root, String rootNamePlayer) {
- ServerUtils.forEachPlayer(trusted -> {
- if (PlayerUtils.isTrusted(trusted)) {
- trusted.sendMessage(Component.text(Text.prefix(rootNamePlayer)).hoverEvent(Component.text(HoverFormatter.format(root)).asHoverEvent()));
- }
- });
- }
-
- public Node generatePlayerInfo(Player p) {
- Node playerInfo = new Node(Sentinel.lang.violations.protections.infoNode.playerInfo);
- playerInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.name, p.getName());
- playerInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.uuid, p.getUniqueId().toString());
- playerInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.operator, p.isOp() ? Sentinel.lang.generic.yes : Sentinel.lang.generic.no);
- playerInfo.addField(Sentinel.lang.violations.protections.infoNode.locationField, Sentinel.lang.violations.protections.infoNode.locationFormat.formatted(Math.round(p.getX()), Math.round(p.getY()), Math.round(p.getZ())));
-
- return playerInfo;
- }
-
- public static Node generateBlockInfo(Block block) {
- Node blockInfo = new Node(Sentinel.lang.violations.protections.infoNode.blockInfo);
- blockInfo.addTextLine(Text.cleanName(block.getType().toString()));
- blockInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.worldField,block.getWorld().getName());
- blockInfo.addField(Sentinel.lang.violations.protections.infoNode.blockLocationField,Sentinel.lang.violations.protections.infoNode.locationFormat.formatted(block.getX(), block.getY(), block.getZ()));
-
- return blockInfo;
- }
-
- public Node generateCommandBlockInfo(CommandBlock commandBlock) {
- Node commandBlockInfo = new Node(Sentinel.lang.violations.protections.infoNode.blockInfo);
- commandBlockInfo.addTextLine(Text.cleanName(commandBlock.getType().toString()));
- commandBlockInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.worldField,commandBlock.getWorld().getName());
- commandBlockInfo.addField(Sentinel.lang.violations.protections.infoNode.blockLocationField,Sentinel.lang.violations.protections.infoNode.locationFormat.formatted(commandBlock.getX(), commandBlock.getY(), commandBlock.getZ()));
-
- String command = commandBlock.getCommand();
- if (command == null || command.isBlank()) {
- return commandBlockInfo;
- } else if (command.length() <= 128) {
- commandBlockInfo.addField(Sentinel.lang.violations.protections.infoNode.commandField, command);
- } else {
- commandBlockInfo.addField(Sentinel.lang.violations.protections.infoNode.commandTooLargeField, FileUtils.createCommandLog(command));
- }
-
- return commandBlockInfo;
- }
-
- public Node generateMinecartInfo(Entity entity) {
- Node minecartInfo = new Node(Sentinel.lang.violations.protections.infoNode.minecartInfo);
- minecartInfo.addTextLine(Text.cleanName(entity.getType().toString()));
- minecartInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.worldField,entity.getWorld().getName());
- minecartInfo.addField(Sentinel.lang.violations.protections.infoNode.cartLocationField,Sentinel.lang.violations.protections.infoNode.locationFormat.formatted(Math.round(entity.getX()), Math.round(entity.getY()), Math.round(entity.getZ())));
-
- return minecartInfo;
- }
-
- public Node generateItemInfo(ItemStack item) {
- Node itemInfo = new Node(Sentinel.lang.violations.protections.infoNode.itemInfo);
- itemInfo.addTextLine(Text.cleanName(item.getType().toString()));
- itemInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.hasMeta,item.hasItemMeta() ? Sentinel.lang.generic.yes : Sentinel.lang.generic.no);
- if (item.hasItemMeta()) {
- itemInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.hasName,item.getItemMeta().hasCustomName() ? Sentinel.lang.generic.yes : Sentinel.lang.generic.no);
- itemInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.hasLore,item.getItemMeta().hasLore() ? Sentinel.lang.generic.yes : Sentinel.lang.generic.no);
- itemInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.hasAttributes,item.getItemMeta().hasAttributeModifiers() ? Sentinel.lang.generic.yes : Sentinel.lang.generic.no);
- itemInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.hasEnchants,item.getItemMeta().hasEnchants() ? Sentinel.lang.generic.yes : Sentinel.lang.generic.no);
- itemInfo.addField(Sentinel.lang.violations.protections.infoNode.nbtStored, FileUtils.createNBTLog(item));
- }
-
- return itemInfo;
- }
-
- public Node generateCommandInfo(String command, Player executor) {
- Node commandInfo = new Node(Sentinel.lang.violations.protections.infoNode.commandInfo);
- String name = command.split(" ")[0].substring(1);
- ServerUtils.verbose("Command Name: " + name);
- Command executed = Bukkit.getServer().getCommandMap().getCommand(name);
-
- commandInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.name,name);
- if (command.length() <= 128) {
- commandInfo.addField(Sentinel.lang.violations.protections.infoNode.commandField, command);
- } else {
- commandInfo.addField(Sentinel.lang.violations.protections.infoNode.commandTooLargeField, FileUtils.createCommandLog(command));
- }
- if (executed == null || executed.getPermission() == null) return commandInfo;
- commandInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.permissionRequired,executed.getPermission());
- commandInfo.addKeyValue(Sentinel.lang.violations.protections.infoNode.permissionSatisfied,executor.hasPermission(executed.getPermission()) ? Sentinel.lang.generic.yes : Sentinel.lang.generic.no);
-
- return commandInfo;
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/helpers/ActionConfiguration.java b/src/main/java/me/trouper/sentinel/server/functions/helpers/ActionConfiguration.java
index 5408505..2131e5d 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/helpers/ActionConfiguration.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/helpers/ActionConfiguration.java
@@ -1,10 +1,12 @@
package me.trouper.sentinel.server.functions.helpers;
-import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.utils.ServerUtils;
import me.trouper.sentinel.utils.trees.Node;
import org.bukkit.Material;
import org.bukkit.block.Block;
+import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
@@ -12,13 +14,15 @@ import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
-public class ActionConfiguration {
+public class ActionConfiguration implements Main {
private Player player;
private boolean deop;
private Cancellable event;
private boolean cancel;
private Block block;
+ private Entity entity;
private boolean destroyBlock;
+ private boolean removeEntity;
private boolean restoreBlock;
private boolean punish;
private List punishmentCommands;
@@ -31,13 +35,14 @@ public class ActionConfiguration {
this.event = builder.event;
this.cancel = builder.cancel;
this.block = builder.block;
+ this.entity = builder.entity;
this.destroyBlock = builder.destroyBlock;
+ this.removeEntity = builder.removeEntity;
this.restoreBlock = builder.restoreBlock;
this.punish = builder.punish;
this.punishmentCommands = builder.punishmentCommands;
this.logToDiscord = builder.logToDiscord;
this.actionNode = builder.actionNode;
- // Removed the actions being run here to prevent double execution
}
public Player getPlayer() {
@@ -80,6 +85,14 @@ public class ActionConfiguration {
this.block = block;
}
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public void setEntity(Entity entity) {
+ this.entity = entity;
+ }
+
public boolean isDestroyBlock() {
return destroyBlock;
}
@@ -88,6 +101,14 @@ public class ActionConfiguration {
this.destroyBlock = destroyBlock;
}
+ public void setRemoveEntity(boolean removeEntity) {
+ this.removeEntity = removeEntity;
+ }
+
+ public boolean getRemoveEntity() {
+ return removeEntity;
+ }
+
public boolean isRestoreBlock() {
return restoreBlock;
}
@@ -134,12 +155,14 @@ public class ActionConfiguration {
private Cancellable event;
private boolean cancel;
private Block block;
+ private Entity entity;
private boolean destroyBlock;
+ private boolean removeEntity;
private boolean restoreBlock;
private boolean punish;
private List punishmentCommands = new ArrayList<>();
private boolean logToDiscord;
- private Node actionNode = new Node(Sentinel.lang.violations.protections.actionNode.actionNodeTitle);
+ private Node actionNode = new Node(main.dir().io.lang.violations.protections.actionNode.actionNodeTitle);
private List> actions = new ArrayList<>();
@@ -156,7 +179,7 @@ public class ActionConfiguration {
if (config.player != null) {
config.player.setOp(false);
}
- config.actionNode.addTextLine(Sentinel.lang.violations.protections.actionNode.userDeoped);
+ config.actionNode.addTextLine(main.dir().io.lang.violations.protections.actionNode.userDeoped);
});
return this;
}
@@ -174,7 +197,7 @@ public class ActionConfiguration {
if (config.event != null) {
config.event.setCancelled(true);
}
- config.actionNode.addTextLine(Sentinel.lang.violations.protections.actionNode.eventCancelled);
+ config.actionNode.addTextLine(main.dir().io.lang.violations.protections.actionNode.eventCancelled);
});
return this;
}
@@ -191,7 +214,7 @@ public class ActionConfiguration {
config.destroyBlock = destroyBlock;
if (config.block != null) {
config.block.setType(Material.AIR);
- config.actionNode.addTextLine(Sentinel.lang.violations.protections.actionNode.destroyedBlock);
+ config.actionNode.addTextLine(main.dir().io.lang.violations.protections.actionNode.destroyedBlock);
}
});
return this;
@@ -202,16 +225,34 @@ public class ActionConfiguration {
actions.add(config -> {
config.restoreBlock = restoreBlock;
if (config.block != null) {
- if (CBWhitelistManager.restore(config.block.getLocation())) {
- config.actionNode.addTextLine(Sentinel.lang.violations.protections.actionNode.restore);
+ CommandBlockHolder holder = main.dir().whitelistManager.getFromList(config.block.getLocation());
+ if (holder != null && holder.restore()) {
+ config.actionNode.addTextLine(main.dir().io.lang.violations.protections.actionNode.restore);
} else {
- config.actionNode.addTextLine(Sentinel.lang.violations.protections.actionNode.restoreFailed);
+ config.actionNode.addTextLine(main.dir().io.lang.violations.protections.actionNode.restoreFailed);
}
}
});
return this;
}
+ public Builder setEntity(Entity entity) {
+ this.entity = entity;
+ actions.add(config -> config.entity = entity);
+ return this;
+ }
+
+ public Builder removeEntity(boolean removeEntity) {
+ this.removeEntity = removeEntity;
+ actions.add(config -> {
+ config.removeEntity = removeEntity;
+ if (config.entity != null) {
+ entity.remove();
+ }
+ });
+ return this;
+ }
+
public Builder punish(boolean punish) {
this.punish = punish;
actions.add(config -> config.punish = punish);
@@ -226,7 +267,7 @@ public class ActionConfiguration {
for (String cmd : punishmentCommands) {
ServerUtils.sendCommand(cmd.replaceAll("%player%", config.player.getName()));
}
- config.actionNode.addTextLine(Sentinel.lang.violations.protections.actionNode.punishmentCommandsExecuted);
+ config.actionNode.addTextLine(main.dir().io.lang.violations.protections.actionNode.punishmentCommandsExecuted);
}
});
return this;
diff --git a/src/main/java/me/trouper/sentinel/server/functions/helpers/CBWhitelistManager.java b/src/main/java/me/trouper/sentinel/server/functions/helpers/CBWhitelistManager.java
index 3a7d125..0f30e64 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/helpers/CBWhitelistManager.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/helpers/CBWhitelistManager.java
@@ -1,185 +1,194 @@
package me.trouper.sentinel.server.functions.helpers;
import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.types.WhitelistedBlock;
-import me.trouper.sentinel.utils.PlayerUtils;
+import me.trouper.sentinel.data.types.CommandBlockHolder;
+import me.trouper.sentinel.data.types.Selection;
+import me.trouper.sentinel.data.types.SerialLocation;
+import me.trouper.sentinel.server.Main;
+import me.trouper.sentinel.server.events.admin.WandEvents;
import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
-import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.CommandBlock;
+import org.bukkit.block.data.Directional;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.minecart.CommandMinecart;
import org.bukkit.persistence.PersistentDataType;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
-public class CBWhitelistManager {
+public class CBWhitelistManager implements Main {
- public static Set autoWhitelist = new HashSet<>();
+ public Set autoWhitelist = new HashSet<>();
- public static void add(CommandBlock cb, UUID owner) {
- ServerUtils.verbose("Adding a command block to the whitelist.");
- boolean alwaysActive = getNBTBoolean(cb, "auto");
- WhitelistedBlock wb = new WhitelistedBlock(owner.toString(),WhitelistedBlock.serialize(cb.getLocation()),getType(cb),alwaysActive,cb.getCommand());
-
- Location wbloc = WhitelistedBlock.fromSerialized(wb.loc());
-
- remove(wbloc);
-
- Sentinel.whitelist.whitelistedCMDBlocks.add(wb);
- Sentinel.whitelist.save();
- if (Bukkit.getPlayer(owner) != null && !Bukkit.getPlayer(owner).isOnline()) return;
- Bukkit.getPlayer(owner).sendMessage(Text.prefix("Successfully whitelisted a &b" + Text.cleanName(cb.getType().toString()) + "&7 with the command &a" + cb.getCommand() + "&7."));
- }
-
- public static void remove(Location where) {
- for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
- Location cbl = WhitelistedBlock.fromSerialized(cb.loc());
- if (cbl.distance(where) < 0.5) {
- Sentinel.whitelist.whitelistedCMDBlocks.remove(cb);
- }
- }
-
- Sentinel.whitelist.save();
- }
-
- public static boolean canRun(Block b) {
- CommandBlock test = (CommandBlock) b.getState();
- String command = test.getCommand();
- boolean alwaysActive = getNBTBoolean(test, "auto");
- for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
- if (!(b.getLocation().distance(WhitelistedBlock.fromSerialized(cb.loc())) < 0.5)) continue;
- if (cb.active() != alwaysActive) return false;
- if (!cb.command().equals(command)) return false;
- if (!cb.type().equals(getType(test))) return false;
- return PlayerUtils.isTrusted(cb.owner());
- }
- return false;
- }
-
- public static WhitelistedBlock get(Location where) {
- for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
- Location cbl = WhitelistedBlock.fromSerialized(cb.loc());
- if (cbl.distance(where) < 0.5) {
- return cb;
- }
- }
- return null;
- }
-
- public static int clearAll() {
- int total = 0;
- for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
- Location remove = WhitelistedBlock.fromSerialized(cb.loc());
- remove(remove);
- remove.getBlock().setType(Material.AIR);
- total++;
- }
- return total;
- }
-
- public static int clearAll(UUID who) {
- int total = 0;
- for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
- if (!cb.owner().equals(who.toString())) continue;
- Location remove = WhitelistedBlock.fromSerialized(cb.loc());
- remove(remove);
- remove.getBlock().setType(Material.AIR);
- total++;
- }
- return total;
- }
-
- public static int restoreAll() {
- int total = 0;
- for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
- if (restore(WhitelistedBlock.fromSerialized(cb.loc()))) total++;
- }
- return total;
- }
-
- public static int restoreAll(UUID who) {
- int total = 0;
- for (WhitelistedBlock cb : Sentinel.whitelist.whitelistedCMDBlocks) {
- if (!cb.owner().equals(who.toString())) continue;
- if (restore(WhitelistedBlock.fromSerialized(cb.loc()))) total++;
- }
- return total;
- }
-
-
- public static boolean restore(Location where) {
- WhitelistedBlock wb = get(where);
- if (wb == null) {
- ServerUtils.verbose("No whitelisted command block found at the specified location.");
- return false;
- }
-
- Block block = where.getBlock();
- block.setType(getBlockType(wb.type()));
- if (!(block.getState() instanceof CommandBlock)) {
- ServerUtils.verbose("Block at the location was not a command block (You shouldn't be seeing this. Report it).");
- return false;
- }
-
- CommandBlock cb = (CommandBlock) block.getState();
- cb.setCommand(wb.command());
- cb.setType(getBlockType(wb.type()));
- setNBTBoolean(cb, "auto", wb.active());
-
- cb.update();
- ServerUtils.verbose("Command block at " + where.toString() + " has been restored.");
- return true;
- }
-
- public static String getType(CommandBlock cb) {
- switch (cb.getType()) {
- case COMMAND_BLOCK -> {
- return "impulse";
- }
- case REPEATING_COMMAND_BLOCK -> {
- return "repeat";
- }
- case CHAIN_COMMAND_BLOCK -> {
- return "chain";
- }
- }
- return null;
- }
-
- private static Material getBlockType(String type) {
- return switch (type) {
- case "impulse" -> Material.COMMAND_BLOCK;
- case "repeat" -> Material.REPEATING_COMMAND_BLOCK;
- case "chain" -> Material.CHAIN_COMMAND_BLOCK;
- default -> throw new IllegalArgumentException("Unknown command block type: " + type);
- };
- }
-
- private static void setNBTBoolean(CommandBlock cmdBlock, String key, boolean value) {
- cmdBlock.getPersistentDataContainer().set(
- getKey(key),
- PersistentDataType.BYTE,
- value ? (byte) 1 : (byte) 0
+ public CommandBlockHolder generateHolder(UUID owner, CommandMinecart cm) {
+ return new CommandBlockHolder(owner.toString(),
+ SerialLocation.uuidToLocation(cm.getUniqueId()),
+ "minecart",
+ cm.getType().name(),
+ false,
+ false,
+ cm.getCommand()
);
}
-
- private static boolean getNBTBoolean(CommandBlock cmdBlock, String key) {
- return cmdBlock.getPersistentDataContainer().has(
- getKey(key),
- PersistentDataType.BYTE
- ) && cmdBlock.getPersistentDataContainer().get(
- getKey(key),
- PersistentDataType.BYTE
- ) == 1;
+ public CommandBlockHolder generateHolder(UUID owner, CommandBlock cb) {
+ return new CommandBlockHolder(owner.toString(),
+ SerialLocation.translate(cb.getLocation()),
+ serializeFacing(cb.getBlock()),
+ serializeType(cb),
+ isAuto(cb),
+ isConditional(cb),
+ cb.getCommand()
+ );
}
- private static NamespacedKey getKey(String key) {
- return new NamespacedKey(Sentinel.getInstance(), key);
+ public void removeSelectionFromWhitelist(Player player) {
+ Selection selection = WandEvents.selections.get(player.getUniqueId());
+ if (selection == null || !selection.isComplete()) {
+ errorAny(player,"You must set 2 points first.");
+ return;
+ }
+ AtomicInteger number = new AtomicInteger();
+ selection.forEachBlock(block -> {
+ if (block.getType().equals(Material.COMMAND_BLOCK) || block.getType().equals(Material.REPEATING_COMMAND_BLOCK) || block.getType().equals(Material.CHAIN_COMMAND_BLOCK)) {
+ getFromList(block.getLocation()).setWhitelisted(false);
+ number.getAndIncrement();
+ }
+ });
+
+ successAny(player,"Removed all {0} command blocks from the whitelist in your selection.",number.get());
}
+
+ public void deleteSelection(Player player) {
+ Selection selection = WandEvents.selections.get(player.getUniqueId());
+ if (selection == null || !selection.isComplete()) {
+ errorAny(player,"You must set 2 points first.");
+ return;
+ }
+ AtomicInteger number = new AtomicInteger();
+ selection.forEachBlock(block -> {
+ if (block.getType().equals(Material.COMMAND_BLOCK) || block.getType().equals(Material.REPEATING_COMMAND_BLOCK) || block.getType().equals(Material.CHAIN_COMMAND_BLOCK)) {
+ getFromList(block.getLocation()).delete();
+ number.getAndIncrement();
+ }
+ });
+
+ successAny(player,"Deleted all {0} command blocks from the whitelist in your selection.",number.get());
+ }
+
+ public void addSelectionToWhitelist(Player player) {
+ Selection selection = WandEvents.selections.get(player.getUniqueId());
+ if (selection == null || !selection.isComplete()) {
+ errorAny(player,"You must set 2 points first.");
+ return;
+ }
+
+ AtomicInteger number = new AtomicInteger();
+ selection.forEachBlock(block -> {
+ if (ServerUtils.isCommandBlock(block)) {
+ getFromList(block.getLocation()).addAndWhitelist();
+ number.getAndIncrement();
+ }
+ });
+
+ successAny(player,"Whitelisted all {0} command blocks in your selection.",number.get());
+ }
+
+ public int clearAll() {
+ int total = 0;
+ for (CommandBlockHolder cb : main.dir().io.whitelistStorage.holders) {
+ cb.destroy();
+ cb.delete();
+ total++;
+
+ if (cb.isCart()) continue;
+ Location remove = SerialLocation.translate(cb.loc());
+ remove.getBlock().setType(Material.AIR);
+ }
+ return total;
+ }
+
+ public int clearAll(UUID who) {
+ int total = 0;
+ for (CommandBlockHolder cb : main.dir().io.whitelistStorage.holders) {
+ if (!cb.owner().equals(who.toString())) continue;
+ cb.destroy();
+ cb.delete();
+ total++;
+
+ if (cb.isCart()) continue;
+ Location remove = SerialLocation.translate(cb.loc());
+ remove.getBlock().setType(Material.AIR);
+ }
+ return total;
+ }
+
+ public int restoreAll() {
+ int total = 0;
+ for (CommandBlockHolder cb : main.dir().io.whitelistStorage.holders) {
+ if (cb.isWhitelisted() && cb.restore()) total++;
+ }
+ return total;
+ }
+
+ public int restoreAll(UUID who) {
+ int total = 0;
+ for (CommandBlockHolder cb : main.dir().io.whitelistStorage.holders) {
+ if (!cb.owner().equals(who.toString())) continue;
+ if (cb.isWhitelisted() && cb.restore()) total++;
+ }
+ return total;
+ }
+
+ public String serializeFacing(Block block) {
+ if (block.getBlockData() instanceof Directional directional) {
+ return directional.getFacing().name();
+ }
+ return "UNKNOWN";
+ }
+
+ public String serializeType(CommandBlock cb) {
+ return cb.getType().name();
+ }
+
+ public boolean isAuto(CommandBlock cb) {
+ return cb.getPersistentDataContainer().getOrDefault(Sentinel.getInstance().getNamespace("auto"), PersistentDataType.BYTE,(byte) 0) == (byte) 1;
+ }
+
+ public boolean isConditional(CommandBlock cb) {
+ return cb.getBlock().getBlockData() instanceof org.bukkit.block.data.type.CommandBlock cbs && cbs.isConditional();
+ }
+
+ public CommandBlockHolder getFromList(UUID entityUUID) {
+ for (CommandBlockHolder existing : main.dir().io.whitelistStorage.holders) {
+ if (existing.loc().isUUID() && existing.loc().toUIID().equals(entityUUID)) {
+ return existing;
+ }
+ }
+ return null;
+ }
+
+ public CommandBlockHolder getFromList(Location loc) {
+ for (CommandBlockHolder existing : main.dir().io.whitelistStorage.holders) {
+ if (existing.loc().isSameLocation(loc)) {
+ return existing;
+ }
+ }
+ return null;
+ }
+
+ public CommandBlockHolder getFromList(SerialLocation loc) {
+ for (CommandBlockHolder existing : main.dir().io.whitelistStorage.holders) {
+ if (existing.loc().isSameLocation(loc)) {
+ return existing;
+ }
+ }
+ return null;
+ }
+
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/helpers/FilterHelpers.java b/src/main/java/me/trouper/sentinel/server/functions/helpers/FilterHelpers.java
deleted file mode 100644
index f5ae2ff..0000000
--- a/src/main/java/me/trouper/sentinel/server/functions/helpers/FilterHelpers.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package me.trouper.sentinel.server.functions.helpers;
-
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.functions.chatfilter.profanity.Severity;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class FilterHelpers {
-
- public static Severity checkSlur(String text, Severity backup) {
- if (containsSlurs(text)) return Severity.SLUR;
- if (containsSwears(text)) return backup;
- return Severity.SAFE;
- }
-
- public static boolean containsSwears(String text) {
- ServerUtils.verbose("ProfanityFilter: Checking for swears");
- for (String swear : Sentinel.swearConfig.swears) {
- if (text.contains(swear)) return true;
- }
-
- Pattern pattern = Pattern.compile(Sentinel.swearConfig.regexSwears, Pattern.CASE_INSENSITIVE);
- Matcher matcher = pattern.matcher(text);
-
- return matcher.find() && Sentinel.swearConfig.useRegex;
- }
-
- public static boolean containsSlurs(String text) {
- ServerUtils.verbose("ProfanityFilter: Checking for slurs");
- for (String slur : Sentinel.strictConfig.strict) {
- if (text.contains(slur)) return true;
- }
-
- Pattern pattern = Pattern.compile(Sentinel.strictConfig.regexStrict, Pattern.CASE_INSENSITIVE);
- Matcher matcher = pattern.matcher(text);
-
- return matcher.find() && Sentinel.strictConfig.useRegex;
- }
-
- public static String removeFalsePositives(String text) {
- for (String falsePositive : Sentinel.fpConfig.swearWhitelist) {
- text = text.replace(falsePositive, "");
- }
- text = text.replaceAll(Sentinel.fpConfig.regexWhitelist,"");
- return text;
- }
-
- public static String convertLeetSpeakCharacters(String text) {
- text = Text.fromLeetString(text);
- return text;
- }
-
- public static String stripSpecialCharacters(String text) {
- text = text.replaceAll("[^A-Za-z0-9.,!?;:'\"()\\[\\]{}]", "").trim();
- return text;
- }
-
- public static String simplifyRepeatingLetters(String text) {
- text = Text.replaceRepeatingLetters(text);
- return text;
- }
-
- public static String removePeriodsAndSpaces(String text) {
- return text.replaceAll("[^A-Za-z0-9]", "").replace(" ", "");
- }
-
- public static String highlightProfanity(String text, String start, String end) {
- String highlightedSwears = highlightSwears(fullSimplify(text), start, end);
- return Text.color(highlightSlurs(highlightedSwears, start, end));
- }
-
- private static String highlightSwears(String text, String start, String end) {
- for (String swear : Sentinel.swearConfig.swears) {
- text = text.replace(swear, start + swear + end);
- }
- return text;
- }
-
- private static String highlightSlurs(String text, String start, String end) {
- for (String slur : Sentinel.strictConfig.strict) {
- text = text.replace(slur, start + slur + end);
- }
- return text;
- }
-
- public static String fullSimplify(String text) {
- String lowercasedText = text.toLowerCase();
- String cleanedText = FilterHelpers.removeFalsePositives(lowercasedText);
- String convertedText = FilterHelpers.convertLeetSpeakCharacters(cleanedText);
- String strippedText = FilterHelpers.stripSpecialCharacters(convertedText);
- String simplifiedText = FilterHelpers.simplifyRepeatingLetters(strippedText);
- return FilterHelpers.removePeriodsAndSpaces(simplifiedText);
- }
-
- public static void restrictMessage(AsyncChatEvent event, boolean silent) {
- if (silent) {
- event.viewers().clear();
- event.viewers().add(event.getPlayer());
- } else {
- event.setCancelled(true);
- }
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/helpers/Message.java b/src/main/java/me/trouper/sentinel/server/functions/helpers/MessageHandler.java
similarity index 53%
rename from src/main/java/me/trouper/sentinel/server/functions/helpers/Message.java
rename to src/main/java/me/trouper/sentinel/server/functions/helpers/MessageHandler.java
index a4896f4..7060132 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/helpers/Message.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/helpers/MessageHandler.java
@@ -4,8 +4,9 @@ import io.github.itzispyder.pdk.utils.ServerUtils;
import io.papermc.paper.chat.ChatRenderer;
import io.papermc.paper.event.player.AsyncChatEvent;
import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.server.commands.SentinelCommand;
-import me.trouper.sentinel.server.events.ChatEvent;
+import me.trouper.sentinel.server.events.violations.players.ChatEvent;
import net.kyori.adventure.chat.SignedMessage;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
@@ -13,28 +14,28 @@ import org.bukkit.entity.Player;
import java.util.*;
-public class Message {
- public static final Map replyMap = new HashMap<>();
- public static void messagePlayer(Player sender, Player receiver, String message) {
+public class MessageHandler implements Main {
+ public final Map replyMap = new HashMap<>();
+ public void messagePlayer(Player sender, Player receiver, String message) {
AsyncChatEvent checkEvent = new AsyncChatEvent(true,sender, new HashSet<>(Arrays.asList(receiver, sender)), ChatRenderer.defaultRenderer(),Component.text(message),Component.text(message), SignedMessage.system(message,Component.text(message)));
if (checkEvent.isCancelled()) return;
new ChatEvent().handleEvent(checkEvent);
if (checkEvent.isCancelled()) return;
- sender.sendMessage(Sentinel.lang.playerInteraction.messageSent.formatted(receiver.getName(),message));
- receiver.sendMessage(Sentinel.lang.playerInteraction.messageReceived.formatted(sender.getName(),message));
+ sender.sendMessage(main.dir().io.lang.playerInteraction.messageSent.formatted(receiver.getName(),message)); // This "sendMessage" call is correct
+ receiver.sendMessage(main.dir().io.lang.playerInteraction.messageReceived.formatted(sender.getName(),message)); // This "sendMessage" call is correct
replyMap.put(receiver.getUniqueId(),sender.getUniqueId());
sendSpy(sender,receiver,message);
}
- public static void sendSpy(Player sender, Player receiver, String message) {
+ public void sendSpy(Player sender, Player receiver, String message) {
ServerUtils.forEachPlayer(player -> {
if (SentinelCommand.spyMap.getOrDefault(player.getUniqueId(),false)) {
TextComponent notification = Component
- .text(Sentinel.lang.socialSpy.spyMessage.formatted(sender.getName(),receiver.getName()))
- .hoverEvent(Component.text(Sentinel.lang.socialSpy.spyMessageHover.formatted(sender.getName(),receiver.getName(),message)));
- player.sendMessage(notification);
+ .text(main.dir().io.lang.socialSpy.spyMessage.formatted(sender.getName(),receiver.getName()))
+ .hoverEvent(Component.text(main.dir().io.lang.socialSpy.spyMessageHover.formatted(sender.getName(),receiver.getName(),message)));
+ player.sendMessage(notification); // This "sendMessage" call is correct
}
});
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/helpers/Report.java b/src/main/java/me/trouper/sentinel/server/functions/helpers/Report.java
index 7f70aa3..08c2d44 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/helpers/Report.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/helpers/Report.java
@@ -37,4 +37,8 @@ public class Report {
public void setStepsTaken(LinkedHashMap stepsTaken) {
this.stepsTaken = stepsTaken;
}
+
+ public void addStep(String name, String step) {
+ getStepsTaken().put(name,step);
+ }
}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/helpers/FalsePositiveReporting.java b/src/main/java/me/trouper/sentinel/server/functions/helpers/ReportHandler.java
similarity index 81%
rename from src/main/java/me/trouper/sentinel/server/functions/helpers/FalsePositiveReporting.java
rename to src/main/java/me/trouper/sentinel/server/functions/helpers/ReportHandler.java
index 329874f..3158efd 100644
--- a/src/main/java/me/trouper/sentinel/server/functions/helpers/FalsePositiveReporting.java
+++ b/src/main/java/me/trouper/sentinel/server/functions/helpers/ReportHandler.java
@@ -2,8 +2,8 @@ package me.trouper.sentinel.server.functions.helpers;
import io.github.itzispyder.pdk.utils.SchedulerUtils;
import io.github.itzispyder.pdk.utils.discord.DiscordEmbed;
-import me.trouper.sentinel.data.Emojis;
-import me.trouper.sentinel.utils.Randomizer;
+import me.trouper.sentinel.data.types.Emojis;
+import me.trouper.sentinel.utils.RandomUtils;
import me.trouper.sentinel.utils.trees.EmbedFormatter;
import org.bukkit.entity.Player;
@@ -11,11 +11,11 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
-public class FalsePositiveReporting {
- public static Map reports = new HashMap<>();
+public class ReportHandler {
+ public Map reports = new HashMap<>();
- public static Report initializeReport(String message) {
- final long reportID = Randomizer.generateID();
+ public Report initializeReport(String message) {
+ final long reportID = RandomUtils.generateID();
LinkedHashMap steps = new LinkedHashMap<>();
steps.put("Original Message", "`%s`".formatted(message));
@@ -25,7 +25,7 @@ public class FalsePositiveReporting {
return new Report(reportID,message,steps);
}
- public static void sendReport(Player sender, Report report) {
+ public void sendReport(Player sender, Report report) {
DiscordEmbed.Builder embed = DiscordEmbed.create()
.author(new DiscordEmbed.Author("Anti-Swear False Positive","",null))
.title("A player has reported a false positive")
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/AbstractCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/AbstractCheck.java
new file mode 100644
index 0000000..5fa7b59
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/AbstractCheck.java
@@ -0,0 +1,10 @@
+package me.trouper.sentinel.server.functions.hotbar;
+
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.data.config.NBTConfig;
+import me.trouper.sentinel.server.Main;
+
+public abstract class AbstractCheck implements Main {
+ public NBTConfig config = main.dir().io.nbtConfig;
+ public abstract boolean passes(T input);
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EntityCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EntityCheck.java
new file mode 100644
index 0000000..33b77fe
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EntityCheck.java
@@ -0,0 +1,76 @@
+package me.trouper.sentinel.server.functions.hotbar.entities;
+
+import de.tr7zw.changeme.nbtapi.NBT;
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.server.functions.hotbar.items.ItemCheck;
+import me.trouper.sentinel.server.functions.hotbar.misc.InventoryCheck;
+import me.trouper.sentinel.utils.InventoryUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Item;
+import org.bukkit.entity.Mob;
+import org.bukkit.entity.Villager;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.MerchantRecipe;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class EntityCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(Entity entity) {
+ if (entity instanceof Item itemEntity) {
+ if (!new ItemCheck().passes(itemEntity.getItemStack())) {
+ ServerUtils.verbose("Entity failed check: Item not allowed.");
+ return false;
+ }
+ }
+ Inventory inv = InventoryUtils.getInventory(entity);
+ if (inv != null && !new InventoryCheck().passes(inv)) {
+ ServerUtils.verbose("Entity inventory failed check.");
+ return false;
+ }
+ if (entity instanceof Villager villager) {
+ for (MerchantRecipe recipe : villager.getRecipes()) {
+ if (!new ItemCheck().passes(recipe.getResult())) {
+ ServerUtils.verbose("Villager recipe failed check.");
+ return false;
+ }
+ }
+ }
+ if (entity instanceof Mob mob) {
+ if (!new EquipmentCheck().passes(mob)) {
+ ServerUtils.verbose("Mob equipment failed check.");
+ return false;
+ }
+ }
+ if (!entity.getPassengers().isEmpty()) {
+ if (!config.allowRecursion) {
+ ServerUtils.verbose("Entity recursion not allowed.");
+ return false;
+ }
+ for (Entity passenger : entity.getPassengers()) {
+ if (!passes(passenger)) {
+ ServerUtils.verbose("Entity passenger failed check.");
+ return false;
+ }
+ }
+ }
+ AtomicBoolean failsTiming = new AtomicBoolean(false);
+ NBT.get(entity, nbt -> {
+ if (nbt.hasTag("DeathTime") && nbt.getInteger("DeathTime") < 1) {
+ ServerUtils.verbose("Entity death time check failed.");
+ failsTiming.set(true);
+ }
+ if (nbt.hasTag("HurtTime") && nbt.getInteger("HurtTime") < 1) {
+ ServerUtils.verbose("Entity hurt time check failed.");
+ failsTiming.set(true);
+ }
+ });
+ if (failsTiming.get()) {
+ ServerUtils.verbose("Entity timing check failed.");
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EntitySnapshotCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EntitySnapshotCheck.java
new file mode 100644
index 0000000..f647e52
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EntitySnapshotCheck.java
@@ -0,0 +1,21 @@
+package me.trouper.sentinel.server.functions.hotbar.entities;
+
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntitySnapshot;
+
+public class EntitySnapshotCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(EntitySnapshot input) {
+ Location loc = new Location(Bukkit.getWorlds().getFirst(), 0, 1000000, 0);
+ Entity temp = input.createEntity(loc);
+ boolean result = new EntityCheck().passes(temp);
+ ServerUtils.verbose("Temp Entity %s Entity Check", result ? "failed" : "passed");
+ temp.remove();
+ return result;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EquipmentCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EquipmentCheck.java
new file mode 100644
index 0000000..3dbb8dd
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/entities/EquipmentCheck.java
@@ -0,0 +1,25 @@
+package me.trouper.sentinel.server.functions.hotbar.entities;
+
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.server.functions.hotbar.items.ItemCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.entity.Mob;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+
+public class EquipmentCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(Mob mob) {
+ ServerUtils.verbose("Running mob check.");
+ for (EquipmentSlot slot : EquipmentSlot.values()) {
+ if (mob.getEquipment().getItem(slot).isEmpty()) continue;
+ ItemStack item = mob.getEquipment().getItem(slot);
+ if (!new ItemCheck().passes(item)) {
+ ServerUtils.verbose("Equipment slot did not pass.");
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/EnchantmentCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/EnchantmentCheck.java
new file mode 100644
index 0000000..7d4275d
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/EnchantmentCheck.java
@@ -0,0 +1,130 @@
+package me.trouper.sentinel.server.functions.hotbar.items;
+
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.Map;
+
+import static org.bukkit.enchantments.Enchantment.MENDING;
+
+public class EnchantmentCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(ItemStack input) {
+ return !hasIllegalEnchants(input);
+ }
+
+ public boolean hasIllegalEnchants(ItemStack item) {
+ ServerUtils.verbose("Checking item for illegal enchants: ", item.getType().name());
+ if (item.hasItemMeta() && item.getItemMeta().hasEnchants()) {
+ ItemMeta meta = item.getItemMeta();
+ Map enchantments = meta.getEnchants();
+ for (Map.Entry entry : enchantments.entrySet()) {
+ Enchantment enchantment = entry.getKey();
+ int level = entry.getValue();
+ if (level > main.dir().io.nbtConfig.globalMaxEnchant || isOverLimit(enchantment, level)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static boolean isOverLimit(Enchantment enchantment, int level) {
+ int maxLevel = main.dir().io.nbtConfig.globalMaxEnchant;
+
+ if (enchantment.equals(MENDING)) {
+ maxLevel = main.dir().io.nbtConfig.maxMending;
+ } else if (enchantment.equals(Enchantment.UNBREAKING)) {
+ maxLevel = main.dir().io.nbtConfig.maxUnbreaking;
+ } else if (enchantment.equals(Enchantment.VANISHING_CURSE)) {
+ maxLevel = main.dir().io.nbtConfig.maxCurseOfVanishing;
+ } else if (enchantment.equals(Enchantment.BINDING_CURSE)) {
+ maxLevel = main.dir().io.nbtConfig.maxCurseOfBinding;
+ } else if (enchantment.equals(Enchantment.AQUA_AFFINITY)) {
+ maxLevel = main.dir().io.nbtConfig.maxAquaAffinity;
+ } else if (enchantment.equals(Enchantment.PROTECTION)) {
+ maxLevel = main.dir().io.nbtConfig.maxProtection;
+ } else if (enchantment.equals(Enchantment.BLAST_PROTECTION)) {
+ maxLevel = main.dir().io.nbtConfig.maxBlastProtection;
+ } else if (enchantment.equals(Enchantment.DEPTH_STRIDER)) {
+ maxLevel = main.dir().io.nbtConfig.maxDepthStrider;
+ } else if (enchantment.equals(Enchantment.FEATHER_FALLING)) {
+ maxLevel = main.dir().io.nbtConfig.maxFeatherFalling;
+ } else if (enchantment.equals(Enchantment.FIRE_PROTECTION)) {
+ maxLevel = main.dir().io.nbtConfig.maxFireProtection;
+ } else if (enchantment.equals(Enchantment.FROST_WALKER)) {
+ maxLevel = main.dir().io.nbtConfig.maxFrostWalker;
+ } else if (enchantment.equals(Enchantment.PROJECTILE_PROTECTION)) {
+ maxLevel = main.dir().io.nbtConfig.maxProjectileProtection;
+ } else if (enchantment.equals(Enchantment.RESPIRATION)) {
+ maxLevel = main.dir().io.nbtConfig.maxRespiration;
+ } else if (enchantment.equals(Enchantment.SOUL_SPEED)) {
+ maxLevel = main.dir().io.nbtConfig.maxSoulSpeed;
+ } else if (enchantment.equals(Enchantment.THORNS)) {
+ maxLevel = main.dir().io.nbtConfig.maxThorns;
+ } else if (enchantment.equals(Enchantment.SWEEPING_EDGE)) {
+ maxLevel = main.dir().io.nbtConfig.maxSweepingEdge;
+ } else if (enchantment.equals(Enchantment.SWIFT_SNEAK)) {
+ maxLevel = main.dir().io.nbtConfig.maxSwiftSneak;
+ } else if (enchantment.equals(Enchantment.BANE_OF_ARTHROPODS)) {
+ maxLevel = main.dir().io.nbtConfig.maxBaneOfArthropods;
+ } else if (enchantment.equals(Enchantment.FIRE_ASPECT)) {
+ maxLevel = main.dir().io.nbtConfig.maxFireAspect;
+ } else if (enchantment.equals(Enchantment.LOOTING)) {
+ maxLevel = main.dir().io.nbtConfig.maxLooting;
+ } else if (enchantment.equals(Enchantment.IMPALING)) {
+ maxLevel = main.dir().io.nbtConfig.maxImpaling;
+ } else if (enchantment.equals(Enchantment.KNOCKBACK)) {
+ maxLevel = main.dir().io.nbtConfig.maxKnockback;
+ } else if (enchantment.equals(Enchantment.SHARPNESS)) {
+ maxLevel = main.dir().io.nbtConfig.maxSharpness;
+ } else if (enchantment.equals(Enchantment.SMITE)) {
+ maxLevel = main.dir().io.nbtConfig.maxSmite;
+ } else if (enchantment.equals(Enchantment.CHANNELING)) {
+ maxLevel = main.dir().io.nbtConfig.maxChanneling;
+ } else if (enchantment.equals(Enchantment.FLAME)) {
+ maxLevel = main.dir().io.nbtConfig.maxFlame;
+ } else if (enchantment.equals(Enchantment.INFINITY)) {
+ maxLevel = main.dir().io.nbtConfig.maxInfinity;
+ } else if (enchantment.equals(Enchantment.LOYALTY)) {
+ maxLevel = main.dir().io.nbtConfig.maxLoyalty;
+ } else if (enchantment.equals(Enchantment.RIPTIDE)) {
+ maxLevel = main.dir().io.nbtConfig.maxRiptide;
+ } else if (enchantment.equals(Enchantment.MULTISHOT)) {
+ maxLevel = main.dir().io.nbtConfig.maxMultishot;
+ } else if (enchantment.equals(Enchantment.PIERCING)) {
+ maxLevel = main.dir().io.nbtConfig.maxPiercing;
+ } else if (enchantment.equals(Enchantment.POWER)) {
+ maxLevel = main.dir().io.nbtConfig.maxPower;
+ } else if (enchantment.equals(Enchantment.PUNCH)) {
+ maxLevel = main.dir().io.nbtConfig.maxPunch;
+ } else if (enchantment.equals(Enchantment.QUICK_CHARGE)) {
+ maxLevel = main.dir().io.nbtConfig.maxQuickCharge;
+ } else if (enchantment.equals(Enchantment.EFFICIENCY)) {
+ maxLevel = main.dir().io.nbtConfig.maxEfficiency;
+ } else if (enchantment.equals(Enchantment.FORTUNE)) {
+ maxLevel = main.dir().io.nbtConfig.maxFortune;
+ } else if (enchantment.equals(Enchantment.LUCK_OF_THE_SEA)) {
+ maxLevel = main.dir().io.nbtConfig.maxLuckOfTheSea;
+ } else if (enchantment.equals(Enchantment.LURE)) {
+ maxLevel = main.dir().io.nbtConfig.maxLure;
+ } else if (enchantment.equals(Enchantment.SILK_TOUCH)) {
+ maxLevel = main.dir().io.nbtConfig.maxSilkTouch;
+ } else if (enchantment.equals(Enchantment.BREACH)) {
+ maxLevel = main.dir().io.nbtConfig.maxBreach;
+ } else if (enchantment.equals(Enchantment.DENSITY)) {
+ maxLevel = main.dir().io.nbtConfig.maxDensity;
+ } else if (enchantment.equals(Enchantment.WIND_BURST)) {
+ maxLevel = main.dir().io.nbtConfig.maxWindBurst;
+ }
+
+ return level > maxLevel;
+ }
+
+
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/ItemCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/ItemCheck.java
new file mode 100644
index 0000000..a092241
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/ItemCheck.java
@@ -0,0 +1,80 @@
+package me.trouper.sentinel.server.functions.hotbar.items;
+
+import de.tr7zw.changeme.nbtapi.NBT;
+import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.server.functions.hotbar.misc.BlockStateCheck;
+import me.trouper.sentinel.server.functions.hotbar.misc.InventoryCheck;
+import me.trouper.sentinel.server.functions.hotbar.nbt.ComponentCheck;
+import me.trouper.sentinel.utils.InventoryUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Arrays;
+
+public class ItemCheck extends AbstractCheck {
+
+
+ @Override
+ public boolean passes(ItemStack item) {
+ try {
+ return scan(item);
+ } catch (Exception ex) {
+ Sentinel.getInstance().getLogger().warning("Caught an exception while handling an item check: " + Arrays.toString(ex.getStackTrace()));
+ return false;
+ }
+ }
+
+
+ private boolean scan(ItemStack item) {
+ ServerUtils.verbose("Checking item: " + item.getType().name());
+
+ // No metadata? Nothing to check.
+ if (item.getItemMeta() == null) {
+ ServerUtils.verbose("Item passes because it has no metadata.");
+ return true;
+ }
+
+ if (!new MetaCheck().passes(item)) {
+ ServerUtils.verbose("Item failed metadata check.");
+ return false;
+ }
+
+
+ // NBT-based checks
+ ReadWriteNBT nbt = NBT.itemStackToNBT(item);
+ ReadWriteNBT components = nbt.getCompound("components");
+ if (components != null) {
+ if (!new ComponentCheck().passes(components)) {
+ ServerUtils.verbose("Components check failed.");
+ return false;
+ }
+ }
+
+ // Spawn egg checks.
+ if (!new SpawnEggCheck().passes(item)) {
+ ServerUtils.verbose("Spawn egg check failed.");
+ return false;
+ }
+
+ if (!new BlockStateCheck().passes(item)) {
+ ServerUtils.verbose("Block State check failed.");
+ return false;
+ }
+
+ // Check for an inventory inside the item.
+ Inventory inv = InventoryUtils.getInventory(item);
+ if (inv != null) {
+ ServerUtils.verbose("Item contains an inventory: " + inv);
+ if (!new InventoryCheck().passes(inv)) {
+ ServerUtils.verbose("Item failed inventory check.");
+ return false;
+ }
+ }
+
+ ServerUtils.verbose("Item passed all checks.");
+ return true;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/MetaCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/MetaCheck.java
new file mode 100644
index 0000000..0caf5e2
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/MetaCheck.java
@@ -0,0 +1,65 @@
+package me.trouper.sentinel.server.functions.hotbar.items;
+
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.BookMeta;
+import org.bukkit.inventory.meta.BundleMeta;
+import org.bukkit.inventory.meta.ItemMeta;
+
+public class MetaCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(ItemStack item) {
+ ItemMeta meta = item.getItemMeta();
+ // Name, lore, potion, attribute and enchantment checks.
+ if (!config.allowName && meta.hasDisplayName()) {
+ ServerUtils.verbose("Custom names not allowed.");
+ return false;
+ }
+ if (!config.allowLore && meta.hasLore()) {
+ ServerUtils.verbose("Custom lore not allowed.");
+ return false;
+ }
+ if (!config.allowBooks && meta instanceof BookMeta) {
+ ServerUtils.verbose("Item failed book check.");
+ return false;
+ }
+ if (!config.allowPotions &&
+ (item.getType().equals(Material.POTION) ||
+ item.getType().equals(Material.SPLASH_POTION) ||
+ item.getType().equals(Material.LINGERING_POTION))) {
+ ServerUtils.verbose("Potions not allowed.");
+ return false;
+ }
+ if (!config.allowAttributes && meta.hasAttributeModifiers()) {
+ ServerUtils.verbose("Attribute modifiers not allowed.");
+ return false;
+ }
+ if (config.globalMaxEnchant != 0 && new EnchantmentCheck().hasIllegalEnchants(item)) {
+ ServerUtils.verbose("Illegal enchantments found.");
+ return false;
+ }
+ // Recursion check for use-remainder items.
+ if (meta.hasUseRemainder()) {
+ if (!config.allowRecursion) {
+ ServerUtils.verbose("Recursion not allowed.");
+ return false;
+ }
+ if (meta.getUseRemainder() != null && !passes(meta.getUseRemainder())) {
+ ServerUtils.verbose("Use remainder item failed check.");
+ return false;
+ }
+ }
+
+ // Bundle check – recursively check the contained items.
+ if (item.getType().name().contains("_BUNDLE") && meta instanceof BundleMeta bm) {
+ for (ItemStack bundleItem : bm.getItems()) {
+ if (!passes(bundleItem)) return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/RateLimitCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/RateLimitCheck.java
new file mode 100644
index 0000000..9323e0b
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/RateLimitCheck.java
@@ -0,0 +1,81 @@
+package me.trouper.sentinel.server.functions.hotbar.items;
+
+import de.tr7zw.changeme.nbtapi.NBT;
+import de.tr7zw.changeme.nbtapi.NBTItem;
+import io.github.itzispyder.pdk.utils.misc.Pair;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class RateLimitCheck extends AbstractCheck> {
+
+
+ public static Map dataUsed = new HashMap<>();
+ public static Map itemsUsed = new HashMap<>();
+
+ @Override
+ public boolean passes(Pair input) {
+ Player player = input.left;
+ UUID uuid = player.getUniqueId();
+ ItemStack item = input.right;
+
+ return itemLimit(uuid,item) && dataLimit(uuid,item);
+ }
+
+ private boolean itemLimit(UUID uuid, ItemStack item) {
+ int currentUsed = itemsUsed.getOrDefault(uuid,0);
+ ServerUtils.verbose("Current Player used items: " + currentUsed);
+ currentUsed++;
+ itemsUsed.put(uuid,currentUsed);
+ return currentUsed <= config.rateLimit.rateLimitItems;
+ }
+
+
+ private boolean dataLimit(UUID uuid, ItemStack item) {
+ int currentData = dataUsed.getOrDefault(uuid,0);
+
+ ServerUtils.verbose("Current Player used data: " + currentData);
+ try {
+ int itemData = NBT.readNbt(item).toString().length();
+ ServerUtils.verbose("Item data: " + itemData);
+ if (currentData < config.rateLimit.maxOverhead) currentData += itemData;
+ } catch (Exception e) {
+ Sentinel.getInstance().getLogger().warning("Could not determine size of item. Blocking.");
+ Sentinel.getInstance().getLogger().warning(Arrays.toString(e.getStackTrace()));
+ return false;
+ }
+
+ dataUsed.put(uuid,currentData);
+
+ ServerUtils.verbose("New Player used data: " + currentData);
+
+ return currentData <= config.rateLimit.rateLimitBytes;
+ }
+
+ public void decayData() {
+ for (UUID uuid : dataUsed.keySet()) {
+ int currentData = dataUsed.get(uuid);
+ if (currentData > 0) {
+ currentData -= config.rateLimit.byteDecay;
+ dataUsed.put(uuid, Math.max(0, currentData));
+ }
+ }
+ }
+
+ public void decayItems() {
+ for (UUID uuid : itemsUsed.keySet()) {
+ int currentItems = itemsUsed.get(uuid);
+ if (currentItems > 0) {
+ currentItems -= config.rateLimit.itemDecay;
+ itemsUsed.put(uuid, Math.max(0, currentItems));
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/SpawnEggCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/SpawnEggCheck.java
new file mode 100644
index 0000000..ac5e7e3
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/items/SpawnEggCheck.java
@@ -0,0 +1,50 @@
+package me.trouper.sentinel.server.functions.hotbar.items;
+
+import de.tr7zw.changeme.nbtapi.NBT;
+import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.server.functions.hotbar.entities.EntitySnapshotCheck;
+import me.trouper.sentinel.server.functions.hotbar.nbt.EntityDataCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.SpawnEggMeta;
+
+public class SpawnEggCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(ItemStack item) {
+ ServerUtils.verbose("Running spawn egg checks on item: ",item.getType().name());
+ if (!item.getType().name().toLowerCase().contains("spawn_egg")) return true;
+ if (!SpawnEggCheck.entityMatches(item)) {
+ ServerUtils.verbose("Spawn egg entity doesn't match item type.");
+ return false;
+ }
+ ReadWriteNBT nbt = NBT.itemStackToNBT(item);
+ ReadWriteNBT components = nbt.getCompound("components");
+ if (components != null) {
+ var entityData = components.getCompound("minecraft:entity_data");
+ if (!new EntityDataCheck().passes(entityData)) {
+ ServerUtils.verbose("Spawn egg entity data check failed.");
+ return false;
+ }
+ }
+
+ if (item.hasItemMeta() && item.getItemMeta() instanceof SpawnEggMeta sem) {
+ if (sem.getSpawnedEntity() != null && !new EntitySnapshotCheck().passes(sem.getSpawnedEntity())) {
+ ServerUtils.verbose("Spawn egg entity snapshot check failed.");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean entityMatches(ItemStack item) {
+ if (item.hasItemMeta() && item.getItemMeta() instanceof SpawnEggMeta sem) {
+ String eggEntityName = item.getType().name().replace("_SPAWN_EGG", "");
+ return sem.getSpawnedEntity() != null &&
+ sem.getSpawnedEntity().getEntityType().name().equals(eggEntityName);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/misc/BlockStateCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/misc/BlockStateCheck.java
new file mode 100644
index 0000000..21009d5
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/misc/BlockStateCheck.java
@@ -0,0 +1,100 @@
+package me.trouper.sentinel.server.functions.hotbar.misc;
+
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.server.functions.hotbar.entities.EntitySnapshotCheck;
+import me.trouper.sentinel.server.functions.hotbar.items.ItemCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.Material;
+import org.bukkit.block.*;
+import org.bukkit.entity.EntityType;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.BlockStateMeta;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.spawner.TrialSpawnerConfiguration;
+
+public class BlockStateCheck extends AbstractCheck {
+ @Override
+ public boolean passes(ItemStack item) {
+ ItemMeta meta = item.getItemMeta();
+
+ if (!(meta instanceof BlockStateMeta blockStateMeta)) {
+ ServerUtils.verbose("Item passes due to not being a block state meta");
+ return true;
+ }
+
+ if (item.getType().name().contains("CAMPFIRE") ) {
+ BlockState bs = blockStateMeta.getBlockState();
+ if (bs instanceof Campfire campfire) {
+ for (int slot = 0; slot < 4; slot++) {
+ org.bukkit.inventory.ItemStack campfireItem = campfire.getItem(slot);
+ if (campfireItem != null && !new ItemCheck().passes(campfireItem)) {
+ ServerUtils.verbose("Campfire item failed check.");
+ return false;
+ }
+ }
+ }
+ }
+
+ // Lectern and Chiseled Bookshelf check (by validating their inventories).
+ if (item.getType().equals(Material.LECTERN)) {
+ BlockState bs = blockStateMeta.getBlockState();
+ if (bs instanceof Lectern lectern) {
+ if (!new InventoryCheck().passes(lectern.getInventory())) {
+ ServerUtils.verbose("Lectern inventory failed check.");
+ return false;
+ }
+ }
+ }
+ if (item.getType().equals(Material.CHISELED_BOOKSHELF)) {
+ BlockState bs = blockStateMeta.getBlockState();
+ if (bs instanceof ChiseledBookshelf bookshelf) {
+ if (!new InventoryCheck().passes(bookshelf.getInventory())) {
+ ServerUtils.verbose("Chiseled bookshelf inventory failed check.");
+ return false;
+ }
+ }
+ }
+
+ // Spawner check.
+ if (item.getType().equals(Material.SPAWNER)) {
+ BlockState bs = blockStateMeta.getBlockState();
+ if (bs instanceof CreatureSpawner spawner) {
+ if (spawner.getSpawnedEntity() != null) {
+ if (spawner.getSpawnedEntity().getEntityType().equals(EntityType.FALLING_BLOCK) ||
+ spawner.getSpawnedEntity().getEntityType().equals(EntityType.COMMAND_BLOCK_MINECART)) {
+ ServerUtils.verbose("Spawner contains disallowed entity type.");
+ return false;
+ }
+ if (!new EntitySnapshotCheck().passes(spawner.getSpawnedEntity())) {
+ ServerUtils.verbose("Spawner entity snapshot check failed.");
+ return false;
+ }
+ }
+ }
+ }
+
+ // Trial Spawner check.
+ if (item.getType() == Material.TRIAL_SPAWNER) {
+ BlockState bs = blockStateMeta.getBlockState();
+ if (bs instanceof TrialSpawner spawner) {
+ ServerUtils.verbose("Running trial spawner check.");
+ if (spawner.getNormalConfiguration() != null) {
+ TrialSpawnerConfiguration config = spawner.getNormalConfiguration();
+ if (config.getSpawnedEntity() != null && !new EntitySnapshotCheck().passes(config.getSpawnedEntity())) {
+ ServerUtils.verbose("Trial Spawner failed check: Normal entity snapshot not allowed.");
+ return false;
+ }
+ }
+ if (spawner.getOminousConfiguration() != null) {
+ TrialSpawnerConfiguration config = spawner.getOminousConfiguration();
+ if (config.getSpawnedEntity() != null && !new EntitySnapshotCheck().passes(config.getSpawnedEntity())) {
+ ServerUtils.verbose("Trial Spawner failed check: Ominous entity snapshot not allowed.");
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/misc/InventoryCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/misc/InventoryCheck.java
new file mode 100644
index 0000000..8f4c6c3
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/misc/InventoryCheck.java
@@ -0,0 +1,35 @@
+package me.trouper.sentinel.server.functions.hotbar.misc;
+
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.server.functions.hotbar.items.ItemCheck;
+import me.trouper.sentinel.utils.InventoryUtils;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+public class InventoryCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(Inventory inv) {
+ ServerUtils.verbose("Running Inventory Check");
+
+ for (ItemStack i : inv.getContents()) {
+ if (i == null || i.getType().isAir()) continue;
+ if (!new ItemCheck().passes(i)) {
+ ServerUtils.verbose("Inventory item failed check.");
+ return false;
+ }
+ Inventory subInventory = InventoryUtils.getInventory(i);
+ if (subInventory != null && !config.allowRecursion) {
+ ServerUtils.verbose("Recursion is disabled. Failing check.");
+ return false;
+ }
+ if (subInventory != null && !passes(subInventory)) {
+ ServerUtils.verbose("Sub-inventory failed check.");
+ return false;
+ }
+ }
+ ServerUtils.verbose("Inventory passed all checks.");
+ return true;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/nbt/ComponentCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/nbt/ComponentCheck.java
new file mode 100644
index 0000000..cb682b7
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/nbt/ComponentCheck.java
@@ -0,0 +1,32 @@
+package me.trouper.sentinel.server.functions.hotbar.nbt;
+
+import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+
+public class ComponentCheck extends AbstractCheck {
+
+ @Override
+ public boolean passes(ReadWriteNBT components) {
+ ServerUtils.verbose("Checking Consumable & tool");
+ if (!config.allowCustomConsumables && components.getCompound("minecraft:consumable") != null) {
+ ServerUtils.verbose("Item is consumable and not allowed.");
+ return false;
+ }
+ if (!config.allowCustomTools && components.getCompound("minecraft:tool") != null) {
+ ServerUtils.verbose("Item is custom tool and not allowed.");
+ return false;
+ }
+
+ ServerUtils.verbose("Checking Entity data");
+
+ ReadWriteNBT entityData = components.getCompound("minecraft:entity_data");
+ if (!new EntityDataCheck().passes(entityData)) {
+ ServerUtils.verbose("Entity Data Check Failed.");
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/src/main/java/me/trouper/sentinel/server/functions/hotbar/nbt/EntityDataCheck.java b/src/main/java/me/trouper/sentinel/server/functions/hotbar/nbt/EntityDataCheck.java
new file mode 100644
index 0000000..a2e035a
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/functions/hotbar/nbt/EntityDataCheck.java
@@ -0,0 +1,40 @@
+package me.trouper.sentinel.server.functions.hotbar.nbt;
+
+import de.tr7zw.changeme.nbtapi.NBT;
+import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
+import me.trouper.sentinel.server.functions.hotbar.AbstractCheck;
+import me.trouper.sentinel.server.functions.hotbar.items.ItemCheck;
+import me.trouper.sentinel.utils.ServerUtils;
+import org.bukkit.inventory.ItemStack;
+
+public class EntityDataCheck extends AbstractCheck {
+ @Override
+ public boolean passes(ReadWriteNBT entityData) {
+ if (entityData == null) {
+ ServerUtils.verbose("Entity Data check passed. There was no data.");
+ return true;
+ }
+
+ ReadWriteNBT itemData = entityData.getCompound("Item");
+ if (itemData != null) {
+ ServerUtils.verbose("Entity data holds an item");
+ ItemStack heldItem = NBT.itemStackFromNBT(itemData);
+ if (heldItem != null && !new ItemCheck().passes(heldItem)) {
+ ServerUtils.verbose("Item contents failed check.");
+ return false;
+ }
+ }
+
+ if (entityData.hasTag("DeathTime") && entityData.getInteger("DeathTime") < 1) {
+ ServerUtils.verbose("Death time check failed.");
+ return false;
+ }
+ if (entityData.hasTag("HurtTime") && entityData.getInteger("HurtTime") < 1) {
+ ServerUtils.verbose("Hurt time check failed.");
+ return false;
+ }
+
+ ServerUtils.verbose("Entity Data check passed. There was no flagging.");
+ return true;
+ }
+}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/Items.java b/src/main/java/me/trouper/sentinel/server/gui/Items.java
index ad5b265..f9c7ee2 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/Items.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/Items.java
@@ -1,10 +1,17 @@
package me.trouper.sentinel.server.gui;
-import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.startup.Auth;
+import me.trouper.sentinel.utils.ItemBuilder;
import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
import me.trouper.sentinel.utils.Text;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextReplacementConfig;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.Style;
+import net.kyori.adventure.text.format.TextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
@@ -18,137 +25,171 @@ public class Items {
public static final ItemStack BLANK = ItemBuilder.create()
.material(Material.LIGHT_GRAY_STAINED_GLASS_PANE)
- .name(Text.color("&7"))
+ .displayName(Component.empty())
.build();
public static final ItemStack GREEN = ItemBuilder.create()
.material(Material.LIME_STAINED_GLASS_PANE)
- .name(Text.color("&7"))
+ .displayName(Component.empty())
.build();
public static final ItemStack RED = ItemBuilder.create()
.material(Material.RED_STAINED_GLASS_PANE)
- .name(Text.color("&7"))
+ .displayName(Component.empty())
.build();
public static final ItemStack BACK = ItemBuilder.create()
.material(Material.ARROW)
- .name(Text.color("&cBack"))
- .lore(Text.color("&8&l➥&7 Return to the previous page"))
+ .displayName(Component.text("Back",NamedTextColor.RED).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(Text.color("&8&l➥&7 Return to the previous page"))
.build();
public static final ItemStack CREDITS = ItemBuilder.create()
.material(Material.SHIELD)
- .name(Text.color("&6&lSentinel &8&l|&f Anti-Nuke"))
- .lore(" ")
- .lore(Text.color("&bVersion&7: &f%s".formatted(Sentinel.getInstance().getDescription().getVersion())))
- .lore(Text.color("&bLicensed to&7: &f%s".formatted(Sentinel.getInstance().nonce)))
- .lore(" ")
- .lore(Text.color("&e&nAuthor(s)&r&e: &e%s").formatted(Sentinel.getInstance().getDescription().getAuthors()))
+ .displayName(Text.color("&6&lSentinel &8&l|&f Anti-Nuke").decoration(TextDecoration.ITALIC,false))
+ .loreComponent(
+ Component.empty(),
+ Text.color("&bVersion&7: &f%s".formatted(Sentinel.getInstance().version)),
+ Text.color("&bLicensed to&7: &f%s".formatted(Sentinel.getInstance().nonce)),
+ Component.empty(),
+ Text.color("&e&nAuthor(s)&r&e: &e%s".formatted(Sentinel.getInstance().getPluginMeta().getAuthors()))
+ )
.enchant(Enchantment.PROTECTION,64)
- .flag(ItemFlag.HIDE_ENCHANTS)
+ .flags(ItemFlag.HIDE_ENCHANTS)
.build();
public static final ItemStack CONFIG = ItemBuilder.create()
+ .displayName(Component.text("Edit Config",Style.style(TextDecoration.BOLD, NamedTextColor.GOLD)).decoration(TextDecoration.ITALIC,false))
.material(Material.PISTON)
- .name(Text.color("&6&lEdit Config"))
- .lore(Text.color("&8&l➥&7 Click this if you hate JSON."))
+ .loreComponent(Text.color("&8&l➥&7 Click this if you hate JSON."))
.enchant(Enchantment.PROTECTION,64)
- .flag(ItemFlag.HIDE_ENCHANTS)
+ .flags(ItemFlag.HIDE_ENCHANTS)
.build();
public static final ItemStack CHAT_CONFIG = ItemBuilder.create()
.material(Material.HOPPER)
- .name(Text.color("&bChat Config"))
- .lore(Text.color("&8&l➥&7 Spam Filter"))
- .lore(Text.color("&8&l➥&7 Profanity Filter"))
- .lore(Text.color("&8&l➥&7 Regex Filters"))
+ .displayName(Component.text("Chat Config",NamedTextColor.AQUA).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(
+ Text.color("&8&l➥&7 Spam Filter"),
+ Text.color("&8&l➥&7 Profanity Filter"),
+ Text.color("&8&l➥&7 Unicode Filter"),
+ Text.color("&8&l➥&7 URL Filter")
+ )
.enchant(Enchantment.PROTECTION,64)
- .flag(ItemFlag.HIDE_ENCHANTS)
+ .flags(ItemFlag.HIDE_ENCHANTS)
.build();
public static final ItemStack ANTI_NUKE_CONFIG = ItemBuilder.create()
.material(Material.TNT)
- .name(Text.color("&cAnti-Nuke Config"))
- .lore(Text.color("&8&l➥&7 Command Block Whitelist"))
- .lore(Text.color("&8&l➥&7 Command Block editing"))
- .lore(Text.color("&8&l➥&7 Command Block placing"))
- .lore(Text.color("&8&l➥&7 Command Block using"))
- .lore(Text.color("&8&l➥&7 Command Block Minecart placing"))
- .lore(Text.color("&8&l➥&7 Command Block Minecart using"))
- .lore(Text.color("&8&l➥&7 Creative Hotbar Items"))
- .enchant(Enchantment.PROTECTION,64)
- .flag(ItemFlag.HIDE_ENCHANTS)
+ .displayName(Component.text("Anti-Nuke Config", NamedTextColor.RED).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(Text.color("&8&l➥&7 Manage all violations"))
+ .enchant(Enchantment.PROTECTION, 64)
+ .flags(ItemFlag.HIDE_ENCHANTS)
+ .build();
+
+ public static final ItemStack WHITELIST = ItemBuilder.create()
+ .material(Material.TNT)
+ .displayName(Component.text("Command Block Whitelist", NamedTextColor.GREEN).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(Text.color("&8&l➥&7 Manage running command blocks"))
+ .enchant(Enchantment.PROTECTION, 64)
+ .flags(ItemFlag.HIDE_ENCHANTS)
+ .build();
+
+ public static final ItemStack NBT = ItemBuilder.create()
+ .material(Material.HONEY_BOTTLE)
+ .displayName(Component.text("NBT Honeypot", NamedTextColor.GREEN).decoration(TextDecoration.ITALIC,false))
+ .loreComponent(Text.color("&8&l➥&7 View caught NBT"))
+ .enchant(Enchantment.PROTECTION, 64)
+ .flags(ItemFlag.HIDE_ENCHANTS)
.build();
public static ItemStack configItem(String valueName, Material material, String description) {
- ServerUtils.verbose("Items#configItem: Creating a config item:\n Value Name -> %s\nMaterial in use -> %s".formatted(valueName,material.toString()));
+ ServerUtils.verbose("Creating a config item:\n Value Name -> %s\nMaterial in use -> %s",
+ valueName, material.toString());
List desc = Arrays.stream(description.split("\n")).toList();
- ItemBuilder item = ItemBuilder.create();
- item.material(material);
- item.name(Text.color("&6%s".formatted(valueName)));
+ ItemBuilder item = ItemBuilder.create()
+ .material(material)
+ .displayName(Component.text(valueName, NamedTextColor.GOLD).decoration(TextDecoration.ITALIC,false));
+
for (String s : desc) {
- item.lore(Text.color("&e%s".formatted(s)));
+ item.loreComponent(Component.text(s, NamedTextColor.YELLOW));
}
- item.lore(Text.color("&8&l➥&7 Click to set a &nnew&r&7 value."));
- item.lore(Text.color("&8&l➥&7 Current Value: &b_ORIGINAL_"));
+
+ item.loreComponent(
+ Text.color("&8&l➥&7 Click to set a &nnew&r&7 value."),
+ Text.color("&8&l➥&7 Current Value: &b_ORIGINAL_")
+ );
return item.build();
}
-
-
public static ItemStack stringListItem(Iterable values, Material material, String valueName, String description) {
- ServerUtils.verbose("Items#stringListItem: Creating a config item:\n Value Name -> %s\nMaterial in use -> %s".formatted(valueName,material.toString()));
- ItemBuilder itemBuilder = ItemBuilder.create();
- itemBuilder.material(material);
- itemBuilder.name(Text.color("&6%s".formatted(valueName)));
+ ServerUtils.verbose("Items#stringListItem: Creating a config item:\n Value Name -> %s\nMaterial in use -> %s",
+ valueName, material.toString());
+
+ ItemBuilder itemBuilder = ItemBuilder.create()
+ .material(material)
+ .displayName(Component.text(valueName, NamedTextColor.GOLD).decoration(TextDecoration.ITALIC,false));
+
List desc = Arrays.stream(description.split("\n")).toList();
for (String s : desc) {
- itemBuilder.lore(Text.color("&e%s".formatted(s)));
+ itemBuilder.loreComponent(Component.text(s, NamedTextColor.YELLOW));
}
- itemBuilder.lore(Text.color("&8&l➥&7 Left-Click to add a new value."));
- itemBuilder.lore(Text.color("&8&l➥&7 Right-Click to clear values."));
- itemBuilder.lore(Text.color("&8&l➥&7 Current Values: "));
- itemBuilder.flag(ItemFlag.HIDE_ATTRIBUTES);
+
+ itemBuilder.loreComponent(
+ Text.color("&8&l➥&7 Left-Click to add a new value."),
+ Text.color("&8&l➥&7 Right-Click to clear values."),
+ Text.color("&8&l➥&7 Current Values: ")
+ ).flags(ItemFlag.HIDE_ATTRIBUTES);
for (String value : values) {
- itemBuilder.lore(Text.color("&9 - &b%s".formatted(value)));
+ itemBuilder.loreComponent(
+ Component.text(" - ", NamedTextColor.BLUE)
+ .append(Component.text(value, NamedTextColor.AQUA))
+ );
}
return itemBuilder.build();
}
public static ItemStack stringItem(String originalValue, ItemStack originalItem) {
- ServerUtils.verbose("Items#stringItem Creating a string item:\n Value -> %s".formatted(originalValue));
+ ServerUtils.verbose("Items#stringItem Creating a string item:\n Value -> %s", originalValue);
if (originalItem == null || !originalItem.hasItemMeta()) return originalItem;
ItemMeta meta = originalItem.getItemMeta();
- if (meta == null || !meta.hasLore()) return originalItem;
- List lore = meta.getLore();
+ if (meta == null) return originalItem;
+
+ List lore = meta.lore();
if (lore == null) return originalItem;
for (int i = 0; i < lore.size(); i++) {
- String line = lore.get(i);
- ServerUtils.verbose("Items#stringItem Looping through lore line: %s/%s".formatted(i,lore.size()));
- if (line.contains("_ORIGINAL_")) {
+ Component line = lore.get(i);
+ String plainText = PlainTextComponentSerializer.plainText().serialize(line);
+
+ ServerUtils.verbose("Items#stringItem Looping through lore line: %s/%s", i, lore.size());
+
+ if (plainText.contains("_ORIGINAL_")) {
try {
- ServerUtils.verbose("Items#stringItem Found a lore on line %s, making replacement value".formatted(i));
- String replace = line.replace("_ORIGINAL_", originalValue);
- ServerUtils.verbose("Items#stringItem After replacement -> %s".formatted(replace));
- lore.set(i,replace);
- ServerUtils.verbose("Items#stringItem Just replaced line %s -> %s".formatted(i,lore.get(i)));
+ ServerUtils.verbose("Items#stringItem Found a lore on line %s, making replacement value", i);
+
+ Component newLine = line.replaceText(TextReplacementConfig.builder()
+ .matchLiteral("_ORIGINAL_")
+ .replacement(originalValue)
+ .build());
+
+ lore.set(i, newLine);
+ ServerUtils.verbose("Items#stringItem Just replaced line %s", i);
} catch (Exception e) {
e.printStackTrace();
}
}
- ServerUtils.verbose("Items#stringItem end of loop %s. continue?".formatted(i));
+ ServerUtils.verbose("Items#stringItem end of loop %s. continue?", i);
}
ServerUtils.verbose("Items#stringItem Broke out of loop, setting the lore");
- meta.setLore(lore);
+ meta.lore(lore);
ServerUtils.verbose("Items#stringItem Setting the meta");
originalItem.setItemMeta(meta);
ServerUtils.verbose("Items#stringItem Returning the item");
@@ -156,70 +197,52 @@ public class Items {
}
public static ItemStack booleanItem(boolean originalValue, ItemStack originalItem) {
- ServerUtils.verbose("Items#booleanItem Creating a string item:\n Value -> %s".formatted(originalValue));
-
- if (originalItem == null || !originalItem.hasItemMeta()) return originalItem;
- ItemMeta meta = originalItem.getItemMeta();
- if (meta == null || !meta.hasLore()) return originalItem;
- List lore = meta.getLore();
- if (lore == null) return originalItem;
-
- for (int i = 0; i < lore.size(); i++) {
- String line = lore.get(i);
- ServerUtils.verbose("Items#booleanItem Looping through lore line: %s/%s".formatted(i,lore.size()));
- if (line.contains("_ORIGINAL_")) {
- try {
- ServerUtils.verbose("Items#booleanItem Found a lore on line %s, making replacement value".formatted(i));
- String replace = line.replace("_ORIGINAL_", "" + originalValue);
- ServerUtils.verbose("Items#booleanItem After replacement -> %s".formatted(replace));
- lore.set(i,replace);
- ServerUtils.verbose("Items#booleanItem Just replaced line %s -> %s".formatted(i,lore.get(i)));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- ServerUtils.verbose("Items#booleanItem end of loop %s. continue?".formatted(i));
- }
-
- ServerUtils.verbose("Items#booleanItem Broke out of loop, setting the lore");
- meta.setLore(lore);
- ServerUtils.verbose("Items#booleanItem Setting the meta");
- originalItem.setItemMeta(meta);
- ServerUtils.verbose("Items#booleanItem Returning the item");
- return originalItem;
+ return replaceOriginalValue(String.valueOf(originalValue), originalItem, "booleanItem");
}
public static ItemStack intItem(int originalValue, ItemStack originalItem) {
- ServerUtils.verbose("Items#intitem Creating a string item:\n Value -> %s".formatted(originalValue));
+ return replaceOriginalValue(String.valueOf(originalValue), originalItem, "intItem");
+ }
+
+ private static ItemStack replaceOriginalValue(String value, ItemStack originalItem, String methodName) {
+ ServerUtils.verbose("Items#%s Creating item with value: %s", methodName, value);
if (originalItem == null || !originalItem.hasItemMeta()) return originalItem;
ItemMeta meta = originalItem.getItemMeta();
- if (meta == null || !meta.hasLore()) return originalItem;
- List lore = meta.getLore();
+ if (meta == null) return originalItem;
+
+ List lore = meta.lore();
if (lore == null) return originalItem;
for (int i = 0; i < lore.size(); i++) {
- String line = lore.get(i);
- ServerUtils.verbose("Items#intitem Looping through lore line: %s/%s".formatted(i,lore.size()));
- if (line.contains("_ORIGINAL_")) {
+ Component line = lore.get(i);
+ String plainText = PlainTextComponentSerializer.plainText().serialize(line);
+
+ ServerUtils.verbose("Items#%s Looping through lore line: %s/%s", methodName, i, lore.size());
+
+ if (plainText.contains("_ORIGINAL_")) {
try {
- ServerUtils.verbose("Items#intitem Found a lore on line %s, making replacement value".formatted(i));
- String replace = line.replace("_ORIGINAL_", "" + originalValue);
- ServerUtils.verbose("Items#intitem After replacement -> %s".formatted(replace));
- lore.set(i,replace);
- ServerUtils.verbose("Items#intitem Just replaced line %s -> %s".formatted(i,lore.get(i)));
+ ServerUtils.verbose("Items#%s Found a lore on line %s, making replacement value", methodName, i);
+
+ Component newLine = line.replaceText(TextReplacementConfig.builder()
+ .matchLiteral("_ORIGINAL_")
+ .replacement(value)
+ .build());
+
+ lore.set(i, newLine);
+ ServerUtils.verbose("Items#%s Just replaced line %s", methodName, i);
} catch (Exception e) {
e.printStackTrace();
}
}
- ServerUtils.verbose("Items#intitem end of loop %s. continue?".formatted(i));
+ ServerUtils.verbose("Items#%s end of loop %s. continue?", methodName, i);
}
- ServerUtils.verbose("Items#intitem Broke out of loop, setting the lore");
- meta.setLore(lore);
- ServerUtils.verbose("Items#intitem Setting the meta");
+ ServerUtils.verbose("Items#%s Broke out of loop, setting the lore", methodName);
+ meta.lore(lore);
+ ServerUtils.verbose("Items#%s Setting the meta", methodName);
originalItem.setItemMeta(meta);
- ServerUtils.verbose("Items#intitem Returning the item");
+ ServerUtils.verbose("Items#%s Returning the item", methodName);
return originalItem;
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/MainGUI.java b/src/main/java/me/trouper/sentinel/server/gui/MainGUI.java
index 1bafef7..04db84a 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/MainGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/MainGUI.java
@@ -2,8 +2,13 @@ package me.trouper.sentinel.server.gui;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.gui.config.ConfigGUI;
+import me.trouper.sentinel.server.gui.nbt.NBTGui;
+import me.trouper.sentinel.server.gui.whitelist.WhitelistGUI;
import me.trouper.sentinel.utils.PlayerUtils;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.utils.OldTXT;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
@@ -17,15 +22,27 @@ public class MainGUI {
public static Set awaitingCallback = new HashSet<>();
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Home"))
+ .title(OldTXT.color("&6&lSentinel &8»&0 Home"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
- .define(12,Items.CREDITS)
- .define(14,Items.CONFIG,this::openConfig)
+ .define(10,Items.CREDITS)
+ .define(12,Items.WHITELIST,this::openWhitelist)
+ .define(14,Items.NBT,this::openNBT)
+ .define(16,Items.CONFIG,this::openConfig)
.build();
+ private void openWhitelist(InventoryClickEvent e) {
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
+ e.getWhoClicked().openInventory(new WhitelistGUI().createGUI((Player) e.getWhoClicked()).getInventory());
+ }
+ private void openNBT(InventoryClickEvent e) {
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
+ e.getWhoClicked().openInventory(new NBTGui().createGUI((Player) e.getWhoClicked()).getInventory());
+ }
+
private void openConfig(InventoryClickEvent e) {
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
}
@@ -42,7 +59,7 @@ public class MainGUI {
public static boolean verify(Player p) {
if (PlayerUtils.isTrusted(p)) return true;
- Sentinel.log.info("WARNING: %s has just attempted to use the GUI without authorization. This has been prevented by Sentinel, as we are NOT Vulcan AntiCheat.");
+ Sentinel.getInstance().getLogger().info("WARNING: %s has just attempted to use the GUI without authorization. This has been prevented by Sentinel, as we are NOT Vulcan AntiCheat.");
p.closeInventory();
return false;
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/PaginatedGUI.java b/src/main/java/me/trouper/sentinel/server/gui/PaginatedGUI.java
new file mode 100644
index 0000000..e3eb201
--- /dev/null
+++ b/src/main/java/me/trouper/sentinel/server/gui/PaginatedGUI.java
@@ -0,0 +1,244 @@
+package me.trouper.sentinel.server.gui;
+
+import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
+import io.github.itzispyder.pdk.plugin.gui.CustomGui;
+import me.trouper.sentinel.Sentinel;
+import me.trouper.sentinel.server.Main;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public abstract class PaginatedGUI implements Main {
+
+ protected static final int ITEMS_PER_PAGE = 45;
+ protected static final Map currentPages = new HashMap<>();
+ protected static final Map> activeFilters = new HashMap<>();
+ protected static final Map chosenOperator = new HashMap<>();
+
+ protected abstract CustomGui backGUI();
+ protected boolean isAsynchronous() {
+ return false;
+ }
+
+
+ public CustomGui createGUI(Player p) {
+ ServerUtils.verbose("Creating GUI for player: %s", p.getName());
+ int page = currentPages.compute(p.getUniqueId(), (k, v) -> realizePage(p, v == null ? 0 : v));
+ return CustomGui.create()
+ .title(getTitle(p))
+ .size(54)
+ .onDefine(inv -> setupPage(p, inv, isAsynchronous()))
+ .defineMain(e -> handleMainClick(p, e))
+ .define(45, createNavigationItem("Previous", page - 1), e -> changePage(p, -1))
+ .define(49, createFilterItem(p), e -> openFilterMenu(p))
+ .define(53, createNavigationItem("Next", page + 1), e -> changePage(p, 1))
+ .build();
+ }
+
+ protected abstract String getTitle(Player p);
+
+ protected void setupPage(Player p, Inventory inv, boolean runAsynchronously) {
+ ServerUtils.verbose(1, "Setting up page for player: %s", p.getName());
+ int page = currentPages.compute(p.getUniqueId(), (k, v) -> realizePage(p, v == null ? 0 : v));
+ FilterOperator operator = chosenOperator.computeIfAbsent(p.getUniqueId(), v -> FilterOperator.AND);
+
+ inv.setItem(45, createNavigationItem("Previous", realizePage(p, page - 1)));
+ inv.setItem(49, createFilterItem(p));
+ inv.setItem(53, createNavigationItem("Next", realizePage(p, page + 1)));
+
+ for (int slot : new int[]{46, 47, 48, 50, 51, 52}) {
+ inv.setItem(slot, createPlaceholderItem(true));
+ }
+
+ Runnable task = ()->{
+ List filtered = filterEntries(p, operator);
+ int totalEntries = filtered.size();
+ int startIndex = page * ITEMS_PER_PAGE;
+ int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, totalEntries);
+ List pageEntries = filtered.subList(startIndex, endIndex);
+ int pageSize = pageEntries.size();
+
+ AtomicInteger remaining = new AtomicInteger(pageSize);
+
+ for (int i = 0; i < pageSize; i++) {
+ T entry = pageEntries.get(i);
+ ItemStack displayItem = createDisplayItem(entry);
+ int slot = i;
+
+ Bukkit.getScheduler().runTask(Sentinel.getInstance(), () -> {
+ inv.setItem(slot, displayItem);
+ if (runAsynchronously) p.playSound(p, Sound.UI_HUD_BUBBLE_POP, SoundCategory.MASTER,1,1.1F);
+ if (remaining.decrementAndGet() == 0) {
+ for (int bottomSlot : new int[]{46, 47, 48, 50, 51, 52}) {
+ inv.setItem(bottomSlot, createPlaceholderItem(false));
+ }
+ if (runAsynchronously) p.playSound(p,Sound.BLOCK_NOTE_BLOCK_CHIME, SoundCategory.MASTER,1,0.8F);
+ }
+ });
+ }
+
+ if (pageSize == 0) {
+ Bukkit.getScheduler().runTask(Sentinel.getInstance(), () -> {
+ for (int bottomSlot : new int[]{46, 47, 48, 50, 51, 52}) {
+ inv.setItem(bottomSlot, createPlaceholderItem(false));
+ }
+ if (runAsynchronously) p.playSound(p,Sound.BLOCK_NOTE_BLOCK_CHIME, SoundCategory.MASTER,1,0.8F);
+ });
+ }
+ };
+
+ if (runAsynchronously) Bukkit.getScheduler().runTaskAsynchronously(Sentinel.getInstance(), task);
+ else task.run();
+ }
+
+ protected abstract void handleMainClick(Player p, InventoryClickEvent e);
+
+ protected abstract ItemStack createDisplayItem(T item);
+
+ protected void openFilterMenu(Player p) {
+ ServerUtils.verbose(1,"Creating filter menu for %s", p);
+ Set filters = activeFilters.computeIfAbsent(p.getUniqueId(), k -> new HashSet<>());
+
+ CustomGui.GuiBuilder filterGui = CustomGui.create()
+ .title(OldTXT.color("&6&lFilters"))
+ .size(27)
+ .defineMain(e -> e.setCancelled(true))
+ .define(26, Items.BACK, e -> {
+ p.playSound(p.getLocation(), Sound.ITEM_BOOK_PAGE_TURN, 1, 0.8F);
+ p.openInventory(createGUI(p).getInventory());
+ });
+
+ addFilterItems(filterGui, p, filters);
+
+ p.openInventory(filterGui.build().getInventory());
+ p.playSound(p,Sound.BLOCK_NOTE_BLOCK_BELL, SoundCategory.MASTER,1,0.8F);
+ }
+
+ protected abstract void addFilterItems(CustomGui.GuiBuilder filterGui, Player p, Set filters);
+
+ protected void toggleFilter(Player p, String filter) {
+ Set filters = activeFilters.computeIfAbsent(p.getUniqueId(), k -> new HashSet<>());
+ ServerUtils.verbose("%s is now toggling the %s filter. Current %s", p, filter, filters);
+ if (filters.contains(filter)) {
+ filters.remove(filter);
+ p.playSound(p,Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,0.8F);
+ } else {
+ filters.add(filter);
+ p.playSound(p,Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1F);
+ }
+ ServerUtils.verbose("Current filters for %s: %s", p, filters);
+
+ openFilterMenu(p);
+ }
+
+ protected int getFilteredCount(Player p) {
+ return filterEntries(p,chosenOperator.getOrDefault(p.getUniqueId(),FilterOperator.AND)).size();
+ }
+
+ private int getFilterCount(Player p) {
+ return activeFilters.get(p.getUniqueId()).size();
+ }
+
+
+ protected void changePage(Player p, int direction) {
+ int current = currentPages.getOrDefault(p.getUniqueId(), 0);
+ if (current + direction < 0) {
+ p.playSound(p, Sound.ITEM_BOOK_PAGE_TURN, SoundCategory.MASTER,1,0.8F);
+ p.openInventory(backGUI().getInventory());
+ return;
+ }
+ int newPage = realizePage(p, current + direction);
+ currentPages.put(p.getUniqueId(), newPage);
+ p.openInventory(createGUI(p).getInventory());
+ }
+
+ protected int realizePage(Player p, int requested) {
+ int validRequested = Math.max(0, requested);
+ int totalEntries = filterEntries(p, chosenOperator.computeIfAbsent(p.getUniqueId(), v -> FilterOperator.AND)).size();
+ int maxPages = Math.max(0, Math.ceilDiv(totalEntries, ITEMS_PER_PAGE) - 1);
+ return Math.min(validRequested, maxPages);
+ }
+
+ private ItemStack createNavigationItem(String direction, int pageTo) {
+ if (pageTo < 0) {
+ return Items.BACK;
+ }
+ return new ItemBuilder()
+ .material(Material.ARROW)
+ .name(OldTXT.color("&b" + direction + "&7 Page"))
+ .lore(OldTXT.color("&7 > &b" + pageTo))
+ .build();
+ }
+
+ private ItemStack createPlaceholderItem(boolean isRed) {
+ Material material = isRed ? Material.RED_STAINED_GLASS_PANE : Material.LIME_STAINED_GLASS_PANE;
+ String name = isRed ? "&cComputing Entries..." : "&aAll Entries Loaded.";
+ return new ItemBuilder()
+ .material(material)
+ .name(OldTXT.color(name))
+ .build();
+ }
+
+ private ItemStack createFilterItem(Player p) {
+ List operatorList = new ArrayList<>();
+ FilterOperator chosen = chosenOperator.computeIfAbsent(p.getUniqueId(), v -> FilterOperator.AND);
+ for (FilterOperator value : FilterOperator.values()) {
+ if (value.equals(chosen)) operatorList.add(OldTXT.color("&b&n" + value.name()));
+ else operatorList.add(OldTXT.color("&b" + value.name()));
+ }
+ return new ItemBuilder()
+ .material(Material.HOPPER)
+ .name(OldTXT.color("&6&lFilters"))
+ .lore(OldTXT.color("&7Filters Selected: &e" + getFilterCount(p)))
+ .lore(OldTXT.color("&7Shift-Click to cycle filter operator."))
+ .lore(OldTXT.color("&7Operator: "))
+ .lore(operatorList)
+ .build();
+ }
+
+ protected abstract List filterEntries(Player p, FilterOperator operator);
+
+ public enum FilterOperator {
+ AND, // All conditions must be met
+ OR, // At least one condition must be met
+ NAND, // At least one condition must NOT be met
+ XOR; // Exactly one condition must be met
+
+ public boolean apply(boolean currentValue, boolean newCondition) {
+ return switch (this) {
+ case AND -> currentValue & newCondition;
+ case OR -> currentValue | newCondition;
+ case NAND -> !(currentValue & newCondition);
+ case XOR -> currentValue ^ newCondition;
+ };
+ }
+ }
+
+ protected ItemStack createFilterToggleItem(String name, Material mat, boolean active) {
+ return new ItemBuilder()
+ .material(mat)
+ .name(OldTXT.color((active ? "&a" : "&c") + name))
+ .lore(OldTXT.color("&7Click to " + (active ? "disable" : "enable")))
+ .build();
+ }
+
+ protected ItemStack createFilterToggleItemValue(String name, Material mat, boolean active, String value) {
+ return new ItemBuilder()
+ .material(mat)
+ .name(OldTXT.color((active ? "&a" : "&c") + name))
+ .lore(OldTXT.color("&7Value&f: &b" + value))
+ .lore(OldTXT.color("&7Left Click to " + (active ? "disable" : "enable")))
+ .lore(OldTXT.color("&7Right Click to set value."))
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/AntiNukeGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/AntiNukeGUI.java
index 9182050..d7fc5a6 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/config/AntiNukeGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/config/AntiNukeGUI.java
@@ -2,12 +2,29 @@ package me.trouper.sentinel.server.gui.config;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import me.trouper.sentinel.server.gui.ConfigGUI;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockBreak;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockEdit;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockPlace;
+import me.trouper.sentinel.server.events.violations.blocks.command.CommandBlockUse;
+import me.trouper.sentinel.server.events.violations.blocks.jigsaw.JigsawBlockBreak;
+import me.trouper.sentinel.server.events.violations.blocks.jigsaw.JigsawBlockPlace;
+import me.trouper.sentinel.server.events.violations.blocks.jigsaw.JigsawBlockUse;
+import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockBreak;
+import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockPlace;
+import me.trouper.sentinel.server.events.violations.blocks.structure.StructureBlockUse;
+import me.trouper.sentinel.server.events.violations.command.DangerousCommand;
+import me.trouper.sentinel.server.events.violations.command.LoggedCommand;
+import me.trouper.sentinel.server.events.violations.command.SpecificCommand;
+import me.trouper.sentinel.server.events.violations.entities.CommandMinecartBreak;
+import me.trouper.sentinel.server.events.violations.entities.CommandMinecartEdit;
+import me.trouper.sentinel.server.events.violations.entities.CommandMinecartPlace;
+import me.trouper.sentinel.server.events.violations.entities.CommandMinecartUse;
+import me.trouper.sentinel.server.events.violations.players.CreativeHotbar;
+import me.trouper.sentinel.server.events.violations.whitelist.CommandBlockExecute;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.nuke.CommandGUI;
-import me.trouper.sentinel.server.gui.config.nuke.checks.*;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.utils.ServerUtils;
+import me.trouper.sentinel.utils.OldTXT;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
@@ -16,37 +33,51 @@ import org.bukkit.inventory.ItemStack;
public class AntiNukeGUI {
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Choose a check"))
- .size(54)
+ .title(OldTXT.color("&6&lSentinel &8»&0 Choose a check"))
+ .size(9*5)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
- .define(53, Items.BACK, e->{
+ .define((9*5)-1, Items.BACK, e->{
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
})
- .define(10,COMMAND_BLOCK_WHITELIST, e->{
- e.getWhoClicked().openInventory(new CBExecuteGUI().home.getInventory());
- })
- .define(12,COMMAND_BLOCK_PLACE, e->{
- e.getWhoClicked().openInventory(new CBPlaceGUI().home.getInventory());
- })
- .define(14,COMMAND_BLOCK_USE, e->{
- e.getWhoClicked().openInventory(new CBUseGUI().home.getInventory());
- })
- .define(16,COMMAND_BLOCK_EDITING, e->{
- e.getWhoClicked().openInventory(new CBEditGUI().home.getInventory());
- })
- .define(37,COMMAND_BLOCK_MINECART_USE, e->{
- e.getWhoClicked().openInventory(new CBMCUseGUI().home.getInventory());
- })
- .define(39,COMMAND_BLOCK_MINECART_PLACE, e->{
- e.getWhoClicked().openInventory(new CBMCPlaceGUI().home.getInventory());
- })
- .define(41,COMMAND_EXECUTE, e->{
- e.getWhoClicked().openInventory(new CommandGUI().home.getInventory());
- })
- .define(43,HOTBAR_ACTION, e->{
- e.getWhoClicked().openInventory(new HotbarActionGUI().home.getInventory());
- })
+ .define(10,getCheckItem(Material.COMMAND_BLOCK,"Command Block Break"),
+ e->e.getWhoClicked().openInventory(new CommandBlockBreak().getConfigGui().getInventory()))
+ .define(11,getCheckItem(Material.COMMAND_BLOCK,"Command Block Edit"),
+ e->e.getWhoClicked().openInventory(new CommandBlockEdit().getConfigGui().getInventory()))
+ .define(12,getCheckItem(Material.COMMAND_BLOCK,"Command Block Place"),
+ e->e.getWhoClicked().openInventory(new CommandBlockPlace().getConfigGui().getInventory()))
+ .define(13,getCheckItem(Material.COMMAND_BLOCK,"Command Block Use"),
+ e->e.getWhoClicked().openInventory(new CommandBlockUse().getConfigGui().getInventory()))
+ .define(14,getCheckItem(Material.JIGSAW,"Jigsaw Block Break"),
+ e->e.getWhoClicked().openInventory(new JigsawBlockBreak().getConfigGui().getInventory()))
+ .define(15,getCheckItem(Material.JIGSAW,"Jigsaw Block Place"),
+ e->e.getWhoClicked().openInventory(new JigsawBlockPlace().getConfigGui().getInventory()))
+ .define(16,getCheckItem(Material.JIGSAW,"Jigsaw Block Use"),
+ e->e.getWhoClicked().openInventory(new JigsawBlockUse().getConfigGui().getInventory()))
+ .define(19,getCheckItem(Material.STRUCTURE_BLOCK,"Structure Block Break"),
+ e->e.getWhoClicked().openInventory(new StructureBlockBreak().getConfigGui().getInventory()))
+ .define(20,getCheckItem(Material.STRUCTURE_BLOCK,"Structure Block Place"),
+ e->e.getWhoClicked().openInventory(new StructureBlockPlace().getConfigGui().getInventory()))
+ .define(21,getCheckItem(Material.STRUCTURE_BLOCK,"Structure Block Use"),
+ e->e.getWhoClicked().openInventory(new StructureBlockUse().getConfigGui().getInventory()))
+ .define(22,getCheckItem(Material.TNT,"Dangerous Commands"),
+ e->e.getWhoClicked().openInventory(new DangerousCommand().getConfigGui().getInventory()))
+ .define(23,getCheckItem(Material.ENDER_PEARL,"Specific Commands"),
+ e->e.getWhoClicked().openInventory(new SpecificCommand().getConfigGui().getInventory()))
+ .define(24,getCheckItem(Material.SPYGLASS,"Logged Commands"),
+ e->e.getWhoClicked().openInventory(new LoggedCommand().getConfigGui().getInventory()))
+ .define(25,getCheckItem(Material.COMMAND_BLOCK_MINECART,"Command Minecart Break"),
+ e->e.getWhoClicked().openInventory(new CommandMinecartBreak().getConfigGui().getInventory()))
+ .define(29,getCheckItem(Material.COMMAND_BLOCK_MINECART,"Command Minecart Place"),
+ e->e.getWhoClicked().openInventory(new CommandMinecartPlace().getConfigGui().getInventory()))
+ .define(30,getCheckItem(Material.COMMAND_BLOCK_MINECART,"Command Minecart Use"),
+ e->e.getWhoClicked().openInventory(new CommandMinecartUse().getConfigGui().getInventory()))
+ .define(31,getCheckItem(Material.COMMAND_BLOCK_MINECART,"Command Minecart Edit"),
+ e->e.getWhoClicked().openInventory(new CommandMinecartEdit().getConfigGui().getInventory()))
+ .define(32,getCheckItem(Material.DIAMOND_SWORD,"NBT Item Pull"),
+ e->e.getWhoClicked().openInventory(new CreativeHotbar().getConfigGui().getInventory()))
+ .define(33,getCheckItem(Material.EMERALD,"Command Block Whitelist"),
+ e->e.getWhoClicked().openInventory(new CommandBlockExecute().getConfigGui().getInventory()))
.build();
private void mainClick(InventoryClickEvent e) {
@@ -55,59 +86,17 @@ public class AntiNukeGUI {
}
private void blankPage(Inventory inv) {
+ ServerUtils.verbose("Making anti-nuke page");
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
}
- private static final ItemStack COMMAND_BLOCK_EDITING = ItemBuilder.create()
- .material(Material.DEBUG_STICK)
- .name(Text.color("&bCommand Block Editing"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
- private static final ItemStack COMMAND_BLOCK_WHITELIST = ItemBuilder.create()
- .material(Material.EMERALD)
- .name(Text.color("&bCommand Block Whitelist"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
- private static final ItemStack COMMAND_BLOCK_MINECART_PLACE = ItemBuilder.create()
- .material(Material.RAIL)
- .name(Text.color("&bCommand Block Minecart Placing"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
- private static final ItemStack COMMAND_BLOCK_MINECART_USE = ItemBuilder.create()
- .material(Material.COMMAND_BLOCK_MINECART)
- .name(Text.color("&bCommand Block Minecart Using"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
- private static final ItemStack COMMAND_BLOCK_PLACE = ItemBuilder.create()
- .material(Material.CHAIN_COMMAND_BLOCK)
- .name(Text.color("&bCommand Block Placing"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
- private static final ItemStack COMMAND_BLOCK_USE = ItemBuilder.create()
- .material(Material.REPEATING_COMMAND_BLOCK)
- .name(Text.color("&bCommand Block Using"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
- private static final ItemStack COMMAND_EXECUTE = ItemBuilder.create()
- .material(Material.SPYGLASS)
- .name(Text.color("&bCommand Execution"))
- .lore(Text.color("&8&l➥&7 Dangerous Commands"))
- .lore(Text.color("&8&l➥&7 Logged Commands"))
- .lore(Text.color("&8&l➥&7 Specific Commands"))
- .build();
-
- private static final ItemStack HOTBAR_ACTION = ItemBuilder.create()
- .material(Material.DIAMOND_SWORD)
- .name(Text.color("&bNBT Items"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
+ private static ItemStack getCheckItem(Material item, String name) {
+ return ItemBuilder.create()
+ .material(item)
+ .name(OldTXT.color("&b" + name))
+ .lore(OldTXT.color("&8&l➥&7 Modify this check"))
+ .build();
+ }
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/ConfigGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/ConfigGUI.java
similarity index 57%
rename from src/main/java/me/trouper/sentinel/server/gui/ConfigGUI.java
rename to src/main/java/me/trouper/sentinel/server/gui/config/ConfigGUI.java
index e2ea3ba..361e55e 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/ConfigGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/config/ConfigGUI.java
@@ -1,26 +1,32 @@
-package me.trouper.sentinel.server.gui;
+package me.trouper.sentinel.server.gui.config;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.server.gui.config.ChatGUI;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.server.gui.Items;
+import me.trouper.sentinel.server.gui.MainGUI;
+import me.trouper.sentinel.server.gui.config.chat.ChatGUI;
+import me.trouper.sentinel.utils.OldTXT;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
public class ConfigGUI {
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Config Home"))
+ .title(OldTXT.color("&6&lSentinel &8»&0 Config Home"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
- .define(12, Items.ANTI_NUKE_CONFIG,e->{
+ .define(12, Items.ANTI_NUKE_CONFIG, e->{
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1F);
e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
})
.define(14,Items.CHAT_CONFIG,e->{
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1F);
e.getWhoClicked().openInventory(new ChatGUI().home.getInventory());
})
.define(26,Items.BACK,e->{
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.ITEM_BOOK_PAGE_TURN, SoundCategory.MASTER,1,1.1F);
e.getWhoClicked().openInventory(new MainGUI().home.getInventory());
})
.build();
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/ChatGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/chat/ChatGUI.java
similarity index 61%
rename from src/main/java/me/trouper/sentinel/server/gui/config/ChatGUI.java
rename to src/main/java/me/trouper/sentinel/server/gui/config/chat/ChatGUI.java
index e745281..cc65af1 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/config/ChatGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/config/chat/ChatGUI.java
@@ -1,17 +1,14 @@
-package me.trouper.sentinel.server.gui.config;
+package me.trouper.sentinel.server.gui.config.chat;
import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import me.trouper.sentinel.server.gui.ConfigGUI;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.chat.ProfanityFilterGUI;
-import me.trouper.sentinel.server.gui.config.chat.SpamFilterGUI;
-import me.trouper.sentinel.server.gui.config.chat.UnicodeFilterGUI;
-import me.trouper.sentinel.server.gui.config.chat.UrlFilterGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.server.gui.config.ConfigGUI;
+import me.trouper.sentinel.utils.OldTXT;
import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
@@ -19,25 +16,28 @@ import org.bukkit.inventory.ItemStack;
public class ChatGUI {
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Edit a Filter"))
+ .title(OldTXT.color("&6&lSentinel &8»&0 Edit a Filter"))
.size(27)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
.define(26,Items.BACK,e->{
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.ITEM_BOOK_PAGE_TURN, SoundCategory.MASTER,1,1.3F);
e.getWhoClicked().openInventory(new ConfigGUI().home.getInventory());
})
.define(16,PROFANITY_FILTER,e->{
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1.4F);
e.getWhoClicked().openInventory(new ProfanityFilterGUI().home.getInventory());
})
.define(14,SPAM_FILTER,e->{
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1.4F);
e.getWhoClicked().openInventory(new SpamFilterGUI().home.getInventory());
})
.define(12,URL_FILTER,e->{
- ServerUtils.verbose("URL Filter Launching");
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1.4F);
e.getWhoClicked().openInventory(new UrlFilterGUI().home.getInventory());
})
.define(10,UNICODE_FILTER,e->{
- ServerUtils.verbose("Unicode Filter Launching");
+ ((Player) e.getWhoClicked()).playSound(e.getWhoClicked(), Sound.UI_BUTTON_CLICK, SoundCategory.MASTER,1,1.4F);
e.getWhoClicked().openInventory(new UnicodeFilterGUI().home.getInventory());
})
.build();
@@ -55,25 +55,25 @@ public class ChatGUI {
private static final ItemStack PROFANITY_FILTER = ItemBuilder.create()
.material(Material.COAL)
- .name(Text.color("&bProfanity Filter"))
- .lore(Text.color("&8&l➥&7 Edit Score Settings"))
+ .name(OldTXT.color("&bProfanity Filter"))
+ .lore(OldTXT.color("&8&l➥&7 Edit Score Settings"))
.build();
private static final ItemStack SPAM_FILTER = ItemBuilder.create()
.material(Material.PORKCHOP)
- .name(Text.color("&bSpam Filter"))
- .lore(Text.color("&8&l➥&7 Edit Heat Settings"))
+ .name(OldTXT.color("&bSpam Filter"))
+ .lore(OldTXT.color("&8&l➥&7 Edit Heat Settings"))
.build();
private static final ItemStack UNICODE_FILTER = ItemBuilder.create()
.material(Material.PAPER)
- .name(Text.color("&bUnicode Filter"))
- .lore(Text.color("&8&l➥&7 Edit regex"))
+ .name(OldTXT.color("&bUnicode Filter"))
+ .lore(OldTXT.color("&8&l➥&7 Edit regex"))
.build();
private static final ItemStack URL_FILTER = ItemBuilder.create()
.material(Material.CHAIN)
- .name(Text.color("&bURL Filter"))
- .lore(Text.color("&8&l➥&7 Edit regex"))
+ .name(OldTXT.color("&bURL Filter"))
+ .lore(OldTXT.color("&8&l➥&7 Edit regex"))
.build();
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.java
index e82f10f..672df82 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/config/chat/ProfanityFilterGUI.java
@@ -4,28 +4,26 @@ import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.MainConfig;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.ChatGUI;
import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.utils.OldTXT;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.function.BiConsumer;
-public class ProfanityFilterGUI {
+public class ProfanityFilterGUI implements Main {
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Editing Profanity Filter"))
+ .title(OldTXT.color("&6&lSentinel &8»&0 Editing Profanity Filter"))
.size(54)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
@@ -44,7 +42,7 @@ public class ProfanityFilterGUI {
}
ServerUtils.verbose("ProfanityFilterGUI#blankPage Page now blank");
ItemStack top = Items.RED;
- if (Sentinel.mainConfig.chat.profanityFilter.enabled) {
+ if (main.dir().io.mainConfig.chat.profanityFilter.enabled) {
top = Items.GREEN;
}
@@ -54,18 +52,18 @@ public class ProfanityFilterGUI {
ServerUtils.verbose("ProfanityFilterGUI#blankPage Adding GUI Items");
inv.setItem(53,Items.BACK);
- inv.setItem(3,Items.booleanItem(Sentinel.mainConfig.chat.profanityFilter.enabled, Items.configItem("Profanity Filter Toggle",Material.CLOCK,"Enable or Disable the whole Profanity filter")));
- inv.setItem(5,Items.booleanItem(Sentinel.mainConfig.chat.profanityFilter.silent, Items.configItem("Silent Mode",Material.FEATHER,"Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
- inv.setItem(10,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.lowScore, Items.configItem("Low Score Gain", Material.WHITE_WOOL, "How much score will be added if the player \ndid not attempt to bypass the filter.")));
- inv.setItem(19,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.mediumLowScore, Items.configItem("Medium-Low Score Gain", Material.LIME_WOOL, "How much score will be added if the player \nused l33t speak to attempt a bypass")));
- inv.setItem(28,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.mediumScore, Items.configItem("Medium Score Gain", Material.YELLOW_WOOL, "How much score will be added if the player \nused sp/ecia|l characters to attempt a bypass")));
- inv.setItem(37,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.mediumHighScore, Items.configItem("Medium-High Score Gain", Material.ORANGE_WOOL, "How much score will be added if the player \nused reeeeeeepeating letters to attempt a bypass")));
- inv.setItem(46,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.highScore, Items.configItem("High Score Gain", Material.RED_WOOL, "How much score will be added if the player \nused pun. ctua, tion or spaces to attempt a bypass")));
- inv.setItem(29,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.regexScore, Items.configItem("Regex Score Gain", Material.DISPENSER, "How much score will be added if the player \nmatched the regex setting throughout \nthe processing of the message")));
- inv.setItem(22,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.punishScore, Items.configItem("Punish Score", Material.IRON_BARS, "If the player's score is above this \nthe punishment commands will be ran.")));
- inv.setItem(33,Items.intItem(Sentinel.mainConfig.chat.profanityFilter.scoreDecay, Items.configItem("Score Decay", Material.DEAD_BUBBLE_CORAL_BLOCK, "How much score players will loose each minute.")));
- inv.setItem(31,Items.stringListItem(Sentinel.mainConfig.chat.profanityFilter.profanityPunishCommands,Material.WOODEN_AXE, "Default Punishment Commands", "%player% will be replaced with the offender's name"));
- inv.setItem(40,Items.stringListItem(Sentinel.mainConfig.chat.profanityFilter.strictPunishCommands,Material.DIAMOND_AXE, "Strict Punishment Commands", "If words from the strict words list are flagged, \nthis list will be ran instead \n%player% will be replaced with the offender's name"));
+ inv.setItem(3,Items.booleanItem(main.dir().io.mainConfig.chat.profanityFilter.enabled, Items.configItem("Profanity Filter Toggle",Material.CLOCK,"Enable or Disable the whole Profanity filter")));
+ inv.setItem(5,Items.booleanItem(main.dir().io.mainConfig.chat.profanityFilter.silent, Items.configItem("Silent Mode",Material.FEATHER,"Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
+ inv.setItem(10,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.lowScore, Items.configItem("Low Score Gain", Material.WHITE_WOOL, "How much score will be added if the player \ndid not attempt to bypass the filter.")));
+ inv.setItem(19,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.mediumLowScore, Items.configItem("Medium-Low Score Gain", Material.LIME_WOOL, "How much score will be added if the player \nused l33t speak to attempt a bypass")));
+ inv.setItem(28,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.mediumScore, Items.configItem("Medium Score Gain", Material.YELLOW_WOOL, "How much score will be added if the player \nused sp/ecia|l characters to attempt a bypass")));
+ inv.setItem(37,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.mediumHighScore, Items.configItem("Medium-High Score Gain", Material.ORANGE_WOOL, "How much score will be added if the player \nused reeeeeeepeating letters to attempt a bypass")));
+ inv.setItem(46,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.highScore, Items.configItem("High Score Gain", Material.RED_WOOL, "How much score will be added if the player \nused pun. ctua, tion or spaces to attempt a bypass")));
+ inv.setItem(29,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.regexScore, Items.configItem("Regex Score Gain", Material.DISPENSER, "How much score will be added if the player \nmatched the regex setting throughout \nthe processing of the message")));
+ inv.setItem(22,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.punishScore, Items.configItem("Punish Score", Material.IRON_BARS, "If the player's score is above this \nthe punishment commands will be ran.")));
+ inv.setItem(33,Items.intItem(main.dir().io.mainConfig.chat.profanityFilter.scoreDecay, Items.configItem("Score Decay", Material.DEAD_BUBBLE_CORAL_BLOCK, "How much score players will loose each minute.")));
+ inv.setItem(31,Items.stringListItem(main.dir().io.mainConfig.chat.profanityFilter.profanityPunishCommands,Material.WOODEN_AXE, "Default Punishment Commands", "%player% will be replaced with the offender's name"));
+ inv.setItem(40,Items.stringListItem(main.dir().io.mainConfig.chat.profanityFilter.strictPunishCommands,Material.DIAMOND_AXE, "Strict Punishment Commands", "If words from the strict words list are flagged, \nthis list will be ran instead \n%player% will be replaced with the offender's name"));
} catch (Exception e) {
e.printStackTrace();
}
@@ -76,35 +74,35 @@ public class ProfanityFilterGUI {
if (!MainGUI.verify((Player) e.getWhoClicked())) return;
switch (e.getSlot()) {
case 3 -> {
- Sentinel.mainConfig.chat.profanityFilter.enabled = !Sentinel.mainConfig.chat.profanityFilter.enabled;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.profanityFilter.enabled = !main.dir().io.mainConfig.chat.profanityFilter.enabled;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
case 5 -> {
- Sentinel.mainConfig.chat.profanityFilter.silent = !Sentinel.mainConfig.chat.profanityFilter.silent;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.profanityFilter.silent = !main.dir().io.mainConfig.chat.profanityFilter.silent;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
- case 10 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.lowScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.lowScore);
- case 19 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.mediumLowScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.mediumLowScore);
- case 28 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.mediumScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.mediumScore);
- case 37 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.mediumHighScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.mediumHighScore);
- case 46 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.highScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.highScore);
- case 29 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.regexScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.regexScore);
- case 22 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.punishScore = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.punishScore);
- case 33 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.scoreDecay = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.profanityFilter.scoreDecay);
+ case 10 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.lowScore = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.lowScore);
+ case 19 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.mediumLowScore = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.mediumLowScore);
+ case 28 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.mediumScore = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.mediumScore);
+ case 37 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.mediumHighScore = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.mediumHighScore);
+ case 46 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.highScore = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.highScore);
+ case 29 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.regexScore = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.regexScore);
+ case 22 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.punishScore = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.punishScore);
+ case 33 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.profanityFilter.scoreDecay = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.profanityFilter.scoreDecay);
case 31 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.profanityFilter.profanityPunishCommands.add(args.getAll().toString());
- },"" + Sentinel.mainConfig.chat.profanityFilter.profanityPunishCommands);
+ },"" + main.dir().io.mainConfig.chat.profanityFilter.profanityPunishCommands);
return;
}
- Sentinel.mainConfig.chat.profanityFilter.profanityPunishCommands.clear();
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.profanityFilter.profanityPunishCommands.clear();
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
@@ -112,17 +110,17 @@ public class ProfanityFilterGUI {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.profanityFilter.strictPunishCommands.add(args.getAll().toString());
- },"" + Sentinel.mainConfig.chat.profanityFilter.strictPunishCommands);
+ },"" + main.dir().io.mainConfig.chat.profanityFilter.strictPunishCommands);
return;
}
- Sentinel.mainConfig.chat.profanityFilter.strictPunishCommands.clear();
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.profanityFilter.strictPunishCommands.clear();
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
}
}
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.mainConfig);
+ public static ConfigUpdater updater = new ConfigUpdater<>(main.dir().io.mainConfig);
private void queuePlayer(Player player, BiConsumer action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
@@ -133,9 +131,9 @@ public class ProfanityFilterGUI {
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
+ successAny(player,"Value updated successfully");
player.openInventory(home.getInventory());
});
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
+ message(player,Component.text("Enter the new value in chat. The value is currently set to {0}. (Click to insert)").clickEvent(ClickEvent.suggestCommand(currentValue)),Component.text(currentValue));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.java
index bcccd27..da8ce0a 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/config/chat/SpamFilterGUI.java
@@ -4,29 +4,26 @@ import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.MainConfig;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.ChatGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.utils.OldTXT;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.function.BiConsumer;
-public class SpamFilterGUI {
+public class SpamFilterGUI implements Main {
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Editing Spam Filter"))
+ .title(OldTXT.color("&6&lSentinel &8»&0 Editing Spam Filter"))
.size(54)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
@@ -34,16 +31,14 @@ public class SpamFilterGUI {
e.getWhoClicked().openInventory(new ChatGUI().home.getInventory());
})
.build();
-
-
-
+
private void blankPage(Inventory inv) {
for (int i = 0; i < inv.getSize(); i++) {
inv.setItem(i,Items.BLANK);
}
ItemStack top = Items.RED;
- if (Sentinel.mainConfig.chat.spamFilter.enabled) {
+ if (main.dir().io.mainConfig.chat.spamFilter.enabled) {
top = Items.GREEN;
}
@@ -52,18 +47,18 @@ public class SpamFilterGUI {
}
inv.setItem(53,Items.BACK);
- inv.setItem(3,Items.booleanItem(Sentinel.mainConfig.chat.spamFilter.enabled, Items.configItem("Spam Filter Toggle", Material.CLOCK, "Enable or disable the whole Spam Filter")));
- inv.setItem(5,Items.booleanItem(Sentinel.mainConfig.chat.spamFilter.silent, Items.configItem("Silent Toggle", Material.FEATHER, "Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
- inv.setItem(10,Items.intItem(Sentinel.mainConfig.chat.spamFilter.defaultGain, Items.configItem("Default Heat Gain", Material.BUCKET, "How much heat will be added to each message.")));
- inv.setItem(19,Items.intItem(Sentinel.mainConfig.chat.spamFilter.lowGain, Items.configItem("Low Heat Gain", Material.WATER_BUCKET, "Extra heat to be added if the \nmessage is greater than 25% similar \nto their previous message.")));
- inv.setItem(28,Items.intItem(Sentinel.mainConfig.chat.spamFilter.mediumGain, Items.configItem("Medium Heat Gain", Material.COD_BUCKET, "Extra heat to be added if the \nmessage is greater than 50% similar \nto their previous message.")));
- inv.setItem(37,Items.intItem(Sentinel.mainConfig.chat.spamFilter.highGain, Items.configItem("High Heat Gain", Material.PUFFERFISH_BUCKET, "Extra heat to be added if the \nmessage is greater than 90% similar \nto their previous message.")));
- inv.setItem(46,Items.intItem(Sentinel.mainConfig.chat.spamFilter.blockHeat, Items.configItem("Block Heat", Material.BARRIER, "If the player's heat is above this \nthen their message will be blocked and \nflagged as spam.")));
- inv.setItem(21,Items.intItem(Sentinel.mainConfig.chat.spamFilter.blockSimilarity, Items.configItem("Block Similarity", Material.BARRIER, "If the message's similarity is above \nthis, it will get automatically blocked \nand flagged as spam.")));
- inv.setItem(23,Items.intItem(Sentinel.mainConfig.chat.spamFilter.punishHeat, Items.configItem("Punish Heat", Material.IRON_BARS, "If the player's heat is above this \nthe punishment commands will be ran.")));
- inv.setItem(25,Items.intItem(Sentinel.mainConfig.chat.spamFilter.heatDecay, Items.configItem("Heat Decay", Material.DEAD_BUBBLE_CORAL_BLOCK, "How much heat players will loose each second.")));
- inv.setItem(32,Items.stringListItem(Sentinel.mainConfig.chat.spamFilter.punishCommands,Material.DIAMOND_AXE, "Punishment Commands", "%player% will be replaced with the offender's name"));
- inv.setItem(34,Items.stringListItem(Sentinel.mainConfig.chat.spamFilter.whitelist,Material.PAPER, "Message Whitelist", "Messages which will be ignored by the spam filter"));
+ inv.setItem(3,Items.booleanItem(main.dir().io.mainConfig.chat.spamFilter.enabled, Items.configItem("Spam Filter Toggle", Material.CLOCK, "Enable or disable the whole Spam Filter")));
+ inv.setItem(5,Items.booleanItem(main.dir().io.mainConfig.chat.spamFilter.silent, Items.configItem("Silent Toggle", Material.FEATHER, "Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
+ inv.setItem(10,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.defaultGain, Items.configItem("Default Heat Gain", Material.BUCKET, "How much heat will be added to each message.")));
+ inv.setItem(19,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.lowGain, Items.configItem("Low Heat Gain", Material.WATER_BUCKET, "Extra heat to be added if the \nmessage is greater than 25% similar \nto their previous message.")));
+ inv.setItem(28,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.mediumGain, Items.configItem("Medium Heat Gain", Material.COD_BUCKET, "Extra heat to be added if the \nmessage is greater than 50% similar \nto their previous message.")));
+ inv.setItem(37,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.highGain, Items.configItem("High Heat Gain", Material.PUFFERFISH_BUCKET, "Extra heat to be added if the \nmessage is greater than 90% similar \nto their previous message.")));
+ inv.setItem(46,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.blockHeat, Items.configItem("Block Heat", Material.BARRIER, "If the player's heat is above this \nthen their message will be blocked and \nflagged as spam.")));
+ inv.setItem(21,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.blockSimilarity, Items.configItem("Block Similarity", Material.BARRIER, "If the message's similarity is above \nthis, it will get automatically blocked \nand flagged as spam.")));
+ inv.setItem(23,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.punishHeat, Items.configItem("Punish Heat", Material.IRON_BARS, "If the player's heat is above this \nthe punishment commands will be ran.")));
+ inv.setItem(25,Items.intItem(main.dir().io.mainConfig.chat.spamFilter.heatDecay, Items.configItem("Heat Decay", Material.DEAD_BUBBLE_CORAL_BLOCK, "How much heat players will loose each second.")));
+ inv.setItem(32,Items.stringListItem(main.dir().io.mainConfig.chat.spamFilter.punishCommands,Material.DIAMOND_AXE, "Punishment Commands", "%player% will be replaced with the offender's name"));
+ inv.setItem(34,Items.stringListItem(main.dir().io.mainConfig.chat.spamFilter.whitelist,Material.PAPER, "Message Whitelist", "Messages which will be ignored by the spam filter"));
}
private void mainClick(InventoryClickEvent e) {
@@ -73,40 +68,40 @@ public class SpamFilterGUI {
switch (e.getSlot()) {
case 3 -> {
- Sentinel.mainConfig.chat.spamFilter.enabled = !Sentinel.mainConfig.chat.spamFilter.enabled;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.spamFilter.enabled = !main.dir().io.mainConfig.chat.spamFilter.enabled;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
case 5 -> {
- Sentinel.mainConfig.chat.spamFilter.silent = !Sentinel.mainConfig.chat.spamFilter.silent;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.spamFilter.silent = !main.dir().io.mainConfig.chat.spamFilter.silent;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
- case 10 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.defaultGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.defaultGain);
- case 19 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.lowGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.lowGain);
- case 28 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.mediumGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.mediumGain);
- case 37 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.highGain = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.highGain);
- case 46 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.blockHeat = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.blockHeat);
- case 21 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.blockSimilarity = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.blockSimilarity);
- case 23 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.punishHeat = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.punishHeat);
- case 25 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.heatDecay = args.getAll().toInt(),"" + Sentinel.mainConfig.chat.spamFilter.heatDecay);
+ case 10 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.defaultGain = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.defaultGain);
+ case 19 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.lowGain = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.lowGain);
+ case 28 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.mediumGain = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.mediumGain);
+ case 37 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.highGain = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.highGain);
+ case 46 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.blockHeat = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.blockHeat);
+ case 21 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.blockSimilarity = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.blockSimilarity);
+ case 23 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.punishHeat = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.punishHeat);
+ case 25 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.spamFilter.heatDecay = args.getAll().toInt(),"" + main.dir().io.mainConfig.chat.spamFilter.heatDecay);
case 32 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.spamFilter.punishCommands.add(args.getAll().toString());
- },"" + Sentinel.mainConfig.chat.spamFilter.punishCommands);
+ },"" + main.dir().io.mainConfig.chat.spamFilter.punishCommands);
return;
}
- Sentinel.mainConfig.chat.spamFilter.punishCommands.clear();
+ main.dir().io.mainConfig.chat.spamFilter.punishCommands.clear();
blankPage(e.getInventory());
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.save();
}
}
}
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.mainConfig);
+ public static ConfigUpdater updater = new ConfigUpdater<>(main.dir().io.mainConfig);
private void queuePlayer(Player player, BiConsumer action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
@@ -117,9 +112,9 @@ public class SpamFilterGUI {
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
+ messageAny(player,"Value updated successfully");
player.openInventory(home.getInventory());
});
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
+ message(player,Component.text("Enter the new value in chat. The value is currently set to {0}. (Click to insert)").clickEvent(ClickEvent.suggestCommand(currentValue)),Component.text(currentValue));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/chat/UnicodeFilterGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/chat/UnicodeFilterGUI.java
index 75c56b1..6f161b6 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/config/chat/UnicodeFilterGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/config/chat/UnicodeFilterGUI.java
@@ -4,13 +4,12 @@ import io.github.itzispyder.pdk.commands.Args;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.MainConfig;
+import me.trouper.sentinel.server.Main;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.ChatGUI;
import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.utils.OldTXT;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@@ -22,10 +21,10 @@ import org.bukkit.inventory.ItemStack;
import java.util.function.BiConsumer;
-public class UnicodeFilterGUI {
+public class UnicodeFilterGUI implements Main {
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Editing Unicode Filter"))
+ .title(OldTXT.color("&6&lSentinel &8»&0 Editing Unicode Filter"))
.size(36)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
@@ -41,7 +40,7 @@ public class UnicodeFilterGUI {
}
ServerUtils.verbose("Unicode Filter GUI blank!");
ItemStack top = Items.RED;
- if (Sentinel.mainConfig.chat.unicodeFilter.enabled) {
+ if (main.dir().io.mainConfig.chat.unicodeFilter.enabled) {
top = Items.GREEN;
}
@@ -49,11 +48,11 @@ public class UnicodeFilterGUI {
inv.setItem(i,top);
}
- inv.setItem(3,Items.booleanItem(Sentinel.mainConfig.chat.unicodeFilter.enabled, Items.configItem("Unicode Filter Toggle", Material.CLOCK,"Enable or Disable the whole Unicode filter")));
- inv.setItem(5,Items.booleanItem(Sentinel.mainConfig.chat.unicodeFilter.silent, Items.configItem("Silent Mode",Material.FEATHER,"Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
- inv.setItem(20,Items.booleanItem(Sentinel.mainConfig.chat.unicodeFilter.punished,Items.configItem("Punished",Material.IRON_BARS,"Toggles execution of punishment commands.")));
- inv.setItem(22,Items.stringItem(Sentinel.mainConfig.chat.unicodeFilter.regex,Items.configItem("Allowed Char Regex",Material.DISPENSER,"Toggles execution of punishment commands.")));
- inv.setItem(24,Items.stringListItem(Sentinel.mainConfig.chat.unicodeFilter.punishCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands which will be executed if punishment is enabled."));
+ inv.setItem(3,Items.booleanItem(main.dir().io.mainConfig.chat.unicodeFilter.enabled, Items.configItem("Unicode Filter Toggle", Material.CLOCK,"Enable or Disable the whole Unicode filter")));
+ inv.setItem(5,Items.booleanItem(main.dir().io.mainConfig.chat.unicodeFilter.silent, Items.configItem("Silent Mode",Material.FEATHER,"Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
+ inv.setItem(20,Items.booleanItem(main.dir().io.mainConfig.chat.unicodeFilter.punished,Items.configItem("Punished",Material.IRON_BARS,"Toggles execution of punishment commands.")));
+ inv.setItem(22,Items.stringItem(main.dir().io.mainConfig.chat.unicodeFilter.regex,Items.configItem("Allowed Char Regex",Material.DISPENSER,"Toggles execution of punishment commands.")));
+ inv.setItem(24,Items.stringListItem(main.dir().io.mainConfig.chat.unicodeFilter.punishCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands which will be executed if punishment is enabled."));
}
@@ -63,41 +62,41 @@ public class UnicodeFilterGUI {
switch (e.getSlot()) {
case 3 -> {
- Sentinel.mainConfig.chat.unicodeFilter.enabled = !Sentinel.mainConfig.chat.unicodeFilter.enabled;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.unicodeFilter.enabled = !main.dir().io.mainConfig.chat.unicodeFilter.enabled;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
case 5 -> {
- Sentinel.mainConfig.chat.unicodeFilter.silent = !Sentinel.mainConfig.chat.unicodeFilter.silent;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.unicodeFilter.silent = !main.dir().io.mainConfig.chat.unicodeFilter.silent;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
case 20 -> {
- Sentinel.mainConfig.chat.unicodeFilter.punished = !Sentinel.mainConfig.chat.unicodeFilter.punished;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.unicodeFilter.punished = !main.dir().io.mainConfig.chat.unicodeFilter.punished;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
- case 22 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.unicodeFilter.regex = args.getAll().toString(),Sentinel.mainConfig.chat.unicodeFilter.regex);
+ case 22 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.unicodeFilter.regex = args.getAll().toString(),main.dir().io.mainConfig.chat.unicodeFilter.regex);
case 24 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.unicodeFilter.punishCommands.add(args.getAll().toString());
- },"" + Sentinel.mainConfig.chat.unicodeFilter.punishCommands);
+ },"" + main.dir().io.mainConfig.chat.unicodeFilter.punishCommands);
return;
}
- Sentinel.mainConfig.chat.unicodeFilter.punishCommands.clear();
+ main.dir().io.mainConfig.chat.unicodeFilter.punishCommands.clear();
blankPage(e.getInventory());
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.save();
}
}
}
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.mainConfig);
+ public static ConfigUpdater updater = new ConfigUpdater<>(main.dir().io.mainConfig);
private void queuePlayer(Player player, BiConsumer action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
@@ -108,9 +107,9 @@ public class UnicodeFilterGUI {
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
+ messageAny(player,"Value updated successfully");
player.openInventory(home.getInventory());
});
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
+ message(player,Component.text("Enter the new value in chat. The value is currently set to {0}. (Click to insert)").clickEvent(ClickEvent.suggestCommand(currentValue)),Component.text(currentValue));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/chat/UrlFilterGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/chat/UrlFilterGUI.java
index aa8989e..cf32f6e 100644
--- a/src/main/java/me/trouper/sentinel/server/gui/config/chat/UrlFilterGUI.java
+++ b/src/main/java/me/trouper/sentinel/server/gui/config/chat/UrlFilterGUI.java
@@ -1,16 +1,14 @@
package me.trouper.sentinel.server.gui.config.chat;
import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.events.CustomListener;
import io.github.itzispyder.pdk.plugin.gui.CustomGui;
import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
import me.trouper.sentinel.data.config.MainConfig;
+import me.trouper.sentinel.server.events.QuickListener;
import me.trouper.sentinel.server.gui.Items;
import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.ChatGUI;
-import me.trouper.sentinel.utils.Text;
+import me.trouper.sentinel.utils.OldTXT;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@@ -22,9 +20,9 @@ import org.bukkit.inventory.ItemStack;
import java.util.function.BiConsumer;
-public class UrlFilterGUI implements CustomListener {
+public class UrlFilterGUI implements QuickListener {
public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Editing Unicode Filter"))
+ .title(OldTXT.color("&6&lSentinel &8»&0 Editing Unicode Filter"))
.size(36)
.onDefine(this::blankPage)
.defineMain(this::mainClick)
@@ -40,7 +38,7 @@ public class UrlFilterGUI implements CustomListener {
}
ItemStack top = Items.RED;
- if (Sentinel.mainConfig.chat.urlFilter.enabled) {
+ if (main.dir().io.mainConfig.chat.urlFilter.enabled) {
top = Items.GREEN;
}
@@ -48,12 +46,12 @@ public class UrlFilterGUI implements CustomListener {
inv.setItem(i,top);
}
- inv.setItem(3,Items.booleanItem(Sentinel.mainConfig.chat.urlFilter.enabled, Items.configItem("Unicode Filter Toggle", Material.CLOCK,"Enable or Disable the whole Unicode filter")));
- inv.setItem(5,Items.booleanItem(Sentinel.mainConfig.chat.urlFilter.silent, Items.configItem("Silent Mode",Material.FEATHER,"Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
- inv.setItem(19,Items.booleanItem(Sentinel.mainConfig.chat.urlFilter.punished,Items.configItem("Punished",Material.IRON_BARS,"Toggles execution of punishment commands.")));
- inv.setItem(21,Items.stringItem(Sentinel.mainConfig.chat.urlFilter.regex,Items.configItem("Allowed Char Regex",Material.DISPENSER,"Toggles execution of punishment commands.")));
- inv.setItem(23,Items.stringListItem(Sentinel.mainConfig.chat.urlFilter.punishCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands which will be executed if punishment is enabled."));
- inv.setItem(25,Items.stringListItem(Sentinel.mainConfig.chat.urlFilter.whitelist,Material.PAPER,"Whitelist","URLs which will not flag the filter."));
+ inv.setItem(3,Items.booleanItem(main.dir().io.mainConfig.chat.urlFilter.enabled, Items.configItem("Unicode Filter Toggle", Material.CLOCK,"Enable or Disable the whole Unicode filter")));
+ inv.setItem(5,Items.booleanItem(main.dir().io.mainConfig.chat.urlFilter.silent, Items.configItem("Silent Mode",Material.FEATHER,"Whether to notify players that their messages \nwere blocked. Enabling could help deter bypassing.")));
+ inv.setItem(19,Items.booleanItem(main.dir().io.mainConfig.chat.urlFilter.punished,Items.configItem("Punished",Material.IRON_BARS,"Toggles execution of punishment commands.")));
+ inv.setItem(21,Items.stringItem(main.dir().io.mainConfig.chat.urlFilter.regex,Items.configItem("Allowed Char Regex",Material.DISPENSER,"Toggles execution of punishment commands.")));
+ inv.setItem(23,Items.stringListItem(main.dir().io.mainConfig.chat.urlFilter.punishCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands which will be executed if punishment is enabled."));
+ inv.setItem(25,Items.stringListItem(main.dir().io.mainConfig.chat.urlFilter.whitelist,Material.PAPER,"Whitelist","URLs which will not flag the filter."));
}
@@ -63,53 +61,53 @@ public class UrlFilterGUI implements CustomListener {
switch (e.getSlot()) {
case 3 -> {
- Sentinel.mainConfig.chat.urlFilter.enabled = !Sentinel.mainConfig.chat.urlFilter.enabled;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.urlFilter.enabled = !main.dir().io.mainConfig.chat.urlFilter.enabled;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
case 5 -> {
- Sentinel.mainConfig.chat.urlFilter.silent = !Sentinel.mainConfig.chat.urlFilter.silent;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.urlFilter.silent = !main.dir().io.mainConfig.chat.urlFilter.silent;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
case 19 -> {
- Sentinel.mainConfig.chat.urlFilter.punished = !Sentinel.mainConfig.chat.urlFilter.punished;
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.chat.urlFilter.punished = !main.dir().io.mainConfig.chat.urlFilter.punished;
+ main.dir().io.mainConfig.save();
blankPage(e.getInventory());
}
- case 21 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.urlFilter.regex = args.getAll().toString(),Sentinel.mainConfig.chat.urlFilter.regex);
+ case 21 -> queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> cfg.chat.urlFilter.regex = args.getAll().toString(),main.dir().io.mainConfig.chat.urlFilter.regex);
case 23 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.urlFilter.punishCommands.add(args.getAll().toString());
- },"" + Sentinel.mainConfig.chat.urlFilter.punishCommands);
+ },"" + main.dir().io.mainConfig.chat.urlFilter.punishCommands);
return;
}
- Sentinel.mainConfig.chat.urlFilter.punishCommands.clear();
+ main.dir().io.mainConfig.chat.urlFilter.punishCommands.clear();
blankPage(e.getInventory());
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.save();
}
case 25 -> {
if (e.isLeftClick()) {
queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
cfg.chat.urlFilter.whitelist.add(args.getAll().toString());
- },"" + Sentinel.mainConfig.chat.urlFilter.whitelist);
+ },"" + main.dir().io.mainConfig.chat.urlFilter.whitelist);
return;
}
- Sentinel.mainConfig.chat.urlFilter.whitelist.clear();
+ main.dir().io.mainConfig.chat.urlFilter.whitelist.clear();
blankPage(e.getInventory());
- Sentinel.mainConfig.save();
+ main.dir().io.mainConfig.save();
}
}
}
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.mainConfig);
+ public static ConfigUpdater updater = new ConfigUpdater<>(main.dir().io.mainConfig);
private void queuePlayer(Player player, BiConsumer action, String currentValue) {
MainGUI.awaitingCallback.add(player.getUniqueId());
@@ -120,9 +118,9 @@ public class UrlFilterGUI implements CustomListener {
}, (cfg, newValue) -> {
action.accept(cfg,new Args(newValue.split("\\s+")));
cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
+ successAny(player,"Value updated successfully");
player.openInventory(home.getInventory());
});
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
+ message(player,Component.text("Enter the new value in chat. The value is currently set to {0}. (Click to insert)").clickEvent(ClickEvent.suggestCommand(currentValue)),Component.text(currentValue));
}
}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/CommandGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/CommandGUI.java
deleted file mode 100644
index 20a51f6..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/CommandGUI.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke;
-
-import io.github.itzispyder.pdk.plugin.builders.ItemBuilder;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.server.gui.config.nuke.checks.command.DangerousCMDGUI;
-import me.trouper.sentinel.server.gui.config.nuke.checks.command.LoggedCMDGUI;
-import me.trouper.sentinel.server.gui.config.nuke.checks.command.SpecificCMDGUI;
-import me.trouper.sentinel.utils.Text;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-public class CommandGUI {
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Choose a check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .define(11,SPECIFIC, e->{
- e.getWhoClicked().openInventory(new SpecificCMDGUI().home.getInventory());
- })
- .define(13,LOGGED, e->{
- e.getWhoClicked().openInventory(new LoggedCMDGUI().home.getInventory());
- })
- .define(15,DANGEROUS, e->{
- e.getWhoClicked().openInventory(new DangerousCMDGUI().home.getInventory());
- })
- .build();
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- MainGUI.verify((Player) e.getWhoClicked());
- }
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
- }
-
- private static final ItemStack SPECIFIC = ItemBuilder.create()
- .material(Material.SPECTRAL_ARROW)
- .name(Text.color("&bSpecific Commands"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-
- private static final ItemStack LOGGED = ItemBuilder.create()
- .material(Material.SPYGLASS)
- .name(Text.color("&bLogged Commands"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
-
- .build();
-
- private static final ItemStack DANGEROUS = ItemBuilder.create()
- .material(Material.TNT)
- .name(Text.color("&bDangerous Commands"))
- .lore(Text.color("&8&l➥&7 Modify this check"))
- .build();
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBEditGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBEditGUI.java
deleted file mode 100644
index 2d6efa6..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBEditGUI.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class CBEditGUI {
-
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 CB Edit Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.commandBlockEdit.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,22,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
- inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockEdit.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
- inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockEdit.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.commandBlockEdit.enabled = !Sentinel.violationConfig.commandBlockEdit.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 2 -> {
- Sentinel.violationConfig.commandBlockEdit.deop = !Sentinel.violationConfig.commandBlockEdit.deop;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 20 -> {
- Sentinel.violationConfig.commandBlockEdit.logToDiscord = !Sentinel.violationConfig.commandBlockEdit.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 6 -> {
- Sentinel.violationConfig.commandBlockEdit.punish = !Sentinel.violationConfig.commandBlockEdit.punish;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 24 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
- cfg.commandBlockEdit.punishmentCommands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandBlockEdit.punishmentCommands);
- return;
- }
- Sentinel.violationConfig.commandBlockEdit.punishmentCommands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- }
- }
-
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
-
- private void queuePlayer(Player player, BiConsumer action, String currentValue) {
- MainGUI.awaitingCallback.add(player.getUniqueId());
- player.closeInventory();
- updater.queuePlayer(player, 20*60, (e)->{
- e.setCancelled(true);
- return LegacyComponentSerializer.legacySection().serialize(e.message());
- }, (cfg, newValue) -> {
- action.accept(cfg,new Args(newValue.split("\\s+")));
- cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
- player.openInventory(home.getInventory());
- });
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBExecuteGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBExecuteGUI.java
deleted file mode 100644
index b02be97..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBExecuteGUI.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks;
-
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.utils.Text;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-public class CBExecuteGUI {
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 CB Whitelist"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack top = Items.RED;
- if (Sentinel.violationConfig.commandBlockExecute.enabled) {
- top = Items.GREEN;
- }
-
- for (int i = 0; i < 9; i++) {
- inv.setItem(i,top);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(4,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.enabled,Items.configItem("Check Toggle", Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(11,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.destroyBlock,Items.configItem("Destroy",Material.NETHERITE_PICKAXE,"Destroy the offending command-block")));
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.attemptRestore,Items.configItem("Restore",Material.COMMAND_BLOCK,"Attempt to restore the block if a \nwhitelisted one exists at the location")));
- inv.setItem(15,Items.booleanItem(Sentinel.violationConfig.commandBlockExecute.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 4 -> {
- Sentinel.violationConfig.commandBlockExecute.enabled = !Sentinel.violationConfig.commandBlockExecute.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 11 -> {
- Sentinel.violationConfig.commandBlockExecute.destroyBlock = !Sentinel.violationConfig.commandBlockExecute.destroyBlock;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 13 -> {
- Sentinel.violationConfig.commandBlockExecute.attemptRestore = !Sentinel.violationConfig.commandBlockExecute.attemptRestore;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 15 -> {
- Sentinel.violationConfig.commandBlockExecute.logToDiscord = !Sentinel.violationConfig.commandBlockExecute.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- }
- }
-}
-
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCPlaceGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCPlaceGUI.java
deleted file mode 100644
index 0d70a52..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCPlaceGUI.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class CBMCPlaceGUI {
-
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 CB MC Place Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.commandBlockMinecartPlace.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,22,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
- inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
- inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.commandBlockMinecartPlace.enabled = !Sentinel.violationConfig.commandBlockMinecartPlace.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 2 -> {
- Sentinel.violationConfig.commandBlockMinecartPlace.deop = !Sentinel.violationConfig.commandBlockMinecartPlace.deop;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 20 -> {
- Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord = !Sentinel.violationConfig.commandBlockMinecartPlace.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 6 -> {
- Sentinel.violationConfig.commandBlockMinecartPlace.punish = !Sentinel.violationConfig.commandBlockMinecartPlace.punish;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 24 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
- cfg.commandBlockMinecartPlace.punishmentCommands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands);
- return;
- }
- Sentinel.violationConfig.commandBlockMinecartPlace.punishmentCommands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- }
- }
-
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
- private void queuePlayer(Player player, BiConsumer action, String currentValue) {
- MainGUI.awaitingCallback.add(player.getUniqueId());
- player.closeInventory();
- updater.queuePlayer(player, 20*60, (e)->{
- e.setCancelled(true);
- return LegacyComponentSerializer.legacySection().serialize(e.message());
- }, (cfg, newValue) -> {
- action.accept(cfg,new Args(newValue.split("\\s+")));
- cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
- player.openInventory(home.getInventory());
- });
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCUseGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCUseGUI.java
deleted file mode 100644
index f47e415..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBMCUseGUI.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class CBMCUseGUI {
-
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 CB MC Use Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.commandBlockMinecartUse.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,22,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
- inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockMinecartUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
- inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.commandBlockMinecartUse.enabled = !Sentinel.violationConfig.commandBlockMinecartUse.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 2 -> {
- Sentinel.violationConfig.commandBlockMinecartUse.deop = !Sentinel.violationConfig.commandBlockMinecartUse.deop;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 20 -> {
- Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord = !Sentinel.violationConfig.commandBlockMinecartUse.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 6 -> {
- Sentinel.violationConfig.commandBlockMinecartUse.punish = !Sentinel.violationConfig.commandBlockMinecartUse.punish;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 24 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
- cfg.commandBlockMinecartUse.punishmentCommands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands);
- return;
- }
- Sentinel.violationConfig.commandBlockMinecartUse.punishmentCommands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- }
- }
-
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
-
- private void queuePlayer(Player player, BiConsumer action, String currentValue) {
- MainGUI.awaitingCallback.add(player.getUniqueId());
- player.closeInventory();
- updater.queuePlayer(player, 20*60,(e)->{
- e.setCancelled(true);
- return LegacyComponentSerializer.legacySection().serialize(e.message());
- }, (cfg, newValue) -> {
- action.accept(cfg,new Args(newValue.split("\\s+")));
- cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
- player.openInventory(home.getInventory());
- });
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBPlaceGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBPlaceGUI.java
deleted file mode 100644
index 9a665ce..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBPlaceGUI.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class CBPlaceGUI {
-
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 CB Place Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.commandBlockPlace.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,22,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
- inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockPlace.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
- inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockPlace.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.commandBlockPlace.enabled = !Sentinel.violationConfig.commandBlockPlace.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 2 -> {
- Sentinel.violationConfig.commandBlockPlace.deop = !Sentinel.violationConfig.commandBlockPlace.deop;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 20 -> {
- Sentinel.violationConfig.commandBlockPlace.logToDiscord = !Sentinel.violationConfig.commandBlockPlace.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 6 -> {
- Sentinel.violationConfig.commandBlockPlace.punish = !Sentinel.violationConfig.commandBlockPlace.punish;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 24 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
- cfg.commandBlockPlace.punishmentCommands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandBlockPlace.punishmentCommands);
- return;
- }
- Sentinel.violationConfig.commandBlockPlace.punishmentCommands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- }
- }
-
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
-
- private void queuePlayer(Player player, BiConsumer action, String currentValue) {
- MainGUI.awaitingCallback.add(player.getUniqueId());
- player.closeInventory();
- updater.queuePlayer(player, 20*60, (e)->{
- e.setCancelled(true);
- return LegacyComponentSerializer.legacySection().serialize(e.message());
- }, (cfg, newValue) -> {
- action.accept(cfg,new Args(newValue.split("\\s+")));
- cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
- player.openInventory(home.getInventory());
- });
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBUseGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBUseGUI.java
deleted file mode 100644
index 1e633f2..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/CBUseGUI.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class CBUseGUI {
-
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 CB Use Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.commandBlockUse.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,22,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
- inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandBlockUse.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
- inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandBlockUse.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.commandBlockUse.enabled = !Sentinel.violationConfig.commandBlockUse.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 2 -> {
- Sentinel.violationConfig.commandBlockUse.deop = !Sentinel.violationConfig.commandBlockUse.deop;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 20 -> {
- Sentinel.violationConfig.commandBlockUse.logToDiscord = !Sentinel.violationConfig.commandBlockUse.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 6 -> {
- Sentinel.violationConfig.commandBlockUse.punish = !Sentinel.violationConfig.commandBlockUse.punish;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 24 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
- cfg.commandBlockUse.punishmentCommands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandBlockUse.punishmentCommands);
- return;
- }
- Sentinel.violationConfig.commandBlockUse.punishmentCommands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- }
- }
-
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
-
- private void queuePlayer(Player player, BiConsumer action, String currentValue) {
- MainGUI.awaitingCallback.add(player.getUniqueId());
- player.closeInventory();
- updater.queuePlayer(player, 20*60, (e)->{
- e.setCancelled(true);
- return LegacyComponentSerializer.legacySection().serialize(e.message());
- }, (cfg, newValue) -> {
- action.accept(cfg,new Args(newValue.split("\\s+")));
- cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
- player.openInventory(home.getInventory());
- });
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/HotbarActionGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/HotbarActionGUI.java
deleted file mode 100644
index 56f723c..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/HotbarActionGUI.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.AntiNukeGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class HotbarActionGUI {
-
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Creative Hotbar Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this:: mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new AntiNukeGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.creativeHotbarAction.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,22,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
- inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.creativeHotbarAction.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
- inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.creativeHotbarAction.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
-
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.creativeHotbarAction.enabled = !Sentinel.violationConfig.creativeHotbarAction.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 2 -> {
- Sentinel.violationConfig.creativeHotbarAction.deop = !Sentinel.violationConfig.creativeHotbarAction.deop;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 20 -> {
- Sentinel.violationConfig.creativeHotbarAction.logToDiscord = !Sentinel.violationConfig.creativeHotbarAction.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 6 -> {
- Sentinel.violationConfig.creativeHotbarAction.punish = !Sentinel.violationConfig.creativeHotbarAction.punish;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 24 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg, args) -> {
- cfg.creativeHotbarAction.punishmentCommands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.creativeHotbarAction.punishmentCommands);
- return;
- }
- Sentinel.violationConfig.creativeHotbarAction.punishmentCommands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- }
- }
-
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
-
- private void queuePlayer(Player player, BiConsumer action, String currentValue) {
- MainGUI.awaitingCallback.add(player.getUniqueId());
- player.closeInventory();
- updater.queuePlayer(player, 20*60, (e)->{
- e.setCancelled(true);
- return LegacyComponentSerializer.legacySection().serialize(e.message());
- }, (cfg, newValue) -> {
- action.accept(cfg,new Args(newValue.split("\\s+")));
- cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
- player.openInventory(home.getInventory());
- });
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/command/DangerousCMDGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/command/DangerousCMDGUI.java
deleted file mode 100644
index 9288a5a..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/command/DangerousCMDGUI.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks.command;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.nuke.CommandGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class DangerousCMDGUI {
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Dangerous Command Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new CommandGUI().home.getInventory());
- })
- .build();
-
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.commandExecute.dangerous.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(2,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.deop,Items.configItem("De-Op",Material.END_CRYSTAL,"Remove the user's operator privileges")));
- inv.setItem(20,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.logToDiscord,Items.configItem("Log",Material.OAK_LOG,"If this check will produce a log to discord")));
- inv.setItem(6,Items.booleanItem(Sentinel.violationConfig.commandExecute.dangerous.punish,Items.configItem("Punish",Material.REDSTONE_TORCH,"Run the punishment commands")));
- inv.setItem(24,Items.stringListItem(Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands,Material.DIAMOND_AXE,"Punishment Commands","Commands that will be ran \nif this check is flagged."));
- inv.setItem(22,Items.stringListItem(Sentinel.violationConfig.commandExecute.dangerous.commands,Material.CRIMSON_HANGING_SIGN,"Commands","Commands that will flag this check."));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.commandExecute.dangerous.enabled = !Sentinel.violationConfig.commandExecute.dangerous.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 2 -> {
- Sentinel.violationConfig.commandExecute.dangerous.deop = !Sentinel.violationConfig.commandExecute.dangerous.deop;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 20 -> {
- Sentinel.violationConfig.commandExecute.dangerous.logToDiscord = !Sentinel.violationConfig.commandExecute.dangerous.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 6 -> {
- Sentinel.violationConfig.commandExecute.dangerous.punish = !Sentinel.violationConfig.commandExecute.dangerous.punish;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 24 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
- cfg.commandExecute.dangerous.punishmentCommands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands);
- return;
- }
- Sentinel.violationConfig.commandExecute.dangerous.punishmentCommands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
-
- case 22 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
- cfg.commandExecute.dangerous.commands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandExecute.dangerous.commands);
- return;
- }
- Sentinel.violationConfig.commandExecute.dangerous.commands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- }
- }
-
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
-
- private void queuePlayer(Player player, BiConsumer action, String currentValue) {
- MainGUI.awaitingCallback.add(player.getUniqueId());
- player.closeInventory();
- updater.queuePlayer(player, 20*60, (e)->{
- e.setCancelled(true);
- return LegacyComponentSerializer.legacySection().serialize(e.message());
- }, (cfg, newValue) -> {
- action.accept(cfg,new Args(newValue.split("\\s+")));
- cfg.save();
- player.sendMessage(Text.prefix("Value updated successfully"));
- player.openInventory(home.getInventory());
- });
- player.sendMessage(Component.text(Text.prefix("Enter the new value in chat. The value is currently set to &b%s&7. (Click to insert)".formatted(currentValue))).clickEvent(ClickEvent.suggestCommand(currentValue)));
- }
-}
diff --git a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/command/LoggedCMDGUI.java b/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/command/LoggedCMDGUI.java
deleted file mode 100644
index 0b2a53b..0000000
--- a/src/main/java/me/trouper/sentinel/server/gui/config/nuke/checks/command/LoggedCMDGUI.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package me.trouper.sentinel.server.gui.config.nuke.checks.command;
-
-import io.github.itzispyder.pdk.commands.Args;
-import io.github.itzispyder.pdk.plugin.gui.CustomGui;
-import io.github.itzispyder.pdk.utils.misc.config.ConfigUpdater;
-import io.papermc.paper.event.player.AsyncChatEvent;
-import me.trouper.sentinel.Sentinel;
-import me.trouper.sentinel.data.config.ViolationConfig;
-import me.trouper.sentinel.server.gui.Items;
-import me.trouper.sentinel.server.gui.MainGUI;
-import me.trouper.sentinel.server.gui.config.nuke.CommandGUI;
-import me.trouper.sentinel.utils.ServerUtils;
-import me.trouper.sentinel.utils.Text;
-import net.kyori.adventure.text.Component;
-import net.kyori.adventure.text.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.List;
-import java.util.function.BiConsumer;
-
-public class LoggedCMDGUI {
- public final CustomGui home = CustomGui.create()
- .title(Text.color("&6&lSentinel &8»&0 Logged Command Check"))
- .size(27)
- .onDefine(this::blankPage)
- .defineMain(this::mainClick)
- .define(26, Items.BACK, e->{
- e.getWhoClicked().openInventory(new CommandGUI().home.getInventory());
- })
- .build();
-
- private void blankPage(Inventory inv) {
- for (int i = 0; i < inv.getSize(); i++) {
- inv.setItem(i,Items.BLANK);
- }
-
- ItemStack ring = Items.RED;
- if (Sentinel.violationConfig.commandExecute.logged.enabled) {
- ring = Items.GREEN;
- }
-
- List ringList = List.of(3,4,5,12,14,21,22,23);
-
- for (Integer i : ringList) {
- inv.setItem(i,ring);
- }
-
- inv.setItem(26,Items.BACK);
- inv.setItem(13,Items.booleanItem(Sentinel.violationConfig.commandExecute.logged.enabled,Items.configItem("Check Toggle",Material.CLOCK,"Enable/Disable this check entirely")));
- inv.setItem(11,Items.booleanItem(Sentinel.violationConfig.commandExecute.logged.logToDiscord,Items.configItem("Log to Discord",Material.OAK_LOG,"If this check will log to discord")));
- inv.setItem(15,Items.stringListItem(Sentinel.violationConfig.commandExecute.logged.commands,Material.CRIMSON_HANGING_SIGN,"Commands","Commands that will flag this check"));
- }
-
- private void mainClick(InventoryClickEvent e) {
- e.setCancelled(true);
- if (!MainGUI.verify((Player) e.getWhoClicked())) return;
- switch (e.getSlot()) {
- case 13 -> {
- Sentinel.violationConfig.commandExecute.logged.enabled = !Sentinel.violationConfig.commandExecute.logged.enabled;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 11 -> {
- Sentinel.violationConfig.commandExecute.logged.logToDiscord = !Sentinel.violationConfig.commandExecute.logged.logToDiscord;
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- case 15 -> {
- if (e.isLeftClick()) {
- queuePlayer((Player) e.getWhoClicked(), (cfg,args) -> {
- cfg.commandExecute.logged.commands.add(args.getAll().toString());
- },"" + Sentinel.violationConfig.commandExecute.logged.commands);
- return;
- }
- Sentinel.violationConfig.commandExecute.logged.commands.clear();
- blankPage(e.getInventory());
- Sentinel.violationConfig.save();
- }
- }
- }
-
- public static ConfigUpdater updater = new ConfigUpdater<>(Sentinel.violationConfig);
-
- private void queuePlayer(Player player, BiConsumer