Compare commits

..
Author SHA1 Message Date
TechnicallyCoded 6286d15a32 Update README.md 2025-08-08 22:46:18 +02:00
TechnicallyCoded 3221637a21 Add comprehensive README 2025-08-08 22:37:29 +02:00
87 changed files with 1652 additions and 6038 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
.gitea/CODEOWNERS linguist-detectable=false
-3
View File
@@ -1,3 +0,0 @@
# Pull requests request review from the eligible staff team(s).
# One approval from either an Admin or Developer satisfies branch protection.
* @trueog/Admins @trueog/Developers
-10
View File
@@ -8,15 +8,6 @@
# IntelliJ
out/
# Eclipse
.classpath
.project
.settings/
# Gradle
.gradle/
build/
# Compiled class file
*.class
@@ -38,7 +29,6 @@ build/
hs_err_pid*
*~
bin/
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
-9
View File
@@ -1,9 +0,0 @@
[submodule "libs/DiamondBank-OG"]
path = libs/DiamondBank-OG
url = https://git.trueog.net/trueog/DiamondBank-OG
[submodule "libs/Utilities-OG"]
path = libs/Utilities-OG
url = https://git.trueog.net/trueog/Utilities-OG
[submodule "libs/GxUI-OG"]
path = libs/GxUI-OG
url = https://git.trueog.net/trueog/GxUI-OG
-18
View File
@@ -1,18 +0,0 @@
# Changelog
## 1.2
- Unified bounty head formatting across item names, armor stand labels, and action bar messaging into a single canonical line showing victim, slayer, and diamond reward.
- Removed redundant bounty head lore now that the item display name carries full claim information.
- `/bounty check` now resolves offline players who still have active bounties, and tab completion suggests their names.
- Bounty check output now formats the amount through the DiamondBank shards-to-diamonds formatter for consistency with head labels and announcements.
- Bounty leaderboard GUI now reads the beheading chance from the `bounty-head-drop-chance` config value instead of hardcoding 50%.
- Added the missing `playerbountiesog.command.admin.bounty.get` permission entry and Italian translation listing; removed dead `death.announce-claimed` lang key.
- Replaced raw stack traces in the bounty data manager with logger output and pruned dead plugin-discovery code from plugin startup.
## 1.1
- Added bounty amounts to bounty head item titles so the selected hotbar item text shows the reward without using the action bar.
- Updated placed bounty head hover labels to render on separate lines for clearer in-world head information.
- Added right-click action bar messaging for bounty heads that shows who claimed the bounty for both hotbar items and placed heads.
- Stored claimant metadata on bounty heads so claim information survives item drops and place/break cycles.
-165
View File
@@ -1,165 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+27 -31
View File
@@ -1,50 +1,46 @@
# PlayerBounties-OG
# PlayerBountiesPlus
## Overview
PlayerBounties-OG is a hard fork of [PlayerBountiesPlus](https://github.com/TechnicallyCoded/PlayerBountiesPlus) that lets players set and claim bounties while blocking teammates from claiming rewards. Hooks into [DiamondBank-OG](https://git.trueog.net/trueog/DiamondBank-OG) for economy handling and supports [SimpleClans](https://git.trueog.net/trueog/Unions-OG) and API-compatible forks such as Unions-OG. Built for Purpur 1.19.4.
PlayerBountiesPlus lets players set and claim bounties while blocking teammates from claiming rewards. Hooks into Vault for economy handling and supports many team plugins.
## Features
- Clan-aware bounty system that prevents teammates from claiming each other's bounties.
- Inventory GUI for viewing bounties.
- Customizable odds for receiving player head from bounty victim.
- Localized messages in multiple languages.
- Integrates [CoreProtect-OG](https://git.trueog.net/trueog/CoreProtect-OG) for player head rollback injection.
- Integrates [DiamondBank-OG](https://git.trueog.net/trueog/DiamondBank-OG) for currency.
- Integrates [LuckPerms](https://git.trueog.net/trueog/LuckPerms) for player name and rank formatting.
- Integrates [SimpleClans](https://git.trueog.net/trueog/Unions-OG) and compatible forks such as Unions-OG for team detection.
- Clan-aware bounty system that prevents teammates from claiming each other's bounties
- Integrates with Vault and supports ClansLite, Parties, BetterTeams, SimpleClans and Towny for team detection
- Inventory GUI for viewing bounties
- PlaceholderAPI support for custom placeholders
- Localized messages in multiple languages
## Commands
- `/bounty set <player> <amount>` – set a bounty on a player
- `/bounty add <player> <amount>` – add diamonds to an existing bounty
- `/bounty top` – list the top bounties
- `/bounty check <player>` – check a player's bounty (online or offline)
- `/bounty check <player>` – check a player's bounty
- `/pbp reload` – reload configuration and messages
- `/pbp version` – display plugin version
- `/pbp bounty set <player> <amount>` – admin set a bounty
- `/pbp bounty add <player> <amount>` – add diamonds to a bounty
- `/pbp bounty remove <player> <amount>` – remove diamonds from a bounty
- `/pbp bounty add <player> <amount>` – add to a bounty
- `/pbp bounty remove <player> <amount>` – remove from a bounty
- `/pbp bounty delete <player>` – delete a bounty
- `/pbp bounty get <player>` – view a bounty
## Permissions
| Permission | Default |
| --- | --- |
| `playerbountiesog.command.bounty` | all |
| `playerbountiesog.command.bounty.set` | all |
| `playerbountiesog.command.bounty.add` | all |
| `playerbountiesog.event.claim` | all |
| `playerbountiesog.command.admin` | op |
| `playerbountiesog.command.admin.version` | op |
| `playerbountiesog.command.admin.reload` | op |
| `playerbountiesog.command.admin.bounty.set` | op |
| `playerbountiesog.command.admin.bounty.add` | op |
| `playerbountiesog.command.admin.bounty.remove` | op |
| `playerbountiesog.command.admin.bounty.delete` | op |
| `playerbountiesog.command.admin.bounty.get` | op |
| `playerbountiesplus.command.bounty` | all |
| `playerbountiesplus.command.bounty.set` | all |
| `playerbountiesplus.event.claim` | all |
| `playerbountiesplus.command.admin` | op |
| `playerbountiesplus.command.admin.version` | op |
| `playerbountiesplus.command.admin.reload` | op |
| `playerbountiesplus.command.admin.bounty.set` | op |
| `playerbountiesplus.command.admin.bounty.add` | op |
| `playerbountiesplus.command.admin.bounty.remove` | op |
| `playerbountiesplus.command.admin.bounty.delete` | op |
| `playerbountiesplus.command.admin.bounty.get` | op |
## Developer Notes
- Commands reside in `com.tcoded.playerbountiesplus.command` with subpackages for bounty and admin actions.
- Event listeners like `DeathListener` handle bounty claim logic.
- Hooks under `com.tcoded.playerbountiesplus.hook` integrate with DiamondBank-OG and supported clan/team plugins such as SimpleClans and Unions-OG.
- Inventory GUIs in `com.tcoded.playerbountiesplus.gui` present bounty data.
- `BountyDataManager` manages persistence of bounties.
- Commands reside in `com.tcoded.playerbountiesplus.command` with subpackages for bounty and admin actions
- Event listeners like `DeathListener` handle bounty claim logic
- Hooks under `com.tcoded.playerbountiesplus.hook` integrate with Vault, PlaceholderAPI and team plugins
- Inventory GUIs in `com.tcoded.playerbountiesplus.gui` present bounty data
- `BountyDataManager` manages persistence of bounties
-4
View File
@@ -1,4 +0,0 @@
#!/usr/bin/bash
# Fetch all submodule content.
git submodule update --force --recursive --init
-148
View File
@@ -1,148 +0,0 @@
/* ------------------------------ Plugins ------------------------------ */
plugins {
id("java") // Import Java plugin.
id("java-library") // Import Java Library plugin.
id("com.diffplug.spotless") version "8.1.0" // Import Spotless plugin.
id("com.gradleup.shadow") version "8.3.9" // Import Shadow plugin.
id("checkstyle") // Import Checkstyle plugin.
eclipse // Import Eclipse plugin.
kotlin("jvm") version "2.1.21" // Import Kotlin JVM plugin.
}
extra["kotlinAttribute"] = Attribute.of("kotlin-tag", Boolean::class.javaObjectType)
val kotlinAttribute: Attribute<Boolean> by rootProject.extra
/* --------------------------- JDK / Kotlin ---------------------------- */
java {
sourceCompatibility = JavaVersion.VERSION_17 // Compile with JDK 17 compatibility.
toolchain { // Select Java toolchain.
languageVersion.set(JavaLanguageVersion.of(17)) // Use JDK 17.
vendor.set(JvmVendorSpec.GRAAL_VM) // Use GraalVM CE.
}
}
kotlin { jvmToolchain(17) }
/* ----------------------------- Metadata ------------------------------ */
group = "com.tcoded" // Declare bundle identifier.
version = "1.1" // Declare plugin version (will be in .jar).
val apiVersion = "1.19" // Declare minecraft server target version.
/* ----------------------------- Resources ----------------------------- */
tasks.named<ProcessResources>("processResources") {
val props = mapOf("version" to version, "apiVersion" to apiVersion)
inputs.properties(props) // Indicates to rerun if version changes.
filesMatching("plugin.yml") { expand(props) }
from("LICENSE") { into("/") } // Bundle licenses into jarfiles.
}
/* ---------------------------- Repos ---------------------------------- */
repositories {
mavenCentral() // Import the Maven Central Maven Repository.
gradlePluginPortal() // Import the Gradle Plugin Portal Maven Repository.
maven { url = uri("https://repo.purpurmc.org/snapshots") } // Import the PurpurMC Maven Repository.
maven { url = uri("https://repo.codemc.io/repository/maven-releases/") }
maven { url = uri("https://repo.codemc.io/repository/maven-snapshots/") }
maven { url = uri("file://${System.getProperty("user.home")}/.m2/repository") }
System.getProperty("SELF_MAVEN_LOCAL_REPO")?.let { // TrueOG Bootstrap mavenLocal().
val dir = file(it)
if (dir.isDirectory) {
println("Using SELF_MAVEN_LOCAL_REPO at: $it")
maven { url = uri("file://${dir.absolutePath}") }
} else {
logger.error("TrueOG Bootstrap not found, defaulting to ~/.m2 for mavenLocal()")
mavenLocal()
}
} ?: logger.error("TrueOG Bootstrap not found, defaulting to ~/.m2 for mavenLocal()")
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
maven { url = uri("https://oss.sonatype.org/content/groups/public/") }
maven { url = uri("https://jitpack.io") }
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
maven { url = uri("https://repo.glaremasters.me/repository/towny/") }
maven { url = uri("https://repo.extendedclip.com/releases/") }
maven { url = uri("https://repo.tcoded.com/public/") }
maven { url = uri("https://maven.playpro.com") }
}
/* ---------------------- Java project deps ---------------------------- */
dependencies {
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare Purpur API version to be packaged.
compileOnly("net.sacredlabyrinth.phaed.simpleclans:SimpleClans:2.15.2")
compileOnly("net.luckperms:api:5.5") // Import LuckPerms API.
compileOnly("net.coreprotect:coreprotect:23.1")
compileOnlyApi(project(":libs:Utilities-OG")) // Import TrueOG Network Utilities-OG Java API (from source).
compileOnlyApi(project(":libs:GxUI-OG")) // Import TrueOG Network GxUI-OG Java API (from source).
compileOnlyApi(project(":libs:DiamondBank-OG")) {
attributes { attribute(kotlinAttribute, true) }
} // Import TrueOG network DiamondBank-OG Kotlin API (from source).
}
apply(from = "eclipse.gradle.kts") // Import eclipse classpath support script.
/* ---------------------- Reproducible jars ---------------------------- */
tasks.withType<AbstractArchiveTask>().configureEach { // Ensure reproducible .jars
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
/* ----------------------------- Shadow -------------------------------- */
tasks.shadowJar {
exclude("io.github.miniplaceholders.*") // Exclude the MiniPlaceholders package from being shadowed.
isEnableRelocation = true
relocationPrefix = "${project.group}.shadow"
archiveClassifier.set("") // Use empty string instead of null.
minimize()
}
tasks.jar { archiveClassifier.set("part") } // Applies to root jarfile only.
tasks.build { dependsOn(tasks.spotlessApply, tasks.shadowJar) } // Build depends on spotless and shadow.
/* --------------------------- Javac opts ------------------------------- */
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add("-parameters") // Enable reflection for java code.
options.isFork = true // Run javac in its own process.
options.compilerArgs.add("-Xlint:deprecation") // Trigger deprecation warning messages.
options.encoding = "UTF-8" // Use UTF-8 file encoding.
}
/* ----------------------------- Auto Formatting ------------------------ */
spotless {
java {
eclipse().configFile("config/formatter/eclipse-java-formatter.xml") // Eclipse java formatting.
leadingTabsToSpaces() // Convert leftover leading tabs to spaces.
removeUnusedImports() // Remove imports that aren't being called.
}
kotlinGradle {
ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } // JetBrains Kotlin formatting.
target("build.gradle.kts", "settings.gradle.kts") // Gradle files to format.
}
}
checkstyle {
toolVersion = "10.18.1" // Declare checkstyle version to use.
configFile = file("config/checkstyle/checkstyle.xml") // Point checkstyle to config file.
isIgnoreFailures = true // Don't fail the build if checkstyle does not pass.
isShowViolations = true // Show the violations in any IDE with the checkstyle plugin.
}
tasks.named("compileJava") {
dependsOn("spotlessApply") // Run spotless before compiling with the JDK.
}
tasks.named("spotlessCheck") {
dependsOn("spotlessApply") // Run spotless before checking if spotless ran.
}
/* ------------------------------ Eclipse SHIM ------------------------- */
// This can't be put in eclipse.gradle.kts because Gradle is weird.
subprojects {
apply(plugin = "java-library")
apply(plugin = "eclipse")
eclipse.project.name = "${project.name}-${rootProject.name}"
tasks.withType<Jar>().configureEach { archiveBaseName.set("${project.name}-${rootProject.name}") }
}
-34
View File
@@ -1,34 +0,0 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
<property name="severity" value="error"/>
</module>
<module name="TreeWalker">
<module name="FinalLocalVariable"/>
<module name="AvoidStarImport"/>
<module name="Indentation">
<property name="severity" value="ignore"/>
</module>
</module>
<module name="RegexpSingleline">
<property name="format" value="\borg\.junit\.jupiter\.api\.Assertions\.fail\s*\(\s*&quot;Not yet implemented&quot;\s*\)\s*;"/>
<property name="message" value="Remove placeholder fail() and implement the test."/>
<property name="ignoreCase" value="true"/>
<property name="severity" value="warning"/>
</module>
<module name="RegexpSingleline">
<property name="format" value="(?&lt;!\w)fail\s*\(\s*&quot;Not yet implemented&quot;\s*\)\s*;"/>
<property name="message" value="Remove placeholder fail() and implement the test."/>
<property name="severity" value="warning"/>
</module>
</module>
-404
View File
@@ -1,404 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="23">
<profile kind="CodeFormatterProfile" name="TrueOG Network Formatting" version="23">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case_after_arrow" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>
-151
View File
@@ -1,151 +0,0 @@
/* This is free and unencumbered software released into the public domain */
import org.gradle.plugins.ide.eclipse.model.EclipseModel
import java.nio.file.Files
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
val kotlinAttribute: Attribute<Boolean> by rootProject.extra
val kotlinPluginProjects = configurations
.getByName("compileClasspath")
.allDependencies
.filterIsInstance<ProjectDependency>()
.filter { it -> it.attributes.getAttribute(kotlinAttribute) != null }
.map { it.path }
kotlinPluginProjects.forEach { evaluationDependsOn(it) }
val ideLibs: Configuration by
configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
}
configure<EclipseModel> {
project {
name = "PlayerBounties-OG-Plugin"
}
classpath {
plusConfigurations.add(ideLibs)
}
}
val ideLibDir = layout.buildDirectory.dir("ide-libs")
val hashRegex = Regex("-[0-9a-fA-F]{10}(?=\\.jar$)") // Black magic.
val copyTasks = mutableListOf<TaskProvider<Copy>>()
kotlinPluginProjects.forEach { path ->
val sub = project(path)
val shadowJarProv = sub.tasks.named("shadowJar")
val copyTask =
tasks.register<Copy>("ideCopy${sub.name.replaceFirstChar(Char::titlecase)}") {
dependsOn(shadowJarProv)
from(shadowJarProv)
into(ideLibDir)
rename { it.replace(hashRegex, "") } // Remove git commit hash from jarfile.
}
copyTasks += copyTask
}
/* Ensure the jars exist before .classpath is generated */
tasks.named("eclipseClasspath").configure { dependsOn(copyTasks) }
/* Supply those jars to the ideLibs configuration (after evaluation) */
afterEvaluate { dependencies { add("ideLibs", fileTree(ideLibDir) { include("*.jar") }) } }
val injectIdeLibs =
tasks.register("injectIdeLibs") {
dependsOn("eclipse") // run after all eclipse files are generated
doLast {
val cpFile = file(".classpath")
if (!cpFile.exists()) return@doLast
val jars = fileTree(ideLibDir.get()) { include("*.jar") }.files.sortedBy { it.name }
if (jars.isEmpty()) return@doLast
// Parse DOM
val dbf = DocumentBuilderFactory.newInstance()
val doc = dbf.newDocumentBuilder().parse(cpFile)
val root = doc.documentElement
// Helper to see if an entry already exists
fun exists(path: String): Boolean =
root.getElementsByTagName("classpathentry").let { list ->
(0 until list.length).any { i ->
val n = list.item(i)
val kind = n.attributes?.getNamedItem("kind")?.nodeValue
val p = n.attributes?.getNamedItem("path")?.nodeValue
kind == "lib" && p == path
}
}
// Remove any entry that points to ide-libs dir (folder or jars) to avoid dupes
val toRemove = mutableListOf<org.w3c.dom.Node>()
val list = root.getElementsByTagName("classpathentry")
val dirPath = ideLibDir.get().asFile.absolutePath
for (i in 0 until list.length) {
val n = list.item(i)
val kind = n.attributes?.getNamedItem("kind")?.nodeValue
val p = n.attributes?.getNamedItem("path")?.nodeValue ?: ""
if (kind == "lib" && (p == dirPath || p.startsWith("$dirPath/"))) {
toRemove += n
}
}
toRemove.forEach { root.removeChild(it) }
// Append our jar entries LAST
jars.forEach { f ->
val abs = f.absolutePath
if (!exists(abs)) {
val entry = doc.createElement("classpathentry")
entry.setAttribute("kind", "lib")
entry.setAttribute("path", abs)
root.appendChild(entry)
}
}
// Write back pretty
val tf =
TransformerFactory.newInstance().newTransformer().apply {
setOutputProperty(OutputKeys.INDENT, "yes")
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "1")
setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no")
setOutputProperty(OutputKeys.ENCODING, "UTF-8")
}
Files.newBufferedWriter(cpFile.toPath()).use { w -> tf.transform(DOMSource(doc), StreamResult(w)) }
}
}
tasks.named("eclipse").configure { finalizedBy(injectIdeLibs) }
val eclipseModel = extensions.getByType<EclipseModel>()
fun Project.addResolvableEclipseConfigs() {
val jarAttr =
objects.named(org.gradle.api.attributes.LibraryElements::class, org.gradle.api.attributes.LibraryElements.JAR)
val apiAttr = objects.named(org.gradle.api.attributes.Usage::class, org.gradle.api.attributes.Usage.JAVA_API)
val compileOnlyRes =
configurations.create("eclipseCompileOnly") {
extendsFrom(configurations.getByName("compileOnly"))
isCanBeResolved = true
isCanBeConsumed = false
attributes.attribute(org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, apiAttr)
attributes.attribute(org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, jarAttr)
}
val compileOnlyApiRes =
configurations.create("eclipseCompileOnlyApi") {
extendsFrom(configurations.getByName("compileOnlyApi"))
isCanBeResolved = true
isCanBeConsumed = false
attributes.attribute(org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, apiAttr)
attributes.attribute(org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, jarAttr)
}
eclipseModel.classpath.plusConfigurations.addAll(listOf(compileOnlyRes, compileOnlyApiRes))
}
addResolvableEclipseConfigs()
Binary file not shown.
-7
View File
@@ -1,7 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
-251
View File
@@ -1,251 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
-94
View File
@@ -1,94 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+2
View File
@@ -0,0 +1,2 @@
jdk:
- openjdk17
Binary file not shown.
Submodule libs/GxUI-OG deleted from 287d0eb3ee.
+183
View File
@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tcoded</groupId>
<artifactId>PlayerBountiesPlus</artifactId>
<version>1.4.17</version>
<packaging>jar</packaging>
<name>PlayerBountiesPlus</name>
<description>Claim bounties only if you are not on the same clan</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<url>https://tcoded.com</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<relocations>
<relocation>
<pattern>com.tcoded.folialib</pattern>
<shadedPattern>com.tcoded.playerbountiesplus.lib.folialib</shadedPattern>
</relocation>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>com.tcoded.playerbountiesplus.lib.bstats</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public</url>
</repository>
<repository>
<id>glaremasters repo</id>
<url>https://repo.glaremasters.me/repository/towny/</url>
</repository>
<repository>
<id>placeholderapi</id>
<url>https://repo.extendedclip.com/releases/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.19.3-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.MilkBowl</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>23.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.CraptiCraft-Development</groupId>
<artifactId>ClansLite-API</artifactId>
<version>1.4.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.TechnicallyCoded</groupId>
<artifactId>FoliaLib</artifactId>
<version>0.4.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alessiodp.parties</groupId>
<artifactId>parties-api</artifactId>
<version>3.2.9</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/parties-api-3.2.9.jar</systemPath>
</dependency>
<dependency>
<groupId>com.github.lightlibs</groupId>
<artifactId>LegacyColorCodeParser</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.LightLibs</groupId>
<artifactId>SpigotUpdateChecker</artifactId>
<version>1.1.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.booksaw</groupId>
<artifactId>BetterTeams</artifactId>
<version>4.8.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.sacredlabyrinth.phaed.simpleclans</groupId>
<artifactId>SimpleClans</artifactId>
<version>2.15.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.SaberLLC</groupId>
<artifactId>Saber-Factions</artifactId>
<version>4.1.4-STABLE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.palmergames.bukkit.towny</groupId>
<artifactId>towny</artifactId>
<version>0.100.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
-13
View File
@@ -1,13 +0,0 @@
rootProject.name = "PlayerBounties-OG"
ProcessBuilder("sh", "bootstrap.sh").directory(rootDir).inheritIO().start().let {
if (it.waitFor() != 0) throw GradleException("bootstrap.sh failed")
}
file("libs")
.listFiles()
?.filter { it.isDirectory && !it.name.startsWith(".") }
?.forEach { dir ->
include(":libs:${dir.name}")
project(":libs:${dir.name}").projectDir = dir
}
@@ -1,303 +0,0 @@
package com.tcoded.playerbountiesplus;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.ServicesManager;
import org.bukkit.plugin.java.JavaPlugin;
import com.tcoded.playerbountiesplus.command.BountyCommand;
import com.tcoded.playerbountiesplus.command.PlayerBountiesPlusAdminCmd;
import com.tcoded.playerbountiesplus.hook.currency.DiamondBankOGHook;
import com.tcoded.playerbountiesplus.hook.logging.CoreProtectHook;
import com.tcoded.playerbountiesplus.hook.currency.EconomyHook;
import com.tcoded.playerbountiesplus.hook.team.TeamHook;
import com.tcoded.playerbountiesplus.listener.BountyHeadLabelListener;
import com.tcoded.playerbountiesplus.listener.BountyHeadListener;
import com.tcoded.playerbountiesplus.listener.BountyIncreasePromptListener;
import com.tcoded.playerbountiesplus.listener.DeathListener;
import com.tcoded.playerbountiesplus.listener.GuiProtectionListener;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import com.tcoded.playerbountiesplus.util.BountyHeadFormatter;
import com.tcoded.playerbountiesplus.util.BountyHeadMetadata;
import com.tcoded.playerbountiesplus.util.LangUtil;
import net.luckperms.api.LuckPerms;
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.utilitiesog.UtilitiesOG;
public final class PlayerBountiesOG extends JavaPlugin {
// Plugin instance declaration.
private static PlayerBountiesOG instance;
public static PlayerBountiesOG getInstance() {
return instance;
}
public static String getPrefix() {
return "&7[&cPlayerBounties&f-&4OG&7] ";
}
// Utilities.
private LangUtil langUtil;
private BountyHeadFormatter bountyHeadFormatter;
private BountyHeadMetadata bountyHeadMetadata;
// Managers.
private BountyDataManager bountyDataManager;
// Hooks.
private EconomyHook ecoHook;
private TeamHook teamHook;
// DiamondBank-OG Economy.
private DiamondBankAPIJava diamondBankAPI;
// LuckPerms API hook.
private LuckPerms luckPerms;
// CoreProtect API hook.
private CoreProtectHook coreProtectHook;
private BountyIncreasePromptListener bountyIncreasePromptListener;
private BountyHeadLabelListener bountyHeadLabelListener;
public PlayerBountiesOG() {
instance = this;
}
@Override
public void onEnable() {
// Config
saveDefaultConfig();
// Initialize the LuckPerms API.
final RegisteredServiceProvider<LuckPerms> luckPermsProvider = getServer().getServicesManager()
.getRegistration(LuckPerms.class);
if (luckPermsProvider != null) {
this.luckPerms = luckPermsProvider.getProvider();
} else {
getLogger().warning(
"LuckPerms not found – bounty claim announcements will not include rank colors or prefixes.");
}
this.coreProtectHook = new CoreProtectHook(this);
if (!this.coreProtectHook.isEnabled()) {
getLogger().warning(
"CoreProtect API v10+ not found - custom bounty head metadata may not rollback correctly.");
}
// Initialize the DiamondBank-OG API.
final RegisteredServiceProvider<DiamondBankAPIJava> provider = getServer().getServicesManager()
.getRegistration(DiamondBankAPIJava.class);
// If the DiamondBank-OG API failed to initialize, do this...
if (provider == null) {
// Tell Bukkit to disable this plugin, and inform the console.
disableSelf("DiamondBank-OG API is null – disabling " + getPluginMeta().getName() + "!");
return;
}
// Assign the active instance of DiamondBank-OG to the API handler.
this.diamondBankAPI = provider.getProvider();
// Utils.
this.reloadLang();
this.bountyHeadFormatter = new BountyHeadFormatter(this.diamondBankAPI, this.luckPerms);
this.bountyHeadMetadata = new BountyHeadMetadata(this);
// Managers.
this.bountyDataManager = new BountyDataManager(this);
this.bountyDataManager.init();
// Economy Hooks.
registerDefaultEcoHooks();
// Team Hooks.
this.teamHook = TeamHook.findTeamHook(this);
if (this.teamHook == null) {
getLogger().warning(
"There is no supported team/clan/party plugin on the server! Feel free to request support for the plugin you use on GitHub or Discord!");
}
// Commands.
final PluginCommand bountyCmd = this.getCommand("bounty");
if (bountyCmd != null) {
final BountyCommand bountyExec = new BountyCommand(this, diamondBankAPI);
bountyCmd.setExecutor(bountyExec);
bountyCmd.setTabCompleter(bountyExec);
}
final PluginCommand adminCmd = this.getCommand("playerbountiesplusadmin");
if (adminCmd != null) {
final PlayerBountiesPlusAdminCmd adminExec = new PlayerBountiesPlusAdminCmd(this);
adminCmd.setExecutor(adminExec);
adminCmd.setTabCompleter(adminExec);
}
// Listeners.
this.getServer().getPluginManager().registerEvents(new DeathListener(this), this);
this.bountyIncreasePromptListener = new BountyIncreasePromptListener(this);
this.getServer().getPluginManager().registerEvents(new BountyHeadListener(this), this);
this.bountyHeadLabelListener = new BountyHeadLabelListener(this);
this.getServer().getPluginManager().registerEvents(this.bountyHeadLabelListener, this);
this.getServer().getPluginManager().registerEvents(this.bountyIncreasePromptListener, this);
this.getServer().getPluginManager().registerEvents(new GuiProtectionListener(this), this);
}
public void reloadLang() {
this.langUtil = new LangUtil(this, StringUtils.lowerCase(this.getConfig().getString("lang", "en_us")));
}
@Override
public void onDisable() {
if (this.bountyHeadLabelListener != null) {
this.bountyHeadLabelListener.shutdown();
}
HandlerList.unregisterAll(this);
UtilitiesOG.logToConsole(getPrefix(), "PlayerBounties-OG has been shut down successfully!");
}
public EconomyHook getEcoHook() {
if (this.ecoHook == null) {
throw new IllegalStateException("Economy hook is not initialized. DiamondBank-OG may be unavailable.");
}
return this.ecoHook;
}
public TeamHook getTeamHook() {
return teamHook;
}
public BountyDataManager getBountyDataManager() {
return bountyDataManager;
}
public LangUtil getLang() {
return this.langUtil;
}
public LuckPerms getLuckPerms() {
return this.luckPerms;
}
public CoreProtectHook getCoreProtectHook() {
return this.coreProtectHook;
}
public BountyHeadFormatter getBountyHeadFormatter() {
return this.bountyHeadFormatter;
}
public BountyHeadMetadata getBountyHeadMetadata() {
return this.bountyHeadMetadata;
}
public BountyIncreasePromptListener getBountyIncreasePromptListener() {
return this.bountyIncreasePromptListener;
}
private void registerDefaultEcoHooks() {
final ServicesManager servicesManager = getServer().getServicesManager();
// De-register old hook.
servicesManager.unregisterAll(this);
// Initialize the DiamondBank-OG hook with the active plugin instance.
final DiamondBankOGHook diamondBankOGHook = new DiamondBankOGHook(getInstance(), diamondBankAPI);
// Set DiamondBank-OG as the active economy implementation used by
// commands/listeners.
this.ecoHook = diamondBankOGHook;
// Register the DiamondBank-OG hook as the active economy hook.
servicesManager.register(EconomyHook.class, diamondBankOGHook, this, ServicePriority.Low);
}
// Helps this plugin kill itself gracefully (in minecraft).
public static void disableSelf(String reason) {
// Run a meta-task on the Bukkit server outside of the context of this plugin.
Bukkit.getScheduler().runTask(Bukkit.getServer().getPluginManager().getPlugin("PlayerBounties-OG"), () -> {
// Attempt to fetch the active instance of this plugin.
final PlayerBountiesOG pluginInstance = getInstance();
// If this plugin is already disabled, do this...
if (!pluginInstance.isEnabled()) {
// Do nothing, task already completed.
return;
}
// Inform console of this plugin being disabled.
UtilitiesOG.logToConsole(getPrefix(), reason);
// Commit sudoku.
Bukkit.getPluginManager().disablePlugin(pluginInstance);
});
}
}
@@ -0,0 +1,224 @@
package com.tcoded.playerbountiesplus;
import com.google.common.collect.ImmutableList;
import com.tcoded.folialib.FoliaLib;
import com.tcoded.lightlibs.updatechecker.SimpleUpdateChecker;
import com.tcoded.playerbountiesplus.command.BountyCommand;
import com.tcoded.playerbountiesplus.command.PlayerBountiesPlusAdminCmd;
import com.tcoded.playerbountiesplus.hook.currency.EconomyHook;
import com.tcoded.playerbountiesplus.hook.currency.DummyEcoHook;
import com.tcoded.playerbountiesplus.hook.currency.VaultHook;
import com.tcoded.playerbountiesplus.hook.placeholder.PlaceholderHook;
import com.tcoded.playerbountiesplus.hook.team.AbstractTeamHook;
import com.tcoded.playerbountiesplus.hook.team.TeamHook;
import com.tcoded.playerbountiesplus.listener.DeathListener;
import com.tcoded.playerbountiesplus.listener.GuiListener;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import com.tcoded.playerbountiesplus.util.LangUtil;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.ChatColor;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.event.HandlerList;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.ServicesManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.List;
public final class PlayerBountiesPlus extends JavaPlugin {
// Instance
private static PlayerBountiesPlus instance;
public static PlayerBountiesPlus getInstance() {
return instance;
}
// Utils
private FoliaLib foliaLib;
private LangUtil langUtil;
// Managers
private BountyDataManager bountyDataManager;
// Hooks
private EconomyHook ecoHook;
private TeamHook teamHook;
private PlaceholderHook placeholderHook;
public PlayerBountiesPlus() {
instance = this;
}
@Override
public void onEnable() {
// Config
saveDefaultConfig();
FileConfiguration config = this.getConfig();
// Utils
this.foliaLib = new FoliaLib(this);
this.reloadLang();
// Managers
this.bountyDataManager = new BountyDataManager(this);
this.bountyDataManager.init();
// Economy Hooks
registerDefaultEcoHooks();
if (!applyEcoHookRegistration()) return;
// Team Hooks
this.teamHook = TeamHook.findTeamHook(this);
if (this.teamHook == null) {
getLogger().warning("There is no supported team/clan/party plugin on the server! Feel free to request support for the plugin you use on GitHub or Discord!");
}
// Placeholder Hooks
this.placeholderHook = PlaceholderHook.findPlaceholderHook(this);
this.placeholderHook.enable();
// Commands
PluginCommand bountyCmd = this.getCommand("bounty");
if (bountyCmd != null) {
BountyCommand bountyExec = new BountyCommand(this);
bountyCmd.setExecutor(bountyExec);
bountyCmd.setTabCompleter(bountyExec);
}
PluginCommand adminCmd = this.getCommand("playerbountiesplusadmin");
if (adminCmd != null) {
PlayerBountiesPlusAdminCmd adminExec = new PlayerBountiesPlusAdminCmd(this);
adminCmd.setExecutor(adminExec);
adminCmd.setTabCompleter(adminExec);
}
// Listeners
this.getServer().getPluginManager().registerEvents(new DeathListener(this), this);
this.getServer().getPluginManager().registerEvents(new GuiListener(), this);
// Update checker
checkUpdate();
// bStats
Metrics metrics = new Metrics(this, 19617);
metrics.addCustomChart(new SimplePie("config_lang", () -> langUtil.getLang()));
metrics.addCustomChart(new SimplePie("datafolder_customlang", () -> Boolean.toString(langUtil.isCustomLang())));
metrics.addCustomChart(new SimplePie("hook_teamhook", () -> teamHook == null ? "None" : teamHook.getPluginName() + " (" + teamHook.getAuthor() + ")"));
metrics.addCustomChart(new SimplePie("server_isfolia", () -> Boolean.toString(foliaLib.isFolia())));
List<Plugin> plugins = ImmutableList.copyOf(this.getServer().getPluginManager().getPlugins());
findPluginWithQuery(plugins, metrics, "team");
findPluginWithQuery(plugins, metrics, "teams");
findPluginWithQuery(plugins, metrics, "clan");
findPluginWithQuery(plugins, metrics, "clans");
findPluginWithQuery(plugins, metrics, "party", "voteparty");
findPluginWithQuery(plugins, metrics, "parties");
findPluginWithQuery(plugins, metrics, "guild");
findPluginWithQuery(plugins, metrics, "guilds");
}
public void reloadLang() {
this.langUtil = new LangUtil(this, this.getConfig().getString("lang", "en_us").toLowerCase());
}
public void checkUpdate() {
SimpleUpdateChecker.checkUpdate(
this,
ChatColor.translateAlternateColorCodes('&', "&f[&bPlayerBountiesPlus&f] "),
108637,
runnable -> this.getFoliaLib().getScheduler().runAsync(wt -> runnable.run())
);
}
@Override
public void onDisable() {
HandlerList.unregisterAll(this);
this.placeholderHook.disable();
}
public EconomyHook getEcoHook() {
return this.ecoHook;
}
public TeamHook getTeamHook() {
return teamHook;
}
public PlaceholderHook getPlaceholderHook() {
return placeholderHook;
}
public BountyDataManager getBountyDataManager() {
return bountyDataManager;
}
public FoliaLib getFoliaLib() {
return this.foliaLib;
}
public LangUtil getLang() {
return this.langUtil;
}
// Utils
private static void findPluginWithQuery(List<Plugin> plugins, Metrics metrics, String pluginNameQuery, String... excludeStrings) {
String firstPluginFound = plugins.stream()
.filter(p -> {
String lowerName = p.getName().toLowerCase();
// If the plugin name doesn't contain the query, skip
if (!lowerName.contains(pluginNameQuery)) return false;
// If the plugin name contains any of the exclude strings, skip
for (String excludeString : excludeStrings) {
if (lowerName.contains(excludeString)) return false;
}
return true;
})
.findFirst()
.map(p -> {
List<String> authors = p.getDescription().getAuthors();
return p.getName() + " (" + (authors.isEmpty() ? "N/A" : authors.get(0)) + ")";
}).orElse(null);
if (firstPluginFound == null) return;
metrics.addCustomChart(new SimplePie("plugins_query_" + pluginNameQuery, () -> firstPluginFound));
}
private void registerDefaultEcoHooks() {
ServicesManager servicesManager = getServer().getServicesManager();
// Unregister old eco hooks
servicesManager.unregisterAll(this);
// Register vault economy hook
VaultHook vaultEcoHook = new VaultHook(this);
boolean ecoPresent = vaultEcoHook.init();
// Register or fallback
if (ecoPresent) servicesManager.register(EconomyHook.class, vaultEcoHook, this, ServicePriority.Low);
else servicesManager.register(EconomyHook.class, new DummyEcoHook(), this, ServicePriority.Lowest);
}
public boolean applyEcoHookRegistration() {
// Get economy hook
ServicesManager servicesManager = getServer().getServicesManager();
RegisteredServiceProvider<EconomyHook> ecoHookProvider = servicesManager.getRegistration(EconomyHook.class);
if (ecoHookProvider == null) {
getLogger().severe("No economy hook is present! Aborting startup!");
return false;
}
String hookName = ecoHookProvider.getProvider().getClass().getSimpleName();
String hookPluginName = ecoHookProvider.getPlugin().getName();
getLogger().info("Using economy hook: " + hookName + " from plugin: " + hookPluginName);
this.ecoHook = ecoHookProvider.getProvider();
return true;
}
}
@@ -1,141 +1,78 @@
package com.tcoded.playerbountiesplus.command;
import com.google.common.collect.Lists;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.command.bounty.BountyCheckCmd;
import com.tcoded.playerbountiesplus.command.bounty.BountySetCmd;
import com.tcoded.playerbountiesplus.command.bounty.BountyTopCmd;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.Lists;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.command.bounty.BountyCheckCmd;
import com.tcoded.playerbountiesplus.command.bounty.BountyAddCmd;
import com.tcoded.playerbountiesplus.command.bounty.BountySetCmd;
import com.tcoded.playerbountiesplus.command.bounty.BountyTopCmd;
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.utilitiesog.UtilitiesOG;
public class BountyCommand implements CommandExecutor, TabCompleter {
private final PlayerBountiesOG plugin;
private final DiamondBankAPIJava diamondBankAPI;
public BountyCommand(PlayerBountiesOG plugin, DiamondBankAPIJava diamondBankAPI) {
private PlayerBountiesPlus plugin;
public BountyCommand(PlayerBountiesPlus plugin) {
this.plugin = plugin;
this.diamondBankAPI = diamondBankAPI;
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String cmdName, String[] args) {
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), "&cERROR: Only players can use this command.");
return true;
}
if (args.length < 1) {
if (StringUtils.equalsIgnoreCase(cmdName, "bounties")) {
return BountyTopCmd.handleCmd(plugin, diamondBankAPI, sender, cmd, cmdName, args);
}
final String noAction = plugin.getLang().getColored("command.bounty.no-action");
UtilitiesOG.trueogMessage((Player) sender, noAction);
sender.sendMessage(plugin.getLang().getColored("command.bounty.no-action"));
return true;
}
final String action = StringUtils.lowerCase(args[0]);
String action = args[0].toLowerCase();
switch (action) {
case "set" -> {
case "set":
return BountySetCmd.handleCmd(plugin, sender, cmd, cmdName, args);
}
case "add" -> {
return BountyAddCmd.handleCmd(plugin, sender, cmd, cmdName, args);
}
case "top" -> {
return BountyTopCmd.handleCmd(plugin, diamondBankAPI, sender, cmd, cmdName, args);
}
case "check" -> {
case "top":
return BountyTopCmd.handleCmd(plugin, sender, cmd, cmdName, args);
case "check":
return BountyCheckCmd.handleCmd(plugin, sender, cmd, cmdName, args);
}
default -> {
// If "/bounty" is run without a valid subcommand, treat it as "/bounty top".
return BountyTopCmd.handleCmd(plugin, diamondBankAPI, sender, cmd, cmdName, args);
}
default:
sender.sendMessage(plugin.getLang().getColored("command.bounty.invalid-action"));
}
return true;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] args)
{
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 1) {
return Lists.newArrayList("set", "add", "top", "check").stream()
.filter(action -> StringUtils.startsWith(action, StringUtils.lowerCase(args[0])))
return Lists.newArrayList("set", "top", "check").stream()
.filter(action -> action.startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
} else if (args.length > 1) {
final String subCommand = StringUtils.lowerCase(args[0]);
return switch (subCommand) {
case "set" -> BountySetCmd
.onTabComplete(sender, args).stream().filter(suggestion -> StringUtils
.startsWith(StringUtils.lowerCase(suggestion), StringUtils.lowerCase(args[1])))
.collect(Collectors.toList());
case "add" -> BountyAddCmd
.onTabComplete(sender, args).stream().filter(suggestion -> StringUtils
.startsWith(StringUtils.lowerCase(suggestion), StringUtils.lowerCase(args[1])))
.collect(Collectors.toList());
case "check" -> BountyCheckCmd
.onTabComplete(sender, args).stream().filter(suggestion -> StringUtils
.startsWith(StringUtils.lowerCase(suggestion), StringUtils.lowerCase(args[1])))
.collect(Collectors.toList());
case "top" -> Collections.emptyList();
default -> Collections.emptyList();
};
String subCommand = args[0].toLowerCase();
switch (subCommand) {
case "set":
return BountySetCmd.onTabComplete(sender, args).stream()
.filter(suggestion -> suggestion.toLowerCase().startsWith(args[1].toLowerCase()))
.collect(Collectors.toList());
case "check":
return BountyCheckCmd.onTabComplete(sender, args).stream()
.filter(suggestion -> suggestion.toLowerCase().startsWith(args[1].toLowerCase()))
.collect(Collectors.toList());
case "top":
return Collections.emptyList(); // No additional arguments for top
default:
return Collections.emptyList();
}
}
return Collections.emptyList();
}
}
}
@@ -1,122 +1,90 @@
package com.tcoded.playerbountiesplus.command;
import com.google.common.collect.Lists;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.command.admin.PlayerBountiesPlusReloadCmd;
import com.tcoded.playerbountiesplus.command.admin.PlayerBountiesPlusVersionCmd;
import com.tcoded.playerbountiesplus.command.admin.bounty.AdminBountyCmd;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.Lists;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.command.admin.PlayerBountiesPlusReloadCmd;
import com.tcoded.playerbountiesplus.command.admin.PlayerBountiesPlusVersionCmd;
import com.tcoded.playerbountiesplus.command.admin.bounty.AdminBountyCmd;
import net.trueog.utilitiesog.UtilitiesOG;
public class PlayerBountiesPlusAdminCmd implements CommandExecutor, TabCompleter {
private static final ArrayList<String> completions = Lists.newArrayList("reload", "version", "bounty", "help");
private final PlayerBountiesOG plugin;
public PlayerBountiesPlusAdminCmd(PlayerBountiesOG plugin) {
private final PlayerBountiesPlus plugin;
public PlayerBountiesPlusAdminCmd(PlayerBountiesPlus plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] args)
{
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length < 1) {
sendHelpMsg(sender);
return true;
}
final String arg0Lower = StringUtils.lowerCase(args[0]);
return switch (arg0Lower) {
case "reload" -> PlayerBountiesPlusReloadCmd.handleCmd(plugin, sender, command, label, args);
case "version" -> PlayerBountiesPlusVersionCmd.handleCmd(plugin, sender, command, label, args);
case "bounty" -> AdminBountyCmd.handleCmd(plugin, sender, command, label, args);
default -> {
String arg0Lower = args[0].toLowerCase();
switch (arg0Lower) {
case "reload":
return PlayerBountiesPlusReloadCmd.handleCmd(plugin, sender, command, label, args);
case "version":
return PlayerBountiesPlusVersionCmd.handleCmd(plugin, sender, command, label, args);
case "bounty":
return AdminBountyCmd.handleCmd(plugin, sender, command, label, args);
default:
sendHelpMsg(sender);
yield true;
}
};
return true;
}
}
private void sendHelpMsg(CommandSender sender) {
final String help = """
&f[&bPlayerBountiesPlus&f] &7PlayerBountiesPlus by TechnicallyCoded
&fAdmin Commands:
&f/pbp reload &7- Reload the configuration file and the messages.
&f/pbp version &7- Check the version of the plugin.
&f/pbp bounty set <player> <amount> &7- Set a player's bounty.
&f/pbp bounty add <player> <amount> &7- Add to a player's bounty.
&f/pbp bounty remove <player> <amount> &7- Remove from a player's bounty.
&f/pbp bounty delete <player> &7- Delete a player's bounty.
&f/pbp help &7- Get this message.\
""";
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), help);
} else {
UtilitiesOG.trueogMessage((Player) sender, help);
}
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',
"&f[&bPlayerBountiesPlus&f] &7PlayerBountiesPlus by TechnicallyCoded\n" +
"&fAdmin Commands:\n" +
"&f/pbp reload &7- Reload the configuration file and the messages.\n" +
"&f/pbp version &7- Check the version of the plugin.\n" +
"&f/pbp bounty set <player> <amount> &7- Set a player's bounty.\n" +
"&f/pbp bounty add <player> <amount> &7- Add to a player's bounty.\n" +
"&f/pbp bounty remove <player> <amount> &7- Remove from a player's bounty.\n" +
"&f/pbp bounty delete <player> &7- Delete a player's bounty.\n" +
"&f/pbp help &7- Get this message."
));
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] args)
{
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 1) {
return completions.stream()
.filter(s -> StringUtils.startsWith(StringUtils.lowerCase(s), StringUtils.lowerCase(args[0])))
.filter(s -> s.toLowerCase().startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
} else if (args.length > 1) {
final String subCommand = StringUtils.lowerCase(args[0]);
return switch (subCommand) {
case "bounty" -> AdminBountyCmd.onTabComplete(sender, args);
case "version" -> PlayerBountiesPlusVersionCmd.onTabComplete(sender, args);
case "reload", "help" -> Collections.emptyList();
default -> Collections.emptyList();
};
String subCommand = args[0].toLowerCase();
switch (subCommand) {
case "bounty":
return AdminBountyCmd.onTabComplete(sender, args);
case "version":
return PlayerBountiesPlusVersionCmd.onTabComplete(sender, args);
case "reload":
case "help":
return Collections.emptyList(); // No additional arguments for reload or help
default:
return Collections.emptyList();
}
}
return Collections.emptyList();
}
}
}
@@ -1,74 +1,43 @@
package com.tcoded.playerbountiesplus.command.admin;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import net.trueog.utilitiesog.UtilitiesOG;
public class PlayerBountiesPlusReloadCmd implements TabCompleter {
private static final String RELOAD_PERMISSION = "playerbountiesog.command.admin.reload";
private static final String RELOAD_PERMISSION = "playerbountiesplus.command.playerbountiesplus.reload";
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String cmdName,
String[] args)
{
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String cmdName, String[] args) {
if (!sender.hasPermission(RELOAD_PERMISSION)) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm).replace("{permission}", RELOAD_PERMISSION);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPermDetailed);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPermDetailed);
}
String noPerm = plugin.getLang().getColored("command.no-permission");
String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", RELOAD_PERMISSION);
sender.sendMessage(noPermDetailed);
return true;
}
plugin.reloadConfig();
plugin.reloadLang();
plugin.checkUpdate();
final String reloadMessage = plugin.getLang().getColored("command.admin.reload.reloaded");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), reloadMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, reloadMessage);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.reload.reloaded"));
return true;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] args)
{
// No additional arguments for reload command.
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
// No additional arguments for reload command
return Collections.emptyList();
}
}
}
@@ -1,58 +1,41 @@
package com.tcoded.playerbountiesplus.command.admin;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.util.LangUtil;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.Collections;
import java.util.List;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.util.LangUtil;
import net.trueog.utilitiesog.UtilitiesOG;
public class PlayerBountiesPlusVersionCmd {
private static final String VERSION_PERMISSION = "playerbountiesog.command.admin.version";
private static final String VERSION_PERMISSION = "playerbountiesplus.command.playerbountiesplus.version";
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String cmdName,
String[] args)
{
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String cmdName, String[] args) {
LangUtil lang = plugin.getLang();
final LangUtil lang = plugin.getLang();
final String version;
String version;
if (sender.hasPermission(VERSION_PERMISSION)) {
version = "v" + plugin.getPluginMeta().getVersion();
version = "v" + plugin.getDescription().getVersion();
} else {
version = "\n" + lang.getColored("command.admin.version.no-permission");
}
if (sender instanceof Player player) {
UtilitiesOG.trueogMessage(player, PlayerBountiesOG.getPrefix()
+ "&6 Authors: &aTechnicallyCoded, NotAlexNoyle &6Version: &e" + version);
} else {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(),
"Authors: TechnicallyCoded, NotAlexNoyle Version: " + version);
}
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',
"&f[&bPlayerBountiesPlus&f] Plugin Information:\n" +
"&fPlugin: &7Running PlayerBountiesPlus " + version + "\n" +
"&fAuthor: &7TechnicallyCoded\n" +
"&fUpdate URL: &9https://www.spigotmc.org/resources/player-bounties-plus.108637/"
));
return true;
}
public static List<String> onTabComplete(CommandSender sender, String[] args) {
// No sub-commands for version, return empty list.
// No sub-commands for version, return empty list
return Collections.emptyList();
}
}
}
@@ -1,167 +1,77 @@
package com.tcoded.playerbountiesplus.command.admin.bounty;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import net.trueog.utilitiesog.UtilitiesOG;
public class AdminBountyAddCmd {
private static final String PERMISSION = "playerbountiesog.command.admin.bounty.add";
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String label,
String[] args)
{
private static final String PERMISSION = "playerbountiesplus.command.admin.bounty.add";
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission(PERMISSION)) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm).replace("{permission}", PERMISSION);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPermDetailed);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPermDetailed);
}
String noPerm = plugin.getLang().getColored("command.no-permission");
String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", PERMISSION);
sender.sendMessage(noPermDetailed);
return true;
}
if (args.length < 4) {
final String missingArguments = plugin.getLang().getColored("command.admin.bounty.add.missing-args");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), missingArguments);
} else {
UtilitiesOG.trueogMessage((Player) sender, missingArguments);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.add.missing-args"));
return true;
}
final String playerName = args[2];
final double amount;
String playerName = args[2];
int amount;
try {
amount = parseAmount(args[3]);
} catch (NumberFormatException numberFormatException) {
final String notNumber = plugin.getLang().getColored("command.admin.bounty.add.amount-nan");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), notNumber);
} else {
UtilitiesOG.trueogMessage((Player) sender, notNumber);
}
amount = Integer.parseInt(args[3]);
} catch (NumberFormatException ex) {
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.add.amount-nan"));
return true;
}
final OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
if (target == null || (!target.hasPlayedBefore() && !target.isOnline())) {
final String playerNotFound = plugin.getLang().getColored("command.admin.bounty.add.player-not-found");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), playerNotFound);
} else {
UtilitiesOG.trueogMessage((Player) sender, playerNotFound);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.add.player-not-found"));
return true;
}
final UUID uuid = target.getUniqueId();
final BountyDataManager m = plugin.getBountyDataManager();
final double current = m.getBounty(uuid);
final double total = current + amount;
UUID uuid = target.getUniqueId();
BountyDataManager m = plugin.getBountyDataManager();
int current = m.getBounty(uuid);
int total = current + amount;
m.setBounty(uuid, total);
m.saveBountiesAsync();
final String bountyAdded = plugin.getLang().getColored("command.admin.bounty.add.success")
.replace("{target}", target.getName()).replace("{amount}", String.valueOf(amount))
.replace("{total}", String.valueOf(total));
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), bountyAdded);
} else {
UtilitiesOG.trueogMessage((Player) sender, bountyAdded);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.add.success")
.replace("{target}", target.getName())
.replace("{amount}", String.valueOf(amount))
.replace("{total}", String.valueOf(total)));
return true;
}
private static double parseAmount(String amountInput) {
if (!amountInput.matches("^\\d+(?:\\.\\d)?$")) {
throw new NumberFormatException("Invalid amount format");
}
return Double.parseDouble(amountInput);
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args)
{
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 3) {
// Suggest all online player names for the username.
return sender.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
// Suggest all online player names for the username
return sender.getServer().getOnlinePlayers().stream()
.map(player -> player.getName())
.collect(Collectors.toList());
} else if (args.length == 4) {
// Suggest a placeholder for the amount.
// Suggest a placeholder for the amount
return Collections.singletonList("<amount>");
}
return Collections.emptyList();
}
}
}
@@ -1,98 +1,69 @@
package com.tcoded.playerbountiesplus.command.admin.bounty;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import net.trueog.utilitiesog.UtilitiesOG;
public class AdminBountyCmd {
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String label,
String[] args)
{
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String label, String[] args) {
if (args.length < 2) {
final String noAction = plugin.getLang().getColored("command.bounty.no-action");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noAction);
} else {
UtilitiesOG.trueogMessage((Player) sender, noAction);
}
sender.sendMessage(plugin.getLang().getColored("command.bounty.no-action"));
return true;
}
final String action = StringUtils.lowerCase(args[1]);
return switch (action) {
case "set" -> AdminBountySetCmd.handleCmd(plugin, sender, cmd, label, args);
case "add" -> AdminBountyAddCmd.handleCmd(plugin, sender, cmd, label, args);
case "remove" -> AdminBountyRemoveCmd.handleCmd(plugin, sender, cmd, label, args);
case "delete" -> AdminBountyDeleteCmd.handleCmd(plugin, sender, cmd, label, args);
case "get" -> AdminBountyGetCmd.handleCmd(plugin, sender, cmd, label, args);
default -> {
final String invalidAction = plugin.getLang().getColored("command.bounty.invalid-action");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), invalidAction);
} else {
UtilitiesOG.trueogMessage((Player) sender, invalidAction);
}
yield true;
}
};
String action = args[1].toLowerCase();
switch (action) {
case "set":
return AdminBountySetCmd.handleCmd(plugin, sender, cmd, label, args);
case "add":
return AdminBountyAddCmd.handleCmd(plugin, sender, cmd, label, args);
case "remove":
return AdminBountyRemoveCmd.handleCmd(plugin, sender, cmd, label, args);
case "delete":
return AdminBountyDeleteCmd.handleCmd(plugin, sender, cmd, label, args);
case "get":
return AdminBountyGetCmd.handleCmd(plugin, sender, cmd, label, args);
default:
sender.sendMessage(plugin.getLang().getColored("command.bounty.invalid-action"));
return true;
}
}
public static List<String> onTabComplete(CommandSender sender, String[] args) {
List<String> suggestions = Collections.emptyList();
if (args.length == 2) {
suggestions = Arrays.asList("set", "add", "remove", "delete", "get");
} else if (args.length > 2) {
final String sub = StringUtils.lowerCase(args[1]);
String sub = args[1].toLowerCase();
switch (sub) {
case "add" -> suggestions = AdminBountyAddCmd.onTabComplete(sender, null, null, args);
case "remove" -> suggestions = AdminBountyRemoveCmd.onTabComplete(sender, null, null, args);
case "delete" -> suggestions = AdminBountyDeleteCmd.onTabComplete(sender, null, null, args);
case "get" -> suggestions = AdminBountyGetCmd.onTabComplete(sender, null, null, args);
case "set" -> suggestions = AdminBountySetCmd.onTabComplete(sender, null, null, args);
case "add":
suggestions = AdminBountyAddCmd.onTabComplete(sender, null, null, args);
break;
case "remove":
suggestions = AdminBountyRemoveCmd.onTabComplete(sender, null, null, args);
break;
case "delete":
suggestions = AdminBountyDeleteCmd.onTabComplete(sender, null, null, args);
break;
case "get":
suggestions = AdminBountyGetCmd.onTabComplete(sender, null, null, args);
break;
case "set":
suggestions = AdminBountySetCmd.onTabComplete(sender, null, null, args);
break;
}
}
final String input = StringUtils.lowerCase(args[args.length - 1]);
return suggestions.stream().filter(opt -> StringUtils.startsWith(StringUtils.lowerCase(opt), input))
String input = args[args.length - 1].toLowerCase();
return suggestions.stream()
.filter(opt -> opt.toLowerCase().startsWith(input))
.collect(Collectors.toList());
}
}
}
@@ -1,10 +1,7 @@
package com.tcoded.playerbountiesplus.command.admin.bounty;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
@@ -12,110 +9,55 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import net.trueog.utilitiesog.UtilitiesOG;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class AdminBountyDeleteCmd {
private static final String PERMISSION = "playerbountiesog.command.admin.bounty.delete";
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String label,
String[] args)
{
private static final String PERMISSION = "playerbountiesplus.command.admin.bounty.delete";
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission(PERMISSION)) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm).replace("{permission}", PERMISSION);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPermDetailed);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPermDetailed);
}
String noPerm = plugin.getLang().getColored("command.no-permission");
String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", PERMISSION);
sender.sendMessage(noPermDetailed);
return true;
}
if (args.length < 3) {
final String missingArguments = plugin.getLang().getColored("command.admin.bounty.delete.missing-args");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), missingArguments);
} else {
UtilitiesOG.trueogMessage((Player) sender, missingArguments);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.delete.missing-args"));
return true;
}
final String playerName = args[2];
final OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
String playerName = args[2];
OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
if (target == null || (!target.hasPlayedBefore() && !target.isOnline())) {
final String playerNotFound = plugin.getLang().getColored("command.admin.bounty.delete.player-not-found");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), playerNotFound);
} else {
UtilitiesOG.trueogMessage((Player) sender, playerNotFound);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.delete.player-not-found"));
return true;
}
final UUID uuid = target.getUniqueId();
final BountyDataManager bountyData = plugin.getBountyDataManager();
bountyData.removeBounty(uuid);
bountyData.saveBountiesAsync();
final String bountyDeletedMessage = plugin.getLang().getColored("command.admin.bounty.delete.success")
.replace("{target}", target.getName());
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), bountyDeletedMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, bountyDeletedMessage);
}
UUID uuid = target.getUniqueId();
BountyDataManager m = plugin.getBountyDataManager();
m.removeBounty(uuid);
m.saveBountiesAsync();
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.delete.success")
.replace("{target}", target.getName()));
return true;
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args)
{
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 3) {
// Suggest all online player names for the username.
return sender.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
// Suggest all online player names for the username
return sender.getServer().getOnlinePlayers().stream()
.map(Player::getName)
.collect(Collectors.toList());
}
return Collections.emptyList();
}
}
}
@@ -1,120 +1,63 @@
package com.tcoded.playerbountiesplus.command.admin.bounty;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import net.trueog.utilitiesog.UtilitiesOG;
public class AdminBountyGetCmd {
private static final String PERMISSION = "playerbountiesog.command.admin.bounty.get";
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String label,
String[] args)
{
private static final String PERMISSION = "playerbountiesplus.command.admin.bounty.get";
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission(PERMISSION)) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm).replace("{permission}", PERMISSION);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPermDetailed);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPermDetailed);
}
String noPerm = plugin.getLang().getColored("command.no-permission");
String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", PERMISSION);
sender.sendMessage(noPermDetailed);
return true;
}
if (args.length < 3) {
final String missingArguments = plugin.getLang().getColored("command.admin.bounty.get.missing-args");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), missingArguments);
} else {
UtilitiesOG.trueogMessage((Player) sender, missingArguments);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.get.missing-args"));
return true;
}
final String playerName = args[2];
String playerName = args[2];
final OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
if (target == null || (!target.hasPlayedBefore() && !target.isOnline())) {
final String playerNotFound = plugin.getLang().getColored("command.admin.bounty.get.player-not-found");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), playerNotFound);
} else {
UtilitiesOG.trueogMessage((Player) sender, playerNotFound);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.get.player-not-found"));
return true;
}
final UUID uuid = target.getUniqueId();
final BountyDataManager m = plugin.getBountyDataManager();
final double current = m.getBounty(uuid);
final String bountyFetch = plugin.getLang().getColored("command.admin.bounty.get.success")
.replace("{target}", target.getName()).replace("{bounty}", String.valueOf(current));
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), bountyFetch);
} else {
UtilitiesOG.trueogMessage((Player) sender, bountyFetch);
}
UUID uuid = target.getUniqueId();
BountyDataManager m = plugin.getBountyDataManager();
int current = m.getBounty(uuid);
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.get.success")
.replace("{target}", target.getName())
.replace("{bounty}", String.valueOf(current)));
return true;
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args)
{
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 3) {
// Suggest all online player names for the username.
return sender.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
// Suggest all online player names for the username
return sender.getServer().getOnlinePlayers().stream()
.map(player -> player.getName())
.collect(Collectors.toList());
}
return Collections.emptyList();
}
}
}
@@ -1,175 +1,82 @@
package com.tcoded.playerbountiesplus.command.admin.bounty;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import net.trueog.utilitiesog.UtilitiesOG;
public class AdminBountyRemoveCmd {
private static final String PERMISSION = "playerbountiesog.command.admin.bounty.remove";
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String label,
String[] args)
{
private static final String PERMISSION = "playerbountiesplus.command.admin.bounty.remove";
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission(PERMISSION)) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm).replace("{permission}", PERMISSION);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPermDetailed);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPermDetailed);
}
String noPerm = plugin.getLang().getColored("command.no-permission");
String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", PERMISSION);
sender.sendMessage(noPermDetailed);
return true;
}
if (args.length < 4) {
final String missingArguments = plugin.getLang().getColored("command.admin.bounty.remove.missing-args");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), missingArguments);
} else {
UtilitiesOG.trueogMessage((Player) sender, missingArguments);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.remove.missing-args"));
return true;
}
final String playerName = args[2];
final double amount;
String playerName = args[2];
int amount;
try {
amount = parseAmount(args[3]);
} catch (NumberFormatException numberFormatException) {
final String notNumberMessage = plugin.getLang().getColored("command.admin.bounty.remove.amount-nan");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), notNumberMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, notNumberMessage);
}
amount = Integer.parseInt(args[3]);
} catch (NumberFormatException ex) {
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.remove.amount-nan"));
return true;
}
final OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
if (target == null || (!target.hasPlayedBefore() && !target.isOnline())) {
final String playerNotFound = plugin.getLang().getColored("command.admin.bounty.remove.player-not-found");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), playerNotFound);
} else {
UtilitiesOG.trueogMessage((Player) sender, playerNotFound);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.remove.player-not-found"));
return true;
}
final UUID uuid = target.getUniqueId();
final BountyDataManager m = plugin.getBountyDataManager();
final double current = m.getBounty(uuid);
double total = current - amount;
UUID uuid = target.getUniqueId();
BountyDataManager m = plugin.getBountyDataManager();
int current = m.getBounty(uuid);
int total = current - amount;
if (total <= 0) {
m.removeBounty(uuid);
total = 0;
} else {
m.setBounty(uuid, total);
}
m.saveBountiesAsync();
final String bountyRemovedMessage = plugin.getLang().getColored("command.admin.bounty.remove.success")
.replace("{target}", target.getName()).replace("{amount}", String.valueOf(amount))
.replace("{total}", String.valueOf(total));
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), bountyRemovedMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, bountyRemovedMessage);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.remove.success")
.replace("{target}", target.getName())
.replace("{amount}", String.valueOf(amount))
.replace("{total}", String.valueOf(total)));
return true;
}
private static double parseAmount(String amountInput) {
if (!amountInput.matches("^\\d+(?:\\.\\d)?$")) {
throw new NumberFormatException("Invalid amount format");
}
return Double.parseDouble(amountInput);
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args)
{
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 3) {
// Suggest all online player names for the username.
return sender.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
// Suggest all online player names for the username
return sender.getServer().getOnlinePlayers().stream()
.map(player -> player.getName())
.collect(Collectors.toList());
} else if (args.length == 4) {
// Suggest a placeholder for the amount.
// Suggest a placeholder for the amount
return Collections.singletonList("<amount>");
}
return Collections.emptyList();
}
}
}
@@ -1,161 +1,74 @@
package com.tcoded.playerbountiesplus.command.admin.bounty;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import net.trueog.utilitiesog.UtilitiesOG;
public class AdminBountySetCmd {
private static final String PERMISSION = "playerbountiesog.command.admin.bounty.set";
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String label,
String[] args)
{
private static final String PERMISSION = "playerbountiesplus.command.admin.bounty.set";
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String label, String[] args) {
if (!sender.hasPermission(PERMISSION)) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm).replace("{permission}", PERMISSION);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPermDetailed);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPermDetailed);
}
String noPerm = plugin.getLang().getColored("command.no-permission");
String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", PERMISSION);
sender.sendMessage(noPermDetailed);
return true;
}
if (args.length < 4) {
final String missingArguments = plugin.getLang().getColored("command.admin.bounty.set.missing-args");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), missingArguments);
} else {
UtilitiesOG.trueogMessage((Player) sender, missingArguments);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.set.missing-args"));
return true;
}
final String playerName = args[2];
final double amount;
String playerName = args[2];
int amount;
try {
amount = parseAmount(args[3]);
} catch (NumberFormatException numberFormatException) {
final String notNumberMessage = plugin.getLang().getColored("command.admin.bounty.set.amount-nan");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), notNumberMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, notNumberMessage);
}
amount = Integer.parseInt(args[3]);
} catch (NumberFormatException ex) {
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.set.amount-nan"));
return true;
}
final OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
OfflinePlayer target = plugin.getServer().getOfflinePlayer(playerName);
if (target == null || (!target.hasPlayedBefore() && !target.isOnline())) {
final String playerNotFound = plugin.getLang().getColored("command.admin.bounty.set.player-not-found");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), playerNotFound);
} else {
UtilitiesOG.trueogMessage((Player) sender, playerNotFound);
}
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.set.player-not-found"));
return true;
}
final UUID uuid = target.getUniqueId();
final BountyDataManager dataManager = plugin.getBountyDataManager();
dataManager.setBounty(uuid, amount);
dataManager.saveBountiesAsync();
final String bountySetMessage = plugin.getLang().getColored("command.admin.bounty.set.success")
.replace("{target}", target.getName()).replace("{bounty}", String.valueOf(amount));
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), bountySetMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, bountySetMessage);
}
UUID uuid = target.getUniqueId();
BountyDataManager m = plugin.getBountyDataManager();
m.setBounty(uuid, amount);
m.saveBountiesAsync();
sender.sendMessage(plugin.getLang().getColored("command.admin.bounty.set.success")
.replace("{target}", target.getName())
.replace("{bounty}", String.valueOf(amount)));
return true;
}
private static double parseAmount(String amountInput) {
if (!amountInput.matches("^\\d+(?:\\.\\d)?$")) {
throw new NumberFormatException("Invalid amount format");
}
return Double.parseDouble(amountInput);
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
@NotNull String label, @NotNull String[] args)
{
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 3) {
// Suggest all online player names for the username.
return sender.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
// Suggest all online player names for the username
return sender.getServer().getOnlinePlayers().stream()
.map(player -> player.getName())
.collect(Collectors.toList());
} else if (args.length == 4) {
// Suggest a placeholder for the amount.
// Suggest a placeholder for the amount
return Collections.singletonList("<amount>");
}
return Collections.emptyList();
}
}
}
@@ -1,365 +0,0 @@
package com.tcoded.playerbountiesplus.command.bounty;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import com.tcoded.playerbountiesplus.util.BountyWorldUtil;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.cacheddata.CachedMetaData;
import net.luckperms.api.model.user.User;
import net.trueog.diamondbankog.DiamondBankException.EconomyDisabledException;
import net.trueog.diamondbankog.DiamondBankException.InsufficientFundsException;
import net.trueog.diamondbankog.DiamondBankException.InvalidPlayerException;
import net.trueog.diamondbankog.DiamondBankException.PlayerNotOnlineException;
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.utilitiesog.UtilitiesOG;
public class BountyAddCmd {
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String cmdName,
String[] args)
{
if (!(sender instanceof Player player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), "&cERROR: Only players can use this command.");
return true;
}
if (!sender.hasPermission("playerbountiesog.command.bounty.add")) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", "playerbountiesog.command.bounty.add");
UtilitiesOG.trueogMessage(player, noPermDetailed);
return true;
}
if (!BountyWorldUtil.isBountyWorldAllowed(plugin, player)) {
UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.world-not-whitelisted")
.replace("{worlds}", BountyWorldUtil.formatBountyWorldWhitelist(plugin)));
return true;
}
if (args.length < 3) {
UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.missing-args"));
return true;
}
final String targetNameArg = args[1];
final double amount;
try {
amount = parseAmount(args[2]);
} catch (NumberFormatException numberFormatException) {
UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.amount-nan"));
return true;
}
final OfflinePlayer target = Bukkit.getOfflinePlayer(targetNameArg);
if (target.getUniqueId() != null) {
return addBounty(plugin, player, target.getUniqueId(), target.getName(), amount, true);
}
UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.player-not-found"));
return true;
}
public static boolean addBounty(PlayerBountiesOG plugin, Player setter, UUID targetUuid, String targetName,
double parsedAmount, boolean saveData)
{
if (!BountyWorldUtil.isBountyWorldAllowed(plugin, setter)) {
UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.world-not-whitelisted")
.replace("{worlds}", BountyWorldUtil.formatBountyWorldWhitelist(plugin)));
return true;
}
final String safeTargetName = StringUtils.defaultIfBlank(targetName,
Bukkit.getOfflinePlayer(targetUuid).getName());
if (safeTargetName == null || safeTargetName.isBlank()) {
UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.add.player-not-found"));
return true;
}
final DiamondBankAPIJava diamondBankAPI = resolveDiamondBankApi(plugin);
final double minimum = plugin.getConfig().getDouble("bounty-minimum", 1.0);
if (parsedAmount < minimum) {
UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.set.under-minimum")
.replace("{minimum}", String.valueOf(minimum)));
return true;
}
final double maximum = plugin.getConfig().getDouble("bounty-maximum", 1000000.0);
if (parsedAmount > maximum) {
UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.set.over-maximum")
.replace("{maximum}", String.valueOf(maximum)));
return true;
}
final long addedShards = diamondBankAPI.diamondsToShards((float) parsedAmount);
if (addedShards <= 0L) {
UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.set.internal-invalid-value"));
return true;
}
if (!chargeSetter(plugin, setter, diamondBankAPI, safeTargetName, addedShards)) {
return true;
}
final BountyDataManager bountyDataManager = plugin.getBountyDataManager();
final long existingShards = diamondBankAPI.diamondsToShards((float) bountyDataManager.getBounty(targetUuid));
final long totalShards = existingShards + addedShards;
final double totalBounty = Double.parseDouble(diamondBankAPI.shardsToDiamonds(totalShards));
bountyDataManager.setBounty(targetUuid, totalBounty);
final LuckPerms luckPerms = resolveLuckPerms(plugin);
final String setterDisplay = formatLuckPermsDisplay(luckPerms, setter);
final String targetDisplay = resolveLuckPermsDisplayName(luckPerms, targetUuid, safeTargetName);
final String addedDisplay = diamondBankAPI.shardsToDiamonds(addedShards);
final String totalDisplay = diamondBankAPI.shardsToDiamonds(totalShards);
UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.add.success")
.replace("{amount}", addedDisplay).replace("{target}", targetDisplay).replace("{total}", totalDisplay));
if (plugin.getConfig().getBoolean("bounty-placed-announce", true)) {
final String announce = plugin.getLang().getColored("command.bounty.add.announce")
.replace("{amount}", addedDisplay).replace("{target}", targetDisplay)
.replace("{total}", totalDisplay).replace("{player}", setterDisplay);
Bukkit.getOnlinePlayers().forEach(
player -> UtilitiesOG.trueogMessage(player, PlayerBountiesOG.getPrefix() + "&a" + announce));
}
if (saveData) {
bountyDataManager.saveBountiesAsync();
}
return true;
}
private static boolean chargeSetter(PlayerBountiesOG plugin, Player setter, DiamondBankAPIJava diamondBankAPI,
String targetName, long addedShards)
{
try {
diamondBankAPI.consumeFromPlayer(setter.getUniqueId(), addedShards,
"Player " + setter.getName() + " contributed " + diamondBankAPI.shardsToDiamonds(addedShards)
+ " Diamonds toward a bounty on " + targetName + ".",
"Plugin: PlayerBounties-OG");
return true;
} catch (EconomyDisabledException economyDisabledException) {
PlayerBountiesOG.disableSelf(
"[PlayerBounties-OG] DiamondBank-OG economy disabled: " + economyDisabledException.getMessage());
return false;
} catch (InvalidPlayerException invalidPlayerException) {
plugin.getLogger().warning("Invalid player for consumeFromPlayer: " + setter.getName());
UtilitiesOG.trueogMessage(setter,
"&cERROR: your player account could not be found by DiamondBank-OG. Contact an administrator!");
return false;
} catch (InsufficientFundsException insufficientFundsException) {
UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.set.not-enough-money"));
return false;
}
// TODO: Remove PlayerNotOnlineException catch block after next DiamondBank-OG
// update.
catch (PlayerNotOnlineException temporaryPlayerNotOnlineError) {
plugin.getLogger().warning("Player " + setter.getName()
+ " not online when attempting to consumeFromPlayer. This error is expected to be removed in the next DiamondBank-OG update.");
temporaryPlayerNotOnlineError.printStackTrace();
return false;
}
}
private static double parseAmount(String amountInput) {
if (!amountInput.matches("^\\d+(?:\\.\\d)?$")) {
throw new NumberFormatException("Invalid amount format");
}
return Double.parseDouble(amountInput);
}
private static DiamondBankAPIJava resolveDiamondBankApi(PlayerBountiesOG plugin) {
final RegisteredServiceProvider<DiamondBankAPIJava> provider = plugin.getServer().getServicesManager()
.getRegistration(DiamondBankAPIJava.class);
if (provider == null) {
throw new IllegalStateException("DiamondBank-OG API is null");
}
return provider.getProvider();
}
private static LuckPerms resolveLuckPerms(PlayerBountiesOG plugin) {
final RegisteredServiceProvider<LuckPerms> provider = plugin.getServer().getServicesManager()
.getRegistration(LuckPerms.class);
return provider == null ? null : provider.getProvider();
}
private static String resolveLuckPermsDisplayName(LuckPerms luckPerms, UUID playerId, String playerName) {
final String safeName = StringUtils.defaultIfBlank(playerName, "Unknown Player");
if (luckPerms == null) {
return "&f" + safeName;
}
final User user = luckPerms.getUserManager().getUser(playerId);
if (user == null) {
return "&f" + safeName;
}
final CachedMetaData meta = user.getCachedData().getMetaData();
final String prefix = StringUtils.trim(StringUtils.defaultString(meta.getPrefix()).replace('§', '&'));
final String suffix = StringUtils.trim(StringUtils.defaultString(meta.getSuffix()).replace('§', '&'));
final boolean metaContainsName = containsVisibleName(prefix, safeName) || containsVisibleName(suffix, safeName);
final StringBuilder out = new StringBuilder();
if (!prefix.isBlank()) {
out.append(prefix).append(' ');
}
if (!metaContainsName) {
out.append(safeName);
}
if (!suffix.isBlank()) {
out.append(' ').append(suffix);
}
return sanitizeDisplay(out.toString(), safeName);
}
private static String formatLuckPermsDisplay(LuckPerms luckPerms, Player player) {
return resolveLuckPermsDisplayName(luckPerms, player.getUniqueId(), player.getName());
}
private static String sanitizeDisplay(String formatted, String fallbackName) {
final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", "")
.replaceAll("\\s*>$", "");
return cleaned.isBlank() ? fallbackName : cleaned;
}
private static boolean containsVisibleName(String text, String playerName) {
if (text == null || playerName == null || playerName.isBlank()) {
return false;
}
final String normalizedText = StringUtils.lowerCase(UtilitiesOG.stripFormatting(text), Locale.ROOT);
final String normalizedName = StringUtils.lowerCase(playerName, Locale.ROOT);
return StringUtils.contains(normalizedText, normalizedName);
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull String[] args) {
if (args.length == 2) {
return sender.getServer().getOnlinePlayers().stream().map(Player::getName)
.filter(name -> StringUtils.startsWith(StringUtils.lowerCase(name), StringUtils.lowerCase(args[1])))
.collect(Collectors.toList());
} else if (args.length == 3) {
return Collections.singletonList("<amount>");
}
return Collections.emptyList();
}
}
@@ -1,163 +1,68 @@
package com.tcoded.playerbountiesplus.command.bounty;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import net.trueog.utilitiesog.UtilitiesOG;
public class BountyCheckCmd {
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String cmdName,
String[] args)
{
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String cmdName, String[] args) {
if (args.length < 2) {
final String noPlayerSpecifiedMessage = plugin.getLang()
.getColored("command.bounty.check.no-player-specified");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPlayerSpecifiedMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPlayerSpecifiedMessage);
}
sender.sendMessage(plugin.getLang().getColored("command.bounty.check.no-player-specified"));
return true;
}
final String playerNameArg = args[1];
String playerNameArg = args[1];
final UUID targetUuid;
final String targetName;
final Player onlineTarget = plugin.getServer().getPlayerExact(playerNameArg);
if (onlineTarget != null) {
targetUuid = onlineTarget.getUniqueId();
targetName = onlineTarget.getName();
} else {
final OfflinePlayer offlineTarget = resolveOfflineTarget(playerNameArg);
if (offlineTarget == null) {
final String playerNotFoundMessage = plugin.getLang()
.getColored("command.bounty.check.player-not-found");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), playerNotFoundMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, playerNotFoundMessage);
}
return true;
}
targetUuid = offlineTarget.getUniqueId();
targetName = StringUtils.defaultIfBlank(offlineTarget.getName(), playerNameArg);
Player target = plugin.getServer().getPlayerExact(playerNameArg);
if (target == null) {
sender.sendMessage(plugin.getLang().getColored("command.bounty.check.player-not-found"));
return true;
}
final BountyDataManager bountyDataManager = plugin.getBountyDataManager();
final boolean hasBounty = bountyDataManager.hasBounty(targetUuid);
UUID playerUUID = target.getUniqueId();
BountyDataManager bountyDataManager = plugin.getBountyDataManager();
boolean hasBounty = bountyDataManager.hasBounty(playerUUID);
if (hasBounty) {
final double bounty = bountyDataManager.getBounty(targetUuid);
final String formattedBounty = plugin.getBountyHeadFormatter().formatDiamonds(bounty) + " Diamonds";
final String bountyFoundMessage = plugin.getLang().getColored("command.bounty.check.bounty-found")
.replace("{target}", targetName).replace("{bounty}", formattedBounty);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), bountyFoundMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, bountyFoundMessage);
}
// Confirmation
int bounty = bountyDataManager.getBounty(playerUUID);
sender.sendMessage(
plugin.getLang().getColored("command.bounty.check.bounty-found")
.replace("{target}", target.getName())
.replace("{bounty}", Integer.toString(bounty))
);
} else {
final String noBountyFoundMessage = plugin.getLang().getColored("command.bounty.check.no-bounty")
.replace("{target}", targetName);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noBountyFoundMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, noBountyFoundMessage);
}
sender.sendMessage(
plugin.getLang().getColored("command.bounty.check.no-bounty")
.replace("{target}", target.getName())
);
}
return true;
}
private static OfflinePlayer resolveOfflineTarget(String name) {
for (OfflinePlayer candidate : Bukkit.getOfflinePlayers()) {
if (StringUtils.equalsIgnoreCase(candidate.getName(), name)) {
return candidate;
}
}
return Bukkit.getOfflinePlayerIfCached(name);
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull String[] args) {
if (args.length != 2) {
return Collections.emptyList();
if (args.length == 2) {
// Suggest online player names for the username
return sender.getServer().getOnlinePlayers().stream()
.map(Player::getName)
.filter(name -> name.toLowerCase().startsWith(args[1].toLowerCase()))
.collect(Collectors.toList());
}
final String prefix = StringUtils.lowerCase(args[1]);
final PlayerBountiesOG plugin = PlayerBountiesOG.getInstance();
final BountyDataManager bountyDataManager = plugin == null ? null : plugin.getBountyDataManager();
final Stream<String> onlineNames = sender.getServer().getOnlinePlayers().stream().map(Player::getName);
final Stream<String> offlineBountyNames = bountyDataManager == null ? Stream.empty()
: bountyDataManager.getBounties().keySet().stream().map(Bukkit::getOfflinePlayer)
.map(OfflinePlayer::getName).filter(name -> name != null && !name.isBlank());
return Stream.concat(onlineNames, offlineBountyNames).distinct()
.filter(name -> StringUtils.startsWith(StringUtils.lowerCase(name), prefix))
.collect(Collectors.toList());
return Collections.emptyList();
}
}
}
@@ -1,434 +1,152 @@
package com.tcoded.playerbountiesplus.command.bounty;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.event.BountySetEvent;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.event.BountySetEvent;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import com.tcoded.playerbountiesplus.util.BountyWorldUtil;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.cacheddata.CachedMetaData;
import net.luckperms.api.model.user.User;
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.utilitiesog.UtilitiesOG;
public class BountySetCmd {
public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String cmdName,
String[] args)
{
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String cmdName, String[] args) {
if (args.length < 3) {
final String missingArgumentsMessage = plugin.getLang().getColored("command.bounty.set.missing-args");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), missingArgumentsMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, missingArgumentsMessage);
}
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.missing-args"));
return true;
}
if (sender instanceof Player && !sender.hasPermission("playerbountiesog.command.bounty.set")) {
final String noPerm = plugin.getLang().getColored("command.no-permission");
final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
if (sender instanceof Player && !sender.hasPermission("playerbountiesplus.command.bounty.set")) {
String noPerm = plugin.getLang().getColored("command.no-permission");
String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed")
.replace("{no-permission-msg}", noPerm)
.replace("{permission}", "playerbountiesog.command.bounty.set");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), noPermDetailed);
} else {
UtilitiesOG.trueogMessage((Player) sender, noPermDetailed);
}
.replace("{permission}", "playerbountiesplus.command.bounty.set");
sender.sendMessage(noPermDetailed);
return true;
}
if (sender instanceof Player player && !BountyWorldUtil.isBountyWorldAllowed(plugin, player)) {
UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.world-not-whitelisted")
.replace("{worlds}", BountyWorldUtil.formatBountyWorldWhitelist(plugin)));
return true;
}
final String playerNameArg = args[1];
final double parsedAmount;
String playerNameArg = args[1];
float amount;
try {
parsedAmount = parseAmount(args[2]);
} catch (NumberFormatException numberFormatException) {
final String notNumberMessage = plugin.getLang().getColored("command.bounty.set.amount-nan");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), notNumberMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, notNumberMessage);
}
amount = Integer.parseInt(args[2]);
} catch (NumberFormatException ex) {
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.amount-nan"));
return true;
}
final Player target = plugin.getServer().getPlayerExact(playerNameArg);
Player target = plugin.getServer().getPlayerExact(playerNameArg);
if (target == null) {
final String playerNotFoundMessage = plugin.getLang().getColored("command.bounty.set.player-not-found");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), playerNotFoundMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, playerNotFoundMessage);
}
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.player-not-found"));
return true;
}
// Check limits.
final double minimum = plugin.getConfig().getDouble("bounty-minimum", 1.0);
if (parsedAmount < minimum) {
final String underMinimumMessage = plugin.getLang().getColored("command.bounty.set.under-minimum")
.replace("{minimum}", String.valueOf(minimum));
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), underMinimumMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, underMinimumMessage);
}
// Check limits
double minimum = plugin.getConfig().getDouble("bounty-minimum", 1.0);
if (amount < minimum) {
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.under-minimum")
.replace("{minimum}", String.valueOf(minimum))
);
return true;
}
final double maximum = plugin.getConfig().getDouble("bounty-maximum", 1000000.0);
if (parsedAmount > maximum) {
final String overMaximumMessage = plugin.getLang().getColored("command.bounty.set.over-maximum")
.replace("{maximum}", String.valueOf(maximum));
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), overMaximumMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, overMaximumMessage);
}
double maximum = plugin.getConfig().getDouble("bounty-maximum", 1000000.0);
if (amount > maximum) {
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.over-maximum")
.replace("{maximum}", String.valueOf(minimum))
);
return true;
}
// Apply bounty multiplier.
double amount = parsedAmount * plugin.getConfig().getDouble("bounty-multiplier", 1.0);
// Check money
if (sender instanceof Player) {
Player player = (Player) sender;
boolean allowed = plugin.getEcoHook().takeEco(player, amount);
// Trigger bounty set event.
final BountySetEvent event = new BountySetEvent(sender instanceof Player ? (Player) sender : null, target,
(float) amount);
if (!allowed) {
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.not-enough-money"));
return true;
}
}
// Apply bounty multiplier
amount *= (float) plugin.getConfig().getDouble("bounty-multiplier", 1.0);
// Trigger bounty set event
BountySetEvent event = new BountySetEvent(sender instanceof Player ? (Player) sender : null, target, amount);
plugin.getServer().getPluginManager().callEvent(event);
amount = event.getAmount();
// Check if event was cancelled.
// Check if event was cancelled
if (event.isCancelled()) {
final String cancelledBounty = plugin.getLang().getColored("command.bounty.set.cancelled");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), cancelledBounty);
} else {
UtilitiesOG.trueogMessage((Player) sender, cancelledBounty);
}
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.cancelled"));
return true;
}
// Sanity check final amount.
// Sanity check final amount
if (amount <= 0) {
final String invalidValueMessage = plugin.getLang().getColored("command.bounty.set.internal-invalid-value");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), invalidValueMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, invalidValueMessage);
}
sender.sendMessage(plugin.getLang().getColored("command.bounty.set.internal-invalid-value"));
return true;
}
// Check economy. Only charge if sender is a player.
if (sender instanceof Player player) {
UUID playerUUID = target.getUniqueId();
final boolean allowed = plugin.getEcoHook().takeEco(player, target, amount);
if (!allowed) {
final String notEnoughDiamondsMessage = plugin.getLang()
.getColored("command.bounty.set.not-enough-money");
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), notEnoughDiamondsMessage);
} else {
UtilitiesOG.trueogMessage((Player) sender, notEnoughDiamondsMessage);
}
return true;
}
}
final UUID playerUUID = target.getUniqueId();
// Calculate total bounty including previous bounties.
final BountyDataManager bountyDataManager = plugin.getBountyDataManager();
final DiamondBankAPIJava diamondBankAPI = resolveDiamondBankApi(plugin);
final long newBountyShards = diamondBankAPI.diamondsToShards(amount);
final long existingBountyShards = diamondBankAPI
.diamondsToShards((float) bountyDataManager.getBounty(playerUUID));
final long totalBountyShards = newBountyShards + existingBountyShards;
final double totalBounty = Double.parseDouble(diamondBankAPI.shardsToDiamonds(totalBountyShards));
// Calculate total bounty including previous bounties
BountyDataManager bountyDataManager = plugin.getBountyDataManager();
int bountyAlreadyPresent = bountyDataManager.getBounty(playerUUID);
int totalBounty = ((int) amount) + bountyAlreadyPresent;
bountyDataManager.setBounty(playerUUID, totalBounty);
// Announcement.
final String extra;
if (existingBountyShards == 0L) {
extra = "";
} else {
extra = plugin.getLang().getColored("command.bounty.set.announce-extra").replace("{total}",
diamondBankAPI.shardsToDiamonds(totalBountyShards));
// Confirmation
sender.sendMessage(
plugin.getLang().getColored("command.bounty.set.success")
.replace("{bounty}", String.valueOf(amount))
.replace("{total}", String.valueOf(totalBounty))
.replace("{target}", target.getName())
.replace("{player}", sender.getName())
);
// Announce
String extra;
if (bountyAlreadyPresent == 0) extra = "";
else {
extra = plugin.getLang().getColored("command.bounty.set.announce-extra")
.replace("{total}", String.valueOf(totalBounty));
}
if (plugin.getConfig().getBoolean("bounty-placed-announce", true)) {
final LuckPerms luckPerms = resolveLuckPerms(plugin);
final String setterDisplay = sender instanceof Player player ? formatLuckPermsDisplay(luckPerms, player)
: sender.getName();
final String targetDisplay = formatLuckPermsDisplay(luckPerms, target);
final String bountyDisplay = diamondBankAPI.shardsToDiamonds(newBountyShards);
Bukkit.getOnlinePlayers()
.forEach((Player player) -> UtilitiesOG.trueogMessage(player,
PlayerBountiesOG.getPrefix() + "&a"
+ plugin.getLang().getColored("command.bounty.set.announce")
.replace("{bounty}", bountyDisplay).replace("{target}", targetDisplay)
.replace("{player}", setterDisplay).replace("{extra}", extra)));
plugin.getServer().broadcastMessage(
plugin.getLang().getColored("command.bounty.set.announce")
.replace("{bounty}", String.valueOf(amount))
.replace("{target}", target.getName())
.replace("{player}", sender.getName())
.replace("{extra}", extra)
);
}
bountyDataManager.saveBountiesAsync();
return true;
}
private static double parseAmount(String amountInput) {
if (!amountInput.matches("^\\d+(?:\\.\\d)?$")) {
throw new NumberFormatException("Invalid amount format");
}
return Double.parseDouble(amountInput);
}
private static DiamondBankAPIJava resolveDiamondBankApi(PlayerBountiesOG plugin) {
final RegisteredServiceProvider<DiamondBankAPIJava> provider = plugin.getServer().getServicesManager()
.getRegistration(DiamondBankAPIJava.class);
if (provider == null) {
throw new IllegalStateException("DiamondBank-OG API is null");
}
return provider.getProvider();
}
private static LuckPerms resolveLuckPerms(PlayerBountiesOG plugin) {
final RegisteredServiceProvider<LuckPerms> provider = plugin.getServer().getServicesManager()
.getRegistration(LuckPerms.class);
return provider == null ? null : provider.getProvider();
}
private static String formatLuckPermsDisplay(LuckPerms luckPerms, Player player) {
final String prefix = stripLeadingReset(stripTrailingReset(getLuckPermsPrefixLegacy(luckPerms, player)));
final String leadingColorCodes = extractLeadingColorCodes(prefix);
if (prefix.isBlank()) {
return player.getName().replaceAll("\\s*>$", "");
}
if (leadingColorCodes.isBlank()) {
return (prefix + " " + player.getName()).replaceAll("\\s*>$", "");
}
return (prefix + " " + leadingColorCodes + player.getName()).replaceAll("\\s*>$", "");
}
private static String getLuckPermsPrefixLegacy(LuckPerms luckPerms, Player player) {
if (luckPerms == null) {
return "";
}
final User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) {
return "";
}
final CachedMetaData meta = user.getCachedData().getMetaData();
final String prefix = meta.getPrefix();
if (prefix == null || prefix.isBlank()) {
return "";
}
return StringUtils.trim(prefix).replace('§', '&');
}
private static String stripTrailingReset(String input) {
if (input == null || input.isBlank()) {
return "";
}
return StringUtils.trim(input.replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", ""));
}
private static String stripLeadingReset(String input) {
if (input == null || input.isBlank()) {
return "";
}
return StringUtils.trim(input.replaceFirst("(?i)^(?:\\s*(?:<reset>|[&§]r))+", ""));
}
private static String extractLeadingColorCodes(String input) {
if (input == null || input.length() < 2) {
return "";
}
final StringBuilder out = new StringBuilder();
for (int i = 0; i < input.length() - 1; i++) {
final char current = input.charAt(i);
if (current != '&' && current != '§') {
break;
}
out.append(current).append(input.charAt(i + 1));
i++;
}
return out.toString();
}
@Nullable
public static List<String> onTabComplete(@NotNull CommandSender sender, @NotNull String[] args) {
if (args.length == 2) {
// Suggest online player names for the username.
return sender.getServer().getOnlinePlayers().stream().map(Player::getName)
.filter(name -> StringUtils.startsWith(StringUtils.lowerCase(name), StringUtils.lowerCase(args[1])))
// Suggest online player names for the username
return sender.getServer().getOnlinePlayers().stream()
.map(Player::getName)
.filter(name -> name.toLowerCase().startsWith(args[1].toLowerCase()))
.collect(Collectors.toList());
} else if (args.length == 3) {
// Suggest a placeholder for the amount.
// Suggest a placeholder for the amount
return Collections.singletonList("<amount>");
}
return Collections.emptyList();
}
}
@@ -1,145 +1,47 @@
package com.tcoded.playerbountiesplus.command.bounty;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.OfflinePlayer;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.gui.MainBountyGui;
import com.tcoded.playerbountiesplus.util.BountyHeadFormatter;
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.utilitiesog.UtilitiesOG;
import java.util.*;
public class BountyTopCmd {
public static boolean handleCmd(PlayerBountiesOG plugin, DiamondBankAPIJava diamondBankAPI, CommandSender sender,
Command cmd, String cmdName, String[] args)
{
public static boolean handleCmd(PlayerBountiesPlus plugin, CommandSender sender, Command cmd, String cmdName, String[] args) {
if (sender instanceof Player player) {
Set<Map.Entry<UUID, Integer>> bountiesSet = plugin.getBountyDataManager().getBounties().entrySet();
List<Map.Entry<UUID, Integer>> bounties = new ArrayList<>(bountiesSet);
bounties.sort((a, b) -> b.getValue() - a.getValue());
final List<MainBountyGui.BountyGuiEntry> entries = buildGuiEntries(plugin);
new MainBountyGui(plugin, player, () -> entries, diamondBankAPI).open();
StringBuilder strb = new StringBuilder();
strb.append(plugin.getLang().getColored("command.bounty.top.top-10") + "\n");
return true;
int bountiesSize = bounties.size();
int maxInList = Math.min(10, bountiesSize);
}
sendTextTopList(plugin, diamondBankAPI, sender);
return true;
}
private static List<MainBountyGui.BountyGuiEntry> buildGuiEntries(PlayerBountiesOG plugin) {
final BountyHeadFormatter formatter = plugin.getBountyHeadFormatter();
final Set<Map.Entry<UUID, Double>> bountiesSet = plugin.getBountyDataManager().getBounties().entrySet();
final List<Map.Entry<UUID, Double>> bounties = new ArrayList<>(bountiesSet);
bounties.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
final List<MainBountyGui.BountyGuiEntry> entries = new ArrayList<>();
for (Map.Entry<UUID, Double> entry : bounties) {
if (entry.getValue() == null || entry.getValue() <= 0D) {
continue;
}
final OfflinePlayer offlinePlayer = plugin.getServer().getOfflinePlayer(entry.getKey());
String targetName = offlinePlayer.getName();
if (targetName == null || targetName.isBlank()) {
targetName = "Unknown Player";
}
final String displayName = formatter.resolvePlayerDisplay(entry.getKey(), targetName);
entries.add(new MainBountyGui.BountyGuiEntry(entry.getKey(), targetName, displayName, entry.getValue()));
}
return entries;
}
private static void sendTextTopList(PlayerBountiesOG plugin, DiamondBankAPIJava diamondBankAPI,
CommandSender sender)
{
final BountyHeadFormatter formatter = plugin.getBountyHeadFormatter();
final Set<Map.Entry<UUID, Double>> bountiesSet = plugin.getBountyDataManager().getBounties().entrySet();
final List<Map.Entry<UUID, Double>> bounties = new ArrayList<>(bountiesSet);
bounties.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
final StringBuilder strb = new StringBuilder();
strb.append(plugin.getLang().getColored("command.bounty.top.top-10")).append('\n');
final int bountiesSize = bounties.size();
final int maxInList = Math.min(10, bountiesSize);
if (bountiesSize > 0) {
for (int i = 0; i < maxInList; i++) {
final Map.Entry<UUID, Double> entry = bounties.get(i);
final OfflinePlayer offlinePlayer = plugin.getServer().getOfflinePlayer(entry.getKey());
String targetName = offlinePlayer.getName();
if (targetName == null || targetName.isBlank()) {
targetName = "Unknown Player";
}
final String formattedBounty = diamondBankAPI
.shardsToDiamonds(diamondBankAPI.diamondsToShards(entry.getValue()));
strb.append("&7 - ");
final String displayName = formatter.resolvePlayerDisplay(entry.getKey(), targetName);
strb.append(displayName);
strb.append(": &b");
strb.append(formattedBounty);
strb.append(" &bDiamonds");
strb.append(ChatColor.GRAY);
strb.append(" - ");
Map.Entry<UUID, Integer> entry = bounties.get(i);
strb.append(plugin.getServer().getOfflinePlayer(entry.getKey()).getName());
strb.append(": ");
strb.append(entry.getValue());
strb.append('\n');
}
} else {
strb.append(plugin.getLang().getColored("command.bounty.top.no-bounties")).append('\n');
}
else {
strb.append(plugin.getLang().getColored("command.bounty.top.no-bounties") + "\n");
}
String message = strb.toString();
message = StringUtils.substring(message, 0, message.length() - 1);
if (!(sender instanceof Player)) {
UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), message);
} else {
UtilitiesOG.trueogMessage((Player) sender, message);
}
message = message.substring(0, message.length() - 1); // remove last \n
sender.sendMessage(message);
return true;
}
}
}
@@ -17,57 +17,41 @@ public class BountyClaimEvent extends Event implements Cancellable {
private boolean cancelled;
public BountyClaimEvent(@NotNull Player claimant, @NotNull Player victim, double amount) {
this.claimant = claimant;
this.victim = victim;
this.amount = amount;
this.cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
public Player getClaimant() {
return claimant;
}
public Player getVictim() {
return victim;
}
public double getAmount() {
return amount;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
@@ -17,67 +17,48 @@ public class BountySetEvent extends Event implements Cancellable {
private boolean cancelled;
public BountySetEvent(Player setter, @NotNull Player target, float amount) {
this.setter = setter;
this.target = target;
this.amount = amount;
this.cancelled = false;
}
/**
* @return The player who set the bounty or null if it's set by console/command
* block.
* @return The player who set the bounty or null if it's set by console/command block.
*/
public Player getSetter() {
return setter;
}
public Player getTarget() {
return target;
}
public double getAmount() {
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@Override
public @NotNull HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}
}
@@ -0,0 +1,14 @@
package com.tcoded.playerbountiesplus.gui;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.InventoryHolder;
public interface IPbpGui extends InventoryHolder {
void open();
void setContents();
void handleClick(InventoryClickEvent event);
}
@@ -1,426 +1,50 @@
package com.tcoded.playerbountiesplus.gui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Material;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
public class MainBountyGui implements IPbpGui {
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.gxui.GUIBase;
import net.trueog.gxui.GUIButton;
import net.trueog.gxui.GUIItem;
import net.trueog.utilitiesog.UtilitiesOG;
import net.kyori.adventure.text.TextComponent;
public class MainBountyGui extends GUIBase {
private static final List<Integer> PYRAMID_SLOTS = List.of(4, 12, 13, 14, 20, 21, 22, 23, 24, 28, 29, 30, 31, 32,
33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44);
private static final int PREVIOUS_PAGE_SLOT = 47;
private static final int PAGE_INFO_SLOT = 49;
private static final int NEXT_PAGE_SLOT = 51;
private static final int CLOSE_SLOT = 53;
private final PlayerBountiesOG plugin;
private final PlayerBountiesPlus plugin;
private final Player viewer;
private final Supplier<List<BountyGuiEntry>> bountySupplier;
private final DiamondBankAPIJava diamondBankAPI;
private final int page;
public MainBountyGui(PlayerBountiesOG plugin, Player viewer, Supplier<List<BountyGuiEntry>> bountySupplier,
DiamondBankAPIJava diamondBankAPI)
{
this(plugin, viewer, bountySupplier, 0, diamondBankAPI);
}
private MainBountyGui(PlayerBountiesOG plugin, Player viewer, Supplier<List<BountyGuiEntry>> bountySupplier,
int page, DiamondBankAPIJava diamondBankAPITransporter)
{
super(plugin, viewer, plugin.getLang().getColored("gui.main.title"), 54, true);
private final Inventory inventory;
public MainBountyGui(PlayerBountiesPlus plugin, Player viewer) {
this.plugin = plugin;
this.viewer = viewer;
this.bountySupplier = bountySupplier;
this.diamondBankAPI = diamondBankAPITransporter;
this.page = Math.max(0, page);
}
public void open() {
super.open(false);
// Create inventory
this.inventory = Bukkit.createInventory(
this,
9 * 3,
plugin.getLang().getColored("gui.main.title")
);
}
@Override
public void setupItems() {
final List<BountyGuiEntry> sortedBounties = getSortedBounties();
final int maxPage = getMaxPage(sortedBounties);
final int currentPage = Math.min(page, maxPage);
addNavigationItems(currentPage, maxPage, sortedBounties.size());
if (sortedBounties.isEmpty()) {
addItem(22,
createStaticItem(Material.WRITABLE_BOOK, "&6&lNo Active Bounties",
List.of(UtilitiesOG.trueogColorize("&7Nobody currently has a bounty."),
UtilitiesOG.trueogColorize("&7Place one with your bounty command to get"),
UtilitiesOG.trueogColorize("&7this leaderboard populated again."))));
return;
}
final int startIndex = currentPage * PYRAMID_SLOTS.size();
final int endIndex = Math.min(startIndex + PYRAMID_SLOTS.size(), sortedBounties.size());
int pyramidIndex = 0;
for (int i = startIndex; i < endIndex; i++) {
final BountyGuiEntry entry = sortedBounties.get(i);
final int globalRank = i + 1;
addItem(PYRAMID_SLOTS.get(pyramidIndex), createBountyItem(entry, globalRank));
pyramidIndex++;
}
public Inventory getInventory() {
return this.inventory;
}
private void addNavigationItems(int currentPage, int maxPage, int totalBounties) {
if (currentPage > 0) {
addItem(PREVIOUS_PAGE_SLOT, createButtonItem(Material.ARROW, "&a&lPrevious Page",
List.of(UtilitiesOG.trueogColorize("&7Go to page &f" + currentPage)), new GUIButton()
{
@Override
public boolean leftClick() {
return openPage(currentPage - 1);
}
@Override
public boolean leftClickShift() {
return openPage(currentPage - 1);
}
@Override
public boolean rightClick() {
return openPage(currentPage - 1);
}
@Override
public boolean rightClickShift() {
return openPage(currentPage - 1);
}
}));
} else {
addItem(PREVIOUS_PAGE_SLOT, createStaticItem(Material.GRAY_DYE, "&7Previous Page",
List.of(UtilitiesOG.trueogColorize("&8Already on the first page."))));
}
addItem(PAGE_INFO_SLOT, createStaticItem(Material.BOOK, "&3&lPage " + (currentPage + 1) + "/" + (maxPage + 1),
List.of(UtilitiesOG.trueogColorize("&6Active bounties: &c" + totalBounties))));
if (currentPage < maxPage) {
addItem(NEXT_PAGE_SLOT, createButtonItem(Material.ARROW, "&a&lNext Page",
List.of(UtilitiesOG.trueogColorize("&7Go to page &f" + (currentPage + 2))), new GUIButton()
{
@Override
public boolean leftClick() {
return openPage(currentPage + 1);
}
@Override
public boolean leftClickShift() {
return openPage(currentPage + 1);
}
@Override
public boolean rightClick() {
return openPage(currentPage + 1);
}
@Override
public boolean rightClickShift() {
return openPage(currentPage + 1);
}
}));
} else {
addItem(NEXT_PAGE_SLOT, createStaticItem(Material.GRAY_DYE, "&7Next Page",
List.of(UtilitiesOG.trueogColorize("&8Already on the last page."))));
}
addItem(CLOSE_SLOT, createButtonItem(Material.BARRIER, "&c&lClose",
List.of(UtilitiesOG.trueogColorize("&7Close the bounty menu.")), new GUIButton()
{
@Override
public boolean leftClick() {
viewer.closeInventory();
return true;
}
@Override
public boolean leftClickShift() {
viewer.closeInventory();
return true;
}
@Override
public boolean rightClick() {
viewer.closeInventory();
return true;
}
@Override
public boolean rightClickShift() {
viewer.closeInventory();
return true;
}
}));
@Override
public void open() {
setContents();
// Open the inventory for the viewer
viewer.openInventory(this.inventory);
}
private boolean openPage(int targetPage) {
new MainBountyGui(plugin, viewer, bountySupplier, targetPage, diamondBankAPI).open();
return true;
@Override
public void setContents() {
// TODO: Populate the inventory
}
private GUIItem createBountyItem(BountyGuiEntry entry, int rank) {
final String displayName = safeDisplayName(entry.displayName());
final ArrayList<TextComponent> lore = new ArrayList<>();
lore.add(UtilitiesOG.trueogColorize("&eBounty: &b" + formatBounty(entry.bountyDiamonds())));
lore.add(UtilitiesOG.trueogColorize("&7Click to increase this player's bounty."));
lore.add(UtilitiesOG.trueogColorize("&8You will be prompted in chat for the amount."));
lore.add(UtilitiesOG.trueogColorize(""));
final double dropChance = Math.max(0D,
Math.min(100D, plugin.getConfig().getDouble("bounty-head-drop-chance", 50D)));
lore.add(UtilitiesOG.trueogColorize("&6Claiming the bounty will give you a " + formatDropChance(dropChance)
+ "% chance of beheading your victim!"));
final GUIItem item;
if (entry.targetName() != null && !entry.targetName().isBlank()) {
item = new GUIItem(Material.PLAYER_HEAD, 1, " &f#" + rank + " " + displayName, entry.targetName());
} else {
item = new GUIItem(Material.PAPER, 1, "&6&l#" + rank + " " + displayName);
}
item.lore(lore);
item.setButton(new GUIButton() {
@Override
public boolean leftClick() {
return promptIncrease(entry);
}
@Override
public boolean leftClickShift() {
return promptIncrease(entry);
}
@Override
public boolean rightClick() {
return promptIncrease(entry);
}
@Override
public boolean rightClickShift() {
return promptIncrease(entry);
}
});
item.setPlayErrorSound(false);
return item;
@Override
public void handleClick(InventoryClickEvent event) {
// TODO: Handle inventory clicks
}
}
private boolean promptIncrease(BountyGuiEntry entry) {
if (entry.targetUuid() == null) {
UtilitiesOG.trueogMessage(viewer, plugin.getLang().getColored("command.bounty.add.player-not-found"));
return true;
}
final String targetName = StringUtils.defaultIfBlank(entry.targetName(), "Unknown Player");
plugin.getBountyIncreasePromptListener().prompt(viewer.getUniqueId(), entry.targetUuid(), targetName);
final String promptMessage = plugin.getLang().getColored("command.bounty.add.prompt").replace("{target}",
safeDisplayName(entry.displayName()));
UtilitiesOG.trueogMessage(viewer, promptMessage);
viewer.closeInventory();
return true;
}
private String formatBounty(double bountyDiamonds) {
final long shards = diamondBankAPI.diamondsToShards(bountyDiamonds);
return diamondBankAPI.shardsToDiamonds(shards) + " Diamonds";
}
private String formatDropChance(double chance) {
if (chance == Math.floor(chance)) {
return Long.toString((long) chance);
}
return StringUtils.stripEnd(StringUtils.stripEnd(String.format("%.2f", chance), "0"), ".");
}
private GUIItem createStaticItem(Material material, String displayName, List<TextComponent> lore) {
final GUIItem item = new GUIItem(material, 1, displayName);
item.lore(new ArrayList<>(lore));
item.setPlayErrorSound(false);
return item;
}
private GUIItem createButtonItem(Material material, String displayName, List<TextComponent> lore,
GUIButton button)
{
final GUIItem item = new GUIItem(material, 1, displayName);
item.lore(new ArrayList<>(lore));
item.setButton(button);
item.setPlayErrorSound(false);
return item;
}
private List<BountyGuiEntry> getSortedBounties() {
final List<BountyGuiEntry> supplied = bountySupplier.get();
if (supplied == null || supplied.isEmpty()) {
return Collections.emptyList();
}
final List<BountyGuiEntry> sorted = new ArrayList<>(supplied);
sorted.removeIf(entry -> entry == null || entry.bountyDiamonds() <= 0D);
sorted.sort(Comparator.comparingDouble(BountyGuiEntry::bountyDiamonds).reversed()
.thenComparing(entry -> safeName(entry.targetName()), String.CASE_INSENSITIVE_ORDER));
return sorted;
}
private int getMaxPage(List<BountyGuiEntry> bounties) {
if (bounties.isEmpty()) {
return 0;
}
return (bounties.size() - 1) / PYRAMID_SLOTS.size();
}
private String safeName(String name) {
return name == null || name.isBlank() ? "Unknown Player" : name;
}
private String safeDisplayName(String displayName) {
if (displayName == null || displayName.isBlank()) {
return "&fUnknown Player";
}
return displayName;
}
public static record BountyGuiEntry(UUID targetUuid, String targetName, String displayName, double bountyDiamonds) {
}
}
@@ -1,149 +0,0 @@
package com.tcoded.playerbountiesplus.hook.currency;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import net.trueog.diamondbankog.DiamondBankException;
import net.trueog.diamondbankog.DiamondBankException.EconomyDisabledException;
import net.trueog.diamondbankog.DiamondBankException.InsufficientFundsException;
import net.trueog.diamondbankog.DiamondBankException.InvalidPlayerException;
import net.trueog.diamondbankog.DiamondBankException.PlayerNotOnlineException;
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.utilitiesog.UtilitiesOG;
public class DiamondBankOGHook implements EconomyHook {
private final PlayerBountiesOG plugin;
private final DiamondBankAPIJava diamondBank;
public DiamondBankOGHook(PlayerBountiesOG plugin, DiamondBankAPIJava diamondBankAPITransporter) {
this.plugin = plugin;
this.diamondBank = diamondBankAPITransporter;
}
@Override
public boolean giveEco(Player player, Player victim, double diamonds) {
final long shards = diamondBank.diamondsToShards(diamonds);
if (shards <= 0L) {
return false;
}
try {
diamondBank.addToPlayerBankShards(
player.getUniqueId(), shards, "Player " + player.getName() + " defeated " + victim.getName()
+ " and earned a bounty of " + diamondBank.shardsToDiamonds(shards) + ".",
"Plugin: PlayerBounties-OG");
} catch (EconomyDisabledException economyDisabledError) {
PlayerBountiesOG
.disableSelf("[PlayerBounties-OG] Paying " + player.getName() + " for killing " + victim.getName()
+ " failed because the economy is disabled! " + economyDisabledError.getMessage());
economyDisabledError.printStackTrace();
return false;
}
return true;
}
@Override
public boolean takeEco(Player player, Player victim, double diamonds) {
final long shards = diamondBank.diamondsToShards(diamonds);
if (shards <= 0L) {
return false;
}
try {
diamondBank
.consumeFromPlayer(player.getUniqueId(), shards,
"Player " + player.getName() + " contributed " + diamondBank.shardsToDiamonds(shards)
+ " Diamonds toward a bounty on " + victim.getName() + ".",
"Plugin: PlayerBounties-OG");
} catch (EconomyDisabledException economyDisabledError) {
PlayerBountiesOG.disableSelf(
"[PlayerBounties-OG] DiamondBank-OG economy disabled: " + economyDisabledError.getMessage());
economyDisabledError.printStackTrace();
return false;
} catch (InvalidPlayerException invalidPlayerError) {
plugin.getLogger().warning("Invalid player for consumeFromPlayer: " + player.getName());
UtilitiesOG.trueogMessage(player,
"&cERROR: your player account could not be found by DiamondBank-OG. Contact an administrator!");
return false;
} catch (InsufficientFundsException insufficientFundsError) {
UtilitiesOG.trueogMessage(player,
"&6WARNING: You do not have enough Diamonds to contribute to that bounty.");
return false;
}
// TODO: Remove PlayerNotOnlineException catch block after next DiamondBank-OG
// update.
catch (PlayerNotOnlineException temporaryPlayerNotOnlineError) {
plugin.getLogger().warning("Player " + player.getName()
+ " not online when attempting to consumeFromPlayer. This error is expected to be removed in the next DiamondBank-OG update.");
temporaryPlayerNotOnlineError.printStackTrace();
return false;
}
return true;
}
public CompletableFuture<Long> getShardBalance(UUID uuid) {
final CompletableFuture<Long> future = new CompletableFuture<>();
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
final long totalShards = diamondBank.getTotalShards(uuid);
future.complete(totalShards);
} catch (DiamondBankException.EconomyDisabledException error) {
PlayerBountiesOG
.disableSelf("The DiamondBank-OG economy is disabled — disabling " + plugin.getName() + "!");
future.completeExceptionally(error);
} catch (Throwable t) {
future.completeExceptionally(t);
}
});
return future;
}
}
@@ -0,0 +1,27 @@
package com.tcoded.playerbountiesplus.hook.currency;
import org.bukkit.entity.Player;
public class DummyEcoHook implements EconomyHook {
@Override
public boolean isValid() {
return false;
}
@Override
public void giveEco(Player player, double amount) {
throw new UnsupportedOperationException("Economy isn't setup. Dummy hook is the active fallback.");
}
@Override
public boolean takeEco(Player player, double amount) {
throw new UnsupportedOperationException("Economy isn't setup. Dummy hook is the active fallback.");
}
@Override
public boolean takeEco(Player player, double amount, boolean force) {
throw new UnsupportedOperationException("Economy isn't setup. Dummy hook is the active fallback.");
}
}
@@ -4,8 +4,12 @@ import org.bukkit.entity.Player;
public interface EconomyHook {
boolean giveEco(Player killer, Player victim, double diamonds);
boolean isValid();
boolean takeEco(Player killer, Player victim, double diamonds);
void giveEco(Player player, double amount);
}
boolean takeEco(Player player, double amount);
boolean takeEco(Player player, double amount, boolean force);
}
@@ -0,0 +1,57 @@
package com.tcoded.playerbountiesplus.hook.currency;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
public class VaultHook implements EconomyHook {
private final PlayerBountiesPlus plugin;
private Economy eco;
public VaultHook(PlayerBountiesPlus plugin) {
this.plugin = plugin;
}
public boolean init() {
if (this.plugin.getServer().getPluginManager().getPlugin("Vault") == null) {
return false;
}
RegisteredServiceProvider<Economy> rsp = this.plugin.getServer().getServicesManager().getRegistration(Economy.class);
if (rsp == null) {
return false;
}
eco = rsp.getProvider();
return true;
}
@Override
public boolean isValid() {
return eco != null;
}
@Override
public void giveEco(Player player, double amount) {
this.eco.depositPlayer(player, amount);
}
@Override
public boolean takeEco(Player player, double amount) {
return this.takeEco(player, amount, false);
}
@Override
public boolean takeEco(Player player, double amount, boolean force) {
double balance = this.eco.getBalance(player);
if (balance < amount && !force) return false;
return this.eco.withdrawPlayer(player, amount).type == EconomyResponse.ResponseType.SUCCESS;
}
}
@@ -1,116 +0,0 @@
package com.tcoded.playerbountiesplus.hook.logging;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.plugin.Plugin;
import net.coreprotect.CoreProtect;
import net.coreprotect.CoreProtectAPI;
public class CoreProtectHook {
private static final int MINIMUM_API_VERSION = 10;
private final CoreProtectAPI coreProtectAPI;
public CoreProtectHook(Plugin plugin) {
this.coreProtectAPI = findCoreProtect(plugin);
}
public boolean isEnabled() {
return this.coreProtectAPI != null;
}
public boolean logPlacement(String user, BlockState blockState) {
if (this.coreProtectAPI == null || user == null || blockState == null) {
return false;
}
return this.coreProtectAPI.logPlacement(user, blockState.getLocation(), blockState.getType(),
blockState.getBlockData());
}
public boolean logRemoval(String user, BlockState blockState) {
if (this.coreProtectAPI == null || user == null || blockState == null) {
return false;
}
return this.coreProtectAPI.logRemoval(user, blockState.getLocation(), blockState.getType(),
blockState.getBlockData());
}
public boolean logContainerTransaction(String user, Location location) {
if (this.coreProtectAPI == null || user == null || location == null) {
return false;
}
return this.coreProtectAPI.logContainerTransaction(user, location);
}
public boolean logInteraction(String user, Location location) {
if (this.coreProtectAPI == null || user == null || location == null) {
return false;
}
return this.coreProtectAPI.logInteraction(user, location);
}
public boolean hasPlaced(String user, Block block, int time, int offset) {
if (this.coreProtectAPI == null || user == null || block == null) {
return false;
}
return this.coreProtectAPI.hasPlaced(user, block, time, offset);
}
private static CoreProtectAPI findCoreProtect(Plugin plugin) {
if (plugin == null) {
return null;
}
final Plugin coreProtectPlugin = plugin.getServer().getPluginManager().getPlugin("CoreProtect-OG");
if (!(coreProtectPlugin instanceof CoreProtect coreProtect)) {
return null;
}
final CoreProtectAPI api = coreProtect.getAPI();
if (api == null || !api.isEnabled() || api.APIVersion() < MINIMUM_API_VERSION) {
return null;
}
return api;
}
}
@@ -0,0 +1,15 @@
package com.tcoded.playerbountiesplus.hook.placeholder;
public class DummyPlaceholderHook implements PlaceholderHook {
@Override
public void enable() {
}
@Override
public void disable() {
}
}
@@ -0,0 +1,63 @@
package com.tcoded.playerbountiesplus.hook.placeholder;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.OfflinePlayer;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PlaceholderAPIHook extends PlaceholderExpansion implements PlaceholderHook {
private final PlayerBountiesPlus pbpPlugin;
public PlaceholderAPIHook(PlayerBountiesPlus pbpPlugin, Plugin papiPlugin) {
this.pbpPlugin = pbpPlugin;
if (!(papiPlugin instanceof PlaceholderAPIPlugin)) {
throw new IllegalArgumentException("Plugin is not PlaceholderAPI");
}
}
@Override
public @NotNull String getIdentifier() {
return pbpPlugin.getName().toLowerCase();
}
@Override
public @NotNull String getAuthor() {
return pbpPlugin.getDescription().getAuthors().get(0);
}
@Override
public @NotNull String getVersion() {
return pbpPlugin.getDescription().getVersion();
}
@Override
public boolean persist() {
return true;
}
@Override
public void enable() {
this.register();
}
@Override
public void disable() {
this.unregister();
}
@Override
public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
if (params.equals("bounty")) {
return String.valueOf(pbpPlugin.getBountyDataManager().getBounty(player.getUniqueId()));
} else if (params.equals("hasbounty")) {
return String.valueOf(pbpPlugin.getBountyDataManager().hasBounty(player.getUniqueId()));
}
return "INVALID-OPTION";
}
}
@@ -0,0 +1,27 @@
package com.tcoded.playerbountiesplus.hook.placeholder;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
public interface PlaceholderHook {
@NotNull
static PlaceholderHook findPlaceholderHook(PlayerBountiesPlus plugin) {
PluginManager pluginManager = plugin.getServer().getPluginManager();
Plugin papiPlugin = pluginManager.getPlugin("PlaceholderAPI");
if (papiPlugin != null) {
return new PlaceholderAPIHook(plugin, papiPlugin);
}
plugin.getLogger().warning("PlaceholderAPI not found, placeholders will be unavailable.");
return new DummyPlaceholderHook();
}
void enable();
void disable();
}
@@ -1,52 +1,38 @@
package com.tcoded.playerbountiesplus.hook.team;
import java.util.List;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import java.util.List;
public abstract class AbstractTeamHook implements TeamHook {
protected PlayerBountiesOG plugin;
protected PlayerBountiesPlus plugin;
protected JavaPlugin teamPlugin;
public AbstractTeamHook(PlayerBountiesOG plugin, Plugin teamPlugin) {
public AbstractTeamHook(PlayerBountiesPlus plugin, Plugin teamPlugin) {
this.plugin = plugin;
this.teamPlugin = (JavaPlugin) teamPlugin;
}
@Override
public String getPluginName() {
return this.teamPlugin.getName();
}
@Override
public String getAuthor() {
final List<String> authors = this.teamPlugin.getPluginMeta().getAuthors();
return authors.isEmpty() ? "N/A" : authors.get(0);
List<String> authors = this.teamPlugin.getDescription().getAuthors();
if (authors.isEmpty()) return "N/A";
return authors.get(0);
}
@Override
public String[] getAuthors() {
final List<String> authors = this.teamPlugin.getPluginMeta().getAuthors();
if (authors.isEmpty()) {
return new String[0];
}
List<String> authors = this.teamPlugin.getDescription().getAuthors();
if (authors.isEmpty()) return new String[0];
return authors.toArray(new String[0]);
}
}
}
@@ -0,0 +1,26 @@
package com.tcoded.playerbountiesplus.hook.team;
import com.alessiodp.parties.api.Parties;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.UUID;
public class AlessioPartiesHook extends AbstractTeamHook {
public AlessioPartiesHook(PlayerBountiesPlus plugin, Plugin partiesPlugin) {
super(plugin, partiesPlugin);
}
@Override
public boolean isFriendly(Player player1, Player player2) {
UUID uuid1 = player1.getUniqueId();
UUID uuid2 = player2.getUniqueId();
if (!Parties.getApi().isPlayerInParty(uuid1)) return false;
if (!Parties.getApi().isPlayerInParty(uuid2)) return false;
return Parties.getApi().areInTheSameParty(uuid1, uuid2);
}
}
@@ -0,0 +1,22 @@
package com.tcoded.playerbountiesplus.hook.team;
import com.booksaw.betterTeams.Team;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class BetterTeamsHook extends AbstractTeamHook {
public BetterTeamsHook(PlayerBountiesPlus plugin, Plugin teamPlugin) {
super(plugin, teamPlugin);
}
@Override
public boolean isFriendly(Player player1, Player player2) {
if (Team.getTeam(player1) == null) return false;
if (Team.getTeam(player2) == null) return false;
return Team.getTeam(player1) == Team.getTeam(player2);
}
}
@@ -0,0 +1,34 @@
package com.tcoded.playerbountiesplus.hook.team;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import me.loving11ish.clans.api.ClansLiteAPI;
import me.loving11ish.clans.api.models.Clan;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
public class ClansLiteHook extends AbstractTeamHook {
private final ClansLiteAPI api;
public ClansLiteHook(PlayerBountiesPlus plugin, Plugin teamPlugin) {
super(plugin, teamPlugin);
api = ClansLiteAPI.getInstance();
}
public @Nullable String getClanId(Player player) {
Clan clan = api.getClanByBukkitPlayer(player);
return clan == null ? null : clan.getClanFinalName();
}
@Override
public boolean isFriendly(Player player1, Player player2) {
String clanId1 = this.getClanId(player1);
String clanId2 = this.getClanId(player2);
if (clanId1 == null) return false;
if (clanId2 == null) return false;
return clanId1.equals(this.getClanId(player2));
}
}
@@ -0,0 +1,18 @@
package com.tcoded.playerbountiesplus.hook.team;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class PartyAndFriendsHook extends AbstractTeamHook {
public PartyAndFriendsHook(PlayerBountiesPlus plugin, Plugin teamPlugin) {
super(plugin, teamPlugin);
}
@Override
public boolean isFriendly(Player player1, Player player2) {
return false; // todo: figure out which of the 5 different APIs I'm supposed to use...
}
}
@@ -0,0 +1,27 @@
package com.tcoded.playerbountiesplus.hook.team;
import com.massivecraft.factions.FPlayers;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class SaberFactionsHook extends AbstractTeamHook {
public SaberFactionsHook(PlayerBountiesPlus plugin, Plugin teamPlugin) {
super(plugin, teamPlugin);
}
@Override
public boolean isFriendly(Player player1, Player player2) {
FPlayers fPlayers = FPlayers.getInstance();
String factionId1 = fPlayers.getByPlayer(player1).getFactionId();
String factionId2 = fPlayers.getByPlayer(player2).getFactionId();
if (factionId1 == null) return false;
if (factionId2 == null) return false;
return factionId1.equals(factionId2);
}
}
@@ -1,42 +1,34 @@
package com.tcoded.playerbountiesplus.hook.team;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import net.sacredlabyrinth.phaed.simpleclans.Clan;
import net.sacredlabyrinth.phaed.simpleclans.SimpleClans;
import net.sacredlabyrinth.phaed.simpleclans.managers.ClanManager;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.UUID;
public class SimpleClansHook extends AbstractTeamHook {
public SimpleClansHook(PlayerBountiesOG plugin, Plugin teamPlugin) {
public SimpleClansHook(PlayerBountiesPlus plugin, Plugin teamPlugin) {
super(plugin, teamPlugin);
}
@Override
public boolean isFriendly(Player player1, Player player2) {
ClanManager clanManager = SimpleClans.getInstance().getClanManager();
final ClanManager clanManager = SimpleClans.getInstance().getClanManager();
UUID uuid1 = player1.getUniqueId();
UUID uuid2 = player2.getUniqueId();
final UUID uuid1 = player1.getUniqueId();
final UUID uuid2 = player2.getUniqueId();
Clan clan1 = clanManager.getClanByPlayerUniqueId(uuid1);
Clan clan2 = clanManager.getClanByPlayerUniqueId(uuid2);
final Clan clan1 = clanManager.getClanByPlayerUniqueId(uuid1);
final Clan clan2 = clanManager.getClanByPlayerUniqueId(uuid2);
if (clan1 == null) {
return false;
}
return clan2 == null ? false : clan1 == clan2;
if (clan1 == null) return false;
if (clan2 == null) return false;
return clan1 == clan2;
}
}
}
@@ -1,39 +1,54 @@
package com.tcoded.playerbountiesplus.hook.team;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
public interface TeamHook {
static AbstractTeamHook findTeamHook(PlayerBountiesOG plugin) {
final PluginManager pluginManager = plugin.getServer().getPluginManager();
// RoinujNosde's SimpleClans: TrueOG Network branch.
// https://git.trueog.net/trueog/Unions-OG
// License: GPLv3
// (https://git.trueog.net/trueog/Unions-OG/raw/branch/master/LICENSE)
final Plugin simpleClansPlugin = pluginManager.getPlugin("SimpleClans");
if (simpleClansPlugin != null && simpleClansPlugin.isEnabled()) {
return new SimpleClansHook(plugin, simpleClansPlugin);
static AbstractTeamHook findTeamHook(PlayerBountiesPlus plugin) {
PluginManager pluginManager = plugin.getServer().getPluginManager();
// loving11ish - ClansLite - https://www.spigotmc.org/resources/clanslite-1-19-4-support.97163/
Plugin clansLitePlugin = pluginManager.getPlugin("ClansLite");
if (clansLitePlugin != null && clansLitePlugin.isEnabled()) {
return new ClansLiteHook(plugin, clansLitePlugin);
}
// Unions-OG is a soft fork of SimpleClans that preserves the same API
// and main class but exposes a different plugin name to Bukkit.
final Plugin unionsPlugin = pluginManager.getPlugin("Unions-OG");
if (unionsPlugin != null && unionsPlugin.isEnabled()) {
// AlessioDP - Parties - https://www.spigotmc.org/resources/parties-an-advanced-parties-manager.3709/
Plugin partiesPlugin = pluginManager.getPlugin("Parties");
if (partiesPlugin != null && partiesPlugin.isEnabled()) {
return new AlessioPartiesHook(plugin, partiesPlugin);
}
return new SimpleClansHook(plugin, unionsPlugin);
// booksaw - BetterTeams - https://www.spigotmc.org/resources/better-teams.17129/
Plugin betterTeamsPlugin = pluginManager.getPlugin("BetterTeams");
if (betterTeamsPlugin != null && betterTeamsPlugin.isEnabled()) {
return new BetterTeamsHook(plugin, betterTeamsPlugin);
}
// RoinujNosde - SimpleClans - https://www.spigotmc.org/resources/simpleclans.71242/
Plugin simpleClansPlugin = pluginManager.getPlugin("SimpleClans");
if (simpleClansPlugin != null && simpleClansPlugin.isEnabled()) {
return new SimpleClansHook(plugin, simpleClansPlugin);
}
// SaberLLC - Factions (SaberFactions) - https://www.spigotmc.org/resources/simpleclans.71242/
Plugin saberFactionsPlugin = pluginManager.getPlugin("Factions");
if (saberFactionsPlugin != null &&
saberFactionsPlugin.getDescription().getMain().equals("com.massivecraft.factions.FactionsPlugin") &&
saberFactionsPlugin.isEnabled()) {
return new SaberFactionsHook(plugin, saberFactionsPlugin);
}
// LlmDl - Towny - https://www.spigotmc.org/resources/towny-advanced.72694/
Plugin townyPlugin = pluginManager.getPlugin("Towny");
if (townyPlugin != null && townyPlugin.isEnabled()) {
return new TownyHook(plugin, simpleClansPlugin);
}
return null;
}
String getPluginName();
@@ -0,0 +1,37 @@
package com.tcoded.playerbountiesplus.hook.team;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.object.Nation;
import com.palmergames.bukkit.towny.object.Town;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class TownyHook extends AbstractTeamHook {
public TownyHook(PlayerBountiesPlus plugin, Plugin teamPlugin) {
super(plugin, teamPlugin);
}
public Town getTown(Player player) {
return TownyAPI.getInstance().getTown(player);
}
public Nation getNation(Player player) {
return TownyAPI.getInstance().getNation(player);
}
@Override
public boolean isFriendly(Player player1, Player player2) {
Town town1 = getTown(player1);
Town town2 = getTown(player2);
Nation nation1 = getNation(player1);
Nation nation2 = getNation(player2);
boolean sameTown = town1 != null && town2 != null && (town1.hasResident(player2) || town1.hasAlly(town2));
boolean sameNation = nation1 != null && nation2 != null && (nation1.equals(nation2) || nation1.hasAlly(nation2));
return sameTown || sameNation;
}
}
@@ -1,239 +0,0 @@
package com.tcoded.playerbountiesplus.listener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.FluidCollisionMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.RayTraceResult;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.util.BountyHeadData;
public final class BountyHeadLabelListener implements Listener {
private static final long UPDATE_PERIOD_TICKS = 2L;
// Two stacked armor stands per head: top = name + slayer, bottom = amount.
// Spacing tuned for small marker stands so the hologram stays compact.
private static final double LABEL_BOTTOM_Y_OFFSET = 0.85D;
private static final double LABEL_TOP_Y_OFFSET = 1.10D;
private final PlayerBountiesOG plugin;
private final Map<HeadLabelKey, LabelPair> activeLabels = new HashMap<>();
private final BukkitTask tickTask;
public BountyHeadLabelListener(PlayerBountiesOG plugin) {
this.plugin = plugin;
this.tickTask = plugin.getServer().getScheduler().runTaskTimer(plugin, this::tick, UPDATE_PERIOD_TICKS,
UPDATE_PERIOD_TICKS);
}
public void shutdown() {
if (tickTask != null) {
tickTask.cancel();
}
clearLabels();
}
private void tick() {
if (!isHoverModeEnabled()) {
clearLabels();
return;
}
final Set<HeadLabelKey> visibleTargets = new HashSet<>();
for (Player player : plugin.getServer().getOnlinePlayers()) {
final HeadTarget target = findTargetedHead(player);
if (target == null) {
continue;
}
visibleTargets.add(target.key());
upsertLabel(target);
}
final Set<HeadLabelKey> staleLabels = new HashSet<>(activeLabels.keySet());
staleLabels.removeAll(visibleTargets);
staleLabels.forEach(this::removeLabel);
}
private HeadTarget findTargetedHead(Player player) {
final double maxRange = Math.max(1D, plugin.getConfig().getDouble("bounty-head-label-range", 8D));
final RayTraceResult rayTrace = player.getWorld().rayTraceBlocks(player.getEyeLocation(),
player.getEyeLocation().getDirection(), maxRange, FluidCollisionMode.NEVER, true);
if (rayTrace == null) {
return null;
}
final Block hitBlock = rayTrace.getHitBlock();
if (hitBlock == null || !isHeadMaterial(hitBlock.getType())) {
return null;
}
final BlockState state = hitBlock.getState();
if (!(state instanceof Skull skull)) {
return null;
}
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(skull.getPersistentDataContainer());
if (headData == null) {
return null;
}
return new HeadTarget(HeadLabelKey.fromBlock(hitBlock), hitBlock.getLocation(), headData);
}
private void upsertLabel(HeadTarget target) {
final LabelPair existing = activeLabels.get(target.key());
if (existing != null && existing.top().isValid() && existing.bottom().isValid()) {
existing.top().customName(plugin.getBountyHeadFormatter().buildCanonicalLineTop(target.data()));
existing.bottom().customName(plugin.getBountyHeadFormatter().buildCanonicalLineBottom(target.data()));
return;
}
if (existing != null) {
removeLabel(target.key());
}
final World world = target.location().getWorld();
final Location bottomLocation = target.location().clone().add(0.5D, LABEL_BOTTOM_Y_OFFSET, 0.5D);
final Location topLocation = target.location().clone().add(0.5D, LABEL_TOP_Y_OFFSET, 0.5D);
final ArmorStand top = world.spawn(topLocation, ArmorStand.class, stand -> {
configureLabelStand(stand);
stand.customName(plugin.getBountyHeadFormatter().buildCanonicalLineTop(target.data()));
});
final ArmorStand bottom = world.spawn(bottomLocation, ArmorStand.class, stand -> {
configureLabelStand(stand);
stand.customName(plugin.getBountyHeadFormatter().buildCanonicalLineBottom(target.data()));
});
activeLabels.put(target.key(), new LabelPair(top, bottom));
}
private static void configureLabelStand(ArmorStand stand) {
stand.setInvisible(true);
stand.setGravity(false);
stand.setMarker(true);
stand.setSmall(true);
stand.setInvulnerable(true);
stand.setSilent(true);
stand.setPersistent(false);
stand.setBasePlate(false);
stand.setArms(false);
stand.setCustomNameVisible(true);
}
private void removeLabel(HeadLabelKey key) {
final LabelPair pair = activeLabels.remove(key);
if (pair == null) {
return;
}
if (pair.top() != null && pair.top().isValid()) {
pair.top().remove();
}
if (pair.bottom() != null && pair.bottom().isValid()) {
pair.bottom().remove();
}
}
private void clearLabels() {
final Set<HeadLabelKey> keys = new HashSet<>(activeLabels.keySet());
keys.forEach(this::removeLabel);
}
private boolean isHoverModeEnabled() {
return StringUtils.equalsIgnoreCase(plugin.getConfig().getString("bounty-head-label-mode", "hover"), "hover");
}
private static boolean isHeadMaterial(Material material) {
return material == Material.PLAYER_HEAD || material == Material.PLAYER_WALL_HEAD;
}
private record HeadTarget(HeadLabelKey key, Location location, BountyHeadData data) {
}
private record LabelPair(ArmorStand top, ArmorStand bottom) {
}
private record HeadLabelKey(UUID worldId, int x, int y, int z) {
private static HeadLabelKey fromBlock(Block block) {
final World world = block.getWorld();
return new HeadLabelKey(world.getUID(), block.getX(), block.getY(), block.getZ());
}
}
}
@@ -1,199 +0,0 @@
package com.tcoded.playerbountiesplus.listener;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.persistence.PersistentDataContainer;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.hook.logging.CoreProtectHook;
import com.tcoded.playerbountiesplus.util.BountyHeadData;
public class BountyHeadListener implements Listener {
private final PlayerBountiesOG plugin;
private final CoreProtectHook coreProtectHook;
public BountyHeadListener(PlayerBountiesOG plugin) {
this.plugin = plugin;
this.coreProtectHook = plugin.getCoreProtectHook();
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlace(BlockPlaceEvent event) {
if (!isHeadMaterial(event.getBlockPlaced().getType())) {
return;
}
final ItemMeta itemMeta = event.getItemInHand().getItemMeta();
if (itemMeta == null) {
return;
}
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(itemMeta.getPersistentDataContainer());
if (headData == null) {
return;
}
final BlockState state = event.getBlockPlaced().getState();
if (!(state instanceof Skull skull)) {
return;
}
plugin.getBountyHeadMetadata().write(skull.getPersistentDataContainer(), headData);
skull.update(true, false);
if (this.coreProtectHook != null) {
this.coreProtectHook.logPlacement(event.getPlayer().getName(), skull);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBreak(BlockBreakEvent event) {
if (!isHeadMaterial(event.getBlock().getType())) {
return;
}
final BlockState state = event.getBlock().getState();
final BlockState snapshot = state;
if (!(state instanceof Skull skull)) {
return;
}
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(skull.getPersistentDataContainer());
if (headData == null) {
return;
}
final ItemStack drop = new ItemStack(Material.PLAYER_HEAD, 1);
final SkullMeta meta = (SkullMeta) drop.getItemMeta();
plugin.getBountyHeadFormatter().applyHeadMeta(meta, headData, skull.getPlayerProfile(),
plugin.getBountyHeadMetadata());
drop.setItemMeta(meta);
if (this.coreProtectHook != null) {
this.coreProtectHook.logRemoval(event.getPlayer().getName(), snapshot);
}
event.setDropItems(false);
event.getBlock().setType(Material.AIR, false);
event.getBlock().getWorld().dropItemNaturally(event.getBlock().getLocation(), drop);
}
@EventHandler(ignoreCancelled = true)
public void onRightClick(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getClickedBlock() != null
&& isHeadMaterial(event.getClickedBlock().getType()))
{
final BlockState state = event.getClickedBlock().getState();
if (state instanceof Skull skull) {
sendClaimantActionbar(event.getPlayer(), skull.getPersistentDataContainer());
return;
}
}
final ItemStack item = event.getItem();
if (item != null && isHeadMaterial(item.getType())) {
sendClaimantActionbar(event.getPlayer(), item.getItemMeta());
}
}
private void sendClaimantActionbar(Player player, ItemMeta itemMeta) {
if (itemMeta == null) {
return;
}
sendClaimantActionbar(player, itemMeta.getPersistentDataContainer());
}
private void sendClaimantActionbar(Player player, PersistentDataContainer dataContainer) {
final BountyHeadData headData = plugin.getBountyHeadMetadata().read(dataContainer);
if (headData == null) {
return;
}
final net.kyori.adventure.text.Component line = plugin.getBountyHeadFormatter().buildCanonicalLine(headData);
// Send action bar immediately
player.sendActionBar(line);
// Also schedule a second send to effectively double the visible duration.
// 40 ticks ~= 2 seconds; sending again after that will keep the action bar
// visible
// for roughly twice the default single-send duration.
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
if (player.isOnline()) {
player.sendActionBar(line);
}
}, 40L);
}
private static boolean isHeadMaterial(Material material) {
return material == Material.PLAYER_HEAD || material == Material.PLAYER_WALL_HEAD;
}
}
@@ -1,100 +0,0 @@
package com.tcoded.playerbountiesplus.listener;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.command.bounty.BountyAddCmd;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.trueog.utilitiesog.UtilitiesOG;
public class BountyIncreasePromptListener implements Listener {
private final PlayerBountiesOG plugin;
private final Map<UUID, PendingIncreasePrompt> pendingPrompts = new ConcurrentHashMap<>();
public BountyIncreasePromptListener(PlayerBountiesOG plugin) {
this.plugin = plugin;
}
public void prompt(UUID setterUuid, UUID targetUuid, String targetName) {
pendingPrompts.put(setterUuid, new PendingIncreasePrompt(targetUuid, targetName));
}
public boolean hasPrompt(UUID setterUuid) {
return pendingPrompts.containsKey(setterUuid);
}
@EventHandler(ignoreCancelled = true)
public void onChat(AsyncChatEvent event) {
final PendingIncreasePrompt prompt = pendingPrompts.get(event.getPlayer().getUniqueId());
if (prompt == null) {
return;
}
event.setCancelled(true);
final String input = StringUtils.trimToEmpty(event.message().examinableName());
if (StringUtils.equalsIgnoreCase(input, "cancel")) {
pendingPrompts.remove(event.getPlayer().getUniqueId());
UtilitiesOG.trueogMessage(event.getPlayer(), plugin.getLang().getColored("command.bounty.add.cancelled"));
return;
}
final double amount;
try {
if (!input.matches("^\\d+(?:\\.\\d)?$")) {
throw new NumberFormatException("Invalid amount format");
}
amount = Double.parseDouble(input);
} catch (NumberFormatException numberFormatException) {
UtilitiesOG.trueogMessage(event.getPlayer(), plugin.getLang().getColored("command.bounty.add.amount-nan"));
return;
}
pendingPrompts.remove(event.getPlayer().getUniqueId());
plugin.getServer().getScheduler().runTask(plugin, () -> BountyAddCmd.addBounty(plugin, event.getPlayer(),
prompt.targetUuid(), prompt.targetName(), amount, true));
}
@EventHandler
public void onQuit(PlayerQuitEvent playerQuitEvent) {
pendingPrompts.remove(playerQuitEvent.getPlayer().getUniqueId());
}
private static record PendingIncreasePrompt(UUID targetUuid, String targetName) {
}
}
@@ -1,403 +1,93 @@
package com.tcoded.playerbountiesplus.listener;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.Sound;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import com.tcoded.playerbountiesplus.event.BountyClaimEvent;
import com.tcoded.playerbountiesplus.hook.team.TeamHook;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.event.BountyClaimEvent;
import com.tcoded.playerbountiesplus.hook.team.TeamHook;
import com.tcoded.playerbountiesplus.manager.BountyDataManager;
import com.tcoded.playerbountiesplus.util.BountyHeadData;
import com.tcoded.playerbountiesplus.util.BountyWorldUtil;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.cacheddata.CachedMetaData;
import net.luckperms.api.model.user.User;
import net.trueog.utilitiesog.UtilitiesOG;
import java.util.UUID;
public class DeathListener implements Listener {
public static final String BOUNTY_HEAD_NAME_KEY = "bounty_head_target";
public static final String BOUNTY_HEAD_UUID_KEY = "bounty_head_target_uuid";
public static final String BOUNTY_HEAD_AMOUNT_KEY = "bounty_head_diamonds";
public static final String BOUNTY_HEAD_CLAIMANT_KEY = "bounty_head_claimant";
public static final String BOUNTY_HEAD_CLAIMANT_UUID_KEY = "bounty_head_claimant_uuid";
private final PlayerBountiesOG plugin;
private final LuckPerms luckPerms;
public DeathListener(PlayerBountiesOG plugin) {
private final PlayerBountiesPlus plugin;
public DeathListener(PlayerBountiesPlus plugin) {
this.plugin = plugin;
this.luckPerms = plugin.getLuckPerms();
}
@EventHandler(priority = EventPriority.HIGH)
public void onDeath(PlayerDeathEvent event) {
Player victim = event.getEntity();
Player killer = victim.getKiller();
final Player victim = event.getEntity();
final Player killer = victim.getKiller();
if (killer != null) {
if (!killer.hasPermission("playerbountiesplus.event.claim")) {
killer.sendMessage(plugin.getLang().getColored("death.no-permission"));
return;
}
if (killer == null) {
BountyDataManager bountyDataManager = this.plugin.getBountyDataManager();
UUID victimId = victim.getUniqueId();
return;
// Bounty check
if (!bountyDataManager.hasBounty(victimId)) {
return;
}
}
int bounty = bountyDataManager.getBounty(victimId);
if (!killer.hasPermission("playerbountiesog.event.claim")) {
// Clan check
TeamHook teamHook = this.plugin.getTeamHook();
if (teamHook != null && teamHook.isFriendly(killer, victim)) {
killer.sendMessage(plugin.getLang().getColored("death.same-team"));
return;
}
UtilitiesOG.trueogMessage(killer, plugin.getLang().getColored("death.no-permission"));
return;
// Trigger Bounty Claimed Event
BountyClaimEvent claimEvent = new BountyClaimEvent(killer, victim, bounty);
this.plugin.getServer().getPluginManager().callEvent(claimEvent);
}
// Check if event is cancelled
if (claimEvent.isCancelled()) {
return;
}
final BountyDataManager bountyDataManager = this.plugin.getBountyDataManager();
final UUID victimId = victim.getUniqueId();
// Give reward!
if (plugin.getConfig().getBoolean("bounty-claimable", true)) {
double claimMultiplier = plugin.getConfig().getDouble("bounty-claim-multiplier", 1.0);
double awardedAmount = bounty * claimMultiplier;
if (!bountyDataManager.hasBounty(victimId)) {
if (awardedAmount > 0) {
this.plugin.getEcoHook().giveEco(killer, awardedAmount);
} else if (awardedAmount < 0) {
this.plugin.getEcoHook().takeEco(killer, Math.abs(awardedAmount));
}
}
return;
// Optional - Take from victim as punishment
if (plugin.getConfig().getBoolean("bounty-take-from-victim", false)) {
this.plugin.getEcoHook().takeEco(victim, bounty, true);
}
}
if (!BountyWorldUtil.isBountyWorldAllowed(plugin, victim.getWorld())) {
UtilitiesOG.trueogMessage(killer, plugin.getLang().getColored("death.world-not-whitelisted")
.replace("{worlds}", BountyWorldUtil.formatBountyWorldWhitelist(plugin)));
return;
}
final TeamHook teamHook = this.plugin.getTeamHook();
if (teamHook != null && teamHook.isFriendly(killer, victim)) {
UtilitiesOG.trueogMessage(killer, plugin.getLang().getColored("death.same-team"));
return;
}
final double bounty = bountyDataManager.getBounty(victimId);
if (bounty <= 0D) {
// Announce Reward
if (plugin.getConfig().getBoolean("bounty-claimed-announce", true)) {
this.plugin.getServer().broadcastMessage(
plugin.getLang().getColored("death.announce-claimed")
.replace("{killer}", killer.getName())
.replace("{victim}", victim.getName())
.replace("{bounty}", String.valueOf(bounty))
);
}
// Remove bounty
bountyDataManager.removeBounty(victimId);
bountyDataManager.saveBountiesAsync();
return;
}
final BountyClaimEvent claimEvent = new BountyClaimEvent(killer, victim, bounty);
this.plugin.getServer().getPluginManager().callEvent(claimEvent);
if (claimEvent.isCancelled()) {
return;
}
final boolean bountyClaimable = plugin.getConfig().getBoolean("bounty-claimable", true);
final double claimMultiplier = plugin.getConfig().getDouble("bounty-claim-multiplier", 1.0D);
final double awardedAmount = Math.max(0D, bounty * claimMultiplier);
if (bountyClaimable && awardedAmount > 0D) {
try {
this.plugin.getEcoHook().giveEco(killer, victim, awardedAmount);
} catch (RuntimeException runtimeException) {
plugin.getLogger().severe("Failed to award bounty payout to " + killer.getName() + " for killing "
+ victim.getName() + ": " + runtimeException.getMessage());
runtimeException.printStackTrace();
UtilitiesOG.trueogMessage(killer,
"&cAn error occurred while awarding the bounty payout. The bounty was not removed.");
return;
}
}
// Suppress the normal Minecraft death message because this death is being
// handled as a bounty claim.
event.deathMessage(null);
final String killerDisplay = formatLuckPermsDisplay(killer);
final String victimDisplay = formatLuckPermsDisplay(victim);
final boolean beheaded = maybeDropPlayerHead(event, killer, victim, bounty);
if (plugin.getConfig().getBoolean("bounty-claimed-announce", true)) {
final String bountyDisplay = formatDiamonds(bounty);
final String message;
if (beheaded) {
message = killerDisplay + "&r &abeheaded " + victimDisplay + "&r &afor &b" + bountyDisplay
+ " &bDiamonds&a!";
} else {
final String awardedDisplay = formatDiamonds(awardedAmount);
if (bountyClaimable && awardedAmount > 0D) {
if (Double.compare(awardedAmount, bounty) == 0) {
message = killerDisplay + "&r &akilled " + victimDisplay + "&r &aand earned &b" + awardedDisplay
+ " &bDiamonds &afor the bounty!";
} else {
message = killerDisplay + "&r &akilled " + victimDisplay + "&r &aand claimed &b" + bountyDisplay
+ " &bDiamonds &afor &b" + awardedDisplay + " &bDiamonds&a!";
}
} else {
message = killerDisplay + "&r &akilled " + victimDisplay + "&r &aand claimed &b" + bountyDisplay
+ " &bDiamonds &abounty!";
}
}
announceBountyClaim(message, killer, victim);
}
bountyDataManager.removeBounty(victimId);
bountyDataManager.saveBountiesAsync();
}
private void announceBountyClaim(String message, Player killer, Player victim) {
Bukkit.getOnlinePlayers().stream().filter(this::isClaimAnnouncementRecipient).forEach(player -> {
UtilitiesOG.trueogMessage(player, message);
player.playSound(player.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 1.0F, 1.0F);
final Particle fireworkParticle = resolveFireworkParticle();
player.spawnParticle(fireworkParticle, killer.getLocation().add(0D, 1D, 0D), 40, 0.6D, 0.8D, 0.6D, 0.01D);
player.spawnParticle(fireworkParticle, victim.getLocation().add(0D, 1D, 0D), 40, 0.6D, 0.8D, 0.6D, 0.01D);
player.spawnParticle(Particle.TOTEM, killer.getLocation().add(0D, 1D, 0D), 20, 0.5D, 0.7D, 0.5D, 0.01D);
});
}
private boolean isClaimAnnouncementRecipient(Player player) {
final List<String> worldWhitelist = plugin.getConfig().getStringList("bounty-claimed-announce-world-whitelist");
final boolean hasConfiguredWorld = worldWhitelist.stream().anyMatch(worldName -> !worldName.isBlank());
return !hasConfiguredWorld || worldWhitelist.stream().anyMatch(
worldName -> StringUtils.equalsIgnoreCase(StringUtils.trim(worldName), player.getWorld().getName()));
}
private Particle resolveFireworkParticle() {
try {
return Particle.valueOf("FIREWORK");
} catch (IllegalArgumentException exception) {
return Particle.FIREWORKS_SPARK;
}
}
private String formatDiamonds(double diamonds) {
return plugin.getBountyHeadFormatter().formatDiamonds(diamonds);
}
private String formatLuckPermsDisplay(Player player) {
final String playerName = player.getName();
final String prefix = stripLeadingReset(stripTrailingReset(getLuckPermsPrefixLegacy(player)));
final String suffix = stripLeadingReset(stripTrailingReset(getLuckPermsSuffixLegacy(player)));
final String leadingColorCodes = extractLeadingColorCodes(prefix);
final StringBuilder out = new StringBuilder();
if (!prefix.isBlank()) {
out.append(prefix).append(" ");
}
if (leadingColorCodes.isBlank()) {
out.append(playerName);
} else {
out.append(leadingColorCodes).append(playerName);
}
if (!suffix.isBlank()) {
out.append(" ").append(suffix);
}
return StringUtils.trim(out.toString()).replaceAll("\\s*>$", "");
}
private boolean maybeDropPlayerHead(PlayerDeathEvent event, Player killer, Player victim, double bounty) {
final double dropChance = Math.max(0D,
Math.min(100D, plugin.getConfig().getDouble("bounty-head-drop-chance", 50D)));
if (ThreadLocalRandom.current().nextDouble(100D) >= dropChance) {
return false;
}
final ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1);
final SkullMeta headMeta = (SkullMeta) head.getItemMeta();
final BountyHeadData headData = new BountyHeadData(victim.getUniqueId(), victim.getName(), bounty,
killer.getUniqueId(), killer.getName());
final PlayerProfile profile = Bukkit.createProfile(victim.getUniqueId());
plugin.getBountyHeadFormatter().applyHeadMeta(headMeta, headData, profile, plugin.getBountyHeadMetadata());
head.setItemMeta(headMeta);
event.getDrops().add(head);
return true;
}
private String getLuckPermsSuffixLegacy(Player player) {
if (luckPerms == null) {
return "";
}
final User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) {
return "";
}
final CachedMetaData meta = user.getCachedData().getMetaData();
final String suffix = meta.getSuffix();
if (suffix == null || suffix.isBlank()) {
return "";
}
return StringUtils.trim(suffix).replace('§', '&');
}
private String getLuckPermsPrefixLegacy(Player player) {
if (luckPerms == null) {
return "";
}
final User user = luckPerms.getUserManager().getUser(player.getUniqueId());
if (user == null) {
return "";
}
final CachedMetaData meta = user.getCachedData().getMetaData();
final String prefix = meta.getPrefix();
if (prefix == null || prefix.isBlank()) {
return "";
}
return StringUtils.trim(prefix).replace('§', '&');
}
private static String stripTrailingReset(String input) {
if (input == null || input.isBlank()) {
return "";
}
return StringUtils.trim(input.replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", ""));
}
private static String stripLeadingReset(String input) {
if (input == null || input.isBlank()) {
return "";
}
return StringUtils.trim(input.replaceFirst("(?i)^(?:\\s*(?:<reset>|[&§]r))+", ""));
}
private static String extractLeadingColorCodes(String input) {
if (input == null || input.length() < 2) {
return "";
}
final StringBuilder out = new StringBuilder();
for (int i = 0; i < input.length() - 1; i++) {
final char current = input.charAt(i);
if (current != '&' && current != '§') {
break;
}
out.append(current).append(input.charAt(i + 1));
i++;
}
return StringUtils.trim(out.toString()).replaceAll("\\s*>$", "");
}
}
@@ -0,0 +1,28 @@
package com.tcoded.playerbountiesplus.listener;
import com.tcoded.playerbountiesplus.gui.IPbpGui;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.InventoryHolder;
public class GuiListener implements Listener {
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
// Get the inventory holder
InventoryHolder holder = event.getView().getTopInventory().getHolder();
// Ensure the holder is a GUI
if (!(holder instanceof IPbpGui gui)) {
return;
}
// Cancel normal click behaviour
event.setCancelled(true);
// Delegate the click handling
gui.handleClick(event);
}
}
@@ -1,78 +0,0 @@
package com.tcoded.playerbountiesplus.listener;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.InventoryView;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import net.trueog.utilitiesog.UtilitiesOG;
public class GuiProtectionListener implements Listener {
private final PlayerBountiesOG plugin;
public GuiProtectionListener(PlayerBountiesOG plugin) {
this.plugin = plugin;
}
@EventHandler(ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) {
if (!isMainBountyGui(event.getView())) {
return;
}
if (event.getRawSlot() < event.getView().getTopInventory().getSize()) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onInventoryDrag(InventoryDragEvent event) {
if (!isMainBountyGui(event.getView())) {
return;
}
final int topInventorySize = event.getView().getTopInventory().getSize();
for (int rawSlot : event.getRawSlots()) {
if (rawSlot < topInventorySize) {
event.setCancelled(true);
return;
}
}
}
private boolean isMainBountyGui(InventoryView view) {
final HumanEntity player = view.getPlayer();
if (player == null) {
return false;
}
return UtilitiesOG.stripFormatting(view.title().examinableName())
.equals(UtilitiesOG.stripFormatting(plugin.getLang().getColored("gui.main.title")));
}
}
@@ -1,132 +1,112 @@
package com.tcoded.playerbountiesplus.manager;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
public class BountyDataManager {
private final PlayerBountiesOG plugin;
private final PlayerBountiesPlus plugin;
private File bountiesFile;
private FileConfiguration bountiesConfig;
private final Object savingFileLock = new Object();
private final AtomicBoolean savingAsync = new AtomicBoolean(false);
private final ConcurrentHashMap<UUID, Double> bounties;
public BountyDataManager(PlayerBountiesOG plugin) {
private final ConcurrentHashMap<UUID, Integer> bounties;
public BountyDataManager(PlayerBountiesPlus plugin) {
this.plugin = plugin;
this.bounties = new ConcurrentHashMap<>();
}
public void init() {
final String bountiesFileName = "bounties.yml";
// Bounties file
String bountiesFileName = "bounties.yml";
bountiesFile = new File(this.plugin.getDataFolder(), bountiesFileName);
if (!bountiesFile.exists()) {
this.plugin.saveResource(bountiesFileName, false);
}
if (!bountiesFile.exists()) this.plugin.saveResource(bountiesFileName, false);
bountiesConfig = YamlConfiguration.loadConfiguration(bountiesFile);
final Set<String> keys = bountiesConfig.getKeys(false);
keys.forEach(key -> this.bounties.put(UUID.fromString(key), bountiesConfig.getDouble(key)));
// Load bounties
Set<String> keys = bountiesConfig.getKeys(false);
for (String key: keys) {
try {
this.bounties.put(UUID.fromString(key), bountiesConfig.getInt(key));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public ConcurrentHashMap<UUID, Double> getBounties() {
public ConcurrentHashMap<UUID, Integer> getBounties() {
return this.bounties;
}
public boolean hasBounty(UUID player) {
return this.bounties.containsKey(player) && this.bounties.get(player) > 0;
}
public void setBounty(UUID player, double amount) {
public void setBounty(UUID player, int amount) {
this.bounties.put(player, amount);
}
public double getBounty(UUID player) {
return this.bounties.getOrDefault(player, 0.0);
public int getBounty(UUID player) {
return this.bounties.getOrDefault(player, 0);
}
public void removeBounty(UUID player) {
this.bounties.remove(player);
}
public void saveBounties() {
synchronized (this.savingFileLock) {
final Set<String> keys = bountiesConfig.getKeys(false);
keys.forEach(key -> bountiesConfig.set(key, null));
this.bounties.entrySet()
.forEach(entry -> this.bountiesConfig.set(entry.getKey().toString(), entry.getValue()));
try {
this.bountiesConfig.save(this.bountiesFile);
} catch (IOException ioException) {
this.plugin.getLogger().log(Level.SEVERE,
"Failed to save bounties file: " + this.bountiesFile.getPath(), ioException);
// Clear existing
Set<String> keys = bountiesConfig.getKeys(false);
for (String key : keys) {
bountiesConfig.set(key, null);
}
}
// Write changes
for (Map.Entry<UUID, Integer> entry : this.bounties.entrySet()) {
this.bountiesConfig.set(entry.getKey().toString(), entry.getValue());
}
// Save to file
try {
this.bountiesConfig.save(this.bountiesFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void saveBountiesAsync() {
if (!this.savingAsync.compareAndSet(false, true)) {
return;
// Wait until the previous save is done
while (this.savingAsync.getAndSet(true)) {
try {
synchronized (this.savingAsync) {
this.savingAsync.wait();
}
} catch (InterruptedException ignored) {}
}
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
try {
this.saveBounties();
} finally {
this.savingAsync.set(false);
// Save
this.plugin.getFoliaLib().getScheduler().runAsync(wt -> {
this.saveBounties();
this.savingAsync.set(false);
synchronized (this.savingAsync) {
this.savingAsync.notifyAll();
}
});
}
}
}
@@ -1,8 +0,0 @@
package com.tcoded.playerbountiesplus.util;
import java.util.UUID;
public record BountyHeadData(UUID targetUuid, String targetName, double bountyAmount, UUID claimantUuid,
String claimantName)
{
}
@@ -1,249 +0,0 @@
package com.tcoded.playerbountiesplus.util;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.inventory.meta.SkullMeta;
import com.destroystokyo.paper.profile.PlayerProfile;
import net.kyori.adventure.text.TextComponent;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.cacheddata.CachedMetaData;
import net.luckperms.api.model.user.User;
import net.luckperms.api.model.user.UserManager;
import net.trueog.diamondbankog.api.DiamondBankAPIJava;
import net.trueog.utilitiesog.UtilitiesOG;
public final class BountyHeadFormatter {
// LuckPerms data for offline players is not in memory, so we load it async
// and cache the resolved display string. Entries expire so rank changes get
// picked up without requiring a server restart.
private static final long DISPLAY_CACHE_TTL_MILLIS = 5L * 60L * 1000L;
private final DiamondBankAPIJava diamondBankAPI;
private final LuckPerms luckPerms;
private final Map<UUID, CachedDisplay> offlineDisplayCache = new ConcurrentHashMap<>();
private final Map<UUID, Boolean> offlineLoadsInFlight = new ConcurrentHashMap<>();
public BountyHeadFormatter(DiamondBankAPIJava diamondBankAPI, LuckPerms luckPerms) {
this.diamondBankAPI = diamondBankAPI;
this.luckPerms = luckPerms;
}
public void applyHeadMeta(SkullMeta meta, BountyHeadData data, PlayerProfile profile, BountyHeadMetadata metadata) {
if (profile != null) {
meta.setPlayerProfile(profile);
}
meta.displayName(buildCanonicalLine(data));
metadata.write(meta.getPersistentDataContainer(), data);
}
public TextComponent buildCanonicalLine(BountyHeadData data) {
return UtilitiesOG.trueogColorize(resolvePlayerDisplay(data.targetUuid(), data.targetName()) + " &cslain by "
+ resolveClaimantDisplay(data) + " &cfor a bounty of &b" + formatDiamonds(data.bountyAmount())
+ " &bDiamonds");
}
public TextComponent buildCanonicalLineTop(BountyHeadData data) {
return UtilitiesOG.trueogColorize(resolvePlayerDisplay(data.targetUuid(), data.targetName()) + " &cslain by "
+ resolveClaimantDisplay(data));
}
public TextComponent buildCanonicalLineBottom(BountyHeadData data) {
return UtilitiesOG.trueogColorize("&cfor a bounty of &b" + formatDiamonds(data.bountyAmount()) + " &bDiamonds");
}
public String resolveClaimantDisplay(BountyHeadData data) {
if (data == null) {
return "&fUnknown";
}
return resolvePlayerDisplay(data.claimantUuid(), data.claimantName());
}
public String resolvePlayerDisplay(UUID targetUuid, String fallbackName) {
final String playerName = StringUtils.defaultIfBlank(fallbackName, "Unknown Player");
if (targetUuid == null || luckPerms == null) {
return "&f" + playerName;
}
final User loadedUser = luckPerms.getUserManager().getUser(targetUuid);
if (loadedUser != null) {
return formatFromUser(loadedUser, playerName);
}
final CachedDisplay cached = offlineDisplayCache.get(targetUuid);
if (cached != null && !cached.isExpired()) {
return cached.display();
}
scheduleOfflineUserLoad(targetUuid, playerName);
return cached != null ? cached.display() : "&f" + playerName;
}
private void scheduleOfflineUserLoad(UUID targetUuid, String playerName) {
if (luckPerms == null) {
return;
}
if (offlineLoadsInFlight.putIfAbsent(targetUuid, Boolean.TRUE) != null) {
return;
}
final UserManager userManager = luckPerms.getUserManager();
userManager.loadUser(targetUuid).whenComplete((user, throwable) -> {
try {
if (user == null) {
return;
}
final String display = formatFromUser(user, playerName);
offlineDisplayCache.put(targetUuid,
new CachedDisplay(display, System.currentTimeMillis() + DISPLAY_CACHE_TTL_MILLIS));
// LuckPerms keeps loaded users resident until explicitly released.
// Release only when the UUID is not currently online so we do not
// evict live data another system may depend on.
if (Bukkit.getPlayer(targetUuid) == null) {
userManager.cleanupUser(user);
}
} finally {
offlineLoadsInFlight.remove(targetUuid);
}
});
}
private String formatFromUser(User user, String playerName) {
final CachedMetaData meta = user.getCachedData().getMetaData();
final String prefix = StringUtils.trim(StringUtils.defaultString(meta.getPrefix()).replace('§', '&'));
final String suffix = StringUtils.trim(StringUtils.defaultString(meta.getSuffix()).replace('§', '&'));
final boolean metaContainsName = containsVisibleName(prefix, playerName)
|| containsVisibleName(suffix, playerName);
final StringBuilder out = new StringBuilder();
if (!prefix.isBlank()) {
out.append(prefix).append(' ');
}
if (!metaContainsName) {
out.append(playerName);
}
if (!suffix.isBlank()) {
out.append(' ').append(suffix);
}
return sanitizeDisplay(out.toString(), playerName);
}
public String formatDiamonds(double diamonds) {
if (diamondBankAPI == null) {
return String.valueOf(diamonds);
}
try {
return diamondBankAPI.shardsToDiamonds(diamondBankAPI.diamondsToShards(diamonds));
} catch (RuntimeException runtimeException) {
return String.valueOf(diamonds);
}
}
private static String sanitizeDisplay(String formatted, String fallbackName) {
final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:<reset>|[&§]r))+$", "")
.replaceAll("\\s*>$", "");
return cleaned.isBlank() ? fallbackName : cleaned;
}
private static boolean containsVisibleName(String text, String playerName) {
if (text == null || playerName == null || playerName.isBlank()) {
return false;
}
final String normalizedText = StringUtils.lowerCase(UtilitiesOG.stripFormatting(text), Locale.ROOT);
final String normalizedName = StringUtils.lowerCase(playerName, Locale.ROOT);
return StringUtils.contains(normalizedText, normalizedName);
}
private record CachedDisplay(String display, long expiresAtMillis) {
boolean isExpired() {
return System.currentTimeMillis() >= expiresAtMillis;
}
}
}
@@ -1,96 +0,0 @@
package com.tcoded.playerbountiesplus.util;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.NamespacedKey;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
import com.tcoded.playerbountiesplus.listener.DeathListener;
public final class BountyHeadMetadata {
private final NamespacedKey targetKey;
private final NamespacedKey targetUuidKey;
private final NamespacedKey amountKey;
private final NamespacedKey claimantKey;
private final NamespacedKey claimantUuidKey;
public BountyHeadMetadata(PlayerBountiesOG plugin) {
this.targetKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_NAME_KEY);
this.targetUuidKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_UUID_KEY);
this.amountKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_AMOUNT_KEY);
this.claimantKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_CLAIMANT_KEY);
this.claimantUuidKey = new NamespacedKey(plugin, DeathListener.BOUNTY_HEAD_CLAIMANT_UUID_KEY);
}
public BountyHeadData read(PersistentDataContainer dataContainer) {
final String targetName = dataContainer.get(targetKey, PersistentDataType.STRING);
final String targetUuid = dataContainer.get(targetUuidKey, PersistentDataType.STRING);
final Double bountyAmount = dataContainer.get(amountKey, PersistentDataType.DOUBLE);
final String claimantName = dataContainer.get(claimantKey, PersistentDataType.STRING);
final String claimantUuid = dataContainer.get(claimantUuidKey, PersistentDataType.STRING);
if (StringUtils.isBlank(targetName) || StringUtils.isBlank(targetUuid) || bountyAmount == null) {
return null;
}
try {
return new BountyHeadData(UUID.fromString(targetUuid), targetName, bountyAmount,
parseOptionalUuid(claimantUuid), claimantName);
} catch (IllegalArgumentException ignored) {
return null;
}
}
public void write(PersistentDataContainer dataContainer, BountyHeadData data) {
dataContainer.set(targetKey, PersistentDataType.STRING, data.targetName());
dataContainer.set(targetUuidKey, PersistentDataType.STRING, data.targetUuid().toString());
dataContainer.set(amountKey, PersistentDataType.DOUBLE, data.bountyAmount());
if (StringUtils.isBlank(data.claimantName()) || data.claimantUuid() == null) {
dataContainer.remove(claimantKey);
dataContainer.remove(claimantUuidKey);
return;
}
dataContainer.set(claimantKey, PersistentDataType.STRING, data.claimantName());
dataContainer.set(claimantUuidKey, PersistentDataType.STRING, data.claimantUuid().toString());
}
private static UUID parseOptionalUuid(String value) {
if (StringUtils.isBlank(value)) {
return null;
}
try {
return UUID.fromString(value);
} catch (IllegalArgumentException ignored) {
return null;
}
}
}
@@ -1,65 +0,0 @@
package com.tcoded.playerbountiesplus.util;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.World;
import org.bukkit.entity.Player;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
public final class BountyWorldUtil {
private static final String BOUNTY_WORLD_WHITELIST_KEY = "bounty-world-whitelist";
private static final List<String> DEFAULT_BOUNTY_WORLD_WHITELIST = List.of("world", "world_nether",
"world_the_end");
private BountyWorldUtil() {
}
public static boolean isBountyWorldAllowed(PlayerBountiesOG plugin, Player player) {
return player != null && isBountyWorldAllowed(plugin, player.getWorld());
}
public static boolean isBountyWorldAllowed(PlayerBountiesOG plugin, World world) {
return world != null && isBountyWorldAllowed(plugin, world.getName());
}
public static boolean isBountyWorldAllowed(PlayerBountiesOG plugin, String worldName) {
final List<String> worldWhitelist = getBountyWorldWhitelist(plugin);
final boolean hasConfiguredWorld = worldWhitelist.stream().anyMatch(world -> !StringUtils.isBlank(world));
return !hasConfiguredWorld || worldWhitelist.stream()
.anyMatch(world -> StringUtils.equalsIgnoreCase(StringUtils.trim(world), worldName));
}
public static String formatBountyWorldWhitelist(PlayerBountiesOG plugin) {
final List<String> worldWhitelist = getBountyWorldWhitelist(plugin).stream().map(StringUtils::trimToEmpty)
.filter(StringUtils::isNotBlank).collect(Collectors.toList());
return worldWhitelist.isEmpty() ? "every world" : StringUtils.join(worldWhitelist, ", ");
}
private static List<String> getBountyWorldWhitelist(PlayerBountiesOG plugin) {
if (plugin.getConfig().contains(BOUNTY_WORLD_WHITELIST_KEY)) {
return plugin.getConfig().getStringList(BOUNTY_WORLD_WHITELIST_KEY);
}
return DEFAULT_BOUNTY_WORLD_WHITELIST;
}
}
@@ -1,221 +1,109 @@
package com.tcoded.playerbountiesplus.util;
import com.tcoded.legacycolorcodeparser.LegacyColorCodeParser;
import com.tcoded.playerbountiesplus.PlayerBountiesPlus;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import com.tcoded.playerbountiesplus.PlayerBountiesOG;
public class LangUtil {
private static final String DEFAULT_LANG_CODE = "en_us";
private final PlayerBountiesOG plugin;
private final Logger logger;
private final PlayerBountiesPlus plugin;
private final File overrideMessagesFile;
private final FileConfiguration messages;
private final String lang;
private final boolean customLang;
public enum SupportedLang {
DE_DE, EN_GB, EN_US, EN_UWU, ES_ES, FR_FR, HI_IN, HU_HU, IT_IT, NL_NL, RU_RU, SE_SE, ZH_CN;
DE_DE,
EN_GB,
EN_US,
EN_UWU,
ES_ES,
FR_FR,
HI_IN,
HU_HU,
IT_IT,
NL_NL,
RU_RU,
SE_SE,
ZH_CN,
;
public static SupportedLang find(String name) {
if (name == null || name.isBlank()) {
return null;
}
for (SupportedLang lang : SupportedLang.values()) {
if (StringUtils.equalsIgnoreCase(lang.name(), name)) {
return lang;
}
if (lang.name().equals(name)) return EN_US;
}
return null;
}
public String fileName() {
return StringUtils.lowerCase(this.name(), Locale.ROOT) + ".yml";
}
}
public LangUtil(PlayerBountiesOG plugin, String configuredLang) {
public LangUtil(PlayerBountiesPlus plugin, String lang) {
this.plugin = plugin;
this.logger = plugin.getLogger();
this.lang = lang;
Logger logger = this.plugin.getLogger();
final SupportedLang resolvedLang = resolveSupportedLang(configuredLang);
this.lang = StringUtils.lowerCase(resolvedLang.name(), Locale.ROOT);
// for (SupportedLang tmpLang : SupportedLang.values()) {
// plugin.saveResource("lang/" + tmpLang.name().toLowerCase() + ".yml", false);
// }
final String englishFilePath = "lang/" + SupportedLang.EN_US.fileName();
final String langFilePath = "lang/" + resolvedLang.fileName();
// Resolve the path of the lang files we're going to use
String englishFilePath = "lang/" + SupportedLang.EN_US.name().toLowerCase() + ".yml";
String langFilePath = "lang/" + lang + ".yml";
final FileConfiguration englishDefaults = loadBundledYaml(englishFilePath, true);
final FileConfiguration selectedLangDefaults = resolvedLang == SupportedLang.EN_US ? englishDefaults
: loadBundledYaml(langFilePath, false);
if (resolvedLang != SupportedLang.EN_US) {
selectedLangDefaults.setDefaults(englishDefaults);
// Load internal default English file - Worst case scenario fallback
InputStream internalEnglishDefaultFile = plugin.getResource(englishFilePath);
if (internalEnglishDefaultFile == null) throw new IllegalStateException("Internal default English file could not be found!");
FileConfiguration englishDefaults = YamlConfiguration.loadConfiguration(new InputStreamReader(internalEnglishDefaultFile));
// Check if language is supported
SupportedLang supportedLang = SupportedLang.find(lang.toUpperCase());
if (supportedLang == null) {
logger.severe(String.format("Unsupported language was found: %s!", lang));
logger.info("You can contribute new languages by following the instructions at the top of the config.yml file :)");
throw new IllegalStateException("Unsupported language in config.yml");
}
// Load user-specified internal language file
InputStream internalLangFile = plugin.getResource(langFilePath);
if (internalLangFile == null) throw new IllegalStateException(String.format("Internal language file could not be found! (Lang: %s)", lang));
FileConfiguration defaults = YamlConfiguration.loadConfiguration(new InputStreamReader(internalLangFile));
defaults.setDefaults(englishDefaults);
// Check if the user has created an override language file
this.overrideMessagesFile = new File(plugin.getDataFolder(), langFilePath);
if (this.overrideMessagesFile.exists()) {
logger.warning(String.format("Using custom override language file for language: %s", lang));
this.messages = YamlConfiguration.loadConfiguration(this.overrideMessagesFile);
this.messages.setDefaults(selectedLangDefaults);
this.messages.setDefaults(defaults);
this.customLang = true;
this.logger.warning("Using custom override language file: " + this.overrideMessagesFile.getPath());
} else {
this.messages = selectedLangDefaults;
this.messages = defaults;
this.customLang = false;
}
}
private SupportedLang resolveSupportedLang(String configuredLang) {
final String normalized = configuredLang == null ? DEFAULT_LANG_CODE
: StringUtils.upperCase(StringUtils.trim(configuredLang), Locale.ROOT);
final SupportedLang supportedLang = SupportedLang.find(normalized);
if (supportedLang != null) {
return supportedLang;
}
this.logger.warning("Unsupported language in config.yml: " + configuredLang + ". Falling back to "
+ DEFAULT_LANG_CODE + ".");
this.logger.info("You can contribute new languages by following the instructions at the top of config.yml.");
return SupportedLang.EN_US;
}
private FileConfiguration loadBundledYaml(String path, boolean required) {
final InputStream resource = this.plugin.getResource(path);
if (resource == null) {
if (required) {
throw new IllegalStateException("Required bundled language file could not be found: " + path);
}
this.logger.warning("Bundled language file not found: " + path + ". Falling back to English.");
return new YamlConfiguration();
}
final InputStream input = resource;
final InputStreamReader reader = new InputStreamReader(input, StandardCharsets.UTF_8);
return YamlConfiguration.loadConfiguration(reader);
public String get(String key) {
if (this.messages == null) return "STARTUP-ERROR-CONTACT-DEV";
return this.messages.getString(key);
}
public String getColored(String key) {
if (key == null || key.isBlank()) {
return "";
}
final String value = this.messages.getString(key);
if (value != null) {
return value;
}
this.logger.warning("Missing language key: " + key + " (lang=" + this.lang + ")");
return key;
}
public List<String> getColoredList(String key) {
if (key == null || key.isBlank()) {
return Collections.emptyList();
}
if (!this.messages.contains(key)) {
this.logger.warning("Missing language list key: " + key + " (lang=" + this.lang + ")");
return List.of(key);
}
final List<String> values = this.messages.getStringList(key);
if (values == null || values.isEmpty()) {
return Collections.emptyList();
}
return new ArrayList<>(values);
}
public boolean contains(String key) {
return this.messages.contains(key);
String text = this.get(key);
text = LegacyColorCodeParser.convertHexToLegacy('&', text);
return ChatColor.translateAlternateColorCodes('&', text);
}
public String getLang() {
return this.lang;
return lang;
}
public boolean isCustomLang() {
return this.customLang;
return customLang;
}
public File getOverrideMessagesFile() {
return this.overrideMessagesFile;
}
}
}
+11 -28
View File
@@ -1,4 +1,7 @@
# PlayerBounties-OG Config File.
# We currently only support a few languages, but please contribute your own translations!
# To contribute new languages, please join our Discord server or open a pull request on GitHub!
# You can find both of these links on the plugin download page: https://www.spigotmc.org/resources/player-bounties-plus.108637/
#
# Manually verified translations:
# de_de - German (Germany)
# en_us - English (US)
@@ -10,52 +13,32 @@
# es_es - Spanish (Spain)
# hi_in - Hindi (India)
# hu_hu - Hungarian (Hungary)
# it_it - Italian (Italy)
# ru_ru - Russian (Russia)
# se_se - Swedish (Sweden)
# zh_cn - Chinese (China)
# en_uwu - English (Don't ask)
lang: "en_us"
# Add more money on the victim player than the command sender spends.
# For example: /bounty set TechnicallyCoded 100 -> turns into a bounty of 200 while only taking 100 from the sender.
# Add more money on the victim player than the command sender spends
# For example: /bounty set TechnicallyCoded 100 -> turns into a bounty of 200 while only taking 100 from the sender
bounty-multiplier: 1.0
# Minimum and maximum bounty amount - These values are checked BEFORE the multiplier above is applied.
bounty-minimum: 1.0
bounty-maximum: 1000000.0
# If we should give the bounty money to the killer.
# If we should give the bounty money to the killer
bounty-claimable: true
# Worlds where players may set, add to, and claim bounties.
# Leave empty to allow bounty placement and claims in every world. World names are case-insensitive.
bounty-world-whitelist: ["world", "world_nether", "world_the_end"]
# Give more or less money to the killer. This value can be negative if you want to.
bounty-claim-multiplier: 1.0
# If we should announce that the bounty was claimed.
# If we should announce that the bounty was claimed
bounty-claimed-announce: true
# Worlds whose players should receive bounty claim and beheading announcements.
# Leave empty to announce to players in every world. World names are case-insensitive.
bounty-claimed-announce-world-whitelist: ["world", "world_nether", "world_the_end"]
# Chance (0-100) that claiming a bounty drops the victim's player head.
bounty-head-drop-chance: 50.0
# How placed bounty heads should display extra labels.
# none = disabled
# hover = show a temporary floating label while a player aims at the head
bounty-head-label-mode: hover
# Maximum range in blocks for detecting a looked-at bounty head.
bounty-head-label-range: 8.0
# If we should announce that the bounty was placed.
# If we should announce that the bounty was placed
bounty-placed-announce: true
# Should the bounty money be taken from the player who dies?
# This can reduce same-team killing (or the use of alts) to claim the bounty from themselves.
bounty-take-from-victim: false
# This can reduce same-team killing (or the use of alts) to claim the bounty from themselves
bounty-take-from-victim: false
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aDer Spieler, den du getötet hast, hat eine aktive Belohnung, aber du bist im selben Team wie er!"
announce-claimed: "&4&l{killer} hat die Belohnung von {victim} im Wert von ${bounty} beansprucht"
no-permission: "&cSie dürfen keine Kopfgelder beanspruchen!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aThe player you killed has an active bounty but you are in the same team as they are!"
announce-claimed: "&4&l{killer} claimed {victim}'s bounty worth ${bounty}"
no-permission: "&cYou are not allowed to claim bounties!"
command:
+4 -13
View File
@@ -1,7 +1,7 @@
death:
same-team: "&aThe player you killed has an active bounty but you are in the same team as they are!"
announce-claimed: "&4&l{killer} claimed {victim}'s bounty worth ${bounty}"
no-permission: "&cYou are not allowed to claim bounties!"
world-not-whitelisted: "&cYou can only claim bounties in these worlds: {worlds}."
command:
no-permission: "&cYou don't have the permission to use this command!"
@@ -36,9 +36,8 @@ command:
player-not-found: "&cThat player is not online or doesn't exist!"
success: "&a{target} currently has a bounty of {bounty}."
bounty:
no-action: "&cYou need to specify an action! /bounty <set/add/top/check>"
no-action: "&cYou need to specify an action! /bounty <set/top/check>"
invalid-action: "&cThat's not a valid action!"
world-not-whitelisted: "&cYou can only set or increase bounties in these worlds: {worlds}."
set:
missing-args: "&cYou need to specify a player and an amount! /bounty set <player> <amount>"
amount-nan: "&cThat's not a valid number!"
@@ -48,17 +47,8 @@ command:
not-enough-money: "&cYou don't have enough money for that!"
internal-invalid-value: "&cAn invalid value was reached during internal processing. Please report this to an administrator!"
success: "&cYou placed a bounty of {bounty} on {target}'s head!"
announce: "\nA bounty of {bounty} was placed on {target}'s &ahead by&r {player}!{extra}\n"
announce: "\nA bounty of {bounty} was placed on {target}'s head by {player}!{extra}\n"
announce-extra: " (Total: {total})"
cancelled: "&cBounty placement was cancelled."
add:
missing-args: "&cYou need to specify a player and an amount! /bounty add <player> <amount>"
amount-nan: "&cThat's not a valid number!"
player-not-found: "&cThat player could not be found!"
success: "&aYou increased {target}'s bounty by {amount}. Total: {total}."
announce: "\n{player} increased {target}'s bounty by {amount}&a! &7(Total: &b{total}&7)\n"
prompt: "&eType how many diamonds to add to {target}'s bounty in chat. Type &ccancel &eto abort."
cancelled: "&cBounty increase cancelled."
check:
no-player-specified: "&cYou need to specify a player! /bounty check <player>"
player-not-found: "&cThat player is not online or doesn't exist!"
@@ -71,3 +61,4 @@ command:
gui:
main:
title: "&eBounties"
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aDa pwayer you kiwwed has an active bounty but you awe in da same team as they awe!"
announce-claimed: "&4&w{killer} cwaimed {victim}'s bounty wowth ${bounty}"
no-permission: "&cYou awe nyot awwowed to cwaim bounties!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aEl jugador que mataste tiene una recompensa activa pero estás en el mismo equipo que él."
announce-claimed: "&4&l{killer} reclamó la recompensa de {victim} valorada en ${bounty}"
no-permission: "&c¡No se le permite reclamar recompensas!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aLe joueur que vous avez tué a une prime sur sa tête mais vous êtes dans la même équipe!"
announce-claimed: "&4&l{killer} a gagné la prime de {victim} au prix de ${bounty}"
no-permission: "&cVous n'êtes pas autorisé à réclamer des primes!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aवह खिलाड़ी जिसे आपने मार डाला है, उसके पास एक सक्रिय इनाम है, लेकिन आप उनकी टीम में हैं!"
announce-claimed: "&4&l{killer} ने {victim} के इनाम {bounty} को मांग लिया"
no-permission: "&cआपको इनामों का दावा करने की अनुमति नहीं है!"
command:
+1
View File
@@ -4,6 +4,7 @@
death:
same-team: "&aA játékos, akit megöltél, aktív fejpénzt volt a fején, de ugyanabba a csapatba tartozol, mint ő!"
announce-claimed: "&4&l{killer} behajtotta {victim} fejpénzét és megkapta jutalmát aminek értéke: ${bounty}"
no-permission: "&cNem igényelheted a fejpénzeket!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aIl giocatore che hai ucciso ha una taglia attiva, ma sei nella stessa squadra!"
announce-claimed: "&4&l{killer} ha reclamato la taglia di {victim} del valore di ${bounty}"
no-permission: "&cNon ti è permesso riscuotere le taglie!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aDe speler die je hebt gedood heeft een actieve beloning, maar je zit in hetzelfde team als zij!"
announce-claimed: "&4&l{killer} heeft de beloning van {victim} ter waarde van ${bounty} geclaimd"
no-permission: "&cU mag geen premies claimen!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aИгрок, которого вы убили, имеет активную награду, но вы находитесь в одной команде с ними!"
announce-claimed: "&4&l{killer} получил награду {victim} на сумму ${bounty}"
no-permission: "&cВам не разрешено требовать наград!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&aDen spelare du dödade har en aktiv prissumma, men du tillhör samma lag som de är!"
announce-claimed: "&4&l{killer} har tagit {victim}s prissumma värd {bounty} dollar"
no-permission: "&cDu får inte hämta in prissummor!"
command:
+1
View File
@@ -1,5 +1,6 @@
death:
same-team: "&a你击杀的玩家有悬赏,但你与他们在同一队伍中!"
announce-claimed: "&4&l{killer} 已领取 {victim} 的悬赏,价值 ${bounty}"
no-permission: "&c你没有权限领取悬赏!"
command:
+25 -27
View File
@@ -1,44 +1,42 @@
name: PlayerBounties-OG
version: '${version}'
main: com.tcoded.playerbountiesplus.PlayerBountiesOG
api-version: '${apiVersion}'
authors: [ TechnicallyCoded, NotAlexNoyle ]
description: A player bounty plugin for TrueOG Network using our custom Diamond Economy.
website: https://git.trueog.net/trueog/PlayerBounties-OG/
folia-supported: false
name: PlayerBountiesPlus
version: '${project.version}'
main: com.tcoded.playerbountiesplus.PlayerBountiesPlus
api-version: 1.13
authors: [ TechnicallyCoded ]
description: Claim bounties only if you are not on the same clan
website: https://tcoded.com
folia-supported: true
depend:
- DiamondBank-OG
- CoreProtect-OG
- Vault
softdepend:
- ClansLite
- Parties
- BetterTeams
- SimpleClans
- Unions-OG
- LuckPerms
- Towny
commands:
bounty:
permission: playerbountiesog.command.bounty
permission: playerbountiesplus.command.bounty
aliases: [bounties, prime, primes]
playerbountiesplusadmin:
permission: playerbountiesog.command.admin
permission: playerbountiesplus.command.admin
aliases: [playerbountiesplus, pbpa, pbp]
permissions:
playerbountiesog.command.bounty:
playerbountiesplus.command.bounty:
default: true
playerbountiesog.command.admin:
playerbountiesplus.command.admin:
default: op
children:
playerbountiesog.command.admin.version: {}
playerbountiesog.command.admin.reload: {}
playerbountiesog.command.admin.bounty.set: {}
playerbountiesog.command.admin.bounty.add: {}
playerbountiesog.command.admin.bounty.remove: {}
playerbountiesog.command.admin.bounty.delete: {}
playerbountiesog.command.admin.bounty.get: {}
playerbountiesog.command.bounty.set:
playerbountiesplus.command.admin.version: {}
playerbountiesplus.command.admin.reload: {}
playerbountiesplus.command.admin.bounty.set: {}
playerbountiesplus.command.admin.bounty.add: {}
playerbountiesplus.command.admin.bounty.remove: {}
playerbountiesplus.command.admin.bounty.delete: {}
playerbountiesplus.command.bounty.set:
default: true
playerbountiesog.command.bounty.add:
default: true
playerbountiesog.event.claim:
playerbountiesplus.event.claim:
default: true