Compare commits

..

3 Commits

80 changed files with 4171 additions and 6062 deletions

View File

@@ -38,7 +38,7 @@ PlaceholderAPI provides a feature to have expansions (separate jar files) for pl
In those cases should you report the issue to the issue tracker of the expansion or plugin. In those cases should you report the issue to the issue tracker of the expansion or plugin.
## Pull requests ## Pull requests
As an open source project we are welcoming all contributions to improve PlaceholderAPI, being it changes to its code, or contributions to its documentation such as the [Wiki] or the Javadocs. As an open source project are we welcoming all contributions to improve PlaceholderAPI, being it changes to its code, or contributions to its documentation such as the [Wiki] or the Javadocs.
> [!IMPORTANT] > [!IMPORTANT]
> When contributing, make sure to both base of and target the mentioned branch. Pull requests targeting the wrong branch may get closed without a warning. > When contributing, make sure to both base of and target the mentioned branch. Pull requests targeting the wrong branch may get closed without a warning.

View File

@@ -21,7 +21,7 @@
### Description ### Description
<!-- What does your Pull request change? --> <!-- What does your Pull request change? -->
Closes N/A <!-- If your PR is based on an issue, change "N/A" to the issue ID (#id) --> Closes N/A <!-- If your PR is based on an issue, change "N/A" the the issue ID (#id) -->
<!-- DO NOT ALTER ANYTHING BELOW THIS LINE! --> <!-- DO NOT ALTER ANYTHING BELOW THIS LINE! -->

View File

@@ -5,10 +5,8 @@ on:
branches: branches:
- development - development
paths: paths:
- "../../spigot/**" - "src/**"
- "../../paper/**" - "build.gradle"
- "build.gradle.kts"
- "settings.gradle.kts"
jobs: jobs:
testBuilds: testBuilds:

View File

@@ -8,15 +8,15 @@
[discord]: https://helpch.at/discord [discord]: https://helpch.at/discord
[spigot]: https://www.spigotmc.org/resources/6245/ [spigot]: https://www.spigotmc.org/resources/6245/
[hangar]: https://hangar.papermc.io/HelpChat/PlaceholderAPI [hangar]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
[modrinth]: https://modrinth.com/plugin/placeholderapi [bbb]: https://builtbybit.com/resources/placeholderapi.24306
[Expansions cloud]: https://ecloud.placeholderapi.com [Expansions cloud]: https://api.extendedclip.com/home
[placeholder list]: https://helpch.at/placeholders [placeholder list]: https://helpch.at/placeholders
[statistics]: https://bstats.org/plugin/bukkit/PlaceholderAPI [statistics]: https://bstats.org/plugin/bukkit/PlaceholderAPI
[ci]: http://ci.extendedclip.com/job/PlaceholderAPI/ [ci]: http://ci.extendedclip.com/job/PlaceholderAPI/
[ciImg]: http://ci.extendedclip.com/buildStatus/icon?job=PlaceholderAPI [ciImg]: http://ci.extendedclip.com/buildStatus/icon?job=PlaceholderAPI
[APIversionImg]: https://repo.extendedclip.com/api/badge/latest/releases/me/clip/placeholderapi?name=API%20Version [APIversionImg]: https://img.shields.io/nexus/placeholderapi/me.clip/placeholderapi?server=https%3A%2F%2Frepo.extendedclip.com&label=API%20Version
[logo]: https://wiki.placeholderapi.com/assets/img/papi-logo.png [logo]: https://wiki.placeholderapi.com/assets/img/papi-logo.png
[contributing]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/.github/CONTRIBUTING.md [contributing]: https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/.github/CONTRIBUTING.md
@@ -32,7 +32,7 @@
Support for specific plugins are provided either by the plugin itself or through expansions. The expansions may be downloaded in-game through the PAPI Expansion Cloud. There are currently over 240+ expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault. Support for specific plugins are provided either by the plugin itself or through expansions. The expansions may be downloaded in-game through the PAPI Expansion Cloud. There are currently over 240+ expansions that support a wide variety of plugins, such as Essentials, Factions, LuckPerms, and Vault.
PlaceholderAPI has been downloaded over 2,000,000 times on Spigot and has been used concurrently on over 50,000 servers, which makes it a must-have for a server of any type or scale. PlaceholderAPI has been downloaded over 1,600,000 times and has been used concurrently on over 40,000 servers, which makes it a must-have for a server of any type or scale.
## Contribute ## Contribute
If you would like to contribute towards PlaceholderAPI should you take a look at our [Contributing file][contributing] for the ins and outs on how you can do that and what you need to keep in mind. If you would like to contribute towards PlaceholderAPI should you take a look at our [Contributing file][contributing] for the ins and outs on how you can do that and what you need to keep in mind.
@@ -50,5 +50,5 @@ If you would like to create your own Placeholder Expansion for PlaceholderAPI, t
- [Placeholder List] - [Placeholder List]
- [Spigot Page][spigot] - [Spigot Page][spigot]
- [Hangar Page][hangar] - [Hangar Page][hangar]
- [Modrinth Page][modrinth] - [BuiltByBit Page][bbb]
- [Plugin Statistics][statistics] - [Plugin Statistics][statistics]

View File

@@ -3,23 +3,15 @@ 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("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 = "me.clip"
version = "2.12.2-DEV-${System.getProperty("BUILD_NUMBER")}" version = "2.11.7-DEV-${System.getProperty("BUILD_NUMBER")}"
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/") maven("https://oss.sonatype.org/content/repositories/snapshots/")
@@ -28,21 +20,18 @@ repositories {
maven("https://repo.codemc.org/repository/maven-public/") maven("https://repo.codemc.org/repository/maven-public/")
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") 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") implementation("org.bstats:bstats-bukkit:3.0.1")
implementation("net.kyori:adventure-platform-bukkit:4.4.1") implementation("net.kyori:adventure-platform-bukkit:4.3.3")
add(paper.compileOnlyConfigurationName, "net.kyori:adventure-platform-bukkit:4.4.1") compileOnly("org.spigotmc:spigot-api:1.21-R0.1-SNAPSHOT")
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") compileOnlyApi("org.jetbrains:annotations:23.0.0")
testImplementation("org.openjdk.jmh:jmh-core:1.32") testImplementation("org.openjdk.jmh:jmh-core:1.32")
testImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.32") testImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.32")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2") testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
} }
@@ -54,8 +43,19 @@ java {
withJavadocJar() withJavadocJar()
withSourcesJar() withSourcesJar()
}
disableAutoTargetJvm() license {
header = rootProject.file("config/headers/main.txt")
include("**/*.java")
mapping("java", "JAVADOC_STYLE")
encoding = "UTF-8"
ext {
set("year", 2024)
}
} }
val javaComponent: SoftwareComponent = components["java"] val javaComponent: SoftwareComponent = components["java"]
@@ -69,36 +69,14 @@ tasks {
dependsOn(named("shadowJar")) dependsOn(named("shadowJar"))
} }
register<JavaCompile>("compilePaper") { withType<JavaCompile> {
source = paper.java
classpath = paper.compileClasspath
destinationDirectory.set(layout.buildDirectory.dir("classes/java/paper"))
options.encoding = "UTF-8" options.encoding = "UTF-8"
options.release = 8 options.release = 8
} }
val plainJar by registering(Jar::class) { withType<Javadoc> {
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 isFailOnError = false
source = sourceSets.main.get().allJava + paper.allJava
classpath = sourceSets.main.get().compileClasspath + paper.compileClasspath
with(options as StandardJavadocDocletOptions) { with(options as StandardJavadocDocletOptions) {
addStringOption("Xdoclint:none", "-quiet") addStringOption("Xdoclint:none", "-quiet")
addStringOption("encoding", "UTF-8") addStringOption("encoding", "UTF-8")
@@ -106,41 +84,13 @@ tasks {
} }
} }
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> { withType<ShadowJar> {
configurations = listOf(project.configurations.runtimeClasspath.get())
from(sourceSets.main.get().output)
archiveClassifier.set("") archiveClassifier.set("")
relocate("org.bstats", "me.clip.placeholderapi.metrics") relocate("org.bstats", "me.clip.placeholderapi.metrics")
relocate("net.kyori", "me.clip.placeholderapi.libs.kyori") relocate("net.kyori", "me.clip.placeholderapi.libs.kyori")
exclude("META-INF/versions/**") 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 { test {
@@ -151,28 +101,16 @@ tasks {
publications { publications {
create<MavenPublication>("maven") { create<MavenPublication>("maven") {
artifactId = "placeholderapi" artifactId = "placeholderapi"
from(javaComponent)
artifact(plainJar) {
builtBy(plainJar)
classifier = ""
}
artifact(combinedSourcesJar) {
builtBy(combinedSourcesJar)
}
artifact(combinedJavadocJar) {
builtBy(combinedJavadocJar)
}
} }
} }
repositories { repositories {
maven { maven {
if ("-DEV" in version.toString()) { if ("-DEV" in version.toString()) {
url = uri("https://repo.extendedclip.com/snapshots") url = uri("https://repo.extendedclip.com/content/repositories/dev/")
} else { } else {
url = uri("https://repo.extendedclip.com/releases") url = uri("https://repo.extendedclip.com/content/repositories/placeholderapi/")
} }
credentials { credentials {

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018-2026 Peter Blood Copyright (c) 2018-2024 Peter Blood
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: 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:

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi; package me.clip.placeholderapi;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@@ -29,7 +28,6 @@ import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational; import me.clip.placeholderapi.expansion.Relational;
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager; import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
@@ -48,9 +46,9 @@ public final class PlaceholderAPI {
private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT); private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT);
private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET); private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET);
static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]"); private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]"); private static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern private static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern
.compile("[%](rel_)([^%]+)[%]"); .compile("[%](rel_)([^%]+)[%]");
@@ -138,8 +136,8 @@ public final class PlaceholderAPI {
* @return String containing all translated placeholders * @return String containing all translated placeholders
*/ */
@NotNull @NotNull
public static List<@NotNull String> setBracketPlaceholders(final OfflinePlayer player, public static List<String> setBracketPlaceholders(final OfflinePlayer player,
@NotNull final List<@NotNull String> text) { @NotNull final List<String> text) {
return text.stream().map(line -> setBracketPlaceholders(player, line)) return text.stream().map(line -> setBracketPlaceholders(player, line))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@@ -152,8 +150,7 @@ public final class PlaceholderAPI {
* @param text Text to set the placeholder values in * @param text Text to set the placeholder values in
* @return String containing all translated placeholders * @return String containing all translated placeholders
*/ */
@NotNull public static String setBracketPlaceholders(Player player, String text) {
public static String setBracketPlaceholders(Player player, @NotNull String text) {
return setBracketPlaceholders((OfflinePlayer) player, text); return setBracketPlaceholders((OfflinePlayer) player, text);
} }
@@ -165,8 +162,7 @@ public final class PlaceholderAPI {
* @param text List of Strings to set the placeholder values in * @param text List of Strings to set the placeholder values in
* @return String containing all translated placeholders * @return String containing all translated placeholders
*/ */
@NotNull public static List<String> setBracketPlaceholders(Player player, List<String> text) {
public static List<String> setBracketPlaceholders(Player player, @NotNull List<String> text) {
return setBracketPlaceholders((OfflinePlayer) player, text); return setBracketPlaceholders((OfflinePlayer) player, text);
} }
@@ -298,21 +294,24 @@ public final class PlaceholderAPI {
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean registerExpansion(PlaceholderExpansion expansion) { public static boolean registerExpansion(PlaceholderExpansion expansion)
{
return expansion.register(); return expansion.register();
} }
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
public static boolean unregisterExpansion(PlaceholderExpansion expansion) { public static boolean unregisterExpansion(PlaceholderExpansion expansion)
{
return expansion.unregister(); return expansion.unregister();
} }
/** /**
* Get map of registered placeholders * Get map of registered placeholders
* *
* @return Map of registered placeholders
* @deprecated Use {@link LocalExpansionManager#getExpansions()} instead. * @deprecated Use {@link LocalExpansionManager#getExpansions()} instead.
*
* @return Map of registered placeholders
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -323,11 +322,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Please use {@link PlaceholderExpansion} to
* register placeholders instead
*
* @param plugin The Plugin to register with this {@link PlaceholderHook} * @param plugin The Plugin to register with this {@link PlaceholderHook}
* @param placeholderHook The {@link PlaceholderHook} to register * @param placeholderHook The {@link PlaceholderHook} to register
* @return always false * @return always false
* @deprecated Please use {@link PlaceholderExpansion} to
* register placeholders instead
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -339,11 +339,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Please use {@link PlaceholderExpansion} to
* register placeholders instead
*
* @param identifier The identifier to use for the {@link PlaceholderHook} * @param identifier The identifier to use for the {@link PlaceholderHook}
* @param placeholderHook The {@link PlaceholderHook} to register * @param placeholderHook The {@link PlaceholderHook} to register
* @return always false * @return always false
* @deprecated Please use {@link PlaceholderExpansion} to
* register placeholders instead
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -355,10 +356,11 @@ public final class PlaceholderAPI {
} }
/** /**
* @param plugin The plugin to unregister
* @return always false
* @deprecated Please use {@link PlaceholderExpansion} to * @deprecated Please use {@link PlaceholderExpansion} to
* unregister placeholders instead * unregister placeholders instead
*
* @param plugin The plugin to unregister
* @return always false
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -370,10 +372,11 @@ public final class PlaceholderAPI {
} }
/** /**
* @param identifier The identifier to unregister
* @return always false
* @deprecated Please use {@link PlaceholderExpansion} to * @deprecated Please use {@link PlaceholderExpansion} to
* unregister placeholders instead * unregister placeholders instead
*
* @param identifier The identifier to unregister
* @return always false
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -385,8 +388,9 @@ public final class PlaceholderAPI {
} }
/** /**
* @return Set of registered identifiers
* @deprecated Will be removed in a future release. * @deprecated Will be removed in a future release.
*
* @return Set of registered identifiers
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -395,8 +399,9 @@ public final class PlaceholderAPI {
} }
/** /**
* @return always null
* @deprecated Will be removed in a future release. * @deprecated Will be removed in a future release.
*
* @return always null
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -405,12 +410,13 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, String)} instead
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The text to parse * @param text The text to parse
* @param pattern The Pattern to use * @param pattern The Pattern to use
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, String)} instead
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -420,12 +426,13 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, List)} instead
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The List of text to parse * @param text The List of text to parse
* @param pattern The Pattern to use * @param pattern The Pattern to use
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Please use {@link #setPlaceholders(OfflinePlayer, List)} instead
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -435,11 +442,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The List of text to parse * @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -449,11 +457,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The List of text to parse * @param text The List of text to parse
* @param pattern The Pattern to use * @param pattern The Pattern to use
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -461,13 +470,13 @@ public final class PlaceholderAPI {
Pattern pattern) { Pattern pattern) {
return setPlaceholders(player, text); return setPlaceholders(player, text);
} }
/** /**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The text to parse * @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Will be removed in a future release.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -476,11 +485,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The List of text to parse * @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Will be removed in a future release.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -489,11 +499,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The text to parse * @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -502,11 +513,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The text to parse * @param text The text to parse
* @param pattern The Pattern to use * @param pattern The Pattern to use
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -515,11 +527,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The List of text to parse * @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, List)} instead.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -529,11 +542,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The text to parse * @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Use {@link #setPlaceholders(OfflinePlayer, String)} instead.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -542,11 +556,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The text to parse * @param text The text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Will be removed in a future release.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -555,11 +570,12 @@ public final class PlaceholderAPI {
} }
/** /**
* @deprecated Will be removed in a future release.
*
* @param player The offline player to parse the placeholders against * @param player The offline player to parse the placeholders against
* @param text The List of text to parse * @param text The List of text to parse
* @param colorize If PlaceholderAPI should also parse color codes * @param colorize If PlaceholderAPI should also parse color codes
* @return String with the parsed placeholders * @return String with the parsed placeholders
* @deprecated Will be removed in a future release.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,9 +21,9 @@
package me.clip.placeholderapi; package me.clip.placeholderapi;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import me.clip.placeholderapi.commands.PlaceholderCommandRouter; import me.clip.placeholderapi.commands.PlaceholderCommandRouter;
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig; import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
@@ -31,10 +31,7 @@ import me.clip.placeholderapi.expansion.Version;
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager; import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;
import me.clip.placeholderapi.expansion.manager.LocalExpansionManager; import me.clip.placeholderapi.expansion.manager.LocalExpansionManager;
import me.clip.placeholderapi.listeners.ServerLoadEventListener; 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.updatechecker.UpdateChecker;
import me.clip.placeholderapi.util.ExpansionSafetyCheck;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bstats.bukkit.Metrics; import org.bstats.bukkit.Metrics;
@@ -44,7 +41,6 @@ import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -90,12 +86,8 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this); private final LocalExpansionManager localExpansionManager = new LocalExpansionManager(this);
@NotNull @NotNull
private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this); private final CloudExpansionManager cloudExpansionManager = new CloudExpansionManager(this);
@NotNull
private final TaskScheduler scheduler = UniversalScheduler.getScheduler(this);
private BukkitAudiences adventure; private BukkitAudiences adventure;
private boolean safetyCheck = false;
/** /**
* Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API * Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API
@@ -153,23 +145,13 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
@Override @Override
public void onLoad() { public void onLoad() {
saveDefaultConfig();
safetyCheck = new ExpansionSafetyCheck(this).runChecks();
if (safetyCheck) {
return;
}
instance = this; instance = this;
saveDefaultConfig();
} }
@Override @Override
public void onEnable() { public void onEnable() {
if (safetyCheck) {
return;
}
setupCommand(); setupCommand();
setupMetrics(); setupMetrics();
setupExpansions(); setupExpansions();
@@ -187,16 +169,12 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
if (safetyCheck) {
return;
}
getCloudExpansionManager().kill(); getCloudExpansionManager().kill();
getLocalExpansionManager().kill(); getLocalExpansionManager().kill();
HandlerList.unregisterAll(this); HandlerList.unregisterAll(this);
scheduler.cancelTasks(this); Bukkit.getScheduler().cancelTasks(this);
adventure.close(); adventure.close();
adventure = null; adventure = null;
@@ -237,11 +215,6 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
return adventure; return adventure;
} }
@NotNull
public TaskScheduler getScheduler() {
return scheduler;
}
/** /**
* Obtain the configuration class for PlaceholderAPI. * Obtain the configuration class for PlaceholderAPI.
* *
@@ -289,8 +262,8 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
Class.forName("org.bukkit.event.server.ServerLoadEvent"); Class.forName("org.bukkit.event.server.ServerLoadEvent");
new ServerLoadEventListener(this); new ServerLoadEventListener(this);
} catch (final ClassNotFoundException ignored) { } catch (final ClassNotFoundException ignored) {
scheduler Bukkit.getScheduler()
.runTaskLater(() -> getLocalExpansionManager().load(Bukkit.getConsoleSender()), 1); .runTaskLater(this, () -> getLocalExpansionManager().load(Bukkit.getConsoleSender()), 1);
} }
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -22,12 +22,10 @@ package me.clip.placeholderapi.commands;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@ package me.clip.placeholderapi.commands;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@@ -31,8 +30,6 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.common.collect.Lists;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.impl.cloud.CommandECloud; import me.clip.placeholderapi.commands.impl.cloud.CommandECloud;
import me.clip.placeholderapi.commands.impl.local.CommandDump; import me.clip.placeholderapi.commands.impl.local.CommandDump;
@@ -120,18 +117,14 @@ public final class PlaceholderCommandRouter implements CommandExecutor, TabCompl
} }
@Override @Override
public List<String> onTabComplete(@NotNull final CommandSender sender, @NotNull final Command command, public List<String> onTabComplete(@NotNull final CommandSender sender,
@NotNull final String alias, @NotNull final String[] args) { @NotNull final Command command, @NotNull final String alias, @NotNull final String[] args) {
final List<String> suggestions = new ArrayList<>(); final List<String> suggestions = new ArrayList<>();
if (args.length > 1) { if (args.length > 1) {
final PlaceholderCommand target = this.commands.get(args[0].toLowerCase(Locale.ROOT)); final PlaceholderCommand target = this.commands.get(args[0].toLowerCase(Locale.ROOT));
if (target != null) { if (target != null) {
if (target.getPermission() != null && !target.getPermission().isEmpty() && !sender.hasPermission(target.getPermission())) {
return suggestions;
}
target.complete(plugin, sender, args[0].toLowerCase(Locale.ROOT), target.complete(plugin, sender, args[0].toLowerCase(Locale.ROOT),
Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions); Arrays.asList(Arrays.copyOfRange(args, 1, args.length)), suggestions);
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -118,11 +118,6 @@ public final class CommandECloud extends PlaceholderCommand {
return; return;
} }
if (!target.getLabel().equalsIgnoreCase("refresh") && plugin.getCloudExpansionManager().isEmpty()) {
Msg.msg(sender, "&cThere is no available data from the eCloud. Please try running &f/papi ecloud refresh&c. If this does not resolve the issue, the eCloud may be blocked by your firewall, server host, or service provider.\n&r\n&cMore information: &fhttps://placeholderapi.com/ecloud-blocked");
return;
}
target.evaluate(plugin, sender, search, params.subList(1, params.size())); target.evaluate(plugin, sender, search, params.subList(1, params.size()));
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.commands.impl.cloud; package me.clip.placeholderapi.commands.impl.cloud;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion; import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
@@ -73,6 +72,11 @@ public final class CommandECloudDownload extends PlaceholderCommand {
return; return;
} }
if (!expansion.isVerified()) {
Msg.msg(sender, "&cThe expansion '&f" + params.get(0) + "&c' is not verified and can only be downloaded manually from &fhttps://placeholderapi.com/ecloud");
return;
}
final CloudExpansion.Version version; final CloudExpansion.Version version;
if (params.size() < 2) { if (params.size() < 2) {
version = expansion.getVersion(expansion.getLatestVersion()); version = expansion.getVersion(expansion.getLatestVersion());
@@ -91,11 +95,6 @@ public final class CommandECloudDownload extends PlaceholderCommand {
} }
} }
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) plugin.getCloudExpansionManager().downloadExpansion(expansion, version)
.whenComplete((file, exception) -> { .whenComplete((file, exception) -> {
if (exception != null) { if (exception != null) {

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@ package me.clip.placeholderapi.commands.impl.cloud;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion; import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
@@ -64,6 +63,9 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand {
.append('\n') .append('\n')
.append("&bAuthor: &f") .append("&bAuthor: &f")
.append(expansion.getAuthor()) .append(expansion.getAuthor())
.append('\n')
.append("&bVerified: ")
.append(expansion.isVerified() ? "&a&l✔" : "&c&l❌")
.append('\n'); .append('\n');
if (params.size() < 2) { if (params.size() < 2) {
@@ -74,9 +76,6 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand {
.append(expansion.getTimeSinceLastUpdate()) .append(expansion.getTimeSinceLastUpdate())
.append(" ago") .append(" ago")
.append('\n') .append('\n')
.append("&bVerified: ")
.append(expansion.getVersion().isVerified() ? "&a&l✔" : "&c&l❌")
.append('\n')
.append("&bRelease Notes: &f") .append("&bRelease Notes: &f")
.append(expansion.getVersion().getReleaseNotes()) .append(expansion.getVersion().getReleaseNotes())
.append('\n'); .append('\n');
@@ -92,9 +91,6 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand {
builder.append("&bVersion: &f") builder.append("&bVersion: &f")
.append(version.getVersion()) .append(version.getVersion())
.append('\n') .append('\n')
.append("&bVerified: ")
.append(version.isVerified() ? "&a&l✔" : "&c&l❌")
.append('\n')
.append("&bRelease Notes: &f") .append("&bRelease Notes: &f")
.append(version.getReleaseNotes()) .append(version.getReleaseNotes())
.append('\n') .append('\n')

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -25,14 +25,12 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.configuration.ExpansionSort; import me.clip.placeholderapi.configuration.ExpansionSort;
@@ -67,7 +65,7 @@ public final class CommandECloudExpansionList extends PlaceholderCommand {
expansion -> "&f" + expansion.getAuthor(); expansion -> "&f" + expansion.getAuthor();
@NotNull @NotNull
private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED = private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED =
expansion -> expansion.getVersion().isVerified() ? "&aY" : "&cN"; expansion -> expansion.isVerified() ? "&aY" : "&cN";
@NotNull @NotNull
private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION = private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION =
expansion -> "&f" + expansion.getLatestVersion(); expansion -> "&f" + expansion.getLatestVersion();
@@ -170,9 +168,7 @@ public final class CommandECloudExpansionList extends PlaceholderCommand {
.append(newline()).append(newline()) .append(newline()).append(newline())
.append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE)) .append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE))
.append(newline()) .append(newline())
.append(text("Version: ", AQUA)).append(text(expansion.getVersion().getVersion(), WHITE)) .append(text("Verified: ", AQUA)).append(text(expansion.isVerified() ? "✔" : "❌", expansion.isVerified() ? GREEN : RED, TextDecoration.BOLD))
.append(newline())
.append(text("Verified: ", AQUA)).append(text(expansion.getVersion().isVerified() ? "✔" : "❌", expansion.getVersion().isVerified() ? GREEN : RED, TextDecoration.BOLD))
.append(newline()) .append(newline())
.append(text("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE)) .append(text("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE))
.toBuilder(); .toBuilder();

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,11 +21,9 @@
package me.clip.placeholderapi.commands.impl.cloud; package me.clip.placeholderapi.commands.impl.cloud;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion; import me.clip.placeholderapi.expansion.cloud.CloudExpansion;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.commands.impl.cloud; package me.clip.placeholderapi.commands.impl.cloud;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.commands.impl.cloud; package me.clip.placeholderapi.commands.impl.cloud;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager; import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.commands.impl.cloud; package me.clip.placeholderapi.commands.impl.cloud;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -29,7 +28,6 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -25,7 +25,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.logging.Level; import java.util.logging.Level;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@ package me.clip.placeholderapi.commands.impl.local;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.commands.impl.local; package me.clip.placeholderapi.commands.impl.local;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.commands.impl.local; package me.clip.placeholderapi.commands.impl.local;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,11 +21,9 @@
package me.clip.placeholderapi.commands.impl.local; package me.clip.placeholderapi.commands.impl.local;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -25,7 +25,6 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,10 +21,8 @@
package me.clip.placeholderapi.commands.impl.local; package me.clip.placeholderapi.commands.impl.local;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.ExpansionSafetyCheck;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.Unmodifiable;
@@ -39,9 +37,7 @@ public final class CommandReload extends PlaceholderCommand {
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin, public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
@NotNull final CommandSender sender, @NotNull final String alias, @NotNull final CommandSender sender, @NotNull final String alias,
@NotNull @Unmodifiable final List<String> params) { @NotNull @Unmodifiable final List<String> params) {
if (!new ExpansionSafetyCheck(plugin).runChecks()) {
plugin.reloadConf(sender); plugin.reloadConf(sender);
} }
}
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.commands.impl.local; package me.clip.placeholderapi.commands.impl.local;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.commands.PlaceholderCommand; import me.clip.placeholderapi.commands.PlaceholderCommand;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.configuration; package me.clip.placeholderapi.configuration;
import java.util.Comparator; import java.util.Comparator;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion; import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.configuration; package me.clip.placeholderapi.configuration;
import java.util.Optional; import java.util.Optional;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -54,10 +53,6 @@ public final class PlaceholderAPIConfig {
return plugin.getConfig().getBoolean("debug", false); return plugin.getConfig().getBoolean("debug", false);
} }
public boolean useAdventureReplacer() {
return plugin.getConfig().getBoolean("use_adventure_provided_replacer", false);
}
public Optional<ExpansionSort> getExpansionSort() { public Optional<ExpansionSort> getExpansionSort() {
final String option = plugin.getConfig() final String option = plugin.getConfig()
@@ -91,11 +86,4 @@ public final class PlaceholderAPIConfig {
return plugin.getConfig().getString("boolean.false", "false"); return plugin.getConfig().getString("boolean.false", "false");
} }
public boolean useAdventureProvidedReplacer() {
return plugin.getConfig().getBoolean("use_adventure_provided_replacer", false);
}
public boolean detectMaliciousExpansions() {
return plugin.getConfig().getBoolean("detect_malicious_expansions", true);
}
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@ package me.clip.placeholderapi.events;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -51,12 +51,7 @@ public enum NMSVersion {
SPIGOT_1_20_R2("v1_20_R2"), SPIGOT_1_20_R2("v1_20_R2"),
SPIGOT_1_20_R3("v1_20_R3"), SPIGOT_1_20_R3("v1_20_R3"),
SPIGOT_1_20_R4("v1_20_R4"), SPIGOT_1_20_R4("v1_20_R4"),
SPIGOT_1_21_R1("v1_21_R1"), 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; private final String version;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@ package me.clip.placeholderapi.expansion;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.PlaceholderHook; import me.clip.placeholderapi.PlaceholderHook;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -44,7 +43,6 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
/** /**
* The type is {@link Type#INTERNAL} by default. * 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}. * For external expansions, the type is updated on {@link me.clip.placeholderapi.expansion.manager.LocalExpansionManager#register(Class) register}.
*
* @since 2.11.4 * @since 2.11.4
*/ */
@ApiStatus.Internal @ApiStatus.Internal
@@ -112,7 +110,12 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
* command is used * command is used
* *
* @return if this expansion should persist through placeholder reloads * @return if this expansion should persist through placeholder reloads
*
* @deprecated PlaceholderExpansions registered through their {@link #register()} and not through
* {@link me.clip.placeholderapi.expansion.manager.LocalExpansionManager#register(Class)}
* will be considered internal now and not be unregistered during Plugin reloads.
*/ */
@Deprecated
public boolean persist() { public boolean persist() {
return false; return false;
} }
@@ -182,7 +185,6 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
/** /**
* Set the type of the expansion * Set the type of the expansion
*
* @param expansionType the new type * @param expansionType the new type
* @since 2.11.4 * @since 2.11.4
*/ */
@@ -433,8 +435,9 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
// === Deprecated API === // === Deprecated API ===
/** /**
* @return The plugin name.
* @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()} * @deprecated As of versions greater than 2.8.7, use {@link #getRequiredPlugin()}
*
* @return The plugin name.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -443,8 +446,9 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
} }
/** /**
* @return The description of the expansion.
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to show a description * @deprecated As of versions greater than 2.8.7, use the expansion cloud to show a description
*
* @return The description of the expansion.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")
@@ -453,8 +457,9 @@ public abstract class PlaceholderExpansion extends PlaceholderHook {
} }
/** /**
* @return The link for the expansion.
* @deprecated As of versions greater than 2.8.7, use the expansion cloud to display a link * @deprecated As of versions greater than 2.8.7, use the expansion cloud to display a link
*
* @return The link for the expansion.
*/ */
@Deprecated @Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.13.0") @ApiStatus.ScheduledForRemoval(inVersion = "2.13.0")

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@ package me.clip.placeholderapi.expansion;
* with that version. * with that version.
* *
* @author Ryan McCarthy * @author Ryan McCarthy
*
* @deprecated Will be removed in a future release. * @deprecated Will be removed in a future release.
*/ */
@Deprecated @Deprecated
@@ -37,6 +38,7 @@ public interface VersionSpecific {
* will be passed to this method so you know what version the server is currently running. * will be passed to this method so you know what version the server is currently running.
* *
* @param v The {@link Version} to check against * @param v The {@link Version} to check against
*
* @return true if your expansion is compatible with the version the server is running. * @return true if your expansion is compatible with the version the server is running.
*/ */
boolean isCompatibleWith(Version v); boolean isCompatibleWith(Version v);

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@ package me.clip.placeholderapi.expansion.cloud;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.clip.placeholderapi.util.TimeUtil; import me.clip.placeholderapi.util.TimeUtil;
@@ -37,7 +36,8 @@ public class CloudExpansion {
dependency_url; dependency_url;
private boolean hasExpansion, private boolean hasExpansion,
shouldUpdate; shouldUpdate,
verified;
private long last_update, private long last_update,
ratings_count; ratings_count;
@@ -135,6 +135,10 @@ public class CloudExpansion {
this.shouldUpdate = shouldUpdate; this.shouldUpdate = shouldUpdate;
} }
public boolean isVerified() {
return verified;
}
public long getLastUpdate() { public long getLastUpdate() {
return last_update; return last_update;
} }
@@ -170,7 +174,6 @@ public class CloudExpansion {
public static class Version { public static class Version {
private String url, version, release_notes; private String url, version, release_notes;
private boolean verified;
public String getUrl() { public String getUrl() {
return url; return url;
@@ -195,13 +198,5 @@ public class CloudExpansion {
public void setReleaseNotes(String release_notes) { public void setReleaseNotes(String release_notes) {
this.release_notes = release_notes; this.release_notes = release_notes;
} }
public boolean isVerified() {
return verified;
}
public void setVerified(boolean verified) {
this.verified = verified;
}
} }
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -25,13 +25,11 @@ import com.google.common.io.Resources;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.net.URL; import java.net.URL;
import java.net.UnknownHostException;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -52,7 +50,6 @@ import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collector; import java.util.stream.Collector;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion; import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
@@ -63,7 +60,7 @@ import org.jetbrains.annotations.Unmodifiable;
public final class CloudExpansionManager { public final class CloudExpansionManager {
@NotNull @NotNull
private static final String API_URL = "https://ecloud.placeholderapi.com/api/v3/?platform=bukkit"; private static final String API_URL = "http://api.extendedclip.com/v2/";
@NotNull @NotNull
private static final Gson GSON = new Gson(); private static final Gson GSON = new Gson();
@@ -116,10 +113,6 @@ public final class CloudExpansionManager {
return ImmutableMap.copyOf(cache); return ImmutableMap.copyOf(cache);
} }
public boolean isEmpty() {
return cache.isEmpty();
}
@NotNull @NotNull
@Unmodifiable @Unmodifiable
public Map<String, CloudExpansion> getCloudExpansionsInstalled() { public Map<String, CloudExpansion> getCloudExpansionsInstalled() {
@@ -202,8 +195,6 @@ public final class CloudExpansionManager {
for (String name : toRemove) { for (String name : toRemove) {
values.remove(name); values.remove(name);
} }
} catch (UnknownHostException e) {
plugin.getLogger().log(Level.WARNING, "There is no data available from the eCloud. Please try running /papi refresh. If this does not resolve the issue, the eCloud may be blocked by your firewall, server host, or service provider.\n\nMore information: https://placeholderapi.com/ecloud-blocked", e);
} catch (Throwable e) { } catch (Throwable e) {
// ugly swallowing of every throwable, but we have to be defensive // ugly swallowing of every throwable, but we have to be defensive
plugin.getLogger().log(Level.WARNING, "Failed to download expansion information", e); plugin.getLogger().log(Level.WARNING, "Failed to download expansion information", e);
@@ -211,8 +202,10 @@ public final class CloudExpansionManager {
// loop through what's left on the main thread // loop through what's left on the main thread
plugin plugin
.getServer()
.getScheduler() .getScheduler()
.runTask( .runTask(
plugin,
() -> { () -> {
try { try {
for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) { for (Map.Entry<String, CloudExpansion> entry : values.entrySet()) {

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@ package me.clip.placeholderapi.expansion.manager;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.io.File; import java.io.File;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Arrays; import java.util.Arrays;
@@ -35,11 +34,10 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.events.ExpansionRegisterEvent; import me.clip.placeholderapi.events.ExpansionRegisterEvent;
import me.clip.placeholderapi.events.ExpansionUnregisterEvent; import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
@@ -48,6 +46,7 @@ import me.clip.placeholderapi.expansion.Cacheable;
import me.clip.placeholderapi.expansion.Cleanable; import me.clip.placeholderapi.expansion.Cleanable;
import me.clip.placeholderapi.expansion.Configurable; import me.clip.placeholderapi.expansion.Configurable;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.PlaceholderExpansion.Type;
import me.clip.placeholderapi.expansion.Taskable; import me.clip.placeholderapi.expansion.Taskable;
import me.clip.placeholderapi.expansion.VersionSpecific; import me.clip.placeholderapi.expansion.VersionSpecific;
import me.clip.placeholderapi.expansion.cloud.CloudExpansion; import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
@@ -215,7 +214,6 @@ public final class LocalExpansionManager implements Listener {
/** /**
* Attempt to register a {@link PlaceholderExpansion} * Attempt to register a {@link PlaceholderExpansion}
*
* @param expansion the expansion to register * @param expansion the expansion to register
* @return if the expansion was registered * @return if the expansion was registered
*/ */
@@ -267,6 +265,9 @@ public final class LocalExpansionManager implements Listener {
if (expansion instanceof VersionSpecific) { if (expansion instanceof VersionSpecific) {
VersionSpecific nms = (VersionSpecific) expansion; VersionSpecific nms = (VersionSpecific) expansion;
Msg.warn("Nag Author(s) %s of expansion %s about their usage of the deprecated "
+ "VersionSpecific interface!", expansion.getAuthor(), expansion.getIdentifier());
Msg.warn("They should switch to a new method of determining the Server version.");
if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) { if (!nms.isCompatibleWith(PlaceholderAPIPlugin.getServerVersion())) {
Msg.warn("Your server version is incompatible with expansion %s %s", Msg.warn("Your server version is incompatible with expansion %s %s",
expansion.getIdentifier(), expansion.getVersion()); expansion.getIdentifier(), expansion.getVersion());
@@ -323,6 +324,15 @@ public final class LocalExpansionManager implements Listener {
@ApiStatus.Internal @ApiStatus.Internal
public boolean unregister(@NotNull final PlaceholderExpansion expansion) { public boolean unregister(@NotNull final PlaceholderExpansion expansion) {
if (expansion.getExpansionType() == Type.INTERNAL || expansion.persist()) {
if (expansion.getExpansionType() == Type.EXTERNAL && expansion.persist()) {
Msg.warn("Nag Author(s) %s about their external expansion %s having persist set to true",
expansion.getAuthor(), expansion.getIdentifier());
}
return true;
}
if (expansions.remove(expansion.getIdentifier().toLowerCase(Locale.ROOT)) == null) { if (expansions.remove(expansion.getIdentifier().toLowerCase(Locale.ROOT)) == null) {
return false; return false;
} }
@@ -396,10 +406,6 @@ public final class LocalExpansionManager implements Listener {
private void unregisterAll() { private void unregisterAll() {
for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) { for (final PlaceholderExpansion expansion : Sets.newHashSet(expansions.values())) {
if (expansion.persist()) {
continue;
}
expansion.unregister(); expansion.unregister();
} }
} }
@@ -443,8 +449,7 @@ public final class LocalExpansionManager implements Listener {
Msg.severe("Failed to load expansion %s (is a dependency missing?)", e, file.getName()); Msg.severe("Failed to load expansion %s (is a dependency missing?)", e, file.getName());
return null; return null;
} catch (Exception e) { } catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Failed to load expansion file: " + file.getAbsolutePath(), e); throw new CompletionException(e.getMessage() + " (expansion file: " + file.getAbsolutePath() + ")", e);
return null;
} }
}); });
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@ package me.clip.placeholderapi.replacer;
import java.util.Locale; import java.util.Locale;
import java.util.function.Function; import java.util.function.Function;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -21,7 +21,6 @@
package me.clip.placeholderapi.replacer; package me.clip.placeholderapi.replacer;
import java.util.function.Function; import java.util.function.Function;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;
}
}
}

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -25,11 +25,7 @@ import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -38,68 +34,65 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
public class UpdateChecker implements Listener { public class UpdateChecker implements Listener {
private static final String MODRINTH_URL = "https://api.modrinth.com/v2/project/lKEzGugV/version";
private static final int RESOURCE_ID = 6245; private final int RESOURCE_ID = 6245;
private final PlaceholderAPIPlugin plugin; private final PlaceholderAPIPlugin plugin;
private final TaskScheduler scheduler;
private final String pluginVersion; private final String pluginVersion;
private String modrinthVersion; private String spigotVersion;
private boolean updateAvailable; private boolean updateAvailable;
public UpdateChecker(PlaceholderAPIPlugin plugin) { public UpdateChecker(PlaceholderAPIPlugin i) {
this.plugin = plugin; plugin = i;
scheduler = plugin.getScheduler(); pluginVersion = i.getDescription().getVersion();
pluginVersion = plugin.getDescription().getVersion();
} }
public boolean hasUpdateAvailable() { public boolean hasUpdateAvailable() {
return updateAvailable; return updateAvailable;
} }
public String getModrinthVersion() { public String getSpigotVersion() {
return modrinthVersion; return spigotVersion;
} }
public void fetch() { public void fetch() {
scheduler.runTaskAsynchronously(() -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try { try {
HttpsURLConnection con = (HttpsURLConnection) new URL(MODRINTH_URL).openConnection(); HttpsURLConnection con = (HttpsURLConnection) new URL(
"https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openConnection();
con.setRequestMethod("GET"); con.setRequestMethod("GET");
final JsonElement json = JsonParser.parseReader(new BufferedReader(new InputStreamReader(con.getInputStream()))); spigotVersion = new BufferedReader(new InputStreamReader(con.getInputStream())).readLine();
modrinthVersion = json.getAsJsonArray().get(0).getAsJsonObject().get("version_number").getAsString();
} catch (Exception ex) { } catch (Exception ex) {
plugin.getLogger().info("Failed to check for updates on modrinth."); plugin.getLogger().info("Failed to check for updates on spigot.");
return; return;
} }
if (modrinthVersion == null || modrinthVersion.isEmpty()) { if (spigotVersion == null || spigotVersion.isEmpty()) {
return; return;
} }
updateAvailable = modrinthIsNewer(); updateAvailable = spigotIsNewer();
if (!updateAvailable) { if (!updateAvailable) {
return; return;
} }
scheduler.runTask(() -> { Bukkit.getScheduler().runTask(plugin, () -> {
plugin.getLogger() plugin.getLogger()
.info("An update for PlaceholderAPI (v" + getModrinthVersion() + ") is available at:"); .info("An update for PlaceholderAPI (v" + getSpigotVersion() + ") is available at:");
plugin.getLogger() plugin.getLogger()
.info("https://modrinth.com/plugin/placeholderapi"); .info("https://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID + "/");
Bukkit.getPluginManager().registerEvents(this, plugin); Bukkit.getPluginManager().registerEvents(this, plugin);
}); });
}); });
} }
private boolean modrinthIsNewer() { private boolean spigotIsNewer() {
if (modrinthVersion == null || modrinthVersion.isEmpty()) { if (spigotVersion == null || spigotVersion.isEmpty()) {
return false; return false;
} }
int[] plV = toReadable(pluginVersion); int[] plV = toReadable(pluginVersion);
int[] spV = toReadable(modrinthVersion); int[] spV = toReadable(spigotVersion);
if (plV[0] < spV[0]) { if (plV[0] < spV[0]) {
return true; return true;
@@ -122,9 +115,10 @@ public class UpdateChecker implements Listener {
public void onJoin(PlayerJoinEvent e) { public void onJoin(PlayerJoinEvent e) {
if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) { if (e.getPlayer().hasPermission("placeholderapi.updatenotify")) {
Msg.msg(e.getPlayer(), Msg.msg(e.getPlayer(),
"&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getModrinthVersion() "&bAn update for &fPlaceholder&7API &e(&fPlaceholder&7API &fv" + getSpigotVersion()
+ "&e)" + "&e)"
, "&bis available at &ehttps://modrinth.com/plugin/placeholderapi"); , "&bis available at &ehttps://www.spigotmc.org/resources/placeholderapi." + RESOURCE_ID
+ "/");
} }
} }
} }

View File

@@ -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;
}
}

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -29,7 +29,6 @@ import static java.util.stream.IntStream.range;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -27,8 +27,6 @@ import java.util.function.BiConsumer;
import java.util.stream.Collector; import java.util.stream.Collector;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -38,14 +36,14 @@ public final class Futures {
private Futures() {} private Futures() {}
public static <T> void onMainThread(@NotNull final PlaceholderAPIPlugin plugin, public static <T> void onMainThread(@NotNull final Plugin plugin,
@NotNull final CompletableFuture<T> future, @NotNull final CompletableFuture<T> future,
@NotNull final BiConsumer<T, Throwable> consumer) { @NotNull final BiConsumer<T, Throwable> consumer) {
future.whenComplete((value, exception) -> { future.whenComplete((value, exception) -> {
if (Bukkit.isPrimaryThread()) { if (Bukkit.isPrimaryThread()) {
consumer.accept(value, exception); consumer.accept(value, exception);
} else { } else {
plugin.getScheduler().runTask(() -> consumer.accept(value, exception)); Bukkit.getScheduler().runTask(plugin, () -> consumer.accept(value, exception));
} }
}); });
} }

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -23,7 +23,6 @@ package me.clip.placeholderapi.util;
import java.util.Arrays; import java.util.Arrays;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.PlaceholderAPIPlugin;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -6,8 +6,6 @@
# Expansions: https://placeholderapi.com/ecloud # Expansions: https://placeholderapi.com/ecloud
# Wiki: https://wiki.placeholderapi.com/ # Wiki: https://wiki.placeholderapi.com/
# Discord: https://helpch.at/discord # Discord: https://helpch.at/discord
# If you're seeing performance issues with plugins that use component replacement, or things don't look quite right,
# switch to the replacer provided by adventure itself by changing use_adventure_provided_replacer to true
# No placeholders are provided with this plugin by default. # No placeholders are provided with this plugin by default.
# Download placeholders: /papi ecloud # Download placeholders: /papi ecloud
check_updates: true check_updates: true
@@ -17,6 +15,4 @@ boolean:
'true': 'yes' 'true': 'yes'
'false': 'no' 'false': 'no'
date_format: MM/dd/yy HH:mm:ss date_format: MM/dd/yy HH:mm:ss
detect_malicious_expansions: true
use_adventure_provided_replacer: false
debug: false debug: false

View File

@@ -1,6 +1,5 @@
name: PlaceholderAPI name: PlaceholderAPI
main: "me.clip.placeholderapi.PlaceholderAPIPlugin" main: "me.clip.placeholderapi.PlaceholderAPIPlugin"
folia-supported: true
version: ${version} version: ${version}
author: HelpChat author: HelpChat

View File

@@ -1,184 +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 me.clip.placeholderapi.replacer.ComponentReplacer;
import me.clip.placeholderapi.replacer.ExactReplacer;
import me.clip.placeholderapi.replacer.RelationalExactReplacer;
import me.clip.placeholderapi.replacer.Replacer;
import net.kyori.adventure.text.Component;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.stream.Collectors;
import static me.clip.placeholderapi.PlaceholderAPI.RELATIONAL_PLACEHOLDER_PATTERN;
public final class PAPIComponents {
private static final Replacer PERCENT_EXACT_REPLACER = new ExactReplacer('%', '%');
private static final Replacer BRACKET_EXACT_REPLACER = new ExactReplacer('{', '}');
private static final RelationalExactReplacer RELATIONAL_EXACT_REPLACER = new RelationalExactReplacer();
/**
* 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 component Component to set the placeholder values in
* @return Component containing all translated placeholders
*/
@NotNull
public static Component setPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
if (PlaceholderAPIPlugin.getInstance().getPlaceholderAPIConfig().useAdventureProvidedReplacer()) {
return component.replaceText(config -> config.match(PlaceholderAPI.PLACEHOLDER_PATTERN).replacement((result, builder) ->
builder.content(PERCENT_EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
}
return ComponentReplacer.replace(component, str -> PlaceholderAPI.setPlaceholders(player, str));
}
/**
* 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 components List of Components to set the placeholder values in
* @return List of Components containing all translated placeholders
*/
@NotNull
public static List<Component> setPlaceholders(final OfflinePlayer player, @NotNull final List<Component> components) {
return components.stream().map(component -> setPlaceholders(player, component)).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 component Component to set the placeholder values in
* @return Component containing all translated placeholders
*/
@NotNull
public static Component setPlaceholders(final Player player, @NotNull final Component component) {
return setPlaceholders((OfflinePlayer) player, component);
}
/**
* 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 components List of Components to set the placeholder values in
* @return List of components containing all translated placeholders
*/
@NotNull
public static List<Component> setPlaceholders(final Player player, @NotNull final List<Component> components) {
return setPlaceholders((OfflinePlayer) player, components);
}
/**
* 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 component Component to set the placeholder values in
* @return Component containing all translated placeholders
*/
@NotNull
public static Component setBracketPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
if (PlaceholderAPIPlugin.getInstance().getPlaceholderAPIConfig().useAdventureReplacer()) {
return component.replaceText(config -> config.match(PlaceholderAPI.BRACKET_PLACEHOLDER_PATTERN).replacement((result, builder) ->
builder.content(BRACKET_EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
}
return ComponentReplacer.replace(component, str -> PlaceholderAPI.setBracketPlaceholders(player, str));
}
/**
* 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 components List of Components to set the placeholder values in
* @return List of Components containing all translated placeholders
*/
@NotNull
public static List<Component> setBracketPlaceholders(final OfflinePlayer player, @NotNull final List<Component> components) {
return components.stream().map(component -> setBracketPlaceholders(player, component)).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 component Component to set the placeholder values in
* @return Component containing all translated placeholders
*/
@NotNull
public static Component setBracketPlaceholders(final Player player, @NotNull final Component component) {
return setBracketPlaceholders((OfflinePlayer) player, component);
}
/**
* 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 components List of Components to set the placeholder values in
* @return List of Components containing all translated placeholders
*/
@NotNull
public static List<Component> setBracketPlaceholders(final Player player, @NotNull final List<Component> components) {
return setBracketPlaceholders((OfflinePlayer) player, components);
}
/**
* 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 component Component to parse the placeholders in
* @return The Component containing the parsed relational placeholders
*/
public static Component setRelationalPlaceholders(Player one, Player two, Component component) {
//todo: custom replacer
return component.replaceText(config -> config.match(RELATIONAL_PLACEHOLDER_PATTERN).replacement((result, builder) ->
builder.content(RELATIONAL_EXACT_REPLACER.apply(result.group(2), one, two, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
}
/**
* 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 components List of Components to parse the placeholder values to
* @return The List of Components containing the parsed relational placeholders
*/
public static List<Component> setRelationalPlaceholders(Player one, Player two, List<Component> components) {
return components.stream().map(line -> setRelationalPlaceholders(one, two, line))
.collect(Collectors.toList());
}
}

View File

@@ -1,174 +0,0 @@
package me.clip.placeholderapi.replacer;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.text.*;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.DataComponentValue;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.Style;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class ComponentReplacer {
@NotNull
public static Component replace(@NotNull final Component component, @NotNull final Function<String, String> replacer) {
return rebuild(component, replacer);
}
@NotNull
private static Component rebuild(@NotNull final Component component, @NotNull final Function<String, String> replacer) {
Component rebuilt;
if (component instanceof TextComponent) {
final TextComponent text = (TextComponent) component;
final String replaced = replacer.apply(text.content());
rebuilt = Component.text(replaced);
} else if (component instanceof TranslatableComponent) {
final TranslatableComponent translatable = (TranslatableComponent) component;
final List<Component> arguments = new ArrayList<>();
for (final ComponentLike arg : translatable.arguments()) {
arguments.add(rebuild(arg.asComponent(), replacer));
}
rebuilt = Component.translatable(translatable.key(), arguments);
} else if (component instanceof KeybindComponent) {
final KeybindComponent keybind = (KeybindComponent) component;
rebuilt = Component.keybind(keybind.keybind());
} else if (component instanceof ScoreComponent) {
final ScoreComponent score = (ScoreComponent) component;
rebuilt = Component.score(score.name(), score.objective());
} else if (component instanceof SelectorComponent) {
final SelectorComponent selector = (SelectorComponent) component;
rebuilt = Component.selector(selector.pattern());
} else {
rebuilt = Component.empty();
}
rebuilt = rebuilt.style(rebuildStyle(component.style(), replacer));
if (!component.children().isEmpty()) {
final List<Component> children = new ArrayList<>();
for (Component child : component.children()) {
children.add(rebuild(child, replacer));
}
rebuilt = rebuilt.children(children);
}
return rebuilt;
}
@NotNull
private static Style rebuildStyle(@NotNull final Style style, @NotNull final Function<String, String> replacer) {
final Style.Builder builder = style.toBuilder();
final ClickEvent click = style.clickEvent();
if (click != null) {
builder.clickEvent(rebuildClickEvent(click, replacer));
}
final HoverEvent<?> hover = style.hoverEvent();
if (hover != null) {
builder.hoverEvent(rebuildHoverEvent(hover, replacer));
}
return builder.build();
}
@NotNull
private static ClickEvent rebuildClickEvent(@NotNull final ClickEvent click, @NotNull final Function<String, String> replacer) {
final ClickEvent.Payload payload = click.payload();
if (!(payload instanceof ClickEvent.Payload.Text)) {
return click;
}
final String original = ((ClickEvent.Payload.Text) payload).value();
final String replaced = replacer.apply(original);
final ClickEvent.Action action = click.action();
switch (action) {
case OPEN_URL:
return ClickEvent.openUrl(replaced);
case OPEN_FILE:
return ClickEvent.openFile(replaced);
case RUN_COMMAND:
return ClickEvent.runCommand(replaced);
case SUGGEST_COMMAND:
return ClickEvent.suggestCommand(replaced);
case COPY_TO_CLIPBOARD:
return ClickEvent.copyToClipboard(replaced);
default:
return click;
}
}
@NotNull
private static HoverEvent<?> rebuildHoverEvent(@NotNull final HoverEvent<?> hover, @NotNull final Function<String, String> replacer) {
final Object value = hover.value();
if (value instanceof Component) {
final Component rebuilt = rebuild((Component) value, replacer);
return HoverEvent.showText(rebuilt);
}
if (value instanceof HoverEvent.ShowItem) {
return rebuildShowItem((HoverEvent.ShowItem) value, replacer);
}
if (value instanceof HoverEvent.ShowEntity) {
final HoverEvent.ShowEntity entity = (HoverEvent.ShowEntity) value;
Component rebuiltName = null;
if (entity.name() != null) {
rebuiltName = rebuild(entity.name(), replacer);
}
return HoverEvent.showEntity(entity.type(), entity.id(), rebuiltName);
}
return hover;
}
@NotNull
private static HoverEvent<?> rebuildShowItem(@NotNull final HoverEvent.ShowItem item, @NotNull final Function<String, String> replacer) {
final BinaryTagHolder nbt = item.nbt();
if (nbt != null && !nbt.string().isEmpty()) {
final String replaced = replacer.apply(nbt.string());
return HoverEvent.showItem(item.item(), item.count(), BinaryTagHolder.binaryTagHolder(replaced));
}
//I'm not 100% sure this is how we're meant to support data components but let's give it a go and see if it causes any issues :)
final Map<Key, DataComponentValue> components = item.dataComponents();
if (!components.isEmpty()) {
final Map<Key, DataComponentValue> rebuilt = new HashMap<>();
for (final Map.Entry<Key, DataComponentValue> entry : components.entrySet()) {
final DataComponentValue value = entry.getValue();
if (!(value instanceof BinaryTagHolder)) {
rebuilt.put(entry.getKey(), value);
continue;
}
rebuilt.put(entry.getKey(), BinaryTagHolder.binaryTagHolder(replacer.apply(((BinaryTagHolder) value).string())));
}
return HoverEvent.showItem(item.item(), item.count(), rebuilt);
}
return HoverEvent.showItem(item);
}
}

View File

@@ -1,76 +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.expansion.PlaceholderExpansion;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.regex.Pattern;
public final class ExactReplacer implements Replacer {
private static final Pattern DELIMITER = Pattern.compile("_");
private final char start;
private final char end;
public ExactReplacer(final char start, final char end) {
this.start = start;
this.end = end;
}
@NotNull
@Override
public String apply(@NotNull String text, @Nullable final OfflinePlayer player,
@NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) {
text = text.substring(1, text.length() - 1);
final String[] parts = DELIMITER.split(text);
final PlaceholderExpansion expansion;
if (parts.length == 0) {
expansion = lookup.apply(text);
} else {
expansion = lookup.apply(parts[0]);
}
if (expansion == null) {
return start + text + end;
}
final String params;
if (text.endsWith("_")) {
params = "";
} else {
params = text.substring(text.indexOf('_') + 1);
}
final String result = expansion.onRequest(player, params);
if (result == null) {
return start + text + end;
}
return result;
}
}

View File

@@ -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.replacer;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.regex.Pattern;
public final class RelationalExactReplacer {
private static final Pattern DELIMITER = Pattern.compile("_");
@NotNull
public String apply(@NotNull String text, @Nullable final Player player1,
@Nullable final Player player2, @NotNull final Function<String,
@Nullable PlaceholderExpansion> lookup) {
final String[] parts = DELIMITER.split(text);
final PlaceholderExpansion expansion;
if (parts.length == 0) {
expansion = lookup.apply(text);
} else {
expansion = lookup.apply(parts[0]);
}
if (expansion == null) {
return "%rel_" + text + '%';
}
if (!(expansion instanceof Relational)) {
return "%rel_" + text + '%';
}
final String params;
if (text.endsWith("_")) {
params = "";
} else {
params = text.substring(text.indexOf('_') + 1);
}
final String result = ((Relational) expansion).onPlaceholderRequest(player1, player2, params);
if (result == null) {
return "%rel_" + text + '%';
}
return result;
}
}

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* This file is part of PlaceholderAPI * This file is part of PlaceholderAPI
* *
* PlaceholderAPI * PlaceholderAPI
* Copyright (c) 2015 - 2026 PlaceholderAPI Team * Copyright (c) 2015 - 2024 PlaceholderAPI Team
* *
* PlaceholderAPI free software: you can redistribute it and/or modify * PlaceholderAPI free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by