mirror of
https://github.com/PlaceholderAPI/PlaceholderAPI
synced 2026-02-04 23:53:20 +01:00
A fresh start
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@
|
|||||||
server/
|
server/
|
||||||
build/
|
build/
|
||||||
out/
|
out/
|
||||||
*.iml
|
*.iml
|
||||||
|
libs/
|
||||||
172
build.gradle.kts
172
build.gradle.kts
@@ -3,191 +3,29 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
|||||||
plugins {
|
plugins {
|
||||||
`java-library`
|
`java-library`
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
// id("com.github.hierynomus.license") version "0.16.1"
|
|
||||||
id("io.github.goooler.shadow") version "8.1.7"
|
id("io.github.goooler.shadow") version "8.1.7"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "me.clip"
|
group = "at.helpch"
|
||||||
version = "2.12.0-DEV-${System.getProperty("BUILD_NUMBER")}"
|
version = "1.0.0"
|
||||||
|
|
||||||
description = "An awesome placeholder provider!"
|
description = "An awesome placeholder provider!"
|
||||||
|
|
||||||
val paper by sourceSets.creating {
|
|
||||||
java.srcDir("src/paper/java")
|
|
||||||
|
|
||||||
// paper can see main code
|
|
||||||
compileClasspath += sourceSets.main.get().output
|
|
||||||
runtimeClasspath += output + compileClasspath
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven("https://oss.sonatype.org/content/repositories/snapshots/")
|
|
||||||
|
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
|
|
||||||
maven("https://repo.codemc.org/repository/maven-public/")
|
|
||||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
|
||||||
maven("https://repo.papermc.io/repository/maven-public/")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.bstats:bstats-bukkit:3.1.0")
|
// compileOnly files("libs/HytaleServer.jar")
|
||||||
implementation("net.kyori:adventure-platform-bukkit:4.4.1")
|
|
||||||
|
|
||||||
add(paper.compileOnlyConfigurationName, "net.kyori:adventure-platform-bukkit:4.4.1")
|
|
||||||
add(paper.compileOnlyConfigurationName, "dev.folia:folia-api:1.21.11-R0.1-SNAPSHOT")
|
|
||||||
|
|
||||||
compileOnly("dev.folia:folia-api:1.21.11-R0.1-SNAPSHOT")
|
|
||||||
compileOnlyApi("org.jetbrains:annotations:23.0.0")
|
|
||||||
|
|
||||||
testImplementation("org.openjdk.jmh:jmh-core:1.32")
|
|
||||||
testImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.32")
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
|
||||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_25
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_25
|
||||||
|
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
|
|
||||||
disableAutoTargetJvm()
|
disableAutoTargetJvm()
|
||||||
}
|
|
||||||
|
|
||||||
val javaComponent: SoftwareComponent = components["java"]
|
|
||||||
|
|
||||||
tasks {
|
|
||||||
processResources {
|
|
||||||
eachFile { expand("version" to project.version) }
|
|
||||||
}
|
|
||||||
|
|
||||||
build {
|
|
||||||
dependsOn(named("shadowJar"))
|
|
||||||
}
|
|
||||||
|
|
||||||
register<JavaCompile>("compilePaper") {
|
|
||||||
source = paper.java
|
|
||||||
classpath = paper.compileClasspath
|
|
||||||
destinationDirectory.set(layout.buildDirectory.dir("classes/java/paper"))
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
options.release = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
val plainJar by registering(Jar::class) {
|
|
||||||
dependsOn("compilePaper")
|
|
||||||
|
|
||||||
archiveClassifier.set("plain")
|
|
||||||
from(sourceSets.main.get().output)
|
|
||||||
from(paper.output)
|
|
||||||
}
|
|
||||||
|
|
||||||
val combinedSourcesJar by registering(Jar::class) {
|
|
||||||
archiveClassifier.set("sources")
|
|
||||||
from(sourceSets.main.get().allSource)
|
|
||||||
from(paper.allSource)
|
|
||||||
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
}
|
|
||||||
|
|
||||||
val combinedJavadoc by registering(Javadoc::class) {
|
|
||||||
isFailOnError = false
|
|
||||||
|
|
||||||
source = sourceSets.main.get().allJava + paper.allJava
|
|
||||||
classpath = sourceSets.main.get().compileClasspath + paper.compileClasspath
|
|
||||||
|
|
||||||
with(options as StandardJavadocDocletOptions) {
|
|
||||||
addStringOption("Xdoclint:none", "-quiet")
|
|
||||||
addStringOption("encoding", "UTF-8")
|
|
||||||
addStringOption("charSet", "UTF-8")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val combinedJavadocJar by registering(Jar::class) {
|
|
||||||
archiveClassifier.set("javadoc")
|
|
||||||
dependsOn(combinedJavadoc)
|
|
||||||
from(combinedJavadoc.get().destinationDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
withType<JavaCompile> {
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
options.release = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
withType<ShadowJar> {
|
|
||||||
configurations = listOf(project.configurations.runtimeClasspath.get())
|
|
||||||
|
|
||||||
from(sourceSets.main.get().output)
|
|
||||||
|
|
||||||
archiveClassifier.set("")
|
|
||||||
|
|
||||||
relocate("org.bstats", "me.clip.placeholderapi.metrics")
|
|
||||||
relocate("net.kyori", "me.clip.placeholderapi.libs.kyori")
|
|
||||||
|
|
||||||
exclude("META-INF/versions/**")
|
|
||||||
|
|
||||||
dependsOn("compilePaper")
|
|
||||||
|
|
||||||
doLast {
|
|
||||||
val paperDir = layout.buildDirectory.dir("classes/java/paper").get().asFile
|
|
||||||
val jarFile = archiveFile.get().asFile
|
|
||||||
|
|
||||||
ant.invokeMethod("zip", mapOf(
|
|
||||||
"destfile" to jarFile,
|
|
||||||
"update" to "true",
|
|
||||||
"basedir" to paperDir
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
create<MavenPublication>("maven") {
|
|
||||||
artifactId = "placeholderapi"
|
|
||||||
|
|
||||||
artifact(plainJar) {
|
|
||||||
builtBy(plainJar)
|
|
||||||
classifier = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
artifact(combinedSourcesJar) {
|
|
||||||
builtBy(combinedSourcesJar)
|
|
||||||
}
|
|
||||||
|
|
||||||
artifact(combinedJavadocJar) {
|
|
||||||
builtBy(combinedJavadocJar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
if ("-DEV" in version.toString()) {
|
|
||||||
url = uri("https://repo.extendedclip.com/snapshots")
|
|
||||||
} else {
|
|
||||||
url = uri("https://repo.extendedclip.com/releases")
|
|
||||||
}
|
|
||||||
|
|
||||||
credentials {
|
|
||||||
username = System.getenv("JENKINS_USER")
|
|
||||||
password = System.getenv("JENKINS_PASS")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publish.get().setDependsOn(listOf(build.get()))
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
testImplementation {
|
|
||||||
extendsFrom(compileOnly.get())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -1,606 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.expansion.Relational;
|
|
||||||
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
|
|
||||||
import me.clip.placeholderapi.replacer.CharsReplacer;
|
|
||||||
import me.clip.placeholderapi.replacer.Replacer;
|
|
||||||
import me.clip.placeholderapi.replacer.Replacer.Closure;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public final class PlaceholderAPI {
|
|
||||||
|
|
||||||
private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT);
|
|
||||||
private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET);
|
|
||||||
|
|
||||||
static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
|
|
||||||
static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
|
|
||||||
static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern
|
|
||||||
.compile("[%](rel_)([^%]+)[%]");
|
|
||||||
|
|
||||||
|
|
||||||
private PlaceholderAPI() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Current API ===
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text Text to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static String setPlaceholders(final OfflinePlayer player,
|
|
||||||
@NotNull final String text) {
|
|
||||||
return REPLACER_PERCENT.apply(text, player,
|
|
||||||
PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text List of Strings to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static List<String> setPlaceholders(final OfflinePlayer player,
|
|
||||||
@NotNull final List<String> text) {
|
|
||||||
return text.stream().map(line -> setPlaceholders(player, line)).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text Text to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static String setPlaceholders(final Player player, @NotNull String text) {
|
|
||||||
return setPlaceholders(((OfflinePlayer) player), text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal %<identifier>_<params>%}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text List of Strings to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static List<String> setPlaceholders(final Player player, @NotNull List<@NotNull String> text) {
|
|
||||||
return setPlaceholders(((OfflinePlayer) player), text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text Text to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static String setBracketPlaceholders(final OfflinePlayer player,
|
|
||||||
@NotNull final String text) {
|
|
||||||
return REPLACER_BRACKET.apply(text, player,
|
|
||||||
PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text List of Strings to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static List<@NotNull String> setBracketPlaceholders(final OfflinePlayer player,
|
|
||||||
@NotNull final List<@NotNull String> text) {
|
|
||||||
return text.stream().map(line -> setBracketPlaceholders(player, line))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text Text to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static String setBracketPlaceholders(Player player, @NotNull String text) {
|
|
||||||
return setBracketPlaceholders((OfflinePlayer) player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates all placeholders into their corresponding values.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal {<identifier>_<params>}}.
|
|
||||||
*
|
|
||||||
* @param player Player to parse the placeholders against
|
|
||||||
* @param text List of Strings to set the placeholder values in
|
|
||||||
* @return String containing all translated placeholders
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static List<String> setBracketPlaceholders(Player player, @NotNull List<String> text) {
|
|
||||||
return setBracketPlaceholders((OfflinePlayer) player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set relational placeholders in the text specified placeholders are matched with the pattern
|
|
||||||
* {@literal %<rel_(identifier)_(params)>%} when set with this method
|
|
||||||
*
|
|
||||||
* @param one First player to compare
|
|
||||||
* @param two Second player to compare
|
|
||||||
* @param text Text to parse the placeholders in
|
|
||||||
* @return The text containing the parsed relational placeholders
|
|
||||||
*/
|
|
||||||
public static String setRelationalPlaceholders(Player one, Player two, String text) {
|
|
||||||
final Matcher matcher = RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
|
|
||||||
|
|
||||||
while (matcher.find()) {
|
|
||||||
final String format = matcher.group(2);
|
|
||||||
final int index = format.indexOf("_");
|
|
||||||
|
|
||||||
if (index <= 0 || index >= format.length()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String identifier = format.substring(0, index).toLowerCase(Locale.ROOT);
|
|
||||||
String params = format.substring(index + 1);
|
|
||||||
final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance()
|
|
||||||
.getLocalExpansionManager().getExpansion(identifier);
|
|
||||||
|
|
||||||
if (!(expansion instanceof Relational)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String value = ((Relational) expansion).onPlaceholderRequest(one, two, params);
|
|
||||||
|
|
||||||
if (value != null) {
|
|
||||||
text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate placeholders in the provided List based on the relation of the two provided players.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<param>%}.
|
|
||||||
*
|
|
||||||
* @param one Player to compare
|
|
||||||
* @param two Player to compare
|
|
||||||
* @param text text to parse the placeholder values to
|
|
||||||
* @return The text containing the parsed relational placeholders
|
|
||||||
*/
|
|
||||||
public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text) {
|
|
||||||
return text.stream().map(line -> setRelationalPlaceholders(one, two, line))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a specific placeholder identifier is currently registered
|
|
||||||
*
|
|
||||||
* @param identifier The identifier to check
|
|
||||||
* @return true if identifier is already registered
|
|
||||||
*/
|
|
||||||
public static boolean isRegistered(@NotNull final String identifier) {
|
|
||||||
return PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()
|
|
||||||
.findExpansionByIdentifier(identifier).isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all registered placeholder identifiers
|
|
||||||
*
|
|
||||||
* @return A Set of type String containing the identifiers of all registered expansions.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static Set<String> getRegisteredIdentifiers() {
|
|
||||||
return ImmutableSet
|
|
||||||
.copyOf(PlaceholderAPIPlugin.getInstance().getLocalExpansionManager().getIdentifiers());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the normal placeholder pattern.
|
|
||||||
*
|
|
||||||
* @return Regex Pattern of {@literal [%]([^%]+)[%]}
|
|
||||||
*/
|
|
||||||
public static Pattern getPlaceholderPattern() {
|
|
||||||
return PLACEHOLDER_PATTERN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the bracket placeholder pattern.
|
|
||||||
*
|
|
||||||
* @return Regex Pattern of {@literal [{]([^{}]+)[}]}
|
|
||||||
*/
|
|
||||||
public static Pattern getBracketPlaceholderPattern() {
|
|
||||||
return BRACKET_PLACEHOLDER_PATTERN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the relational placeholder pattern.
|
|
||||||
*
|
|
||||||
* @return Regex Pattern of {@literal [%](rel_)([^%]+)[%]}
|
|
||||||
*/
|
|
||||||
public static Pattern getRelationalPlaceholderPattern() {
|
|
||||||
return RELATIONAL_PLACEHOLDER_PATTERN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a String contains any PlaceholderAPI placeholders ({@literal
|
|
||||||
* %<identifier>_<params>%}).
|
|
||||||
*
|
|
||||||
* @param text String to check
|
|
||||||
* @return true if String contains any matches to the normal placeholder pattern, false otherwise
|
|
||||||
*/
|
|
||||||
public static boolean containsPlaceholders(String text) {
|
|
||||||
return text != null && PLACEHOLDER_PATTERN.matcher(text).find();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a String contains any PlaceholderAPI bracket placeholders ({@literal
|
|
||||||
* {<identifier>_<params>}}).
|
|
||||||
*
|
|
||||||
* @param text String to check
|
|
||||||
* @return true if String contains any matches to the bracket placeholder pattern, false otherwise
|
|
||||||
*/
|
|
||||||
public static boolean containsBracketPlaceholders(String text) {
|
|
||||||
return text != null && BRACKET_PLACEHOLDER_PATTERN.matcher(text).find();
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Deprecated API ===
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static boolean registerExpansion(PlaceholderExpansion expansion) {
|
|
||||||
return expansion.register();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static boolean unregisterExpansion(PlaceholderExpansion expansion) {
|
|
||||||
return expansion.unregister();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get map of registered placeholders
|
|
||||||
*
|
|
||||||
* @return Map of registered placeholders
|
|
||||||
* @deprecated Use {@link LocalExpansionManager#getExpansions()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static Map<String, PlaceholderHook> getPlaceholders() {
|
|
||||||
return PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()
|
|
||||||
.getExpansions().stream()
|
|
||||||
.collect(Collectors.toMap(PlaceholderExpansion::getIdentifier, ex -> ex));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param plugin The Plugin to register with this {@link PlaceholderHook}
|
|
||||||
* @param placeholderHook The {@link PlaceholderHook} to register
|
|
||||||
* @return always false
|
|
||||||
* @deprecated Please use {@link PlaceholderExpansion} to
|
|
||||||
* register placeholders instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static boolean registerPlaceholderHook(Plugin plugin, PlaceholderHook placeholderHook) {
|
|
||||||
Msg.warn("Nag author(s) %s of plugin %s about their usage of the deprecated PlaceholderHook"
|
|
||||||
+ " class! This class will be removed in v2.13.0!", plugin.getDescription().getAuthors(),
|
|
||||||
plugin.getName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param identifier The identifier to use for the {@link PlaceholderHook}
|
|
||||||
* @param placeholderHook The {@link PlaceholderHook} to register
|
|
||||||
* @return always false
|
|
||||||
* @deprecated Please use {@link PlaceholderExpansion} to
|
|
||||||
* register placeholders instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static boolean registerPlaceholderHook(String identifier,
|
|
||||||
PlaceholderHook placeholderHook) {
|
|
||||||
Msg.warn("%s is attempting to register placeholders via deprecated PlaceholderHook class."
|
|
||||||
+ " This class is no longer supported and will be removed in v2.13.0!", identifier);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param plugin The plugin to unregister
|
|
||||||
* @return always false
|
|
||||||
* @deprecated Please use {@link PlaceholderExpansion} to
|
|
||||||
* unregister placeholders instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static boolean unregisterPlaceholderHook(Plugin plugin) {
|
|
||||||
Msg.warn("Nag author(s) %s of plugin %s about their usage of the PlaceholderAPI class."
|
|
||||||
+ " This way of unregistering placeholders is no longer supported and will be removed"
|
|
||||||
+ " in v2.13.0!", plugin.getDescription().getAuthors(), plugin.getName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param identifier The identifier to unregister
|
|
||||||
* @return always false
|
|
||||||
* @deprecated Please use {@link PlaceholderExpansion} to
|
|
||||||
* unregister placeholders instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static boolean unregisterPlaceholderHook(String identifier) {
|
|
||||||
Msg.warn("%s is attempting to unregister placeholders via PlaceholderAPI class."
|
|
||||||
+ " This way of unregistering placeholders is no longer supported and will be removed"
|
|
||||||
+ " in v2.13.0!", identifier);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Set of registered identifiers
|
|
||||||
* @deprecated Will be removed in a future release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static Set<String> getRegisteredPlaceholderPlugins() {
|
|
||||||
return getRegisteredIdentifiers();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return always null
|
|
||||||
* @deprecated Will be removed in a future release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static Set<String> getExternalPlaceholderPlugins() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The text to parse
|
|
||||||
* @param pattern The Pattern to use
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, String)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static String setPlaceholders(OfflinePlayer player,
|
|
||||||
String text, Pattern pattern, boolean colorize) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The List of text to parse
|
|
||||||
* @param pattern The Pattern to use
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, List)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static List<String> setPlaceholders(OfflinePlayer player,
|
|
||||||
List<String> text, Pattern pattern, boolean colorize) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The List of text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static List<String> setPlaceholders(OfflinePlayer player, List<String> text,
|
|
||||||
boolean colorize) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The List of text to parse
|
|
||||||
* @param pattern The Pattern to use
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static List<String> setPlaceholders(OfflinePlayer player, List<String> text,
|
|
||||||
Pattern pattern) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Will be removed in a future release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static String setPlaceholders(Player player, String text, boolean colorize) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The List of text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Will be removed in a future release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static List<String> setPlaceholders(Player player, List<String> text, boolean colorize) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static String setPlaceholders(OfflinePlayer player, String text, boolean colorize) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The text to parse
|
|
||||||
* @param pattern The Pattern to use
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static String setPlaceholders(OfflinePlayer player, String text, Pattern pattern) {
|
|
||||||
return setPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The List of text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static List<String> setBracketPlaceholders(OfflinePlayer player, List<String> text,
|
|
||||||
boolean colorize) {
|
|
||||||
return setBracketPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static String setBracketPlaceholders(OfflinePlayer player, String text, boolean colorize) {
|
|
||||||
return setBracketPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Will be removed in a future release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static String setBracketPlaceholders(Player player, String text, boolean colorize) {
|
|
||||||
return setBracketPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param player The offline player to parse the placeholders against
|
|
||||||
* @param text The List of text to parse
|
|
||||||
* @param colorize If PlaceholderAPI should also parse color codes
|
|
||||||
* @return String with the parsed placeholders
|
|
||||||
* @deprecated Will be removed in a future release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static List<String> setBracketPlaceholders(Player player, List<String> text,
|
|
||||||
boolean colorize) {
|
|
||||||
return setBracketPlaceholders(player, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set relational placeholders in the text specified placeholders are matched with the pattern
|
|
||||||
* {@literal %<rel_(identifier)_(params)>%} when set with this method
|
|
||||||
*
|
|
||||||
* @param one Player to compare
|
|
||||||
* @param two Player to compare
|
|
||||||
* @param text Text to parse the placeholders in
|
|
||||||
* @param colorize If color codes ({@literal &[0-1a-fk-o]}) should be translated
|
|
||||||
* @return The text containing the parsed relational placeholders
|
|
||||||
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static String setRelationalPlaceholders(Player one, Player two, String text,
|
|
||||||
boolean colorize) {
|
|
||||||
return setRelationalPlaceholders(one, two, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate placeholders in the provided list based on the relation of the two provided players.
|
|
||||||
* <br>The pattern of a valid placeholder is {@literal %rel_<identifier>_<params>%}.
|
|
||||||
*
|
|
||||||
* @param one First player to compare
|
|
||||||
* @param two Second player to compare
|
|
||||||
* @param text Text to parse the placeholders in
|
|
||||||
* @param colorize If color codes ({@literal &[0-1a-fk-o]}) should be translated
|
|
||||||
* @return The text containing the parsed relational placeholders
|
|
||||||
* @deprecated Use {@link #setRelationalPlaceholders(Player, Player, List)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public static List<String> setRelationalPlaceholders(Player one, Player two, List<String> text,
|
|
||||||
boolean colorize) {
|
|
||||||
return setRelationalPlaceholders(one, two, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommandRouter;
|
|
||||||
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.expansion.Version;
|
|
||||||
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;
|
|
||||||
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
|
|
||||||
import me.clip.placeholderapi.listeners.ServerLoadEventListener;
|
|
||||||
import me.clip.placeholderapi.scheduler.UniversalScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
|
||||||
import me.clip.placeholderapi.updatechecker.UpdateChecker;
|
|
||||||
import me.clip.placeholderapi.util.ExpansionSafetyCheck;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
|
||||||
import org.bstats.bukkit.Metrics;
|
|
||||||
import org.bstats.charts.AdvancedPie;
|
|
||||||
import org.bstats.charts.SimplePie;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Yes I have a shit load of work to do...
|
|
||||||
*
|
|
||||||
* @author Ryan McCarthy
|
|
||||||
*/
|
|
||||||
public final class PlaceholderAPIPlugin extends JavaPlugin {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final Version VERSION;
|
|
||||||
private static PlaceholderAPIPlugin instance;
|
|
||||||
|
|
||||||
static {
|
|
||||||
String version = Bukkit.getServer().getBukkitVersion().split("-")[0];
|
|
||||||
String suffix;
|
|
||||||
if (version.chars()
|
|
||||||
.filter(c -> c == '.')
|
|
||||||
.count() == 1) {
|
|
||||||
suffix = "R1";
|
|
||||||
version = 'v' + version.replace('.', '_') + '_' + suffix;
|
|
||||||
} else {
|
|
||||||
int minor = Integer.parseInt(version.split("\\.")[2].charAt(0) + "");
|
|
||||||
version = 'v' + version.replace('.', '_').replace("_" + minor, "") + '_' + "R" + (minor - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isSpigot;
|
|
||||||
try {
|
|
||||||
Class.forName("org.spigotmc.SpigotConfig");
|
|
||||||
isSpigot = true;
|
|
||||||
} catch (final ExceptionInInitializerError | ClassNotFoundException ignored) {
|
|
||||||
isSpigot = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VERSION = new Version(version, isSpigot);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderAPIConfig config = new PlaceholderAPIConfig(this);
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this);
|
|
||||||
@NotNull
|
|
||||||
private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this);
|
|
||||||
@NotNull
|
|
||||||
private final TaskScheduler scheduler = UniversalScheduler.getScheduler(this);
|
|
||||||
|
|
||||||
private BukkitAudiences adventure;
|
|
||||||
private boolean safetyCheck = false;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API
|
|
||||||
* class, this is the main class that extends JavaPlugin. For most API methods, use static methods
|
|
||||||
* available from the class: {@link PlaceholderAPI}
|
|
||||||
*
|
|
||||||
* @return PlaceholderAPIPlugin instance
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static PlaceholderAPIPlugin getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configurable {@linkplain String} value that should be returned when a boolean is true
|
|
||||||
*
|
|
||||||
* @return string value of true
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static String booleanTrue() {
|
|
||||||
return getInstance().getPlaceholderAPIConfig().booleanTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configurable {@linkplain String} value that should be returned when a boolean is false
|
|
||||||
*
|
|
||||||
* @return string value of false
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static String booleanFalse() {
|
|
||||||
return getInstance().getPlaceholderAPIConfig().booleanFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configurable {@linkplain SimpleDateFormat} object that is used to parse time for
|
|
||||||
* generic time based placeholders
|
|
||||||
*
|
|
||||||
* @return date format
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public static SimpleDateFormat getDateFormat() {
|
|
||||||
try {
|
|
||||||
return new SimpleDateFormat(getInstance().getPlaceholderAPIConfig().dateFormat());
|
|
||||||
} catch (final IllegalArgumentException ex) {
|
|
||||||
Msg.warn("Configured date format ('%s') is invalid! Defaulting to 'MM/dd/yy HH:mm:ss'",
|
|
||||||
ex, getInstance().getPlaceholderAPIConfig().dateFormat());
|
|
||||||
return new SimpleDateFormat("MM/dd/yy HH:mm:ss");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static Version getServerVersion() {
|
|
||||||
return VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoad() {
|
|
||||||
saveDefaultConfig();
|
|
||||||
|
|
||||||
safetyCheck = new ExpansionSafetyCheck(this).runChecks();
|
|
||||||
|
|
||||||
if (safetyCheck) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
if (safetyCheck) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setupCommand();
|
|
||||||
setupMetrics();
|
|
||||||
setupExpansions();
|
|
||||||
|
|
||||||
adventure = BukkitAudiences.create(this);
|
|
||||||
|
|
||||||
if (config.isCloudEnabled()) {
|
|
||||||
getCloudExpansionManager().load();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.checkUpdates()) {
|
|
||||||
new UpdateChecker(this).fetch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
if (safetyCheck) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCloudExpansionManager().kill();
|
|
||||||
getLocalExpansionManager().kill();
|
|
||||||
|
|
||||||
HandlerList.unregisterAll(this);
|
|
||||||
|
|
||||||
scheduler.cancelTasks(this);
|
|
||||||
|
|
||||||
adventure.close();
|
|
||||||
adventure = null;
|
|
||||||
|
|
||||||
instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reloadConf(@NotNull final CommandSender sender) {
|
|
||||||
getLocalExpansionManager().kill();
|
|
||||||
|
|
||||||
reloadConfig();
|
|
||||||
|
|
||||||
getLocalExpansionManager().load(sender);
|
|
||||||
|
|
||||||
if (config.isCloudEnabled()) {
|
|
||||||
getCloudExpansionManager().load();
|
|
||||||
} else {
|
|
||||||
getCloudExpansionManager().kill();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public LocalExpansionManager getLocalExpansionManager() {
|
|
||||||
return localExpansionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public CloudExpansionManager getCloudExpansionManager() {
|
|
||||||
return cloudExpansionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public BukkitAudiences getAdventure() {
|
|
||||||
if (adventure == null) {
|
|
||||||
throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return adventure;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public TaskScheduler getScheduler() {
|
|
||||||
return scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the configuration class for PlaceholderAPI.
|
|
||||||
*
|
|
||||||
* @return PlaceholderAPIConfig instance
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public PlaceholderAPIConfig getPlaceholderAPIConfig() {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupCommand() {
|
|
||||||
final PluginCommand pluginCommand = getCommand("placeholderapi");
|
|
||||||
if (pluginCommand == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PlaceholderCommandRouter router = new PlaceholderCommandRouter(this);
|
|
||||||
pluginCommand.setExecutor(router);
|
|
||||||
pluginCommand.setTabCompleter(router);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupMetrics() {
|
|
||||||
final Metrics metrics = new Metrics(this, 438);
|
|
||||||
metrics.addCustomChart(new SimplePie("using_expansion_cloud",
|
|
||||||
() -> getPlaceholderAPIConfig().isCloudEnabled() ? "yes" : "no"));
|
|
||||||
|
|
||||||
metrics.addCustomChart(new SimplePie("using_spigot", () -> getServerVersion().isSpigot() ? "yes" : "no"));
|
|
||||||
|
|
||||||
metrics.addCustomChart(new AdvancedPie("expansions_used", () -> {
|
|
||||||
final Map<String, Integer> values = new HashMap<>();
|
|
||||||
|
|
||||||
for (final PlaceholderExpansion expansion : getLocalExpansionManager().getExpansions()) {
|
|
||||||
values.put(expansion.getRequiredPlugin() == null ? expansion.getIdentifier()
|
|
||||||
: expansion.getRequiredPlugin(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupExpansions() {
|
|
||||||
Bukkit.getPluginManager().registerEvents(getLocalExpansionManager(), this);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class.forName("org.bukkit.event.server.ServerLoadEvent");
|
|
||||||
new ServerLoadEventListener(this);
|
|
||||||
} catch (final ClassNotFoundException ignored) {
|
|
||||||
scheduler
|
|
||||||
.runTaskLater(() -> getLocalExpansionManager().load(Bukkit.getConsoleSender()), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi;
|
|
||||||
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public abstract class PlaceholderHook {
|
|
||||||
@Nullable
|
|
||||||
public String onRequest(final OfflinePlayer player, @NotNull final String params) {
|
|
||||||
if (player != null && player.isOnline()) {
|
|
||||||
return onPlaceholderRequest(player.getPlayer(), params);
|
|
||||||
}
|
|
||||||
|
|
||||||
return onPlaceholderRequest(null, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String onPlaceholderRequest(final Player player, @NotNull final String params) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public abstract class PlaceholderCommand {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final String label;
|
|
||||||
@NotNull
|
|
||||||
private final Set<String> alias;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String permission;
|
|
||||||
|
|
||||||
|
|
||||||
protected PlaceholderCommand(@NotNull final String label, @NotNull final String... alias) {
|
|
||||||
this.label = label;
|
|
||||||
this.alias = Sets.newHashSet(alias);
|
|
||||||
|
|
||||||
setPermission("placeholderapi." + label);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static Stream<PlaceholderCommand> filterByPermission(@NotNull final CommandSender sender,
|
|
||||||
@NotNull final Stream<PlaceholderCommand> commands) {
|
|
||||||
return commands.filter(
|
|
||||||
target -> target.getPermission() == null || sender.hasPermission(target.getPermission()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void suggestByParameter(@NotNull final Stream<String> possible,
|
|
||||||
@NotNull final List<String> suggestions, @Nullable final String parameter) {
|
|
||||||
if (parameter == null) {
|
|
||||||
possible.forEach(suggestions::add);
|
|
||||||
} else {
|
|
||||||
possible.filter(suggestion -> suggestion.toLowerCase(Locale.ROOT).startsWith(parameter.toLowerCase(Locale.ROOT)))
|
|
||||||
.forEach(suggestions::add);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public final String getLabel() {
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public final Set<String> getAlias() {
|
|
||||||
return ImmutableSet.copyOf(alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public final Set<String> getLabels() {
|
|
||||||
return ImmutableSet.<String>builder().add(label).addAll(alias).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public final String getPermission() {
|
|
||||||
return permission;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPermission(@NotNull final String permission) {
|
|
||||||
this.permission = permission;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.impl.cloud.CommandECloud;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandDump;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandExpansionRegister;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandExpansionUnregister;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandHelp;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandInfo;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandList;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandParse;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandReload;
|
|
||||||
import me.clip.placeholderapi.commands.impl.local.CommandVersion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
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.Unmodifiable;
|
|
||||||
|
|
||||||
public final class PlaceholderCommandRouter implements CommandExecutor, TabCompleter {
|
|
||||||
|
|
||||||
@Unmodifiable
|
|
||||||
private static final List<PlaceholderCommand> COMMANDS = ImmutableList.of(new CommandHelp(),
|
|
||||||
new CommandInfo(),
|
|
||||||
new CommandList(),
|
|
||||||
new CommandDump(),
|
|
||||||
new CommandECloud(),
|
|
||||||
new CommandParse(),
|
|
||||||
new CommandReload(),
|
|
||||||
new CommandVersion(),
|
|
||||||
new CommandExpansionRegister(),
|
|
||||||
new CommandExpansionUnregister());
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderAPIPlugin plugin;
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
private final Map<String, PlaceholderCommand> commands;
|
|
||||||
|
|
||||||
|
|
||||||
public PlaceholderCommandRouter(@NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
|
|
||||||
final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder();
|
|
||||||
|
|
||||||
for (final PlaceholderCommand command : COMMANDS) {
|
|
||||||
command.getLabels().forEach(label -> commands.put(label, command));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.commands = commands.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull final CommandSender sender, @NotNull final Command command,
|
|
||||||
@NotNull final String alias, @NotNull final String[] args) {
|
|
||||||
if (args.length == 0) {
|
|
||||||
final PlaceholderCommand fallback = commands.get("version");
|
|
||||||
if (fallback != null) {
|
|
||||||
fallback.evaluate(plugin, sender, "", Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String search = args[0].toLowerCase(Locale.ROOT);
|
|
||||||
final PlaceholderCommand target = commands.get(search);
|
|
||||||
|
|
||||||
if (target == null) {
|
|
||||||
Msg.msg(sender, "&cUnknown command &7" + search);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String permission = target.getPermission();
|
|
||||||
if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) {
|
|
||||||
Msg.msg(sender, "&cYou do not have permission to do this!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
.evaluate(plugin, sender, search, Arrays.asList(Arrays.copyOfRange(args, 1, args.length)));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> onTabComplete(@NotNull final CommandSender sender,
|
|
||||||
@NotNull final Command command, @NotNull final String alias, @NotNull final String[] args) {
|
|
||||||
final List<String> suggestions = new ArrayList<>();
|
|
||||||
|
|
||||||
if (args.length > 1) {
|
|
||||||
final PlaceholderCommand target = this.commands.get(args[0].toLowerCase(Locale.ROOT));
|
|
||||||
|
|
||||||
if (target != null) {
|
|
||||||
target.complete(plugin, sender, args[0].toLowerCase(Locale.ROOT),
|
|
||||||
Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return suggestions;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Stream<String> targets = PlaceholderCommand
|
|
||||||
.filterByPermission(sender, commands.values().stream()).map(PlaceholderCommand::getLabels)
|
|
||||||
.flatMap(Collection::stream);
|
|
||||||
PlaceholderCommand.suggestByParameter(targets, suggestions, args.length == 0 ? null : args[0]);
|
|
||||||
|
|
||||||
return suggestions;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public final class CommandECloud extends PlaceholderCommand {
|
|
||||||
|
|
||||||
@Unmodifiable
|
|
||||||
private static final List<PlaceholderCommand> COMMANDS = ImmutableList
|
|
||||||
.of(new CommandECloudClear(),
|
|
||||||
new CommandECloudStatus(),
|
|
||||||
new CommandECloudUpdate(),
|
|
||||||
new CommandECloudRefresh(),
|
|
||||||
new CommandECloudDownload(),
|
|
||||||
new CommandECloudExpansionInfo(),
|
|
||||||
new CommandECloudExpansionList(),
|
|
||||||
new CommandECloudExpansionPlaceholders());
|
|
||||||
|
|
||||||
static {
|
|
||||||
COMMANDS
|
|
||||||
.forEach(command -> command.setPermission("placeholderapi.ecloud." + command.getLabel()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
private final Map<String, PlaceholderCommand> commands;
|
|
||||||
|
|
||||||
|
|
||||||
public CommandECloud() {
|
|
||||||
super("ecloud");
|
|
||||||
|
|
||||||
final ImmutableMap.Builder<String, PlaceholderCommand> commands = ImmutableMap.builder();
|
|
||||||
|
|
||||||
for (final PlaceholderCommand command : COMMANDS) {
|
|
||||||
command.getLabels().forEach(label -> commands.put(label, command));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.commands = commands.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&b&lPlaceholderAPI &8- &7eCloud Help Menu &8- ",
|
|
||||||
" ",
|
|
||||||
"&b/papi &fecloud status",
|
|
||||||
" &7&oView status of the eCloud",
|
|
||||||
"&b/papi &fecloud list <all/{author}/installed> {page}",
|
|
||||||
" &7&oList all/author specific available expansions",
|
|
||||||
"&b/papi &fecloud info <expansion name> {version}",
|
|
||||||
" &7&oView information about a specific expansion available on the eCloud",
|
|
||||||
"&b/papi &fecloud placeholders <expansion name>",
|
|
||||||
" &7&oView placeholders for an expansion",
|
|
||||||
"&b/papi &fecloud download <expansion name> {version}",
|
|
||||||
" &7&oDownload an expansion from the eCloud",
|
|
||||||
"&b/papi &fecloud update <expansion name/all>",
|
|
||||||
" &7&oUpdate a specific/all installed expansions",
|
|
||||||
"&b/papi &fecloud refresh",
|
|
||||||
" &7&oFetch the most up to date list of expansions available.",
|
|
||||||
"&b/papi &fecloud clear",
|
|
||||||
" &7&oClear the expansion cloud cache.");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String search = params.get(0).toLowerCase(Locale.ROOT);
|
|
||||||
final PlaceholderCommand target = commands.get(search);
|
|
||||||
|
|
||||||
if (target == null) {
|
|
||||||
Msg.msg(sender, "&cUnknown command &7ecloud " + search);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String permission = target.getPermission();
|
|
||||||
if (permission != null && !permission.isEmpty() && !sender.hasPermission(permission)) {
|
|
||||||
Msg.msg(sender, "&cYou do not have permission to do this!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!plugin.getPlaceholderAPIConfig().isCloudEnabled()) {
|
|
||||||
Msg.msg(sender, "&cThe eCloud Manager is not enabled! To enable it, set 'cloud_enabled' to true and reload the plugin.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
target.evaluate(plugin, sender, search, params.subList(1, params.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() <= 1) {
|
|
||||||
final Stream<String> targets = filterByPermission(sender, commands.values().stream())
|
|
||||||
.map(PlaceholderCommand::getLabels).flatMap(Collection::stream);
|
|
||||||
suggestByParameter(targets, suggestions, params.isEmpty() ? null : params.get(0));
|
|
||||||
|
|
||||||
return; // send sub commands
|
|
||||||
}
|
|
||||||
|
|
||||||
final String search = params.get(0).toLowerCase(Locale.ROOT);
|
|
||||||
final PlaceholderCommand target = commands.get(search);
|
|
||||||
|
|
||||||
if (target == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
target.complete(plugin, sender, search, params.subList(1, params.size()), suggestions);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandECloudClear extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandECloudClear() {
|
|
||||||
super("clear");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
plugin.getCloudExpansionManager().clean();
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&aThe eCloud cache has been cleared!");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandECloudDownload extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandECloudDownload() {
|
|
||||||
super("download");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isBlockedExpansion(String name) {
|
|
||||||
String env = System.getenv("PAPI_BLOCKED_EXPANSIONS");
|
|
||||||
if (env == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.stream(env.split(","))
|
|
||||||
.anyMatch(s -> s.equalsIgnoreCase(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must supply the name of an expansion.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBlockedExpansion(params.get(0))) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cThis expansion can't be downloaded.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final CloudExpansion expansion = plugin.getCloudExpansionManager()
|
|
||||||
.findCloudExpansionByName(params.get(0)).orElse(null);
|
|
||||||
if (expansion == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cFailed to find an expansion named: &f" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final CloudExpansion.Version version;
|
|
||||||
if (params.size() < 2) {
|
|
||||||
version = expansion.getVersion(expansion.getLatestVersion());
|
|
||||||
if (version == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cCould not find latest version for expansion.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
version = expansion.getVersion(params.get(1));
|
|
||||||
if (version == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cCould not find specified version: &f" + params.get(1),
|
|
||||||
"&7Available versions: &f" + expansion.getAvailableVersions());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!version.isVerified()) {
|
|
||||||
Msg.msg(sender, "&cThe expansion '&f" + params.get(0) + "&c' is not verified and can only be downloaded manually from &fhttps://ecloud.placeholderapi.com");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.getCloudExpansionManager().downloadExpansion(expansion, version)
|
|
||||||
.whenComplete((file, exception) -> {
|
|
||||||
if (exception != null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cFailed to download expansion: &f" + exception.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&aSuccessfully downloaded expansion &f" + expansion.getName() + " [" + version
|
|
||||||
.getVersion() + "] &ato file: &f" + file.getName(),
|
|
||||||
"&aMake sure to type &f/papi reload &ato enable your new expansion!");
|
|
||||||
|
|
||||||
plugin.getCloudExpansionManager().load();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.size() <= 1) {
|
|
||||||
final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values()
|
|
||||||
.stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_'));
|
|
||||||
suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager()
|
|
||||||
.findCloudExpansionByName(params.get(0));
|
|
||||||
if (!expansion.isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestByParameter(expansion.get().getAvailableVersions().stream(), suggestions, params.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandECloudExpansionInfo extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandECloudExpansionInfo() {
|
|
||||||
super("info");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must specify the name of the expansion.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final CloudExpansion expansion = plugin.getCloudExpansionManager()
|
|
||||||
.findCloudExpansionByName(params.get(0)).orElse(null);
|
|
||||||
if (expansion == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cThere is no expansion with the name: &f" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
builder.append("&bExpansion: &f")
|
|
||||||
.append(expansion.shouldUpdate() ? "&e" : "&a")
|
|
||||||
.append(expansion.getName())
|
|
||||||
.append('\n')
|
|
||||||
.append("&bAuthor: &f")
|
|
||||||
.append(expansion.getAuthor())
|
|
||||||
.append('\n');
|
|
||||||
|
|
||||||
if (params.size() < 2) {
|
|
||||||
builder.append("&bLatest Version: &f")
|
|
||||||
.append(expansion.getLatestVersion())
|
|
||||||
.append('\n')
|
|
||||||
.append("&bReleased: &f")
|
|
||||||
.append(expansion.getTimeSinceLastUpdate())
|
|
||||||
.append(" ago")
|
|
||||||
.append('\n')
|
|
||||||
.append("&bVerified: ")
|
|
||||||
.append(expansion.getVersion().isVerified() ? "&a&l✔" : "&c&l❌")
|
|
||||||
.append('\n')
|
|
||||||
.append("&bRelease Notes: &f")
|
|
||||||
.append(expansion.getVersion().getReleaseNotes())
|
|
||||||
.append('\n');
|
|
||||||
} else {
|
|
||||||
final CloudExpansion.Version version = expansion.getVersion(params.get(1));
|
|
||||||
if (version == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cCould not find specified version: &f" + params.get(1),
|
|
||||||
"&aVersions: &f" + expansion.getAvailableVersions());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.append("&bVersion: &f")
|
|
||||||
.append(version.getVersion())
|
|
||||||
.append('\n')
|
|
||||||
.append("&bVerified: ")
|
|
||||||
.append(version.isVerified() ? "&a&l✔" : "&c&l❌")
|
|
||||||
.append('\n')
|
|
||||||
.append("&bRelease Notes: &f")
|
|
||||||
.append(version.getReleaseNotes())
|
|
||||||
.append('\n')
|
|
||||||
.append("&bDownload URL: &f")
|
|
||||||
.append(version.getUrl())
|
|
||||||
.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender, builder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.size() <= 1) {
|
|
||||||
final Stream<String> names = plugin.getCloudExpansionManager().getCloudExpansions().values()
|
|
||||||
.stream().map(CloudExpansion::getName).map(name -> name.replace(' ', '_'));
|
|
||||||
suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Optional<CloudExpansion> expansion = plugin.getCloudExpansionManager()
|
|
||||||
.findCloudExpansionByName(params.get(0));
|
|
||||||
if (!expansion.isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestByParameter(expansion.get().getAvailableVersions().stream(), suggestions, params.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,354 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.common.primitives.Ints;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.configuration.ExpansionSort;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Format;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.TextComponent;
|
|
||||||
import net.kyori.adventure.text.event.ClickEvent;
|
|
||||||
import net.kyori.adventure.text.event.HoverEvent;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.text.format.TextDecoration;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
import static net.kyori.adventure.text.Component.*;
|
|
||||||
import static net.kyori.adventure.text.format.NamedTextColor.*;
|
|
||||||
|
|
||||||
public final class CommandECloudExpansionList extends PlaceholderCommand {
|
|
||||||
|
|
||||||
private static final int PAGE_SIZE = 10;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final Function<CloudExpansion, Object> EXPANSION_NAME =
|
|
||||||
expansion -> (expansion.shouldUpdate() ? "&6" : expansion.hasExpansion() ? "&a" : "&7")
|
|
||||||
+ expansion.getName();
|
|
||||||
@NotNull
|
|
||||||
private static final Function<CloudExpansion, Object> EXPANSION_AUTHOR =
|
|
||||||
expansion -> "&f" + expansion.getAuthor();
|
|
||||||
@NotNull
|
|
||||||
private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED =
|
|
||||||
expansion -> expansion.getVersion().isVerified() ? "&aY" : "&cN";
|
|
||||||
@NotNull
|
|
||||||
private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION =
|
|
||||||
expansion -> "&f" + expansion.getLatestVersion();
|
|
||||||
@NotNull
|
|
||||||
private static final Function<CloudExpansion, Object> EXPANSION_CURRENT_VERSION =
|
|
||||||
expansion -> "&f" + PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()
|
|
||||||
.findExpansionByName(expansion.getName()).map(PlaceholderExpansion::getVersion)
|
|
||||||
.orElse("Unknown");
|
|
||||||
|
|
||||||
|
|
||||||
@Unmodifiable
|
|
||||||
private static final Set<String> OPTIONS = ImmutableSet.of("all", "installed");
|
|
||||||
|
|
||||||
|
|
||||||
public CommandECloudExpansionList() {
|
|
||||||
super("list");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static Collection<CloudExpansion> getExpansions(@NotNull final String target,
|
|
||||||
@NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
switch (target.toLowerCase(Locale.ROOT)) {
|
|
||||||
case "all":
|
|
||||||
return plugin.getCloudExpansionManager().getCloudExpansions().values();
|
|
||||||
case "installed":
|
|
||||||
return plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values();
|
|
||||||
default:
|
|
||||||
return plugin.getCloudExpansionManager().getCloudExpansionsByAuthor(target).values();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static List<CloudExpansion> getPage(@NotNull final List<CloudExpansion> expansions,
|
|
||||||
final int page) {
|
|
||||||
final int head = (page * PAGE_SIZE);
|
|
||||||
final int tail = Math.min(expansions.size(), head + PAGE_SIZE);
|
|
||||||
|
|
||||||
if (expansions.size() < head) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return expansions.subList(head, tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addExpansionTitle(@NotNull final StringBuilder builder,
|
|
||||||
@NotNull final String target, final int page) {
|
|
||||||
switch (target.toLowerCase(Locale.ROOT)) {
|
|
||||||
case "all":
|
|
||||||
builder.append("&bAll Expansions");
|
|
||||||
break;
|
|
||||||
case "installed":
|
|
||||||
builder.append("&bInstalled Expansions");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
builder.append("&bExpansions by &f")
|
|
||||||
.append(target);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (page == -1) {
|
|
||||||
builder.append('\n');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.append(" &bPage&7: &a")
|
|
||||||
.append(page)
|
|
||||||
.append("&r");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Component getMessage(@NotNull final List<CloudExpansion> expansions,
|
|
||||||
final int page, final int limit, @NotNull final String target) {
|
|
||||||
final SimpleDateFormat format = PlaceholderAPIPlugin.getDateFormat();
|
|
||||||
|
|
||||||
final TextComponent.Builder message = text();
|
|
||||||
|
|
||||||
for (int index = 0; index < expansions.size(); index++) {
|
|
||||||
final CloudExpansion expansion = expansions.get(index);
|
|
||||||
final TextComponent.Builder line = text();
|
|
||||||
|
|
||||||
final int expansionNumber = index + ((page - 1) * PAGE_SIZE) + 1;
|
|
||||||
line.append(text(expansionNumber + ". ", DARK_GRAY));
|
|
||||||
|
|
||||||
final NamedTextColor expansionColour;
|
|
||||||
|
|
||||||
if (expansion.shouldUpdate()) {
|
|
||||||
expansionColour = GOLD;
|
|
||||||
} else {
|
|
||||||
if (expansion.hasExpansion()) {
|
|
||||||
expansionColour = GREEN;
|
|
||||||
} else {
|
|
||||||
expansionColour = GRAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line.append(text(expansion.getName(), expansionColour));
|
|
||||||
|
|
||||||
line.clickEvent(ClickEvent.suggestCommand("/papi ecloud download " + expansion.getName()));
|
|
||||||
|
|
||||||
final TextComponent.Builder hoverText = text("Click to download this expansion!", AQUA)
|
|
||||||
.append(newline()).append(newline())
|
|
||||||
.append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE))
|
|
||||||
.append(newline())
|
|
||||||
.append(text("Verified: ", AQUA)).append(text(expansion.getVersion().isVerified() ? "✔" : "❌", expansion.getVersion().isVerified() ? GREEN : RED, TextDecoration.BOLD))
|
|
||||||
.append(newline())
|
|
||||||
.append(text("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE))
|
|
||||||
.toBuilder();
|
|
||||||
|
|
||||||
Optional.ofNullable(expansion.getDescription())
|
|
||||||
.filter(description -> !description.isEmpty())
|
|
||||||
.ifPresent(description -> hoverText.append(newline()).append(newline())
|
|
||||||
.append(text(description.replace("\r", "").trim(), WHITE))
|
|
||||||
);
|
|
||||||
|
|
||||||
line.hoverEvent(HoverEvent.showText(hoverText.build()));
|
|
||||||
|
|
||||||
if (index != expansions.size() - 1) {
|
|
||||||
line.append(newline());
|
|
||||||
}
|
|
||||||
|
|
||||||
message.append(line.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (limit > 1) {
|
|
||||||
message.append(newline());
|
|
||||||
|
|
||||||
final TextComponent.Builder left = text("◀", page > 1 ? GRAY : DARK_GRAY).toBuilder();
|
|
||||||
|
|
||||||
if (page > 1) {
|
|
||||||
left.clickEvent(ClickEvent.runCommand("/papi ecloud list " + target + " " + (page - 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
final TextComponent.Builder right = text("▶", page < limit ? GRAY : DARK_GRAY).toBuilder();
|
|
||||||
|
|
||||||
if (page < limit) {
|
|
||||||
right.clickEvent(ClickEvent.runCommand("/papi ecloud list " + target + " " + (page + 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
message.append(left, text(" " + page + " ", GREEN), right);
|
|
||||||
}
|
|
||||||
|
|
||||||
return message.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addExpansionTable(@NotNull final List<CloudExpansion> expansions,
|
|
||||||
@NotNull final StringBuilder message, final int startIndex,
|
|
||||||
@NotNull final String versionTitle,
|
|
||||||
@NotNull final Function<CloudExpansion, Object> versionFunction) {
|
|
||||||
final Map<String, Function<CloudExpansion, Object>> functions = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
final AtomicInteger counter = new AtomicInteger(startIndex);
|
|
||||||
functions.put("&f", expansion -> "&8" + counter.getAndIncrement() + ".");
|
|
||||||
|
|
||||||
functions.put("&9Name", EXPANSION_NAME);
|
|
||||||
functions.put("&9Author", EXPANSION_AUTHOR);
|
|
||||||
functions.put("&9Verified", EXPANSION_VERIFIED);
|
|
||||||
functions.put(versionTitle, versionFunction);
|
|
||||||
|
|
||||||
final List<List<String>> rows = new ArrayList<>();
|
|
||||||
|
|
||||||
rows.add(0, new ArrayList<>(functions.keySet()));
|
|
||||||
|
|
||||||
for (final CloudExpansion expansion : expansions) {
|
|
||||||
rows.add(functions.values().stream().map(function -> function.apply(expansion))
|
|
||||||
.map(Objects::toString).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> table = Format.tablify(Format.Align.LEFT, rows)
|
|
||||||
.orElse(Collections.emptyList());
|
|
||||||
if (table.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.add(1, "&8" + Strings.repeat("-", table.get(0).length() - (rows.get(0).size() * 2)));
|
|
||||||
|
|
||||||
message.append(String.join("\n", table));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must specify an option. [all, {author}, installed]");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean installed = params.get(0).equalsIgnoreCase("installed");
|
|
||||||
final List<CloudExpansion> expansions = Lists
|
|
||||||
.newArrayList(getExpansions(params.get(0), plugin));
|
|
||||||
|
|
||||||
if (expansions.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cNo expansions available to list.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
expansions
|
|
||||||
.sort(plugin.getPlaceholderAPIConfig().getExpansionSort().orElse(ExpansionSort.LATEST));
|
|
||||||
|
|
||||||
if (!(sender instanceof Player) && params.size() < 2) {
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
addExpansionTitle(builder, params.get(0), -1);
|
|
||||||
addExpansionTable(expansions,
|
|
||||||
builder,
|
|
||||||
1,
|
|
||||||
installed ? "&9Version" : "&9Latest Version",
|
|
||||||
installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION);
|
|
||||||
|
|
||||||
Msg.msg(sender, builder.toString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int page;
|
|
||||||
|
|
||||||
if (params.size() < 2) {
|
|
||||||
page = 1;
|
|
||||||
} else {
|
|
||||||
//noinspection UnstableApiUsage
|
|
||||||
final Integer parsed = Ints.tryParse(params.get(1));
|
|
||||||
if (parsed == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cPage number must be an integer.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE);
|
|
||||||
|
|
||||||
if (parsed < 1 || parsed > limit) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cPage number must be in the range &8[&a1&7..&a" + limit + "&8]");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
page = parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
final List<CloudExpansion> values = getPage(expansions, page - 1);
|
|
||||||
|
|
||||||
addExpansionTitle(builder, params.get(0), page);
|
|
||||||
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
addExpansionTable(values,
|
|
||||||
builder,
|
|
||||||
((page - 1) * PAGE_SIZE) + 1,
|
|
||||||
installed ? "&9Version" : "&9Latest Version",
|
|
||||||
installed ? EXPANSION_CURRENT_VERSION : EXPANSION_LATEST_VERSION);
|
|
||||||
|
|
||||||
Msg.msg(sender, builder.toString());
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender, builder.toString());
|
|
||||||
|
|
||||||
final int limit = (int) Math.ceil((double) expansions.size() / PAGE_SIZE);
|
|
||||||
|
|
||||||
final Component message = getMessage(values, page, limit, params.get(0));
|
|
||||||
plugin.getAdventure().player((Player) sender).sendMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.size() <= 1) {
|
|
||||||
suggestByParameter(
|
|
||||||
Sets.union(OPTIONS, plugin.getCloudExpansionManager().getCloudExpansionAuthors())
|
|
||||||
.stream(), suggestions, params.isEmpty() ? null : params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestByParameter(IntStream.rangeClosed(1,
|
|
||||||
(int) Math.ceil((double) getExpansions(params.get(0), plugin).size() / PAGE_SIZE))
|
|
||||||
.mapToObj(Objects::toString), suggestions, params.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandECloudExpansionPlaceholders extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandECloudExpansionPlaceholders() {
|
|
||||||
super("placeholders");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must specify the name of the expansion.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final CloudExpansion expansion = plugin.getCloudExpansionManager()
|
|
||||||
.findCloudExpansionByName(params.get(0)).orElse(null);
|
|
||||||
if (expansion == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cThere is no expansion with the name: &f" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> placeholders = expansion.getPlaceholders();
|
|
||||||
if (placeholders == null || placeholders.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cThe expansion specified does not have placeholders listed.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<List<String>> partitions = Lists
|
|
||||||
.partition(placeholders.stream().sorted().collect(Collectors.toList()), 10);
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&6" + placeholders.size() + "&7 placeholders: &a",
|
|
||||||
partitions.stream().map(partition -> String.join(", ", partition))
|
|
||||||
.collect(Collectors.joining("\n")));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Stream<String> names = plugin.getCloudExpansionManager()
|
|
||||||
.getCloudExpansions()
|
|
||||||
.values()
|
|
||||||
.stream()
|
|
||||||
.map(CloudExpansion::getName)
|
|
||||||
.map(name -> name.replace(' ', '_'));
|
|
||||||
|
|
||||||
suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandECloudRefresh extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandECloudRefresh() {
|
|
||||||
super("refresh");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
plugin.getCloudExpansionManager().load();
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&aThe eCloud manager has been refreshed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandECloudStatus extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandECloudStatus() {
|
|
||||||
super("status");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
final CloudExpansionManager manager = plugin.getCloudExpansionManager();
|
|
||||||
|
|
||||||
final int updateCount = manager.getCloudUpdateCount();
|
|
||||||
final int authorCount = manager.getCloudExpansionAuthorCount();
|
|
||||||
final int expansionCount = manager.getCloudExpansions().size();
|
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
builder.append("&bThere are &a").append(expansionCount)
|
|
||||||
.append("&b expansions available on the eCloud.").append('\n');
|
|
||||||
builder.append("&7A total of &f").append(authorCount)
|
|
||||||
.append("&7 authors have contributed to the eCloud.").append('\n');
|
|
||||||
|
|
||||||
if (updateCount > 0) {
|
|
||||||
builder.append("&eYou have &f").append(updateCount)
|
|
||||||
.append(updateCount > 1 ? "&e expansions" : "&e expansion").append(" installed that ")
|
|
||||||
.append(updateCount > 1 ? "have an" : "has an").append(" update available.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender, builder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Futures;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* please don't flame me for this code, I will fix this shit later.
|
|
||||||
*/
|
|
||||||
public final class CommandECloudUpdate extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandECloudUpdate() {
|
|
||||||
super("update");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CompletableFuture<List<@Nullable Class<? extends PlaceholderExpansion>>> downloadAndDiscover(
|
|
||||||
@NotNull final List<CloudExpansion> expansions, @NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
return expansions.stream()
|
|
||||||
.map(expansion -> plugin.getCloudExpansionManager()
|
|
||||||
.downloadExpansion(expansion, expansion.getVersion()))
|
|
||||||
.map(future -> future.thenCompose(plugin.getLocalExpansionManager()::findExpansionInFile))
|
|
||||||
.collect(Futures.collector());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must define 'all' or the name of an expansion to update.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean multiple = params.get(0).equalsIgnoreCase("all");
|
|
||||||
final List<CloudExpansion> expansions = new ArrayList<>();
|
|
||||||
|
|
||||||
// gather target expansions
|
|
||||||
if (multiple) {
|
|
||||||
expansions.addAll(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values());
|
|
||||||
} else {
|
|
||||||
plugin.getCloudExpansionManager().findCloudExpansionByName(params.get(0))
|
|
||||||
.ifPresent(expansions::add);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the ones that are the latest version
|
|
||||||
expansions.removeIf(expansion -> !expansion.shouldUpdate());
|
|
||||||
|
|
||||||
if (expansions.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cNo updates available for " + (!multiple ? "this expansion."
|
|
||||||
: "your active expansions."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&aUpdating expansions: " + expansions.stream().map(CloudExpansion::getName)
|
|
||||||
.collect(Collectors.joining("&7, &6", "&8[&6", "&8]&r")));
|
|
||||||
|
|
||||||
Futures.onMainThread(plugin, downloadAndDiscover(expansions, plugin), (classes, exception) -> {
|
|
||||||
if (exception != null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cFailed to update expansions: &e" + exception.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&aSuccessfully downloaded updates, registering new versions.");
|
|
||||||
|
|
||||||
final String message = classes.stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.map(plugin.getLocalExpansionManager()::register)
|
|
||||||
.filter(Optional::isPresent)
|
|
||||||
.map(Optional::get)
|
|
||||||
.map(expansion -> " &a" + expansion.getName() + " &f" + expansion.getVersion())
|
|
||||||
.collect(Collectors.joining("\n"));
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&7Registered expansions:", message);
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<CloudExpansion> installed = Lists
|
|
||||||
.newArrayList(plugin.getCloudExpansionManager().getCloudExpansionsInstalled().values());
|
|
||||||
installed.removeIf(expansion -> !expansion.shouldUpdate());
|
|
||||||
|
|
||||||
if (!installed.isEmpty() && (params.isEmpty() || "all"
|
|
||||||
.startsWith(params.get(0).toLowerCase(Locale.ROOT)))) {
|
|
||||||
suggestions.add("all");
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestByParameter(
|
|
||||||
installed.stream().map(CloudExpansion::getName).map(name -> name.replace(" ", "_")),
|
|
||||||
suggestions, params.isEmpty() ? null : params.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import com.google.common.io.CharStreams;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.time.format.FormatStyle;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.CompletionException;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public final class CommandDump extends PlaceholderCommand {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final String URL = "https://paste.helpch.at/";
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final Gson gson = new Gson();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter
|
|
||||||
.ofLocalizedDateTime(FormatStyle.LONG)
|
|
||||||
.withLocale(Locale.US)
|
|
||||||
.withZone(ZoneId.of("UTC"));
|
|
||||||
|
|
||||||
|
|
||||||
public CommandDump() {
|
|
||||||
super("dump");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
postDump(makeDump(plugin)).whenComplete((key, exception) -> {
|
|
||||||
if (exception != null) {
|
|
||||||
plugin.getLogger().log(Level.WARNING, "failed to post dump details", exception);
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cFailed to post dump details, check console.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&aSuccessfully posted dump: " + URL + key);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private CompletableFuture<String> postDump(@NotNull final String dump) {
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
|
||||||
try {
|
|
||||||
final HttpURLConnection connection = ((HttpURLConnection) new URL(URL + "documents")
|
|
||||||
.openConnection());
|
|
||||||
connection.setRequestMethod("POST");
|
|
||||||
connection.setRequestProperty("Content-Type", "text/plain; charset=utf-8");
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
|
|
||||||
connection.connect();
|
|
||||||
|
|
||||||
try (final OutputStream stream = connection.getOutputStream()) {
|
|
||||||
stream.write(dump.getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
try (final InputStream stream = connection.getInputStream()) {
|
|
||||||
final String json = CharStreams.toString(new InputStreamReader(stream, StandardCharsets.UTF_8));
|
|
||||||
return gson.fromJson(json, JsonObject.class).get("key").getAsString();
|
|
||||||
}
|
|
||||||
} catch (final IOException ex) {
|
|
||||||
throw new CompletionException(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private String makeDump(@NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
builder.append("Generated: ")
|
|
||||||
.append(DATE_FORMAT.format(Instant.now()))
|
|
||||||
.append("\n\n");
|
|
||||||
|
|
||||||
builder.append("PlaceholderAPI: ")
|
|
||||||
.append(plugin.getDescription().getVersion())
|
|
||||||
.append("\n\n");
|
|
||||||
|
|
||||||
builder.append("Expansions Registered:")
|
|
||||||
.append('\n');
|
|
||||||
|
|
||||||
final List<PlaceholderExpansion> expansions = plugin.getLocalExpansionManager()
|
|
||||||
.getExpansions()
|
|
||||||
.stream()
|
|
||||||
.sorted(
|
|
||||||
Comparator.comparing(PlaceholderExpansion::getIdentifier)
|
|
||||||
.thenComparing(PlaceholderExpansion::getAuthor)
|
|
||||||
)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
int size = expansions.stream().map(e -> e.getIdentifier().length())
|
|
||||||
.max(Integer::compareTo)
|
|
||||||
.orElse(0);
|
|
||||||
|
|
||||||
for (final PlaceholderExpansion expansion : expansions) {
|
|
||||||
builder.append(" ")
|
|
||||||
.append(String.format("%-" + size + "s", expansion.getIdentifier()))
|
|
||||||
.append(" [Author: ")
|
|
||||||
.append(expansion.getAuthor())
|
|
||||||
.append(", Version: ")
|
|
||||||
.append(expansion.getVersion())
|
|
||||||
.append("]\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.append('\n');
|
|
||||||
|
|
||||||
builder.append("Expansions Directory:")
|
|
||||||
.append('\n');
|
|
||||||
|
|
||||||
final String[] jars = plugin.getLocalExpansionManager()
|
|
||||||
.getExpansionsFolder()
|
|
||||||
.list((dir, name) -> name.toLowerCase(Locale.ROOT).endsWith(".jar"));
|
|
||||||
|
|
||||||
|
|
||||||
if (jars == null) {
|
|
||||||
builder.append(" ¨[Warning]: Could not load jar files from expansions folder.");
|
|
||||||
} else {
|
|
||||||
for (final String jar : jars) {
|
|
||||||
builder.append(" ")
|
|
||||||
.append(jar)
|
|
||||||
.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.append('\n');
|
|
||||||
|
|
||||||
builder.append("Server Info: ")
|
|
||||||
.append(plugin.getServer().getBukkitVersion())
|
|
||||||
.append('/')
|
|
||||||
.append(plugin.getServer().getVersion())
|
|
||||||
.append("\n");
|
|
||||||
|
|
||||||
builder.append("Java Version: ")
|
|
||||||
.append(System.getProperty("java.version"))
|
|
||||||
.append("\n\n");
|
|
||||||
|
|
||||||
builder.append("Plugin Info:")
|
|
||||||
.append('\n');
|
|
||||||
|
|
||||||
List<Plugin> plugins = Arrays.stream(plugin.getServer().getPluginManager().getPlugins())
|
|
||||||
.sorted(Comparator.comparing(Plugin::getName))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
size = plugins.stream().map(pl -> pl.getName().length())
|
|
||||||
.max(Integer::compareTo)
|
|
||||||
.orElse(0);
|
|
||||||
|
|
||||||
for (final Plugin other : plugins) {
|
|
||||||
builder.append(" ")
|
|
||||||
.append(String.format("%-" + size + "s", other.getName()))
|
|
||||||
.append(" [Authors: [")
|
|
||||||
.append(String.join(", ", other.getDescription().getAuthors()))
|
|
||||||
.append("], Version: ")
|
|
||||||
.append(other.getDescription().getVersion())
|
|
||||||
.append("]")
|
|
||||||
.append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
|
|
||||||
import me.clip.placeholderapi.util.Futures;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandExpansionRegister extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandExpansionRegister() {
|
|
||||||
super("register");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.size() < 1) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must specify the name of an expansion file.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final LocalExpansionManager manager = plugin.getLocalExpansionManager();
|
|
||||||
|
|
||||||
final File file = new File(manager.getExpansionsFolder(), params.get(0));
|
|
||||||
if (!file.exists() || !file.getParentFile().equals(manager.getExpansionsFolder())) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cThe file &f" + file.getName() + "&c doesn't exist!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Futures.onMainThread(plugin, manager.findExpansionInFile(file), (clazz, exception) -> {
|
|
||||||
if (exception != null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cFailed to find expansion in file: &f" + file);
|
|
||||||
|
|
||||||
plugin.getLogger()
|
|
||||||
.log(Level.WARNING, "failed to find expansion in file: " + file, exception);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clazz == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cNo expansion class found in file: &f" + file);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Optional<PlaceholderExpansion> expansion = manager.register(clazz);
|
|
||||||
if (!expansion.isPresent()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cFailed to register expansion from &f" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&aSuccessfully registered expansion: &f" + expansion.get().getName());
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String[] fileNames = plugin.getLocalExpansionManager().getExpansionsFolder()
|
|
||||||
.list((dir, name) -> name.endsWith(".jar"));
|
|
||||||
if (fileNames == null || fileNames.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestByParameter(Arrays.stream(fileNames), suggestions,
|
|
||||||
params.isEmpty() ? null : params.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandExpansionUnregister extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandExpansionUnregister() {
|
|
||||||
super("unregister");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must specify the name of the expansion.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Optional<PlaceholderExpansion> expansion = plugin.getLocalExpansionManager()
|
|
||||||
.findExpansionByName(params.get(0));
|
|
||||||
if (!expansion.isPresent()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cThere is no expansion loaded with the identifier: &f" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String message = !expansion.get().unregister() ?
|
|
||||||
"&cFailed to unregister expansion: &f" :
|
|
||||||
"&aSuccessfully unregistered expansion: &f";
|
|
||||||
|
|
||||||
Msg.msg(sender, message + expansion.get().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions,
|
|
||||||
params.isEmpty() ? null : params.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.plugin.PluginDescriptionFile;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandHelp extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandHelp() {
|
|
||||||
super("help");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
final PluginDescriptionFile description = plugin.getDescription();
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&b&lPlaceholderAPI &8- &7Help Menu &8- &7(&f" + description.getVersion() + "&7)",
|
|
||||||
" ",
|
|
||||||
"&b/papi &fbcparse &9<me|--null|player name> <message>",
|
|
||||||
" &7&oParse a message with placeholders and broadcast it",
|
|
||||||
"&b/papi &fcmdparse &9<me|player> <command with placeholders>",
|
|
||||||
" &7&oParse a message with relational placeholders",
|
|
||||||
"&b/papi &fdump",
|
|
||||||
" &7&oDump all relevant information needed to help debug issues into a paste link.",
|
|
||||||
"&b/papi &finfo &9<placeholder name>",
|
|
||||||
" &7&oView information for a specific expansion",
|
|
||||||
"&b/papi &flist",
|
|
||||||
" &7&oList active expansions",
|
|
||||||
"&b/papi &fparse &9<me|--null|player name> <message>",
|
|
||||||
" &7&oParse a message with placeholders",
|
|
||||||
"&b/papi &fparserel &9<player one> <player two> <message>",
|
|
||||||
" &7&oParse a message with relational placeholders",
|
|
||||||
"&b/papi &fregister &9<file name>",
|
|
||||||
" &7&oRegister an expansion by the name of the file",
|
|
||||||
"&b/papi &freload",
|
|
||||||
" &7&oReload the config of PAPI",
|
|
||||||
"&b/papi &funregister &9<expansion name>",
|
|
||||||
" &7&oUnregister an expansion by name",
|
|
||||||
"&b/papi &fversion",
|
|
||||||
" &7&oView plugin info/version");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandInfo extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandInfo() {
|
|
||||||
super("info");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.isEmpty()) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must specify the name of the expansion.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PlaceholderExpansion expansion = plugin.getLocalExpansionManager()
|
|
||||||
.findExpansionByIdentifier(params.get(0)).orElse(null);
|
|
||||||
if (expansion == null) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cThere is no expansion loaded with the identifier: &f" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
builder.append("&7Placeholder expansion info for: &r")
|
|
||||||
.append(expansion.getName())
|
|
||||||
.append('\n')
|
|
||||||
.append("&7Status: &r")
|
|
||||||
.append(expansion.isRegistered() ? "&aRegistered" : "7cNotRegistered")
|
|
||||||
.append('\n');
|
|
||||||
|
|
||||||
final String author = expansion.getAuthor();
|
|
||||||
if (author != null) {
|
|
||||||
builder.append("&7Author: &r")
|
|
||||||
.append(author)
|
|
||||||
.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
final String version = expansion.getVersion();
|
|
||||||
if (version != null) {
|
|
||||||
builder.append("&7Version: &r")
|
|
||||||
.append(version)
|
|
||||||
.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
final String requiredPlugin = expansion.getRequiredPlugin();
|
|
||||||
if (requiredPlugin != null) {
|
|
||||||
builder.append("&7Requires plugin: &r")
|
|
||||||
.append(requiredPlugin)
|
|
||||||
.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<String> placeholders = expansion.getPlaceholders();
|
|
||||||
if (placeholders != null && !placeholders.isEmpty()) {
|
|
||||||
builder.append("&8&m-- &7Placeholders &8&m--&r")
|
|
||||||
.append('\n');
|
|
||||||
|
|
||||||
for (final String placeholder : placeholders) {
|
|
||||||
builder.append(placeholder)
|
|
||||||
.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.msg(sender, builder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestByParameter(PlaceholderAPI.getRegisteredIdentifiers().stream(), suggestions,
|
|
||||||
params.isEmpty() ? null : params.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandList extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandList() {
|
|
||||||
super("list");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
final Set<String> identifiers = PlaceholderAPI.getRegisteredIdentifiers();
|
|
||||||
if (identifiers.isEmpty()) {
|
|
||||||
Msg.msg(sender, "&cThere are no placeholder hooks active!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<List<String>> partitions = Lists
|
|
||||||
.partition(identifiers.stream().sorted().collect(Collectors.toList()), 10);
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&7A total of &f" + identifiers.size() + "&7 placeholder hook(s) are active: &a",
|
|
||||||
partitions.stream().map(partition -> String.join("&7, &a", partition))
|
|
||||||
.collect(Collectors.joining("\n")));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandParse extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandParse() {
|
|
||||||
super("parse", "bcparse", "parserel", "cmdparse");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
switch (alias.toLowerCase(Locale.ROOT)) {
|
|
||||||
case "parserel":
|
|
||||||
evaluateParseRelation(sender, params);
|
|
||||||
break;
|
|
||||||
case "parse":
|
|
||||||
evaluateParseSingular(sender, params, false, false);
|
|
||||||
break;
|
|
||||||
case "bcparse":
|
|
||||||
evaluateParseSingular(sender, params, true, false);
|
|
||||||
break;
|
|
||||||
case "cmdparse":
|
|
||||||
evaluateParseSingular(sender, params, false, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
switch (alias.toLowerCase(Locale.ROOT)) {
|
|
||||||
case "parserel":
|
|
||||||
completeParseRelation(params, suggestions);
|
|
||||||
break;
|
|
||||||
case "parse":
|
|
||||||
case "bcparse":
|
|
||||||
case "cmdparse":
|
|
||||||
completeParseSingular(sender, params, suggestions);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void evaluateParseSingular(@NotNull final CommandSender sender,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, final boolean broadcast,
|
|
||||||
final boolean command) {
|
|
||||||
if (params.size() < 2) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must provide a target and message: &b/papi "
|
|
||||||
+ (command ? "cmdparse" : (broadcast ? "bcparse" : "parse"))
|
|
||||||
+ " &7{target} &a{message}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OfflinePlayer player;
|
|
||||||
|
|
||||||
if ("me".equalsIgnoreCase(params.get(0))) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
player = ((Player) sender);
|
|
||||||
} else if ("--null".equalsIgnoreCase(params.get(0))) {
|
|
||||||
player = null;
|
|
||||||
} else {
|
|
||||||
final OfflinePlayer target = resolvePlayer(params.get(0));
|
|
||||||
if (target == null) {
|
|
||||||
Msg.msg(sender, "&cFailed to find player: &7" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
player = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String message = PlaceholderAPI
|
|
||||||
.setPlaceholders(player, String.join(" ", params.subList(1, params.size())));
|
|
||||||
|
|
||||||
if (command) {
|
|
||||||
Bukkit.dispatchCommand(sender, message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (broadcast) {
|
|
||||||
Bukkit.broadcastMessage(message);
|
|
||||||
} else {
|
|
||||||
sender.sendMessage(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void evaluateParseRelation(@NotNull final CommandSender sender,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (params.size() < 3) {
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&cYou must supply two targets, and a message: &b/papi parserel &7{target one} "
|
|
||||||
+ "{target two} &a{message}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OfflinePlayer playerOne;
|
|
||||||
|
|
||||||
if ("me".equalsIgnoreCase(params.get(0))) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
playerOne = ((Player) sender);
|
|
||||||
} else {
|
|
||||||
playerOne = resolvePlayer(params.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerOne == null || !playerOne.isOnline()) {
|
|
||||||
Msg.msg(sender, "&cFailed to find player: &f" + params.get(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OfflinePlayer playerTwo;
|
|
||||||
|
|
||||||
if ("me".equalsIgnoreCase(params.get(1))) {
|
|
||||||
if (!(sender instanceof Player)) {
|
|
||||||
Msg.msg(sender, "&cYou must be a player to use &7me&c as a target!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
playerTwo = ((Player) sender);
|
|
||||||
} else {
|
|
||||||
playerTwo = resolvePlayer(params.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerTwo == null || !playerTwo.isOnline()) {
|
|
||||||
Msg.msg(sender, "&cFailed to find player: &f" + params.get(1));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String message = PlaceholderAPI
|
|
||||||
.setRelationalPlaceholders((Player) playerOne, (Player) playerTwo,
|
|
||||||
String.join(" ", params.subList(2, params.size())));
|
|
||||||
|
|
||||||
sender.sendMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void completeParseSingular(@NotNull final CommandSender sender,
|
|
||||||
@NotNull @Unmodifiable final List<String> params, @NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() <= 1) {
|
|
||||||
if (sender instanceof Player && (params.isEmpty() || "me"
|
|
||||||
.startsWith(params.get(0).toLowerCase(Locale.ROOT)))) {
|
|
||||||
suggestions.add("me");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("--null".startsWith(params.get(0).toLowerCase(Locale.ROOT))) {
|
|
||||||
suggestions.add("--null");
|
|
||||||
}
|
|
||||||
|
|
||||||
final Stream<String> names = Bukkit.getOnlinePlayers().stream().map(Player::getName);
|
|
||||||
suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(0));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String name = params.get(params.size() - 1);
|
|
||||||
if (!name.startsWith("%") || name.endsWith("%")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int index = name.indexOf('_');
|
|
||||||
if (index == -1) {
|
|
||||||
return; // no arguments supplied yet
|
|
||||||
}
|
|
||||||
|
|
||||||
final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance()
|
|
||||||
.getLocalExpansionManager().findExpansionByIdentifier(name.substring(1, index))
|
|
||||||
.orElse(null);
|
|
||||||
if (expansion == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Set<String> possible = new HashSet<>(expansion.getPlaceholders());
|
|
||||||
|
|
||||||
PlaceholderAPIPlugin.getInstance()
|
|
||||||
.getCloudExpansionManager()
|
|
||||||
.findCloudExpansionByName(expansion.getName())
|
|
||||||
.ifPresent(cloud -> possible.addAll(cloud.getPlaceholders()));
|
|
||||||
|
|
||||||
suggestByParameter(possible.stream(), suggestions, params.get(params.size() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void completeParseRelation(@NotNull @Unmodifiable final List<String> params,
|
|
||||||
@NotNull final List<String> suggestions) {
|
|
||||||
if (params.size() > 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Stream<String> names = Bukkit.getOnlinePlayers().stream().map(Player::getName);
|
|
||||||
suggestByParameter(names, suggestions, params.isEmpty() ? null : params.get(params.size() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private OfflinePlayer resolvePlayer(@NotNull final String name) {
|
|
||||||
OfflinePlayer target = Bukkit.getPlayerExact(name);
|
|
||||||
|
|
||||||
if (target == null) {
|
|
||||||
// Not the best option, but Spigot doesn't offer a good replacement (as usual)
|
|
||||||
target = Bukkit.getOfflinePlayer(name);
|
|
||||||
|
|
||||||
return target.hasPlayedBefore() ? target : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.util.ExpansionSafetyCheck;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandReload extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandReload() {
|
|
||||||
super("reload");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
if (!new ExpansionSafetyCheck(plugin).runChecks()) {
|
|
||||||
plugin.reloadConf(sender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.commands.impl.local;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.plugin.PluginDescriptionFile;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CommandVersion extends PlaceholderCommand {
|
|
||||||
|
|
||||||
public CommandVersion() {
|
|
||||||
super("version");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
|
||||||
final PluginDescriptionFile description = plugin.getDescription();
|
|
||||||
|
|
||||||
Msg.msg(sender,
|
|
||||||
"&b&lPlaceholderAPI &7(&f" + description.getVersion() + "&7)",
|
|
||||||
"&7Author: &f" + description.getAuthors(),
|
|
||||||
"&7PAPI Commands: &b/papi &fhelp",
|
|
||||||
"&7eCloud Commands&8: &b/papi &fecloud");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.configuration;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public enum ExpansionSort implements Comparator<CloudExpansion> {
|
|
||||||
|
|
||||||
NAME(Comparator.comparing(CloudExpansion::getName)),
|
|
||||||
AUTHOR(Comparator.comparing(CloudExpansion::getAuthor)),
|
|
||||||
LATEST(Comparator.comparing(CloudExpansion::getLastUpdate).reversed());
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Comparator<CloudExpansion> comparator;
|
|
||||||
|
|
||||||
ExpansionSort(@NotNull final Comparator<CloudExpansion> comparator) {
|
|
||||||
this.comparator = comparator;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int compare(final CloudExpansion expansion1, final CloudExpansion expansion2) {
|
|
||||||
return comparator.compare(expansion1, expansion2);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.configuration;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public final class PlaceholderAPIConfig {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderAPIPlugin plugin;
|
|
||||||
|
|
||||||
public PlaceholderAPIConfig(@NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean checkUpdates() {
|
|
||||||
return plugin.getConfig().getBoolean("check_updates");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isCloudEnabled() {
|
|
||||||
return plugin.getConfig().getBoolean("cloud_enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCloudEnabled(boolean state) {
|
|
||||||
plugin.getConfig().set("cloud_enabled", state);
|
|
||||||
plugin.saveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isDebugMode() {
|
|
||||||
return plugin.getConfig().getBoolean("debug", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Optional<ExpansionSort> getExpansionSort() {
|
|
||||||
final String option = plugin.getConfig()
|
|
||||||
.getString("cloud_sorting", ExpansionSort.LATEST.name());
|
|
||||||
|
|
||||||
try {
|
|
||||||
//noinspection ConstantConditions (bad spigot annotation)
|
|
||||||
return Optional.of(ExpansionSort.valueOf(option.toUpperCase()));
|
|
||||||
} catch (final IllegalArgumentException ignored) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String dateFormat() {
|
|
||||||
//noinspection ConstantConditions (bad spigot annotation)
|
|
||||||
return plugin.getConfig().getString("date_format", "MM/dd/yy HH:mm:ss");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String booleanTrue() {
|
|
||||||
//noinspection ConstantConditions (bad spigot annotation)
|
|
||||||
return plugin.getConfig().getString("boolean.true", "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String booleanFalse() {
|
|
||||||
//noinspection ConstantConditions (bad spigot annotation)
|
|
||||||
return plugin.getConfig().getString("boolean.false", "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean detectMaliciousExpansions() {
|
|
||||||
return plugin.getConfig().getBoolean("detect_malicious_expansions", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.events;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import org.bukkit.event.Cancellable;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event indicates that a <b>single</b> {@link PlaceholderExpansion PlaceholderExpansion} has
|
|
||||||
* been registered in PlaceholderAPI.
|
|
||||||
*
|
|
||||||
* <p>To know when <b>all</b> Expansions have been registered, use the
|
|
||||||
* {@link me.clip.placeholderapi.events.ExpansionsLoadedEvent ExpansionsLoadedEvent} instead.
|
|
||||||
*/
|
|
||||||
public final class ExpansionRegisterEvent extends Event implements Cancellable {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final HandlerList HANDLERS = new HandlerList();
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderExpansion expansion;
|
|
||||||
private boolean cancelled;
|
|
||||||
|
|
||||||
public ExpansionRegisterEvent(@NotNull final PlaceholderExpansion expansion) {
|
|
||||||
this.expansion = expansion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link PlaceholderExpansion PlaceholderExpansion} that was registered in PlaceholderAPI.
|
|
||||||
* <br>The PlaceholderExpansion will be available for use when the event
|
|
||||||
* {@link #isCancelled() was not cancelled}!
|
|
||||||
*
|
|
||||||
* @return Current instance of the registered {@link PlaceholderExpansion PlaceholderExpansion}
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public PlaceholderExpansion getExpansion() {
|
|
||||||
return expansion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if this event was cancelled or not.
|
|
||||||
* <br>A cancelled Event will result in the {@link #getExpansion() PlaceholderExpansion} NOT
|
|
||||||
* being added to PlaceholderAPI's internal list and will therefore be considered not registered
|
|
||||||
* anymore.
|
|
||||||
*
|
|
||||||
* @return Whether the event has been cancelled or not.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return cancelled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCancelled(boolean cancelled) {
|
|
||||||
this.cancelled = cancelled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.events;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event indicates that a {@link PlaceholderExpansion PlaceholderExpansion} has been
|
|
||||||
* unregistered by PlaceholderAPI.
|
|
||||||
*
|
|
||||||
* <p>Note that this event is triggered <b>before</b> the PlaceholderExpansion is completely
|
|
||||||
* removed.
|
|
||||||
* <br>This includes removing any Listeners, stopping active tasks and clearing the cache of
|
|
||||||
* the PlaceholderExpansion.
|
|
||||||
*/
|
|
||||||
public final class ExpansionUnregisterEvent extends Event {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final HandlerList HANDLERS = new HandlerList();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderExpansion expansion;
|
|
||||||
|
|
||||||
public ExpansionUnregisterEvent(@NotNull final PlaceholderExpansion expansion) {
|
|
||||||
this.expansion = expansion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link PlaceholderExpansion PlaceholderExpansion} that was unregistered.
|
|
||||||
*
|
|
||||||
* @return The {@link PlaceholderExpansion PlaceholderExpansion} instance.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public PlaceholderExpansion getExpansion() {
|
|
||||||
return expansion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.events;
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event indicated that <b>all</b> {@link PlaceholderExpansion PlaceholderExpansions} have
|
|
||||||
* been registered in PlaceholderAPI and can now be used.
|
|
||||||
* <br>This even will also be triggered whenever PlaceholderAPI gets reloaded.
|
|
||||||
*
|
|
||||||
* <p>All PlaceholderExpansions, except for those loaded by plugins, are loaded
|
|
||||||
* after Spigot triggered its ServerLoadEvent (1.13+), or after PlaceholderAPI has been enabled.
|
|
||||||
*/
|
|
||||||
public class ExpansionsLoadedEvent extends Event {
|
|
||||||
|
|
||||||
private final List<PlaceholderExpansion> expansions;
|
|
||||||
|
|
||||||
public ExpansionsLoadedEvent(List<PlaceholderExpansion> expansions) {
|
|
||||||
this.expansions = Collections.unmodifiableList(expansions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a unmodifiable list of {@link PlaceholderExpansion PlaceholderExpansions} that
|
|
||||||
* have been registered by PlaceholderAPI.
|
|
||||||
*
|
|
||||||
* <p><b>This list does not include manually registered PlaceholderExpansions.</b>
|
|
||||||
*
|
|
||||||
* @return List of {@link PlaceholderExpansion registered PlaceholderExpansions}.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public final List<PlaceholderExpansion> getExpansions() {
|
|
||||||
return expansions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final HandlerList HANDLERS = new HandlerList();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.events;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderHook;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This event is no longer used.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public final class PlaceholderHookUnloadEvent extends Event {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final HandlerList HANDLERS = new HandlerList();
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final String plugin;
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderHook placeholderHook;
|
|
||||||
|
|
||||||
public PlaceholderHookUnloadEvent(@NotNull final String plugin,
|
|
||||||
@NotNull final PlaceholderHook placeholderHook) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.placeholderHook = placeholderHook;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static HandlerList getHandlerList() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public String getHookName() {
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public PlaceholderHook getHook() {
|
|
||||||
return placeholderHook;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
return HANDLERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.exceptions;
|
|
||||||
|
|
||||||
public final class NoDefaultCommandException extends RuntimeException {
|
|
||||||
|
|
||||||
public NoDefaultCommandException(final String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Classes implementing this interface will have a {@link #clear() clear void} that is called
|
|
||||||
* by PlaceholderAPI whenever the {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}
|
|
||||||
* is unregistered.
|
|
||||||
*
|
|
||||||
* <p>This allows you to execute things such as clearing internal caches, saving data to files, etc.
|
|
||||||
*
|
|
||||||
* @author Ryan McCarthy
|
|
||||||
*/
|
|
||||||
public interface Cacheable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the implementing class is unregistered from PlaceholderAPI
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Classes implementing this interface will have a {@link #cleanup(Player) cleanup void} that is
|
|
||||||
* called by PlaceholderAPI whenever a Player leaves the server.
|
|
||||||
*
|
|
||||||
* <p>This can be useful for cases where you keep data of the player in a cache or similar
|
|
||||||
* and want to free up space whenever they leave.
|
|
||||||
*
|
|
||||||
* @author Ryan McCarthy
|
|
||||||
*/
|
|
||||||
public interface Cleanable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a player leaves the server
|
|
||||||
*
|
|
||||||
* @param p (@link Player} who left the server
|
|
||||||
*/
|
|
||||||
void cleanup(Player p);
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementing this interface allows {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansions}
|
|
||||||
* to set a list of default configuration values through the {@link #getDefaults() getDefaults method}
|
|
||||||
* that should be added to the config.yml of PlaceholderAPI.
|
|
||||||
*
|
|
||||||
* <p>The entries will be added under {@code expansions} as their own section.
|
|
||||||
* <h2>Example:</h2>
|
|
||||||
* returning a Map with key {@code foo} and value {@code bar} will result in the following config entry:
|
|
||||||
*
|
|
||||||
* <pre><code>
|
|
||||||
* expansions:
|
|
||||||
* myexpansion:
|
|
||||||
* foo: "bar"
|
|
||||||
* </code></pre>
|
|
||||||
*
|
|
||||||
* <p><b>The configuration is set before the PlaceholderExpansion is registered!</b>
|
|
||||||
*
|
|
||||||
* @author Ryan McCarthy
|
|
||||||
*/
|
|
||||||
public interface Configurable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The map returned by this method will be used to set config options in PlaceholderAPI's config.yml.
|
|
||||||
*
|
|
||||||
* <p>The key and value pairs are set under a section named after your
|
|
||||||
* {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion} in the
|
|
||||||
* {@code expansions} section of the config.
|
|
||||||
*
|
|
||||||
* @return Map of config path / values which need to be added / removed from the PlaceholderAPI
|
|
||||||
* config.yml file
|
|
||||||
*/
|
|
||||||
Map<String, Object> getDefaults();
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
public enum NMSVersion {
|
|
||||||
|
|
||||||
UNKNOWN("unknown"),
|
|
||||||
SPIGOT_1_7_R1("v1_7_R1"),
|
|
||||||
SPIGOT_1_7_R2("v1_7_R2"),
|
|
||||||
SPIGOT_1_7_R3("v1_7_R3"),
|
|
||||||
SPIGOT_1_7_R4("v1_7_R4"),
|
|
||||||
SPIGOT_1_8_R1("v1_8_R1"),
|
|
||||||
SPIGOT_1_8_R2("v1_8_R2"),
|
|
||||||
SPIGOT_1_8_R3("v1_8_R3"),
|
|
||||||
SPIGOT_1_9_R1("v1_9_R1"),
|
|
||||||
SPIGOT_1_9_R2("v1_9_R2"),
|
|
||||||
SPIGOT_1_10_R1("v1_10_R1"),
|
|
||||||
SPIGOT_1_11_R1("v1_11_R1"),
|
|
||||||
SPIGOT_1_12_R1("v1_12_R1"),
|
|
||||||
SPIGOT_1_13_R1("v1_13_R1"),
|
|
||||||
SPIGOT_1_13_R2("v1_13_R2"),
|
|
||||||
SPIGOT_1_14_R1("v1_14_R1"),
|
|
||||||
SPIGOT_1_15_R1("v1_15_R1"),
|
|
||||||
SPIGOT_1_16_R1("v1_16_R1"),
|
|
||||||
SPIGOT_1_16_R2("v1_16_R2"),
|
|
||||||
SPIGOT_1_16_R3("v1_16_R3"),
|
|
||||||
SPIGOT_1_17_R1("v1_17_R1"),
|
|
||||||
SPIGOT_1_18_R1("v1_18_R1"),
|
|
||||||
SPIGOT_1_19_R1("v1_19_R1"),
|
|
||||||
SPIGOT_1_19_R2("v1_19_R2"),
|
|
||||||
SPIGOT_1_19_R3("v1_19_R3"),
|
|
||||||
SPIGOT_1_20_R1("v1_20_R1"),
|
|
||||||
SPIGOT_1_20_R2("v1_20_R2"),
|
|
||||||
SPIGOT_1_20_R3("v1_20_R3"),
|
|
||||||
SPIGOT_1_20_R4("v1_20_R4"),
|
|
||||||
SPIGOT_1_21_R1("v1_21_R1"),
|
|
||||||
SPIGOT_1_21_R2("V1_21_R2"),
|
|
||||||
SPIGOT_1_21_R3("V1_21_R3"),
|
|
||||||
SPIGOT_1_21_R4("V1_21_R4"),
|
|
||||||
SPIGOT_1_21_R5("V1_21_R5"),
|
|
||||||
SPIGOT_1_21_R6("V1_21_R6");
|
|
||||||
|
|
||||||
private final String version;
|
|
||||||
|
|
||||||
NMSVersion(String version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NMSVersion getVersion(String version) {
|
|
||||||
for (NMSVersion v : values()) {
|
|
||||||
if (v.getVersion().equalsIgnoreCase(version)) {
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NMSVersion.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,479 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.PlaceholderHook;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.Contract;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Any class extending this will be able to get registered as a PlaceholderExpansion.
|
|
||||||
* <br>The registration either happens automatically when the jar file containing a
|
|
||||||
* class extending this one is located under the {@code PlaceholderAPI/expansions}
|
|
||||||
* directory or when the {@link #register()} method is called by said class.
|
|
||||||
*/
|
|
||||||
public abstract class PlaceholderExpansion extends PlaceholderHook {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type is {@link Type#INTERNAL} by default.
|
|
||||||
* For external expansions, the type is updated on {@link me.clip.placeholderapi.expansion.manager.LocalExpansionManager#register(Class) register}.
|
|
||||||
*
|
|
||||||
* @since 2.11.4
|
|
||||||
*/
|
|
||||||
@ApiStatus.Internal
|
|
||||||
protected Type expansionType = Type.INTERNAL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholder identifier of this expansion. May not contain {@literal %},
|
|
||||||
* {@literal {}} or _
|
|
||||||
*
|
|
||||||
* @return placeholder identifier that is associated with this expansion
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public abstract String getIdentifier();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The author of this expansion
|
|
||||||
*
|
|
||||||
* @return name of the author for this expansion
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public abstract String getAuthor();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The version of this expansion
|
|
||||||
*
|
|
||||||
* @return current version of this expansion
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public abstract String getVersion();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of this expansion
|
|
||||||
*
|
|
||||||
* @return {@link #getIdentifier()} by default, name of this expansion if specified
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public String getName() {
|
|
||||||
return getIdentifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the plugin that this expansion hooks into. by default will null
|
|
||||||
*
|
|
||||||
* @return plugin name that this expansion requires to function
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public String getRequiredPlugin() {
|
|
||||||
return getPlugin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholders associated with this expansion
|
|
||||||
*
|
|
||||||
* @return placeholder list that this expansion provides
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public List<String> getPlaceholders() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expansions that do not use the ecloud and instead register from the dependency should set this
|
|
||||||
* to true to ensure that your placeholder expansion is not unregistered when the papi reload
|
|
||||||
* command is used
|
|
||||||
*
|
|
||||||
* @return if this expansion should persist through placeholder reloads
|
|
||||||
*/
|
|
||||||
public boolean persist() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if this placeholder identifier has already been registered
|
|
||||||
*
|
|
||||||
* @return true if the identifier for this expansion is already registered
|
|
||||||
*/
|
|
||||||
public final boolean isRegistered() {
|
|
||||||
return getPlaceholderAPI().getLocalExpansionManager().findExpansionByIdentifier(getIdentifier())
|
|
||||||
.map(it -> it.equals(this)).orElse(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If any requirements need to be checked before this expansion should register, you can check
|
|
||||||
* them here
|
|
||||||
*
|
|
||||||
* @return true if this hook meets all the requirements to register
|
|
||||||
*/
|
|
||||||
public boolean canRegister() {
|
|
||||||
return getRequiredPlugin() == null
|
|
||||||
|| Bukkit.getPluginManager().getPlugin(getRequiredPlugin()) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to register this PlaceholderExpansion
|
|
||||||
*
|
|
||||||
* @return true if this expansion is now registered with PlaceholderAPI
|
|
||||||
*/
|
|
||||||
public boolean register() {
|
|
||||||
return getPlaceholderAPI().getLocalExpansionManager().register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to unregister this PlaceholderExpansion
|
|
||||||
*
|
|
||||||
* @return true if this expansion is now unregistered with PlaceholderAPI
|
|
||||||
*/
|
|
||||||
public final boolean unregister() {
|
|
||||||
return getPlaceholderAPI().getLocalExpansionManager().unregister(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quick getter for the {@link PlaceholderAPIPlugin} instance
|
|
||||||
*
|
|
||||||
* @return {@link PlaceholderAPIPlugin} instance
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public final PlaceholderAPIPlugin getPlaceholderAPI() {
|
|
||||||
return PlaceholderAPIPlugin.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the type of the expansion
|
|
||||||
*
|
|
||||||
* @return the type of the expansion
|
|
||||||
* @since 2.11.4
|
|
||||||
*/
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public Type getExpansionType() {
|
|
||||||
return expansionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the type of the expansion
|
|
||||||
*
|
|
||||||
* @param expansionType the new type
|
|
||||||
* @since 2.11.4
|
|
||||||
*/
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public void setExpansionType(Type expansionType) {
|
|
||||||
this.expansionType = expansionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Configuration ===
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the ConfigurationSection of the expansion located in the config.yml of PlaceholderAPI or
|
|
||||||
* null when not specified.
|
|
||||||
* <br>You may use the {@link Configurable} interface to define default values set
|
|
||||||
*
|
|
||||||
* @return ConfigurationSection that this expansion has.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public final ConfigurationSection getConfigSection() {
|
|
||||||
return getPlaceholderAPI().getConfig().getConfigurationSection("expansions." + getIdentifier());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the ConfigurationSection relative to the {@link #getConfigSection() default one} set
|
|
||||||
* by the expansion or null when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the ConfigurationSection from. This is relative to the default section
|
|
||||||
* @return ConfigurationSection relative to the default section
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public final ConfigurationSection getConfigSection(@NotNull final String path) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? null : section.getConfigurationSection(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the Object relative to the {@link #getConfigSection() default ConfigurationSection} set
|
|
||||||
* by the expansion or the provided Default Object, when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the Object from. This is relative to the default section
|
|
||||||
* @param def The default Object to return when the ConfigurationSection returns null
|
|
||||||
* @return Object from the provided path or the default one provided
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
@Contract("_, !null -> !null")
|
|
||||||
public final Object get(@NotNull final String path, final Object def) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? def : section.get(path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the int relative to the {@link #getConfigSection() default ConfigurationSection} set
|
|
||||||
* by the expansion or the provided Default int, when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the int from. This is relative to the default section
|
|
||||||
* @param def The default int to return when the ConfigurationSection returns null
|
|
||||||
* @return int from the provided path or the default one provided
|
|
||||||
*/
|
|
||||||
public final int getInt(@NotNull final String path, final int def) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? def : section.getInt(path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the long relative to the {@link #getConfigSection() default ConfigurationSection} set
|
|
||||||
* by the expansion or the provided Default long, when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the long from. This is relative to the default section
|
|
||||||
* @param def The default long to return when the ConfigurationSection returns null
|
|
||||||
* @return long from the provided path or the default one provided
|
|
||||||
*/
|
|
||||||
public final long getLong(@NotNull final String path, final long def) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? def : section.getLong(path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the double relative to the {@link #getConfigSection() default ConfigurationSection} set
|
|
||||||
* by the expansion or the provided Default double, when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the double from. This is relative to the default section
|
|
||||||
* @param def The default double to return when the ConfigurationSection returns null
|
|
||||||
* @return double from the provided path or the default one provided
|
|
||||||
*/
|
|
||||||
public final double getDouble(@NotNull final String path, final double def) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? def : section.getDouble(path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the String relative to the {@link #getConfigSection() default ConfigurationSection} set
|
|
||||||
* by the expansion or the provided Default String, when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the String from. This is relative to the default section
|
|
||||||
* @param def The default String to return when the ConfigurationSection returns null. Can be null
|
|
||||||
* @return String from the provided path or the default one provided
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
@Contract("_, !null -> !null")
|
|
||||||
public final String getString(@NotNull final String path, @Nullable final String def) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? def : section.getString(path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a String List relative to the {@link #getConfigSection() default ConfigurationSection} set
|
|
||||||
* by the expansion or an empty List, when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the String list from. This is relative to the default section
|
|
||||||
* @return String list from the provided path or an empty list
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public final List<String> getStringList(@NotNull final String path) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? Collections.emptyList() : section.getStringList(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the boolean relative to the {@link #getConfigSection() default ConfigurationSection} set
|
|
||||||
* by the expansion or the default boolean, when the default ConfigurationSection is null
|
|
||||||
*
|
|
||||||
* @param path The path to get the boolean from. This is relative to the default section
|
|
||||||
* @param def The default boolean to return when the ConfigurationSection is null
|
|
||||||
* @return boolean from the provided path or the default one provided
|
|
||||||
*/
|
|
||||||
public final boolean getBoolean(@NotNull final String path, final boolean def) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section == null ? def : section.getBoolean(path, def);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the {@link #getConfigSection() default ConfigurationSection} contains the provided path
|
|
||||||
* or not. This will return {@code false} when either the default section is null, or doesn't
|
|
||||||
* contain the provided path
|
|
||||||
*
|
|
||||||
* @param path The path to check
|
|
||||||
* @return true when the default ConfigurationSection is not null and contains the path, false otherwise
|
|
||||||
*/
|
|
||||||
public final boolean configurationContains(@NotNull final String path) {
|
|
||||||
final ConfigurationSection section = getConfigSection();
|
|
||||||
return section != null && section.contains(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the provided message with the provided Level in the console.
|
|
||||||
* <br>The message will be prefixed with {@link #getName() <code>[<expansion name>]</code>}
|
|
||||||
*
|
|
||||||
* @param level The Level at which the message should be logged with
|
|
||||||
* @param msg The message to log
|
|
||||||
*/
|
|
||||||
public void log(Level level, String msg) {
|
|
||||||
getPlaceholderAPI().getLogger().log(level, "[" + getName() + "] " + msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the provided message and Throwable with the provided Level in the console.
|
|
||||||
* <br>The message will be prefixed with {@link #getName() <code>[<expansion name>]</code>}
|
|
||||||
*
|
|
||||||
* @param level The Level at which the message should be logged with
|
|
||||||
* @param msg The message to log
|
|
||||||
* @param throwable The Throwable to log
|
|
||||||
*/
|
|
||||||
public void log(Level level, String msg, Throwable throwable) {
|
|
||||||
getPlaceholderAPI().getLogger().log(level, "[" + getName() + "] " + msg, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the provided message with Level "info".
|
|
||||||
* <br>The message will be prefixed with {@link #getName() <code>[<expansion name>]</code>}
|
|
||||||
*
|
|
||||||
* @param msg The message to log
|
|
||||||
*/
|
|
||||||
public void info(String msg) {
|
|
||||||
log(Level.INFO, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the provided message with Level "warning".
|
|
||||||
* <br>The message will be prefixed with {@link #getName() <code>[<expansion name>]</code>}
|
|
||||||
*
|
|
||||||
* @param msg The message to log
|
|
||||||
*/
|
|
||||||
public void warning(String msg) {
|
|
||||||
log(Level.WARNING, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the provided message with Level "severe" (error).
|
|
||||||
* <br>The message will be prefixed with {@link #getName() <code>[<expansion name>]</code>}
|
|
||||||
*
|
|
||||||
* @param msg The message to log
|
|
||||||
*/
|
|
||||||
public void severe(String msg) {
|
|
||||||
log(Level.SEVERE, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the provided message and Throwable with Level "severe" (error).
|
|
||||||
* <br>The message will be prefixed with {@link #getName() <code>[<expansion name>]</code>}
|
|
||||||
*
|
|
||||||
* @param msg The message to log
|
|
||||||
* @param throwable The Throwable to log
|
|
||||||
*/
|
|
||||||
public void severe(String msg, Throwable throwable) {
|
|
||||||
log(Level.SEVERE, msg, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the provided Object is an instance of this PlaceholderExpansion.
|
|
||||||
* <br>This method will perform the following checks in order:
|
|
||||||
* <br><ul>
|
|
||||||
* <li>Checks if Object equals the class. Returns true when equal and continues otherwise</li>
|
|
||||||
* <li>Checks if the Object is an instance of a PlaceholderExpansion. Returns false if not</li>
|
|
||||||
* <li>Checks if the Object's Identifier, Author and version equal the one of this class</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param o The Object to check
|
|
||||||
* @return true or false depending on the above mentioned checks
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean equals(final Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(o instanceof PlaceholderExpansion)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PlaceholderExpansion expansion = (PlaceholderExpansion) o;
|
|
||||||
|
|
||||||
return getIdentifier().equals(expansion.getIdentifier()) &&
|
|
||||||
getAuthor().equals(expansion.getAuthor()) &&
|
|
||||||
getVersion().equals(expansion.getVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a String containing the Expansion's name, author and version
|
|
||||||
*
|
|
||||||
* @return String containing name, author and version of the expansion
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
return String.format("PlaceholderExpansion[name: '%s', author: '%s', version: '%s', type: '%s']", getName(),
|
|
||||||
getAuthor(), getVersion(), getExpansionType());
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Deprecated API ===
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The plugin name.
|
|
||||||
* @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public String getPlugin() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The description of the expansion.
|
|
||||||
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to show a description
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public String getDescription() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The link for the expansion.
|
|
||||||
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to display a link
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
|
|
||||||
public String getLink() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An expansion provided by a plugin is considered internal
|
|
||||||
*/
|
|
||||||
INTERNAL,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An expansion loaded from the expansions folder is considered external
|
|
||||||
*/
|
|
||||||
EXTERNAL
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementing this interface allows your {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}
|
|
||||||
* to be used as a relational placeholder expansion.
|
|
||||||
*
|
|
||||||
* <p>Relational placeholders take two Players as input and are always prefixed with {@code rel_},
|
|
||||||
* so {@code %foo_bar%} becomes {@code %rel_foo_bar%}
|
|
||||||
*/
|
|
||||||
public interface Relational {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called whenever a placeholder starting with {@code rel_} is called.
|
|
||||||
*
|
|
||||||
* @param one The first player used for the placeholder.
|
|
||||||
* @param two The second player used for the placeholder.
|
|
||||||
* @param identifier The text right after the expansion's name (%expansion_<b>identifier</b>%)
|
|
||||||
* @return Parsed String from the expansion.
|
|
||||||
*/
|
|
||||||
String onPlaceholderRequest(Player one, Player two, String identifier);
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementing this interface adds the {@link #start() start} and {@link #stop() stop} void
|
|
||||||
* methods to your {@link me.clip.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansion}.
|
|
||||||
*
|
|
||||||
* <p>This can be used to execute methods and tasks whenever the PlaceholderExpansion has been
|
|
||||||
* successfully (un)registered.
|
|
||||||
*/
|
|
||||||
public interface Taskable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the implementing class has successfully been registered to the placeholder map.
|
|
||||||
* <br>Tasks that need to be performed when this expansion is registered should go here
|
|
||||||
*/
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the implementing class has been unregistered from PlaceholderAPI.
|
|
||||||
* <br>Tasks that need to be performed when this expansion has unregistered should go here
|
|
||||||
*/
|
|
||||||
void stop();
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public final class Version {
|
|
||||||
|
|
||||||
private final boolean isSpigot;
|
|
||||||
private final String version;
|
|
||||||
|
|
||||||
public Version(String version, boolean isSpigot) {
|
|
||||||
this.version = version;
|
|
||||||
this.isSpigot = isSpigot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return version == null ? "unknown" : version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSpigot() {
|
|
||||||
return isSpigot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean compareTo(String version) {
|
|
||||||
return getVersion().equalsIgnoreCase(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Placeholder expansions which use NMS code should be version specific. Implementing this class
|
|
||||||
* allows you to perform checks based on the version the server is running. The isCompatibleWith
|
|
||||||
* method will be passed the server version and allow you to return if your expansion is compatible
|
|
||||||
* with that version.
|
|
||||||
*
|
|
||||||
* @author Ryan McCarthy
|
|
||||||
* @deprecated Will be removed in a future release.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public interface VersionSpecific {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called before the expansion is attempted to be registered The server version
|
|
||||||
* will be passed to this method so you know what version the server is currently running.
|
|
||||||
*
|
|
||||||
* @param v The {@link Version} to check against
|
|
||||||
* @return true if your expansion is compatible with the version the server is running.
|
|
||||||
*/
|
|
||||||
boolean isCompatibleWith(Version v);
|
|
||||||
}
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion.cloud;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.util.TimeUtil;
|
|
||||||
|
|
||||||
|
|
||||||
public class CloudExpansion {
|
|
||||||
|
|
||||||
private String name,
|
|
||||||
author,
|
|
||||||
latest_version,
|
|
||||||
description,
|
|
||||||
source_url,
|
|
||||||
dependency_url;
|
|
||||||
|
|
||||||
private boolean hasExpansion,
|
|
||||||
shouldUpdate;
|
|
||||||
|
|
||||||
private long last_update,
|
|
||||||
ratings_count;
|
|
||||||
|
|
||||||
private double average_rating;
|
|
||||||
|
|
||||||
private List<String> placeholders;
|
|
||||||
|
|
||||||
private List<Version> versions;
|
|
||||||
|
|
||||||
public CloudExpansion() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTimeSinceLastUpdate() {
|
|
||||||
int time = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - getLastUpdate());
|
|
||||||
return TimeUtil.getTime(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthor() {
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthor(String author) {
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Version getVersion() {
|
|
||||||
return getLatestVersion() == null ? null : getVersion(getLatestVersion());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Version getVersion(String version) {
|
|
||||||
return versions == null ? null : versions.stream()
|
|
||||||
.filter(v -> v.getVersion().equals(version))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getAvailableVersions() {
|
|
||||||
return versions.stream().map(Version::getVersion).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLatestVersion() {
|
|
||||||
return latest_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLatestVersion(String latest_version) {
|
|
||||||
this.latest_version = latest_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescription(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSourceUrl() {
|
|
||||||
return source_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSourceUrl(String source_url) {
|
|
||||||
this.source_url = source_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDependencyUrl() {
|
|
||||||
return dependency_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDependencyUrl(String dependency_url) {
|
|
||||||
this.dependency_url = dependency_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasExpansion() {
|
|
||||||
return hasExpansion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHasExpansion(boolean hasExpansion) {
|
|
||||||
this.hasExpansion = hasExpansion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldUpdate() {
|
|
||||||
return shouldUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShouldUpdate(boolean shouldUpdate) {
|
|
||||||
this.shouldUpdate = shouldUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastUpdate() {
|
|
||||||
return last_update;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastUpdate(long last_update) {
|
|
||||||
this.last_update = last_update;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getRatingsCount() {
|
|
||||||
return ratings_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getAverage_rating() {
|
|
||||||
return average_rating;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getPlaceholders() {
|
|
||||||
return placeholders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlaceholders(List<String> placeholders) {
|
|
||||||
this.placeholders = placeholders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Version> getVersions() {
|
|
||||||
return versions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersions(List<Version> versions) {
|
|
||||||
this.versions = versions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Version {
|
|
||||||
|
|
||||||
private String url, version, release_notes;
|
|
||||||
private boolean verified;
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersion(String version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getReleaseNotes() {
|
|
||||||
return release_notes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReleaseNotes(String release_notes) {
|
|
||||||
this.release_notes = release_notes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVerified() {
|
|
||||||
return verified;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVerified(boolean verified) {
|
|
||||||
this.verified = verified;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion.manager;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.io.Resources;
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.channels.Channels;
|
|
||||||
import java.nio.channels.ReadableByteChannel;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.CompletionException;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collector;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class CloudExpansionManager {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final String API_URL = "https://ecloud.placeholderapi.com/api/v3/";
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final Gson GSON = new Gson();
|
|
||||||
@NotNull
|
|
||||||
private static final Type TYPE = new TypeToken<Map<String, CloudExpansion>>() {}.getType();
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Collector<CloudExpansion, ?, Map<String, CloudExpansion>> INDEXED_NAME_COLLECTOR = Collectors
|
|
||||||
.toMap(CloudExpansionManager::toIndexName, Function.identity());
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderAPIPlugin plugin;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Map<String, CloudExpansion> cache = new HashMap<>();
|
|
||||||
@NotNull
|
|
||||||
private final Map<String, CompletableFuture<File>> await = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final ExecutorService ASYNC_EXECUTOR =
|
|
||||||
Executors.newCachedThreadPool(
|
|
||||||
new ThreadFactoryBuilder().setNameFormat("placeholderapi-io-#%1$d").build());
|
|
||||||
|
|
||||||
public CloudExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static String toIndexName(@NotNull final String name) {
|
|
||||||
return name.toLowerCase(Locale.ROOT).replace(' ', '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static String toIndexName(@NotNull final CloudExpansion expansion) {
|
|
||||||
return toIndexName(expansion.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void load() {
|
|
||||||
clean();
|
|
||||||
fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void kill() {
|
|
||||||
clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public Map<String, CloudExpansion> getCloudExpansions() {
|
|
||||||
return ImmutableMap.copyOf(cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public Map<String, CloudExpansion> getCloudExpansionsInstalled() {
|
|
||||||
if (cache.isEmpty()) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache.values()
|
|
||||||
.stream()
|
|
||||||
.filter(CloudExpansion::hasExpansion)
|
|
||||||
.collect(INDEXED_NAME_COLLECTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public Map<String, CloudExpansion> getCloudExpansionsByAuthor(@NotNull final String author) {
|
|
||||||
if (cache.isEmpty()) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache.values()
|
|
||||||
.stream()
|
|
||||||
.filter(expansion -> author.equalsIgnoreCase(expansion.getAuthor()))
|
|
||||||
.collect(INDEXED_NAME_COLLECTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public Set<String> getCloudExpansionAuthors() {
|
|
||||||
return cache.values().stream().map(CloudExpansion::getAuthor).collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCloudExpansionAuthorCount() {
|
|
||||||
return getCloudExpansionAuthors().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCloudUpdateCount() {
|
|
||||||
return ((int) plugin.getLocalExpansionManager()
|
|
||||||
.getExpansions()
|
|
||||||
.stream()
|
|
||||||
.filter(expansion -> findCloudExpansionByName(expansion.getName())
|
|
||||||
.map(CloudExpansion::shouldUpdate).orElse(false))
|
|
||||||
.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Optional<CloudExpansion> findCloudExpansionByName(@NotNull final String name) {
|
|
||||||
return Optional.ofNullable(cache.get(toIndexName(name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clean() {
|
|
||||||
cache.clear();
|
|
||||||
|
|
||||||
await.values().forEach(future -> future.cancel(true));
|
|
||||||
await.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fetch() {
|
|
||||||
plugin.getLogger().info("Fetching available expansion information...");
|
|
||||||
|
|
||||||
ASYNC_EXECUTOR.submit(
|
|
||||||
() -> {
|
|
||||||
// a defence tactic! use ConcurrentHashMap instead of normal HashMap
|
|
||||||
Map<String, CloudExpansion> values = new ConcurrentHashMap<>();
|
|
||||||
try {
|
|
||||||
//noinspection UnstableApiUsage
|
|
||||||
String json = Resources.toString(new URL(API_URL), StandardCharsets.UTF_8);
|
|
||||||
values.putAll(GSON.fromJson(json, TYPE));
|
|
||||||
|
|
||||||
List<String> toRemove = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) {
|
|
||||||
CloudExpansion expansion = entry.getValue();
|
|
||||||
if (expansion.getLatestVersion() == null
|
|
||||||
|| expansion.getVersion(expansion.getLatestVersion()) == null) {
|
|
||||||
toRemove.add(entry.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String name : toRemove) {
|
|
||||||
values.remove(name);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
// ugly swallowing of every throwable, but we have to be defensive
|
|
||||||
plugin.getLogger().log(Level.WARNING, "Failed to download expansion information", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop through what's left on the main thread
|
|
||||||
plugin
|
|
||||||
.getScheduler()
|
|
||||||
.runTask(
|
|
||||||
() -> {
|
|
||||||
try {
|
|
||||||
for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) {
|
|
||||||
String name = entry.getKey();
|
|
||||||
CloudExpansion expansion = entry.getValue();
|
|
||||||
|
|
||||||
expansion.setName(name);
|
|
||||||
|
|
||||||
Optional<PlaceholderExpansion> localOpt =
|
|
||||||
plugin.getLocalExpansionManager().findExpansionByName(name);
|
|
||||||
if (localOpt.isPresent()) {
|
|
||||||
PlaceholderExpansion local = localOpt.get();
|
|
||||||
if (local.isRegistered()) {
|
|
||||||
expansion.setHasExpansion(true);
|
|
||||||
expansion.setShouldUpdate(
|
|
||||||
!local.getVersion().equalsIgnoreCase(expansion.getLatestVersion()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.put(toIndexName(expansion), expansion);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
// ugly swallowing of every throwable, but we have to be defensive
|
|
||||||
plugin
|
|
||||||
.getLogger()
|
|
||||||
.log(Level.WARNING, "Failed to download expansion information", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDownloading(@NotNull final CloudExpansion expansion) {
|
|
||||||
return await.containsKey(toIndexName(expansion));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public CompletableFuture<File> downloadExpansion(@NotNull final CloudExpansion expansion,
|
|
||||||
@NotNull final CloudExpansion.Version version) {
|
|
||||||
final CompletableFuture<File> previous = await.get(toIndexName(expansion));
|
|
||||||
if (previous != null) {
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
final File file = new File(plugin.getLocalExpansionManager().getExpansionsFolder(),
|
|
||||||
"Expansion-" + toIndexName(expansion) + ".jar");
|
|
||||||
|
|
||||||
final CompletableFuture<File> download = CompletableFuture.supplyAsync(() -> {
|
|
||||||
try (final ReadableByteChannel source = Channels.newChannel(new URL(version.getUrl())
|
|
||||||
.openStream()); final FileOutputStream target = new FileOutputStream(file)) {
|
|
||||||
target.getChannel().transferFrom(source, 0, Long.MAX_VALUE);
|
|
||||||
} catch (final IOException ex) {
|
|
||||||
throw new CompletionException(ex);
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}, ASYNC_EXECUTOR);
|
|
||||||
|
|
||||||
download.whenCompleteAsync((value, exception) -> {
|
|
||||||
await.remove(toIndexName(expansion));
|
|
||||||
|
|
||||||
if (exception != null) {
|
|
||||||
Msg.severe("Failed to download %s:%s", exception, expansion.getName(), expansion.getVersion());
|
|
||||||
}
|
|
||||||
}, ASYNC_EXECUTOR);
|
|
||||||
|
|
||||||
await.put(toIndexName(expansion), download);
|
|
||||||
|
|
||||||
return download;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,498 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion.manager;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.events.ExpansionRegisterEvent;
|
|
||||||
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
|
|
||||||
import me.clip.placeholderapi.events.ExpansionsLoadedEvent;
|
|
||||||
import me.clip.placeholderapi.expansion.Cacheable;
|
|
||||||
import me.clip.placeholderapi.expansion.Cleanable;
|
|
||||||
import me.clip.placeholderapi.expansion.Configurable;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.expansion.Taskable;
|
|
||||||
import me.clip.placeholderapi.expansion.VersionSpecific;
|
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
|
||||||
import me.clip.placeholderapi.util.FileUtil;
|
|
||||||
import me.clip.placeholderapi.util.Futures;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
import org.bukkit.event.server.PluginDisableEvent;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
public final class LocalExpansionManager implements Listener {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final String EXPANSIONS_FOLDER_NAME = "expansions";
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static final Set<MethodSignature> ABSTRACT_EXPANSION_METHODS = Arrays.stream(PlaceholderExpansion.class.getDeclaredMethods())
|
|
||||||
.filter(method -> Modifier.isAbstract(method.getModifiers()))
|
|
||||||
.map(method -> new MethodSignature(method.getName(), method.getParameterTypes()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final File folder;
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderAPIPlugin plugin;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Map<String, PlaceholderExpansion> expansions = new ConcurrentHashMap<>();
|
|
||||||
private final ReentrantLock expansionsLock = new ReentrantLock();
|
|
||||||
|
|
||||||
|
|
||||||
public LocalExpansionManager(@NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.folder = new File(plugin.getDataFolder(), EXPANSIONS_FOLDER_NAME);
|
|
||||||
|
|
||||||
if (!this.folder.exists() && !folder.mkdirs()) {
|
|
||||||
Msg.warn("Failed to create expansions folder!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void load(@NotNull final CommandSender sender) {
|
|
||||||
registerAll(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void kill() {
|
|
||||||
unregisterAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public File getExpansionsFolder() {
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public Collection<String> getIdentifiers() {
|
|
||||||
expansionsLock.lock();
|
|
||||||
try {
|
|
||||||
return ImmutableSet.copyOf(expansions.keySet());
|
|
||||||
} finally {
|
|
||||||
expansionsLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Unmodifiable
|
|
||||||
public Collection<PlaceholderExpansion> getExpansions() {
|
|
||||||
expansionsLock.lock();
|
|
||||||
try {
|
|
||||||
return ImmutableSet.copyOf(expansions.values());
|
|
||||||
} finally {
|
|
||||||
expansionsLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public PlaceholderExpansion getExpansion(@NotNull final String identifier) {
|
|
||||||
expansionsLock.lock();
|
|
||||||
try {
|
|
||||||
return expansions.get(identifier.toLowerCase(Locale.ROOT));
|
|
||||||
} finally {
|
|
||||||
expansionsLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Optional<PlaceholderExpansion> findExpansionByName(@NotNull final String name) {
|
|
||||||
expansionsLock.lock();
|
|
||||||
try {
|
|
||||||
PlaceholderExpansion bestMatch = null;
|
|
||||||
for (Map.Entry<String, PlaceholderExpansion> entry : expansions.entrySet()) {
|
|
||||||
PlaceholderExpansion expansion = entry.getValue();
|
|
||||||
if (expansion.getName().equalsIgnoreCase(name)) {
|
|
||||||
bestMatch = expansion;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.ofNullable(bestMatch);
|
|
||||||
} finally {
|
|
||||||
expansionsLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Optional<PlaceholderExpansion> findExpansionByIdentifier(
|
|
||||||
@NotNull final String identifier) {
|
|
||||||
return Optional.ofNullable(getExpansion(identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Optional<PlaceholderExpansion> register(
|
|
||||||
@NotNull final Class<? extends PlaceholderExpansion> clazz) {
|
|
||||||
try {
|
|
||||||
final PlaceholderExpansion expansion = createExpansionInstance(clazz);
|
|
||||||
|
|
||||||
if (expansion == null) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
Objects.requireNonNull(expansion.getAuthor(), "The expansion author is null!");
|
|
||||||
Objects.requireNonNull(expansion.getIdentifier(), "The expansion identifier is null!");
|
|
||||||
Objects.requireNonNull(expansion.getVersion(), "The expansion version is null!");
|
|
||||||
|
|
||||||
if (expansion.getRequiredPlugin() != null && !expansion.getRequiredPlugin().isEmpty()) {
|
|
||||||
if (!Bukkit.getPluginManager().isPluginEnabled(expansion.getRequiredPlugin())) {
|
|
||||||
Msg.warn("Cannot load expansion %s due to a missing plugin: %s", expansion.getIdentifier(),
|
|
||||||
expansion.getRequiredPlugin());
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expansion.setExpansionType(PlaceholderExpansion.Type.EXTERNAL);
|
|
||||||
|
|
||||||
if (!expansion.register()) {
|
|
||||||
Msg.warn("Cannot load expansion %s due to an unknown issue.", expansion.getIdentifier());
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.of(expansion);
|
|
||||||
} catch (LinkageError | NullPointerException ex) {
|
|
||||||
final String reason;
|
|
||||||
|
|
||||||
if (ex instanceof LinkageError) {
|
|
||||||
reason = " (Is a dependency missing?)";
|
|
||||||
} else {
|
|
||||||
reason = " - One of its properties is null which is not allowed!";
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.severe("Failed to load expansion class %s%s", ex, clazz.getSimpleName(), reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to register a {@link PlaceholderExpansion}
|
|
||||||
*
|
|
||||||
* @param expansion the expansion to register
|
|
||||||
* @return if the expansion was registered
|
|
||||||
*/
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public boolean register(@NotNull final PlaceholderExpansion expansion) {
|
|
||||||
final String identifier = expansion.getIdentifier().toLowerCase(Locale.ROOT);
|
|
||||||
|
|
||||||
if (!expansion.canRegister()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid loading two external expansions with the same identifier
|
|
||||||
if (expansion.getExpansionType() == PlaceholderExpansion.Type.EXTERNAL && expansions.containsKey(identifier)) {
|
|
||||||
Msg.warn("Failed to load external expansion %s. Identifier is already in use.", expansion.getIdentifier());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expansion instanceof Configurable) {
|
|
||||||
Map<String, Object> defaults = ((Configurable) expansion).getDefaults();
|
|
||||||
String pre = "expansions." + identifier + ".";
|
|
||||||
FileConfiguration cfg = plugin.getConfig();
|
|
||||||
boolean save = false;
|
|
||||||
|
|
||||||
if (defaults != null) {
|
|
||||||
for (Map.Entry<String, Object> entries : defaults.entrySet()) {
|
|
||||||
if (entries.getKey() == null || entries.getKey().isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entries.getValue() == null) {
|
|
||||||
if (cfg.contains(pre + entries.getKey())) {
|
|
||||||
save = true;
|
|
||||||
cfg.set(pre + entries.getKey(), null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!cfg.contains(pre + entries.getKey())) {
|
|
||||||
save = true;
|
|
||||||
cfg.set(pre + entries.getKey(), entries.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (save) {
|
|
||||||
plugin.saveConfig();
|
|
||||||
plugin.reloadConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expansion instanceof VersionSpecific) {
|
|
||||||
VersionSpecific nms = (VersionSpecific) expansion;
|
|
||||||
if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) {
|
|
||||||
Msg.warn("Your server version is incompatible with expansion %s %s",
|
|
||||||
expansion.getIdentifier(), expansion.getVersion());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final PlaceholderExpansion removed = getExpansion(identifier);
|
|
||||||
if (removed != null && !removed.unregister()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ExpansionRegisterEvent event = new ExpansionRegisterEvent(expansion);
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
|
|
||||||
if (event.isCancelled()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
expansionsLock.lock();
|
|
||||||
try {
|
|
||||||
expansions.put(identifier, expansion);
|
|
||||||
} finally {
|
|
||||||
expansionsLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expansion instanceof Listener) {
|
|
||||||
Bukkit.getPluginManager().registerEvents(((Listener) expansion), plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.info(
|
|
||||||
"Successfully registered %s expansion: %s [%s]",
|
|
||||||
expansion.getExpansionType().name().toLowerCase(),
|
|
||||||
expansion.getIdentifier(),
|
|
||||||
expansion.getVersion()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (expansion instanceof Taskable) {
|
|
||||||
((Taskable) expansion).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check eCloud for updates only if the expansion is external
|
|
||||||
if (plugin.getPlaceholderAPIConfig().isCloudEnabled() && expansion.getExpansionType() == PlaceholderExpansion.Type.EXTERNAL) {
|
|
||||||
final Optional<CloudExpansion> cloudExpansionOptional = plugin.getCloudExpansionManager().findCloudExpansionByName(identifier);
|
|
||||||
if (cloudExpansionOptional.isPresent()) {
|
|
||||||
CloudExpansion cloudExpansion = cloudExpansionOptional.get();
|
|
||||||
cloudExpansion.setHasExpansion(true);
|
|
||||||
cloudExpansion.setShouldUpdate(!cloudExpansion.getLatestVersion().equals(expansion.getVersion()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public boolean unregister(@NotNull final PlaceholderExpansion expansion) {
|
|
||||||
if (expansions.remove(expansion.getIdentifier().toLowerCase(Locale.ROOT)) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.getPluginManager().callEvent(new ExpansionUnregisterEvent(expansion));
|
|
||||||
|
|
||||||
if (expansion instanceof Listener) {
|
|
||||||
HandlerList.unregisterAll((Listener) expansion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expansion instanceof Taskable) {
|
|
||||||
((Taskable) expansion).stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expansion instanceof Cacheable) {
|
|
||||||
((Cacheable) expansion).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plugin.getPlaceholderAPIConfig().isCloudEnabled()) {
|
|
||||||
plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName())
|
|
||||||
.ifPresent(cloud -> {
|
|
||||||
cloud.setHasExpansion(false);
|
|
||||||
cloud.setShouldUpdate(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerAll(@NotNull final CommandSender sender) {
|
|
||||||
Msg.info("Placeholder expansion registration initializing...");
|
|
||||||
|
|
||||||
Futures.onMainThread(plugin, findExpansionsOnDisk(), (classes, exception) -> {
|
|
||||||
if (exception != null) {
|
|
||||||
Msg.severe("Failed to load class files of expansion.", exception);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<PlaceholderExpansion> registered = classes.stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.map(this::register)
|
|
||||||
.filter(Optional::isPresent)
|
|
||||||
.map(Optional::get)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
final long needsUpdate = registered.stream()
|
|
||||||
.map(expansion -> plugin.getCloudExpansionManager().findCloudExpansionByName(expansion.getName()).orElse(null))
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.filter(CloudExpansion::shouldUpdate)
|
|
||||||
.count();
|
|
||||||
|
|
||||||
StringBuilder message = new StringBuilder(registered.size() == 0 ? "&6" : "&a")
|
|
||||||
.append(registered.size())
|
|
||||||
.append(' ')
|
|
||||||
.append("placeholder hook(s) registered!");
|
|
||||||
|
|
||||||
if (needsUpdate > 0) {
|
|
||||||
message.append(' ')
|
|
||||||
.append("&6")
|
|
||||||
.append(needsUpdate)
|
|
||||||
.append(' ')
|
|
||||||
.append("placeholder hook(s) have an update available.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Msg.msg(sender, message.toString());
|
|
||||||
|
|
||||||
Bukkit.getPluginManager().callEvent(new ExpansionsLoadedEvent(registered));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unregisterAll() {
|
|
||||||
for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) {
|
|
||||||
if (expansion.persist()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
expansion.unregister();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public CompletableFuture<@NotNull List<@Nullable Class<? extends PlaceholderExpansion>>> findExpansionsOnDisk() {
|
|
||||||
File[] files = folder.listFiles((dir, name) -> name.endsWith(".jar"));
|
|
||||||
if (files == null) {
|
|
||||||
return CompletableFuture.completedFuture(Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.stream(files)
|
|
||||||
.map(this::findExpansionInFile)
|
|
||||||
.collect(Futures.collector());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public CompletableFuture<@Nullable Class<? extends PlaceholderExpansion>> findExpansionInFile(
|
|
||||||
@NotNull final File file) {
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
|
||||||
try {
|
|
||||||
final Class<? extends PlaceholderExpansion> expansionClass = FileUtil.findClass(file, PlaceholderExpansion.class);
|
|
||||||
|
|
||||||
if (expansionClass == null) {
|
|
||||||
Msg.severe("Failed to load expansion %s, as it does not have a class which"
|
|
||||||
+ " extends PlaceholderExpansion", file.getName());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<MethodSignature> expansionMethods = Arrays.stream(expansionClass.getDeclaredMethods())
|
|
||||||
.map(method -> new MethodSignature(method.getName(), method.getParameterTypes()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
if (!expansionMethods.containsAll(ABSTRACT_EXPANSION_METHODS)) {
|
|
||||||
Msg.severe("Failed to load expansion %s, as it does not have the required"
|
|
||||||
+ " methods declared for a PlaceholderExpansion.", file.getName());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return expansionClass;
|
|
||||||
} catch (VerifyError | NoClassDefFoundError e) {
|
|
||||||
Msg.severe("Failed to load expansion %s (is a dependency missing?)", e, file.getName());
|
|
||||||
return null;
|
|
||||||
} catch (Exception e) {
|
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to load expansion file: " + file.getAbsolutePath(), e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public PlaceholderExpansion createExpansionInstance(
|
|
||||||
@NotNull final Class<? extends PlaceholderExpansion> clazz) throws LinkageError {
|
|
||||||
try {
|
|
||||||
return clazz.getDeclaredConstructor().newInstance();
|
|
||||||
} catch (final Exception ex) {
|
|
||||||
if (ex.getCause() instanceof LinkageError) {
|
|
||||||
throw ((LinkageError) ex.getCause());
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.warn("There was an issue with loading an expansion.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onQuit(@NotNull final PlayerQuitEvent event) {
|
|
||||||
for (final PlaceholderExpansion expansion : getExpansions()) {
|
|
||||||
if (!(expansion instanceof Cleanable)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
((Cleanable) expansion).cleanup(event.getPlayer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGH)
|
|
||||||
public void onPluginDisable(@NotNull final PluginDisableEvent event) {
|
|
||||||
final String name = event.getPlugin().getName();
|
|
||||||
if (name.equals(plugin.getName())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final PlaceholderExpansion expansion : getExpansions()) {
|
|
||||||
if (!name.equalsIgnoreCase(expansion.getRequiredPlugin())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
expansion.unregister();
|
|
||||||
Msg.info("Unregistered placeholder expansion %s", expansion.getIdentifier());
|
|
||||||
Msg.info("Reason: required plugin %s was disabled.", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.expansion.manager;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public final class MethodSignature {
|
|
||||||
private final String name;
|
|
||||||
private final Class<?>[] params;
|
|
||||||
|
|
||||||
protected MethodSignature(String name, Class<?>[] params) {
|
|
||||||
this.name = name;
|
|
||||||
this.params = params;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?>[] getParams() {
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
MethodSignature that = (MethodSignature) o;
|
|
||||||
return Objects.equals(name, that.name) && Arrays.equals(params, that.params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = Objects.hash(name);
|
|
||||||
result = 31 * result + Arrays.hashCode(params);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.listeners;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.server.ServerLoadEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public final class ServerLoadEventListener implements Listener {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final PlaceholderAPIPlugin plugin;
|
|
||||||
|
|
||||||
public ServerLoadEventListener(@NotNull final PlaceholderAPIPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onServerLoad(@NotNull final ServerLoadEvent event) {
|
|
||||||
HandlerList.unregisterAll(this);
|
|
||||||
plugin.getLocalExpansionManager().load(Bukkit.getConsoleSender());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.replacer;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public final class CharsReplacer implements Replacer {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final Closure closure;
|
|
||||||
|
|
||||||
public CharsReplacer(@NotNull final Closure closure) {
|
|
||||||
this.closure = closure;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String apply(@NotNull final String text, @Nullable final OfflinePlayer player,
|
|
||||||
@NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) {
|
|
||||||
final char[] chars = text.toCharArray();
|
|
||||||
final StringBuilder builder = new StringBuilder(text.length());
|
|
||||||
|
|
||||||
final StringBuilder identifier = new StringBuilder();
|
|
||||||
final StringBuilder parameters = new StringBuilder();
|
|
||||||
|
|
||||||
for (int i = 0; i < chars.length; i++) {
|
|
||||||
final char l = chars[i];
|
|
||||||
|
|
||||||
if (l != closure.head || i + 1 >= chars.length) {
|
|
||||||
builder.append(l);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean identified = false;
|
|
||||||
boolean invalid = true;
|
|
||||||
boolean hadSpace = false;
|
|
||||||
|
|
||||||
while (++i < chars.length) {
|
|
||||||
final char p = chars[i];
|
|
||||||
|
|
||||||
if (p == ' ' && !identified) {
|
|
||||||
hadSpace = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (p == closure.tail) {
|
|
||||||
invalid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p == '_' && !identified) {
|
|
||||||
identified = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (identified) {
|
|
||||||
parameters.append(p);
|
|
||||||
} else {
|
|
||||||
identifier.append(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final String identifierString = identifier.toString();
|
|
||||||
final String lowercaseIdentifierString = identifierString.toLowerCase(Locale.ROOT);
|
|
||||||
final String parametersString = parameters.toString();
|
|
||||||
|
|
||||||
identifier.setLength(0);
|
|
||||||
parameters.setLength(0);
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
builder.append(closure.head).append(identifierString);
|
|
||||||
|
|
||||||
if (identified) {
|
|
||||||
builder.append('_').append(parametersString);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hadSpace) {
|
|
||||||
builder.append(' ');
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final PlaceholderExpansion placeholder = lookup.apply(lowercaseIdentifierString);
|
|
||||||
if (placeholder == null) {
|
|
||||||
builder.append(closure.head).append(identifierString);
|
|
||||||
|
|
||||||
if (identified) {
|
|
||||||
builder.append('_');
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.append(parametersString).append(closure.tail);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String replacement = placeholder.onRequest(player, parametersString);
|
|
||||||
if (replacement == null) {
|
|
||||||
builder.append(closure.head).append(identifierString);
|
|
||||||
|
|
||||||
if (identified) {
|
|
||||||
builder.append('_');
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.append(parametersString).append(closure.tail);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.append(replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.replacer;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public interface Replacer {
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
String apply(@NotNull final String text, @Nullable final OfflinePlayer player,
|
|
||||||
@NotNull final Function<String, @Nullable PlaceholderExpansion> lookup);
|
|
||||||
|
|
||||||
|
|
||||||
enum Closure {
|
|
||||||
BRACKET('{', '}'),
|
|
||||||
PERCENT('%', '%');
|
|
||||||
|
|
||||||
|
|
||||||
public final char head, tail;
|
|
||||||
|
|
||||||
Closure(final char head, final char tail) {
|
|
||||||
this.head = head;
|
|
||||||
this.tail = tail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just modified BukkitRunnable
|
|
||||||
*/
|
|
||||||
public abstract class UniversalRunnable implements Runnable {
|
|
||||||
MyScheduledTask task;
|
|
||||||
|
|
||||||
public synchronized void cancel() throws IllegalStateException {
|
|
||||||
checkScheduled();
|
|
||||||
task.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this task has been cancelled.
|
|
||||||
*
|
|
||||||
* @return true if the task has been cancelled
|
|
||||||
* @throws IllegalStateException if task was not scheduled yet
|
|
||||||
*/
|
|
||||||
public synchronized boolean isCancelled() throws IllegalStateException {
|
|
||||||
checkScheduled();
|
|
||||||
return task.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules this in the Bukkit scheduler to run on next tick.
|
|
||||||
*
|
|
||||||
* @param plugin the reference to the plugin scheduling task
|
|
||||||
* @return {@link MyScheduledTask}
|
|
||||||
* @throws IllegalArgumentException if plugin is null
|
|
||||||
* @throws IllegalStateException if this was already scheduled
|
|
||||||
* @see TaskScheduler#runTask(Runnable)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public synchronized MyScheduledTask runTask(Plugin plugin) throws IllegalArgumentException, IllegalStateException {
|
|
||||||
checkNotYetScheduled();
|
|
||||||
return setupTask(UniversalScheduler.getScheduler(plugin).runTask(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Asynchronous tasks should never access any API in Bukkit. Great care
|
|
||||||
* should be taken to assure the thread-safety of asynchronous tasks.</b>
|
|
||||||
* <p>
|
|
||||||
* Schedules this in the Bukkit scheduler to run asynchronously.
|
|
||||||
*
|
|
||||||
* @param plugin the reference to the plugin scheduling task
|
|
||||||
* @return {@link MyScheduledTask}
|
|
||||||
* @throws IllegalArgumentException if plugin is null
|
|
||||||
* @throws IllegalStateException if this was already scheduled
|
|
||||||
* @see TaskScheduler#runTaskAsynchronously(Runnable)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public synchronized MyScheduledTask runTaskAsynchronously(Plugin plugin) throws IllegalArgumentException, IllegalStateException {
|
|
||||||
checkNotYetScheduled();
|
|
||||||
return setupTask(UniversalScheduler.getScheduler(plugin).runTaskAsynchronously(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules this to run after the specified number of server ticks.
|
|
||||||
*
|
|
||||||
* @param plugin the reference to the plugin scheduling task
|
|
||||||
* @param delay the ticks to wait before running the task
|
|
||||||
* @return {@link MyScheduledTask}
|
|
||||||
* @throws IllegalArgumentException if plugin is null
|
|
||||||
* @throws IllegalStateException if this was already scheduled
|
|
||||||
* @see TaskScheduler#runTaskLater(Runnable, long)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public synchronized MyScheduledTask runTaskLater(Plugin plugin, long delay) throws IllegalArgumentException, IllegalStateException {
|
|
||||||
checkNotYetScheduled();
|
|
||||||
return setupTask(UniversalScheduler.getScheduler(plugin).runTaskLater(this, delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Asynchronous tasks should never access any API in Bukkit. Great care
|
|
||||||
* should be taken to assure the thread-safety of asynchronous tasks.</b>
|
|
||||||
* <p>
|
|
||||||
* Schedules this to run asynchronously after the specified number of
|
|
||||||
* server ticks.
|
|
||||||
*
|
|
||||||
* @param plugin the reference to the plugin scheduling task
|
|
||||||
* @param delay the ticks to wait before running the task
|
|
||||||
* @return {@link MyScheduledTask}
|
|
||||||
* @throws IllegalArgumentException if plugin is null
|
|
||||||
* @throws IllegalStateException if this was already scheduled
|
|
||||||
* @see TaskScheduler#runTaskLaterAsynchronously(Runnable, long)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public synchronized MyScheduledTask runTaskLaterAsynchronously(Plugin plugin, long delay) throws IllegalArgumentException, IllegalStateException {
|
|
||||||
checkNotYetScheduled();
|
|
||||||
return setupTask(UniversalScheduler.getScheduler(plugin).runTaskLaterAsynchronously(this, delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules this to repeatedly run until cancelled, starting after the
|
|
||||||
* specified number of server ticks.
|
|
||||||
*
|
|
||||||
* @param plugin the reference to the plugin scheduling task
|
|
||||||
* @param delay the ticks to wait before running the task
|
|
||||||
* @param period the ticks to wait between runs
|
|
||||||
* @return {@link MyScheduledTask}
|
|
||||||
* @throws IllegalArgumentException if plugin is null
|
|
||||||
* @throws IllegalStateException if this was already scheduled
|
|
||||||
* @see TaskScheduler#runTaskTimer(Runnable, long, long)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public synchronized MyScheduledTask runTaskTimer(Plugin plugin, long delay, long period) throws IllegalArgumentException, IllegalStateException {
|
|
||||||
checkNotYetScheduled();
|
|
||||||
return setupTask(UniversalScheduler.getScheduler(plugin).runTaskTimer(this, delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Asynchronous tasks should never access any API in Bukkit. Great care
|
|
||||||
* should be taken to assure the thread-safety of asynchronous tasks.</b>
|
|
||||||
* <p>
|
|
||||||
* Schedules this to repeatedly run asynchronously until cancelled,
|
|
||||||
* starting after the specified number of server ticks.
|
|
||||||
*
|
|
||||||
* @param plugin the reference to the plugin scheduling task
|
|
||||||
* @param delay the ticks to wait before running the task for the first
|
|
||||||
* time
|
|
||||||
* @param period the ticks to wait between runs
|
|
||||||
* @return {@link MyScheduledTask}
|
|
||||||
* @throws IllegalArgumentException if plugin is null
|
|
||||||
* @throws IllegalStateException if this was already scheduled
|
|
||||||
* @see TaskScheduler#runTaskTimerAsynchronously(Runnable, long, long)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public synchronized MyScheduledTask runTaskTimerAsynchronously(Plugin plugin, long delay, long period) throws IllegalArgumentException, IllegalStateException {
|
|
||||||
checkNotYetScheduled();
|
|
||||||
return setupTask(UniversalScheduler.getScheduler(plugin).runTaskTimerAsynchronously(this, delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkScheduled() {
|
|
||||||
if (task == null) {
|
|
||||||
throw new IllegalStateException("Not scheduled yet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkNotYetScheduled() {
|
|
||||||
if (task != null) {
|
|
||||||
throw new IllegalStateException("Already scheduled");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private MyScheduledTask setupTask(final MyScheduledTask task) {
|
|
||||||
this.task = task;
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.bukkit.BukkitScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.folia.FoliaScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.paper.PaperScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.utils.JavaUtil;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class UniversalScheduler {
|
|
||||||
private static final boolean IS_FOLIA = JavaUtil.classExists("io.papermc.paper.threadedregions.RegionizedServer");
|
|
||||||
private static final boolean IS_CANVAS = JavaUtil.classExists("io.canvasmc.canvas.server.ThreadedServer");
|
|
||||||
private static final boolean IS_EXPANDED_SCHEDULING_AVAILABLE = JavaUtil.classExists("io.papermc.paper.threadedregions.scheduler.ScheduledTask");
|
|
||||||
|
|
||||||
public static TaskScheduler getScheduler(Plugin plugin) {
|
|
||||||
return IS_FOLIA || IS_CANVAS ? new FoliaScheduler(plugin) : (IS_EXPANDED_SCHEDULING_AVAILABLE ? new PaperScheduler(plugin) : new BukkitScheduler(plugin));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler.bukkit;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
public class BukkitScheduledTask implements MyScheduledTask {
|
|
||||||
|
|
||||||
BukkitTask task;
|
|
||||||
|
|
||||||
boolean isRepeating;
|
|
||||||
|
|
||||||
public BukkitScheduledTask(final BukkitTask task) {
|
|
||||||
this.task = task;
|
|
||||||
this.isRepeating = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BukkitScheduledTask(final BukkitTask task, boolean isRepeating) {
|
|
||||||
this.task = task;
|
|
||||||
this.isRepeating = isRepeating;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancel() {
|
|
||||||
task.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return task.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Plugin getOwningPlugin() {
|
|
||||||
return task.getOwner();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCurrentlyRunning() {
|
|
||||||
return Bukkit.getServer().getScheduler().isCurrentlyRunning(this.task.getTaskId()); //There's no other way. Fuck bukkit
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRepeatingTask() {
|
|
||||||
return isRepeating;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler.bukkit;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class BukkitScheduler implements TaskScheduler {
|
|
||||||
final Plugin plugin;
|
|
||||||
|
|
||||||
public BukkitScheduler(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGlobalThread() {
|
|
||||||
return Bukkit.getServer().isPrimaryThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEntityThread(Entity entity) {
|
|
||||||
return Bukkit.getServer().isPrimaryThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRegionThread(Location location) {
|
|
||||||
return Bukkit.getServer().isPrimaryThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTask(Runnable runnable) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTask(plugin, runnable));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLater(Runnable runnable, long delay) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskLater(plugin, runnable, delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimer(Runnable runnable, long delay, long period) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskAsynchronously(Runnable runnable) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLaterAsynchronously(Runnable runnable, long delay) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimerAsynchronously(Runnable runnable, long delay, long period) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Useless? Or...
|
|
||||||
public MyScheduledTask runTask(Plugin plugin, Runnable runnable) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTask(plugin, runnable));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLater(Plugin plugin, Runnable runnable, long delay) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskLater(plugin, runnable, delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimer(Plugin plugin, Runnable runnable, long delay, long period) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskAsynchronously(Plugin plugin, Runnable runnable) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLaterAsynchronously(Plugin plugin, Runnable runnable, long delay) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimerAsynchronously(Plugin plugin, Runnable runnable, long delay, long period) {
|
|
||||||
return new BukkitScheduledTask(Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Runnable runnable) {
|
|
||||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancelTasks() {
|
|
||||||
Bukkit.getScheduler().cancelTasks(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancelTasks(Plugin plugin) {
|
|
||||||
Bukkit.getScheduler().cancelTasks(plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler.folia;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask;
|
|
||||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class FoliaScheduledTask implements MyScheduledTask {
|
|
||||||
private final ScheduledTask task;
|
|
||||||
|
|
||||||
public FoliaScheduledTask(final ScheduledTask task) {
|
|
||||||
this.task = task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
this.task.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return this.task.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Plugin getOwningPlugin() {
|
|
||||||
return this.task.getOwningPlugin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCurrentlyRunning() {
|
|
||||||
final ScheduledTask.ExecutionState state = this.task.getExecutionState();
|
|
||||||
return state == ScheduledTask.ExecutionState.RUNNING || state == ScheduledTask.ExecutionState.CANCELLED_RUNNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRepeatingTask() {
|
|
||||||
return this.task.isRepeatingTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler.folia;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask;
|
|
||||||
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
|
|
||||||
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
|
|
||||||
import io.papermc.paper.threadedregions.scheduler.RegionScheduler;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class FoliaScheduler implements TaskScheduler {
|
|
||||||
|
|
||||||
final Plugin plugin;
|
|
||||||
|
|
||||||
public FoliaScheduler(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final RegionScheduler regionScheduler = Bukkit.getServer().getRegionScheduler();
|
|
||||||
private final GlobalRegionScheduler globalRegionScheduler = Bukkit.getServer().getGlobalRegionScheduler();
|
|
||||||
private final AsyncScheduler asyncScheduler = Bukkit.getServer().getAsyncScheduler();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGlobalThread() {
|
|
||||||
return Bukkit.getServer().isGlobalTickThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTickThread() {
|
|
||||||
return Bukkit.getServer().isPrimaryThread(); // The Paper implementation checks whether this is a tick thread, this method exists to avoid confusion.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEntityThread(Entity entity) {
|
|
||||||
return Bukkit.getServer().isOwnedByCurrentRegion(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRegionThread(Location location) {
|
|
||||||
return Bukkit.getServer().isOwnedByCurrentRegion(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTask(Runnable runnable) {
|
|
||||||
return new FoliaScheduledTask(globalRegionScheduler.run(plugin, task -> runnable.run()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLater(Runnable runnable, long delay) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
if (delay <= 0) {
|
|
||||||
return runTask(runnable);
|
|
||||||
}
|
|
||||||
return new FoliaScheduledTask(globalRegionScheduler.runDelayed(plugin, task -> runnable.run(), delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimer(Runnable runnable, long delay, long period) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
delay = getOneIfNotPositive(delay);
|
|
||||||
return new FoliaScheduledTask(globalRegionScheduler.runAtFixedRate(plugin, task -> runnable.run(), delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTask(Plugin plugin, Runnable runnable) {
|
|
||||||
return new FoliaScheduledTask(globalRegionScheduler.run(plugin, task -> runnable.run()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLater(Plugin plugin, Runnable runnable, long delay) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
if (delay <= 0) {
|
|
||||||
return runTask(plugin, runnable);
|
|
||||||
}
|
|
||||||
return new FoliaScheduledTask(globalRegionScheduler.runDelayed(plugin, task -> runnable.run(), delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimer(Plugin plugin, Runnable runnable, long delay, long period) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
delay = getOneIfNotPositive(delay);
|
|
||||||
return new FoliaScheduledTask(globalRegionScheduler.runAtFixedRate(plugin, task -> runnable.run(), delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTask(Location location, Runnable runnable) {
|
|
||||||
return new FoliaScheduledTask(regionScheduler.run(plugin, location, task -> runnable.run()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLater(Location location, Runnable runnable, long delay) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
if (delay <= 0) {
|
|
||||||
return runTask(runnable);
|
|
||||||
}
|
|
||||||
return new FoliaScheduledTask(regionScheduler.runDelayed(plugin, location, task -> runnable.run(), delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimer(Location location, Runnable runnable, long delay, long period) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
delay = getOneIfNotPositive(delay);
|
|
||||||
return new FoliaScheduledTask(regionScheduler.runAtFixedRate(plugin, location, task -> runnable.run(), delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTask(Entity entity, Runnable runnable) {
|
|
||||||
return new FoliaScheduledTask(entity.getScheduler().run(plugin, task -> runnable.run(), null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLater(Entity entity, Runnable runnable, long delay) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
if (delay <= 0) {
|
|
||||||
return runTask(entity, runnable);
|
|
||||||
}
|
|
||||||
return new FoliaScheduledTask(entity.getScheduler().runDelayed(plugin, task -> runnable.run(), null, delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimer(Entity entity, Runnable runnable, long delay, long period) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
delay = getOneIfNotPositive(delay);
|
|
||||||
return new FoliaScheduledTask(entity.getScheduler().runAtFixedRate(plugin, task -> runnable.run(), null, delay, period));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskAsynchronously(Runnable runnable) {
|
|
||||||
return new FoliaScheduledTask(asyncScheduler.runNow(plugin, task -> runnable.run()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLaterAsynchronously(Runnable runnable, long delay) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
delay = getOneIfNotPositive(delay);
|
|
||||||
return new FoliaScheduledTask(asyncScheduler.runDelayed(plugin, task -> runnable.run(), delay * 50L, TimeUnit.MILLISECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimerAsynchronously(Runnable runnable, long delay, long period) {
|
|
||||||
return new FoliaScheduledTask(asyncScheduler.runAtFixedRate(plugin, task -> runnable.run(), delay * 50, period * 50, TimeUnit.MILLISECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskAsynchronously(Plugin plugin, Runnable runnable) {
|
|
||||||
return new FoliaScheduledTask(asyncScheduler.runNow(plugin, task -> runnable.run()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskLaterAsynchronously(Plugin plugin, Runnable runnable, long delay) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
delay = getOneIfNotPositive(delay);
|
|
||||||
return new FoliaScheduledTask(asyncScheduler.runDelayed(plugin, task -> runnable.run(), delay * 50L, TimeUnit.MILLISECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MyScheduledTask runTaskTimerAsynchronously(Plugin plugin, Runnable runnable, long delay, long period) {
|
|
||||||
//Folia exception: Delay ticks may not be <= 0
|
|
||||||
delay = getOneIfNotPositive(delay);
|
|
||||||
return new FoliaScheduledTask(asyncScheduler.runAtFixedRate(plugin, task -> runnable.run(), delay * 50, period * 50, TimeUnit.MILLISECONDS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Runnable runnable) {
|
|
||||||
globalRegionScheduler.execute(plugin, runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Location location, Runnable runnable) {
|
|
||||||
regionScheduler.execute(plugin, location, runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Entity entity, Runnable runnable) {
|
|
||||||
entity.getScheduler().execute(plugin, runnable, null, 1L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancelTasks() {
|
|
||||||
globalRegionScheduler.cancelTasks(plugin);
|
|
||||||
asyncScheduler.cancelTasks(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancelTasks(Plugin plugin) {
|
|
||||||
globalRegionScheduler.cancelTasks(plugin);
|
|
||||||
asyncScheduler.cancelTasks(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getOneIfNotPositive(long x) {
|
|
||||||
return x <= 0 ? 1L : x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler.paper;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.folia.FoliaScheduler;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
//Thanks to Towny
|
|
||||||
public class PaperScheduler extends FoliaScheduler {
|
|
||||||
public PaperScheduler(Plugin plugin) {
|
|
||||||
super(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGlobalThread() {
|
|
||||||
// isGlobalThread does not exist on paper, match the bukkit task scheduler's behaviour.
|
|
||||||
return Bukkit.getServer().isPrimaryThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,346 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler.scheduling.schedulers;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
public interface TaskScheduler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia</b>: Returns whether the current thread is ticking the global region <br>
|
|
||||||
* <b>Paper and Bukkit</b>: Returns {@link org.bukkit.Server#isPrimaryThread}
|
|
||||||
*/
|
|
||||||
boolean isGlobalThread();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@link org.bukkit.Server#isPrimaryThread}
|
|
||||||
*/
|
|
||||||
default boolean isTickThread() {
|
|
||||||
return Bukkit.getServer().isPrimaryThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Returns whether the current thread is ticking a region and that the region
|
|
||||||
* being ticked owns the specified entity. Note that this function is the only appropriate method of
|
|
||||||
* checking for ownership of an entity, as retrieving the entity's location is undefined unless the
|
|
||||||
* entity is owned by the current region
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: returns {@link org.bukkit.Server#isPrimaryThread}
|
|
||||||
*
|
|
||||||
* @param entity Specified entity
|
|
||||||
*/
|
|
||||||
boolean isEntityThread(Entity entity);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Returns whether the current thread is ticking a region and that the region
|
|
||||||
* being ticked owns the chunk at the specified world and block position as included in the specified location
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: returns {@link org.bukkit.Server#isPrimaryThread}
|
|
||||||
*
|
|
||||||
* @param location Specified location, must have a non-null world.
|
|
||||||
*/
|
|
||||||
boolean isRegionThread(Location location);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a task to be executed on the next tick <br>
|
|
||||||
* <b>Folia and Paper</b>: ...on the global region <br>
|
|
||||||
* <b>Bukkit</b>: ...on the main thread
|
|
||||||
*
|
|
||||||
* @param runnable The task to execute
|
|
||||||
*/
|
|
||||||
MyScheduledTask runTask(Runnable runnable);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a task to be executed after the specified delay in ticks <br>
|
|
||||||
* <b>Folia and Paper</b>: ...on the global region <br>
|
|
||||||
* <b>Bukkit</b>: ...on the main thread
|
|
||||||
*
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The delay, in ticks
|
|
||||||
*/
|
|
||||||
MyScheduledTask runTaskLater(Runnable runnable, long delay);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a repeating task to be executed after the initial delay with the specified period <br>
|
|
||||||
* <b>Folia and Paper</b>: ...on the global region <br>
|
|
||||||
* <b>Bukkit</b>: ...on the main thread
|
|
||||||
*
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The initial delay, in ticks.
|
|
||||||
* @param period The period, in ticks.
|
|
||||||
*/
|
|
||||||
MyScheduledTask runTaskTimer(Runnable runnable, long delay, long period);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTask(Runnable)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask runTask(Plugin plugin, Runnable runnable) {
|
|
||||||
return runTask(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTaskLater(Runnable, long)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask runTaskLater(Plugin plugin, Runnable runnable, long delay) {
|
|
||||||
return runTaskLater(runnable, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTaskTimer(Runnable, long, long)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask runTaskTimer(Plugin plugin, Runnable runnable, long delay, long period) {
|
|
||||||
return runTaskTimer(runnable, delay, period);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location on the next tick
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: same as {@link #runTask(Runnable)}
|
|
||||||
*
|
|
||||||
* @param location The location which the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
*/
|
|
||||||
default MyScheduledTask runTask(Location location, Runnable runnable) {
|
|
||||||
return runTask(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location after the
|
|
||||||
* specified delay in ticks
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskLater(Runnable, long)}
|
|
||||||
*
|
|
||||||
* @param location The location which the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The delay, in ticks.
|
|
||||||
*/
|
|
||||||
default MyScheduledTask runTaskLater(Location location, Runnable runnable, long delay) {
|
|
||||||
return runTaskLater(runnable, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Schedules a repeating task to be executed on the region which owns the location
|
|
||||||
* after the initial delay with the specified period
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskTimer(Runnable, long, long)}
|
|
||||||
*
|
|
||||||
* @param location The location which the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The initial delay, in ticks.
|
|
||||||
* @param period The period, in ticks.
|
|
||||||
*/
|
|
||||||
default MyScheduledTask runTaskTimer(Location location, Runnable runnable, long delay, long period) {
|
|
||||||
return runTaskTimer(runnable, delay, period);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTaskLater(Runnable, long)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask scheduleSyncDelayedTask(Runnable runnable, long delay) {
|
|
||||||
return runTaskLater(runnable, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #execute(Runnable)} or {@link #runTask(Runnable)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask scheduleSyncDelayedTask(Runnable runnable) {
|
|
||||||
return runTask(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTaskTimer(Runnable, long, long)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask scheduleSyncRepeatingTask(Runnable runnable, long delay, long period) {
|
|
||||||
return runTaskTimer(runnable, delay, period);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location
|
|
||||||
* of given entity on the next tick
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: same as {@link #runTask(Runnable)}
|
|
||||||
*
|
|
||||||
* @param entity The entity whose location the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
*/
|
|
||||||
default MyScheduledTask runTask(Entity entity, Runnable runnable) {
|
|
||||||
return runTask(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location
|
|
||||||
* of given entity after the specified delay in ticks
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskLater(Runnable, long)}
|
|
||||||
*
|
|
||||||
* @param entity The entity whose location the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The delay, in ticks.
|
|
||||||
*/
|
|
||||||
default MyScheduledTask runTaskLater(Entity entity, Runnable runnable, long delay) {
|
|
||||||
return runTaskLater(runnable, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <b>Folia and Paper</b>: Schedules a repeating task to be executed on the region which owns the
|
|
||||||
* location of given entity after the initial delay with the specified period
|
|
||||||
* <p>
|
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskTimer(Runnable, long, long)}
|
|
||||||
*
|
|
||||||
* @param entity The entity whose location the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The initial delay, in ticks.
|
|
||||||
* @param period The period, in ticks.
|
|
||||||
*/
|
|
||||||
default MyScheduledTask runTaskTimer(Entity entity, Runnable runnable, long delay, long period) {
|
|
||||||
return runTaskTimer(runnable, delay, period);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules the specified task to be executed asynchronously immediately
|
|
||||||
*
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @return The {@link MyScheduledTask} that represents the scheduled task
|
|
||||||
*/
|
|
||||||
MyScheduledTask runTaskAsynchronously(Runnable runnable);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules the specified task to be executed asynchronously after the time delay has passed
|
|
||||||
*
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The time delay to pass before the task should be executed
|
|
||||||
* @return The {@link MyScheduledTask} that represents the scheduled task
|
|
||||||
*/
|
|
||||||
MyScheduledTask runTaskLaterAsynchronously(Runnable runnable, long delay);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules the specified task to be executed asynchronously after the initial delay has passed,
|
|
||||||
* and then periodically executed with the specified period
|
|
||||||
*
|
|
||||||
* @param runnable The task to execute
|
|
||||||
* @param delay The time delay to pass before the first execution of the task, in ticks
|
|
||||||
* @param period The time between task executions after the first execution of the task, in ticks
|
|
||||||
* @return The {@link MyScheduledTask} that represents the scheduled task
|
|
||||||
*/
|
|
||||||
MyScheduledTask runTaskTimerAsynchronously(Runnable runnable, long delay, long period);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTaskAsynchronously(Runnable)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask runTaskAsynchronously(Plugin plugin, Runnable runnable) {
|
|
||||||
return runTaskAsynchronously(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTaskLaterAsynchronously(Runnable, long)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask runTaskLaterAsynchronously(Plugin plugin, Runnable runnable, long delay) {
|
|
||||||
return runTaskLaterAsynchronously(runnable, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated: use {@link #runTaskTimerAsynchronously(Runnable, long, long)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default MyScheduledTask runTaskTimerAsynchronously(Plugin plugin, Runnable runnable, long delay, long period) {
|
|
||||||
return runTaskTimerAsynchronously(runnable, delay, period);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls a method on the main thread and returns a Future object. This task will be executed
|
|
||||||
* by the main(Bukkit)/global(FoliaandPaper) server thread.
|
|
||||||
* <p>
|
|
||||||
* Note: The Future.get() methods must NOT be called from the main thread.
|
|
||||||
* <p>
|
|
||||||
* Note2: There is at least an average of 10ms latency until the isDone() method returns true.
|
|
||||||
*
|
|
||||||
* @param task Task to be executed
|
|
||||||
*/
|
|
||||||
default <T> Future<T> callSyncMethod(final Callable<T> task) {
|
|
||||||
CompletableFuture<T> completableFuture = new CompletableFuture<>();
|
|
||||||
execute(() -> {
|
|
||||||
try {
|
|
||||||
completableFuture.complete(task.call());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return completableFuture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a task to be executed on the global region
|
|
||||||
*
|
|
||||||
* @param runnable The task to execute
|
|
||||||
*/
|
|
||||||
void execute(Runnable runnable);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a task to be executed on the region which owns the location
|
|
||||||
*
|
|
||||||
* @param location The location which the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
*/
|
|
||||||
default void execute(Location location, Runnable runnable) {
|
|
||||||
execute(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules a task to be executed on the region which owns the location of given entity
|
|
||||||
*
|
|
||||||
* @param entity The entity which location the region executing should own
|
|
||||||
* @param runnable The task to execute
|
|
||||||
*/
|
|
||||||
default void execute(Entity entity, Runnable runnable) {
|
|
||||||
execute(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to cancel all tasks scheduled by this plugin
|
|
||||||
*/
|
|
||||||
void cancelTasks();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to cancel all tasks scheduled by the specified plugin
|
|
||||||
*
|
|
||||||
* @param plugin specified plugin
|
|
||||||
*/
|
|
||||||
void cancelTasks(Plugin plugin);
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Sevastjan
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
* a copy of this software and associated documentation files (the "Software"),
|
|
||||||
* to deal in the Software without restriction, including without limitation
|
|
||||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
* and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
* Software is furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.scheduler.scheduling.tasks;
|
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public interface MyScheduledTask {
|
|
||||||
/**
|
|
||||||
* Cancels executing task
|
|
||||||
*/
|
|
||||||
void cancel();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if task is cancelled, false otherwise
|
|
||||||
*/
|
|
||||||
boolean isCancelled();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The plugin under which the task was scheduled.
|
|
||||||
*/
|
|
||||||
Plugin getOwningPlugin();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if task is currently executing, false otherwise
|
|
||||||
*/
|
|
||||||
boolean isCurrentlyRunning();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if task is repeating, false otherwise
|
|
||||||
*/
|
|
||||||
boolean isRepeatingTask();
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package me.clip.placeholderapi.scheduler.utils;
|
|
||||||
|
|
||||||
public class JavaUtil {
|
|
||||||
public static boolean classExists(String className) {
|
|
||||||
try {
|
|
||||||
Class.forName(className);
|
|
||||||
return true;
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.updatechecker;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
|
||||||
import me.clip.placeholderapi.util.Msg;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
|
|
||||||
public class UpdateChecker implements Listener {
|
|
||||||
|
|
||||||
private static final int RESOURCE_ID = 6245;
|
|
||||||
private final PlaceholderAPIPlugin plugin;
|
|
||||||
private final TaskScheduler scheduler;
|
|
||||||
private final String pluginVersion;
|
|
||||||
private String spigotVersion;
|
|
||||||
private boolean updateAvailable;
|
|
||||||
|
|
||||||
public UpdateChecker(PlaceholderAPIPlugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
scheduler = plugin.getScheduler();
|
|
||||||
pluginVersion = plugin.getDescription().getVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasUpdateAvailable() {
|
|
||||||
return updateAvailable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSpigotVersion() {
|
|
||||||
return spigotVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fetch() {
|
|
||||||
scheduler.runTaskAsynchronously(() -> {
|
|
||||||
try {
|
|
||||||
HttpsURLConnection con = (HttpsURLConnection) new URL(
|
|
||||||
"https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openConnection();
|
|
||||||
con.setRequestMethod("GET");
|
|
||||||
spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
plugin.getLogger().info("Failed to check for updates on spigot.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spigotVersion == null || spigotVersion.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAvailable = spigotIsNewer();
|
|
||||||
|
|
||||||
if (!updateAvailable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduler.runTask(() -> {
|
|
||||||
plugin.getLogger()
|
|
||||||
.info("An update for PlaceholderAPI (v" + getSpigotVersion() + ") is available at:");
|
|
||||||
plugin.getLogger()
|
|
||||||
.info("https://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + "/");
|
|
||||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean spigotIsNewer() {
|
|
||||||
if (spigotVersion == null || spigotVersion.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] plV = toReadable(pluginVersion);
|
|
||||||
int[] spV = toReadable(spigotVersion);
|
|
||||||
|
|
||||||
if (plV[0] < spV[0]) {
|
|
||||||
return true;
|
|
||||||
} else if ((plV[1] < spV[1])) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return plV[2] < spV[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] toReadable(String version) {
|
|
||||||
if (version.contains("-DEV")) {
|
|
||||||
version = version.split("-DEV")[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.stream(version.split("\\.")).mapToInt(Integer::parseInt).toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
|
||||||
public void onJoin(PlayerJoinEvent e) {
|
|
||||||
if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) {
|
|
||||||
Msg.msg(e.getPlayer(),
|
|
||||||
"&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion()
|
|
||||||
+ "&e)"
|
|
||||||
, "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID
|
|
||||||
+ "/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
import com.google.common.hash.Hashing;
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import com.google.common.io.Resources;
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public final class ExpansionSafetyCheck {
|
|
||||||
private static final String MESSAGE =
|
|
||||||
"\n###############################################\n" +
|
|
||||||
"###############################################\n" +
|
|
||||||
"PlaceholderAPI performs checks at startup and /papi reload for known malicious expansions. If you're seeing this message, there are the following malicious expansions in plugins/PlaceholderAPI/expansions.\n" +
|
|
||||||
"%s" +
|
|
||||||
"To prevent further infection PlaceholderAPI has stopped the server.\n" +
|
|
||||||
"If you're seeing this message after updating PAPI, your server may have been infected for some time, so best practice is a complete system wipe and reinstall of your server software and plugins to be safe.\n" +
|
|
||||||
"If you're seeing this after downloading an expansion however, PAPI hasn't loaded any of the malicious expansions above so you should be safe to simply delete the expansion in question.\n" +
|
|
||||||
"###############################################\n" +
|
|
||||||
"###############################################";
|
|
||||||
|
|
||||||
private final PlaceholderAPIPlugin main;
|
|
||||||
|
|
||||||
public ExpansionSafetyCheck(@NotNull final PlaceholderAPIPlugin main) {
|
|
||||||
this.main = main;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean runChecks() {
|
|
||||||
if (!main.getPlaceholderAPIConfig().detectMaliciousExpansions()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final File expansionsFolder = new File(main.getDataFolder(), "expansions");
|
|
||||||
|
|
||||||
if (!expansionsFolder.exists()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Set<String> knownMaliciousExpansions;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final String hashes = Resources.toString(new URL("https://check.placeholderapi.com"), StandardCharsets.UTF_8);
|
|
||||||
knownMaliciousExpansions = Arrays.stream(hashes.split("\n")).collect(Collectors.toSet());
|
|
||||||
} catch (Exception e) {
|
|
||||||
main.getLogger().log(Level.SEVERE, "Failed to download anti malware hash check list from https://check.placeholderapi.com", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Set<String> maliciousPaths = new HashSet<>();
|
|
||||||
|
|
||||||
for (File file : expansionsFolder.listFiles()) {
|
|
||||||
try {
|
|
||||||
final String hash = Hashing.sha256().hashBytes(Files.asByteSource(file).read()).toString();
|
|
||||||
|
|
||||||
if (knownMaliciousExpansions.contains(hash)) {
|
|
||||||
maliciousPaths.add(file.getAbsolutePath());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
main.getLogger().log(Level.SEVERE, "Error occurred while trying to read " + file.getAbsolutePath(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maliciousPaths.isEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
main.getLogger().severe(String.format(MESSAGE, maliciousPaths.stream().map(p -> "HASH OF " + p + " MATCHES KNOWN MALICIOUS EXPANSION DELETE IMMEDIATELY\n").collect(Collectors.joining())));
|
|
||||||
|
|
||||||
main.getServer().shutdown();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarInputStream;
|
|
||||||
|
|
||||||
public class FileUtil {
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static <T> Class<? extends T> findClass(@NotNull final File file,
|
|
||||||
@NotNull final Class<T> clazz) throws IOException, ClassNotFoundException {
|
|
||||||
if (!file.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final URL jar = file.toURI().toURL();
|
|
||||||
final URLClassLoader loader = new URLClassLoader(new URL[]{jar}, clazz.getClassLoader());
|
|
||||||
final List<String> matches = new ArrayList<>();
|
|
||||||
final List<Class<? extends T>> classes = new ArrayList<>();
|
|
||||||
|
|
||||||
try (final JarInputStream stream = new JarInputStream(jar.openStream())) {
|
|
||||||
JarEntry entry;
|
|
||||||
while ((entry = stream.getNextJarEntry()) != null) {
|
|
||||||
final String name = entry.getName();
|
|
||||||
if (name.isEmpty() || !name.endsWith(".class")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
matches.add(name.substring(0, name.lastIndexOf('.')).replace('/', '.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final String match : matches) {
|
|
||||||
try {
|
|
||||||
final Class<?> loaded = loader.loadClass(match);
|
|
||||||
if (clazz.isAssignableFrom(loaded)) {
|
|
||||||
classes.add(loaded.asSubclass(clazz));
|
|
||||||
}
|
|
||||||
} catch (final NoClassDefFoundError ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (classes.isEmpty()) {
|
|
||||||
loader.close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return classes.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
|
||||||
import static java.lang.Math.min;
|
|
||||||
import static java.util.Arrays.stream;
|
|
||||||
import static java.util.stream.Collectors.joining;
|
|
||||||
import static java.util.stream.Collectors.toList;
|
|
||||||
import static java.util.stream.IntStream.range;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For the record, I am not sorry.
|
|
||||||
*/
|
|
||||||
public final class Format {
|
|
||||||
|
|
||||||
private Format() {}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static Optional<List<String>> tablify(@NotNull final Align align,
|
|
||||||
@NotNull final List<List<String>> rows) {
|
|
||||||
return findSpacing(rows)
|
|
||||||
.map(spacing -> buildFormat(align, spacing))
|
|
||||||
.map(format -> rows.stream()
|
|
||||||
.map(
|
|
||||||
row -> String.format(format, row.toArray()).substring(align == Align.RIGHT ? 2 : 0))
|
|
||||||
.collect(toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static String buildFormat(@NotNull final Align align, final int[] spacing) {
|
|
||||||
return stream(spacing)
|
|
||||||
.mapToObj(space -> "%" + (align == Align.LEFT ? "-" : "") + (space + 2) + "s")
|
|
||||||
.collect(joining());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static Optional<int[]> findSpacing(@NotNull final List<List<String>> rows) {
|
|
||||||
return rows.stream()
|
|
||||||
.map(row -> row.stream().mapToInt(String::length).toArray())
|
|
||||||
.reduce((l, r) -> range(0, min(l.length, r.length)).map(i -> max(l[i], r[i])).toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Align {
|
|
||||||
LEFT, RIGHT
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.stream.Collector;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public final class Futures {
|
|
||||||
|
|
||||||
private Futures() {}
|
|
||||||
|
|
||||||
|
|
||||||
public static <T> void onMainThread(@NotNull final PlaceholderAPIPlugin plugin,
|
|
||||||
@NotNull final CompletableFuture<T> future,
|
|
||||||
@NotNull final BiConsumer<T, Throwable> consumer) {
|
|
||||||
future.whenComplete((value, exception) -> {
|
|
||||||
if (Bukkit.isPrimaryThread()) {
|
|
||||||
consumer.accept(value, exception);
|
|
||||||
} else {
|
|
||||||
plugin.getScheduler().runTask(() -> consumer.accept(value, exception));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static <T> Collector<CompletableFuture<T>, ?, CompletableFuture<List<T>>> collector() {
|
|
||||||
return Collectors.collectingAndThen(Collectors.toList(), Futures::of);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static <T> CompletableFuture<List<T>> of(
|
|
||||||
@NotNull final Stream<CompletableFuture<T>> futures) {
|
|
||||||
return of(futures.collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static <T> CompletableFuture<List<T>> of(
|
|
||||||
@NotNull final Collection<CompletableFuture<T>> futures) {
|
|
||||||
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
|
||||||
.thenApplyAsync($ -> awaitCompletion(futures));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static <T> List<T> awaitCompletion(
|
|
||||||
@NotNull final Collection<CompletableFuture<T>> futures) {
|
|
||||||
return futures.stream().map(CompletableFuture::join).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public final class Msg {
|
|
||||||
|
|
||||||
public static void log(Level level, String msg, Object... args) {
|
|
||||||
PlaceholderAPIPlugin.getInstance().getLogger().log(level, String.format(msg, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void info(String msg, Object... args) {
|
|
||||||
log(Level.INFO, msg, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void warn(String msg, Object... args) {
|
|
||||||
log(Level.WARNING, msg, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void warn(String msg, Throwable throwable, Object... args) {
|
|
||||||
PlaceholderAPIPlugin.getInstance().getLogger().log(Level.WARNING, String.format(msg, args), throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void severe(String msg, Object... args) {
|
|
||||||
log(Level.SEVERE, msg, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void severe(String msg, Throwable throwable, Object... args) {
|
|
||||||
PlaceholderAPIPlugin.getInstance().getLogger().log(Level.SEVERE, String.format(msg, args), throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void msg(@NotNull final CommandSender sender, @NotNull final String... messages) {
|
|
||||||
if (messages.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void broadcast(@NotNull final String... messages) {
|
|
||||||
if (messages.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.broadcastMessage(
|
|
||||||
Arrays.stream(messages).map(Msg::color).collect(Collectors.joining("\n")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String color(@NotNull final String text) {
|
|
||||||
return ChatColor.translateAlternateColorCodes('&', text);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
public enum TimeFormat {
|
|
||||||
DAYS,
|
|
||||||
HOURS,
|
|
||||||
MINUTES,
|
|
||||||
SECONDS
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.util;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.StringJoiner;
|
|
||||||
|
|
||||||
public class TimeUtil {
|
|
||||||
|
|
||||||
public static String getRemaining(final int seconds, final TimeFormat type) {
|
|
||||||
return getRemaining((long) seconds, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getRemaining(final long seconds, final TimeFormat type) {
|
|
||||||
switch (type) {
|
|
||||||
default:
|
|
||||||
return String.valueOf(seconds);
|
|
||||||
|
|
||||||
case SECONDS:
|
|
||||||
return String.valueOf(seconds % 60);
|
|
||||||
|
|
||||||
case MINUTES:
|
|
||||||
return String.valueOf((seconds / 60) % 60);
|
|
||||||
|
|
||||||
case HOURS:
|
|
||||||
return String.valueOf((seconds / 3600) % 24);
|
|
||||||
|
|
||||||
case DAYS:
|
|
||||||
return String.valueOf(seconds / 86400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format the given value with s, m, h and d (seconds, minutes, hours and days)
|
|
||||||
*
|
|
||||||
* @param duration {@link Duration} (eg, Duration.of(20, {@link ChronoUnit#SECONDS}) for 20
|
|
||||||
* seconds)
|
|
||||||
* @return formatted time
|
|
||||||
*/
|
|
||||||
public static String getTime(final Duration duration) {
|
|
||||||
return getTime(duration.getSeconds());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getTime(final int seconds) {
|
|
||||||
return getTime((long) seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getTime(long seconds) {
|
|
||||||
final StringJoiner joiner = new StringJoiner(" ");
|
|
||||||
|
|
||||||
long minutes = seconds / 60;
|
|
||||||
long hours = minutes / 60;
|
|
||||||
final long days = hours / 24;
|
|
||||||
|
|
||||||
seconds %= 60;
|
|
||||||
minutes %= 60;
|
|
||||||
hours %= 24;
|
|
||||||
|
|
||||||
if (days > 0) {
|
|
||||||
joiner.add(days + "d");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hours > 0) {
|
|
||||||
joiner.add(hours + "h");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minutes > 0) {
|
|
||||||
joiner.add(minutes + "m");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seconds > 0) {
|
|
||||||
joiner.add(seconds + "s");
|
|
||||||
}
|
|
||||||
|
|
||||||
return joiner.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
|
||||||
import me.clip.placeholderapi.replacer.CharsReplacer;
|
|
||||||
import me.clip.placeholderapi.replacer.Replacer;
|
|
||||||
import org.bukkit.OfflinePlayer;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public interface Values {
|
|
||||||
|
|
||||||
String SMALL_TEXT = "My name is %player_name%";
|
|
||||||
String LARGE_TEXT = "My name is %player_name% and my location is (%player_x%, %player_y%, %player_z%), this placeholder is invalid %server_name%";
|
|
||||||
|
|
||||||
ImmutableMap<String, PlaceholderExpansion> PLACEHOLDERS = ImmutableMap.<String, PlaceholderExpansion>builder()
|
|
||||||
.put("player", new MockPlayerPlaceholderExpansion())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
|
|
||||||
Replacer CHARS_REPLACER = new CharsReplacer(Replacer.Closure.PERCENT);
|
|
||||||
|
|
||||||
|
|
||||||
final class MockPlayerPlaceholderExpansion extends PlaceholderExpansion {
|
|
||||||
|
|
||||||
public static final String PLAYER_X = "10";
|
|
||||||
public static final String PLAYER_Y = "20";
|
|
||||||
public static final String PLAYER_Z = "30";
|
|
||||||
public static final String PLAYER_NAME = "Sxtanna";
|
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String getIdentifier() {
|
|
||||||
return "player";
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String getAuthor() {
|
|
||||||
return "Sxtanna";
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public String getVersion() {
|
|
||||||
return "1.0";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) {
|
|
||||||
final String[] parts = params.split("_");
|
|
||||||
if (parts.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (parts[0]) {
|
|
||||||
case "name":
|
|
||||||
return PLAYER_NAME;
|
|
||||||
case "x":
|
|
||||||
return PLAYER_X;
|
|
||||||
case "y":
|
|
||||||
return PLAYER_Y;
|
|
||||||
case "z":
|
|
||||||
return PLAYER_Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.replacer;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.Values;
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
|
||||||
|
|
||||||
public class ReplacerBenchmarks {
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void measureCharsReplacerSmallText() {
|
|
||||||
Values.CHARS_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
public void measureCharsReplacerLargeText() {
|
|
||||||
Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of PlaceholderAPI
|
|
||||||
*
|
|
||||||
* PlaceholderAPI
|
|
||||||
* Copyright (c) 2015 - 2026 PlaceholderAPI Team
|
|
||||||
*
|
|
||||||
* PlaceholderAPI free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PlaceholderAPI is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package me.clip.placeholderapi.replacer;
|
|
||||||
|
|
||||||
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_NAME;
|
|
||||||
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_X;
|
|
||||||
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Y;
|
|
||||||
import static me.clip.placeholderapi.Values.MockPlayerPlaceholderExpansion.PLAYER_Z;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import me.clip.placeholderapi.Values;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
public final class ReplacerUnitTester {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCharsReplacerProducesExpectedSingleValue() {
|
|
||||||
assertEquals(PLAYER_NAME,
|
|
||||||
Values.CHARS_REPLACER.apply("%player_name%", null, Values.PLACEHOLDERS::get));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCharsReplacerProducesExpectedSentence() {
|
|
||||||
assertEquals(String.format(
|
|
||||||
"My name is %s and my location is (%s, %s, %s), this placeholder is invalid %%server_name%%",
|
|
||||||
PLAYER_NAME, PLAYER_X, PLAYER_Y, PLAYER_Z),
|
|
||||||
Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testResultsAreTheSameAsReplacement() {
|
|
||||||
final String resultChars = Values.CHARS_REPLACER
|
|
||||||
.apply("%player_name%", null, Values.PLACEHOLDERS::get);
|
|
||||||
|
|
||||||
assertEquals(PLAYER_NAME, resultChars);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCharsReplacerIgnoresMalformed() {
|
|
||||||
final String text = "10% and %hello world 15%";
|
|
||||||
|
|
||||||
assertEquals(text, Values.CHARS_REPLACER.apply(text, null, Values.PLACEHOLDERS::get));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user