Compare commits

..

4 Commits

Author SHA1 Message Date
PiggyPiglet
3d81cc443b click event stuff 2026-01-18 20:07:47 +08:00
PiggyPiglet
2d686b679f we're really getting somewhere!@1
who the fuck decided to use 2 space instead of 4
2026-01-18 20:07:33 +08:00
PiggyPiglet
5fbc5ee1cb Start merging chars replacer logic into adventure replacer
very rough no judge
2026-01-18 20:03:16 +08:00
PiggyPiglet
4378a439fc Uhh 2026-01-18 20:03:16 +08:00
72 changed files with 1498 additions and 1625 deletions

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

@@ -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,700,000 times on Spigot and has been used concurrently on over 45,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.

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.8-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/")
@@ -32,17 +24,17 @@ repositories {
} }
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.4.1")
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("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
compileOnly("dev.folia:folia-api:1.20.1-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")
} }
@@ -58,6 +50,19 @@ java {
disableAutoTargetJvm() 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"]
tasks { tasks {
@@ -69,36 +74,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 +89,18 @@ 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("me/clip/placeholderapi/PAPIComponents.java")
// exclude("me/clip/placeholderapi/commands/TestCommand.java")
// }
destinationDirectory = file("server/1.21/plugins/")
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,19 +111,7 @@ 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)
}
} }
} }

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

@@ -0,0 +1,121 @@
package me.clip.placeholderapi;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Relational;
import me.clip.placeholderapi.replacer.ExactReplacer;
import me.clip.placeholderapi.replacer.Replacer;
import net.kyori.adventure.text.Component;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.checkerframework.checker.units.qual.N;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public final class PAPIComponents {
private static final Replacer EXACT_REPLACER = new ExactReplacer();
@NotNull
public static Component setPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
// TODO: explore a custom TextReplacementRenderer which doesn't use regex for performance benefits i.e. merge CharsReplacer with kyori TextReplacementRenderer
return component.replaceText(config -> config.match(PlaceholderAPI.PLACEHOLDER_PATTERN).replacement((result, builder) ->
builder.content(EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
}
@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());
}
@NotNull
public static Component setPlaceholders(final Player player, @NotNull final Component component) {
return setPlaceholders((OfflinePlayer) player, component);
}
@NotNull
public static List<Component> setPlaceholders(final Player player, @NotNull final List<Component> components) {
return setPlaceholders((OfflinePlayer) player, components);
}
@NotNull
public static Component setBracketPlaceholders(final OfflinePlayer player, @NotNull final Component component) {
return component.replaceText(config -> config.match(PlaceholderAPI.BRACKET_PLACEHOLDER_PATTERN).replacement((result, builder) ->
builder.content(EXACT_REPLACER.apply(result.group(), player, PlaceholderAPIPlugin.getInstance().getLocalExpansionManager()::getExpansion))));
}
@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());
}
@NotNull
public static Component setBracketPlaceholders(final Player player, @NotNull final Component component) {
return setBracketPlaceholders((OfflinePlayer) player, component);
}
@NotNull
public static List<Component> setBracketPlaceholders(final Player player, @NotNull final List<Component> components) {
return setBracketPlaceholders((OfflinePlayer) player, components);
}
// public static Component setRelationalPlaceholders(Player one, Player two, Component component) {
// return component.replaceText(config -> config.match(PlaceholderAPI.RELATIONAL_PLACEHOLDER_PATTERN).replacement((result, builder) -> {
//
// final String format = result.group(2);
// final int index = format.indexOf("_");
//
// if (index <= 0 || index >= format.length()) {
// continue;
// }
//
// String identifier = format.substring(0, index).toLowerCase(Locale.ROOT);
// String params = format.substring(index + 1);
// final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance()
// .getLocalExpansionManager().getExpansion(identifier);
//
// if (!(expansion instanceof Relational)) {
// continue;
// }
//
// final String value = ((Relational) expansion).onPlaceholderRequest(one, two, params);
//
// if (value != null) {
// text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
// }
//
//
// }));
//
// final Matcher matcher = PlaceholderAPI.RELATIONAL_PLACEHOLDER_PATTERN.matcher(text);
//
// while (matcher.find()) {
// final String format = matcher.group(2);
// final int index = format.indexOf("_");
//
// if (index <= 0 || index >= format.length()) {
// continue;
// }
//
// String identifier = format.substring(0, index).toLowerCase(Locale.ROOT);
// String params = format.substring(index + 1);
// final PlaceholderExpansion expansion = PlaceholderAPIPlugin.getInstance()
// .getLocalExpansionManager().getExpansion(identifier);
//
// if (!(expansion instanceof Relational)) {
// continue;
// }
//
// final String value = ((Relational) expansion).onPlaceholderRequest(one, two, params);
//
// if (value != null) {
// text = text.replaceAll(Pattern.quote(matcher.group()), Matcher.quoteReplacement(value));
// }
// }
//
// return text;
// }
}

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,13 +28,13 @@ 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;
import me.clip.placeholderapi.replacer.CharsReplacer; import me.clip.placeholderapi.replacer.CharsReplacer;
import me.clip.placeholderapi.replacer.Replacer; import me.clip.placeholderapi.replacer.Replacer;
import me.clip.placeholderapi.replacer.Replacer.Closure; import me.clip.placeholderapi.replacer.Replacer.Closure;
import me.clip.placeholderapi.replacer.ExactReplacer;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -53,6 +52,7 @@ public final class PlaceholderAPI {
static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern static final Pattern RELATIONAL_PLACEHOLDER_PATTERN = Pattern
.compile("[%](rel_)([^%]+)[%]"); .compile("[%](rel_)([^%]+)[%]");
private static final Replacer TEST = new ExactReplacer();
private PlaceholderAPI() { private PlaceholderAPI() {
} }
@@ -298,21 +298,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 +326,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 +343,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 +360,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 +376,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 +392,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 +403,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 +414,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 +430,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 +446,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 +461,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 +474,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 +489,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 +503,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 +517,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 +531,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 +546,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 +560,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 +574,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
@@ -23,8 +23,8 @@ package me.clip.placeholderapi;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
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.commands.TestCommand;
import me.clip.placeholderapi.configuration.PlaceholderAPIConfig; import me.clip.placeholderapi.configuration.PlaceholderAPIConfig;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import me.clip.placeholderapi.expansion.Version; import me.clip.placeholderapi.expansion.Version;
@@ -44,7 +44,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;
@@ -94,8 +93,9 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
private final TaskScheduler scheduler = UniversalScheduler.getScheduler(this); private final TaskScheduler scheduler = UniversalScheduler.getScheduler(this);
private BukkitAudiences adventure; private BukkitAudiences adventure;
private boolean safetyCheck = false;
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
@@ -151,6 +151,10 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
return VERSION; return VERSION;
} }
@Override
public void onLoad() {
instance = this;
@Override @Override
public void onLoad() { public void onLoad() {
saveDefaultConfig(); saveDefaultConfig();
@@ -174,8 +178,6 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
setupMetrics(); setupMetrics();
setupExpansions(); setupExpansions();
adventure = BukkitAudiences.create(this);
if (config.isCloudEnabled()) { if (config.isCloudEnabled()) {
getCloudExpansionManager().load(); getCloudExpansionManager().load();
} }
@@ -185,6 +187,11 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
} }
} }
@Override
public void onDisable() {
getCloudExpansionManager().kill();
getLocalExpansionManager().kill();
@Override @Override
public void onDisable() { public void onDisable() {
if (safetyCheck) { if (safetyCheck) {
@@ -194,8 +201,6 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
getCloudExpansionManager().kill(); getCloudExpansionManager().kill();
getLocalExpansionManager().kill(); getLocalExpansionManager().kill();
HandlerList.unregisterAll(this);
scheduler.cancelTasks(this); scheduler.cancelTasks(this);
adventure.close(); adventure.close();
@@ -230,7 +235,7 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
@NotNull @NotNull
public BukkitAudiences getAdventure() { public BukkitAudiences getAdventure() {
if (adventure == null) { if(adventure == null) {
throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!"); throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!");
} }

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
@@ -20,11 +20,14 @@
package me.clip.placeholderapi; package me.clip.placeholderapi;
import net.kyori.adventure.text.Component;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public abstract class PlaceholderHook { public abstract class PlaceholderHook {
@Nullable @Nullable
public String onRequest(final OfflinePlayer player, @NotNull final String params) { public String onRequest(final OfflinePlayer player, @NotNull final String params) {

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
@@ -32,7 +32,6 @@ 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 +119,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

@@ -0,0 +1,57 @@
package me.clip.placeholderapi.commands;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import me.clip.placeholderapi.PAPIComponents;
import me.clip.placeholderapi.PlaceholderAPI;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.event.HoverEventSource;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.OfflinePlayer;
public class TestCommand implements BasicCommand {
private static final MiniMessage MINI = MiniMessage.miniMessage();
@Override
public void execute(final CommandSourceStack commandSourceStack, final String[] strings) {
// final Component component = Component.text("Woo! Test: %player_name%").color(TextColor.color(50, 168, 82)).hoverEvent(HoverEvent.showText(Component.text("OMG %player_gamemode%")));
final Component component = Component.text("Woo! Test: %player_name%");
String ser = MINI.serialize(component);
System.out.println(ser);
commandSourceStack.getSender().sendMessage(
PAPIComponents.setPlaceholders((OfflinePlayer) commandSourceStack.getSender(), component)
);
long tmp = System.currentTimeMillis();
for (int i = 0; i < 100000; ++i) {
PAPIComponents.setPlaceholders((OfflinePlayer) commandSourceStack.getSender(), component);
}
commandSourceStack.getSender().sendMessage(String.valueOf(System.currentTimeMillis() - tmp));
tmp = System.currentTimeMillis();
for (int i = 0; i < 100000; ++i) {
PlaceholderAPI.setPlaceholders((OfflinePlayer) commandSourceStack.getSender(), "Woo! Test: %player_name%");
}
commandSourceStack.getSender().sendMessage(String.valueOf(System.currentTimeMillis() - tmp));
tmp = System.currentTimeMillis();
for (int i = 0; i < 100000; ++i) {
final String serr = MINI.serialize(component);
final String repl = PlaceholderAPI.setPlaceholders((OfflinePlayer) commandSourceStack.getSender(), serr);
MINI.deserialize(repl);
}
commandSourceStack.getSender().sendMessage(String.valueOf(System.currentTimeMillis() - tmp));
Component.text()
.append(Component.text().content("yes ").color(TextColor.color(50,50,50)))
.append(Component.text("%player_name%"))
.append(Component.text(" omg").color(TextColor.color(200,200,200)));
}
}

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

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
@@ -65,14 +65,6 @@ public final class CommandECloudDownload extends PlaceholderCommand {
return; return;
} }
final CloudExpansion expansion = plugin.getCloudExpansionManager()
.findCloudExpansionByName(params.get(0)).orElse(null);
if (expansion == null) {
Msg.msg(sender,
"&cFailed to find an expansion named: &f" + params.get(0));
return;
}
final CloudExpansion.Version version; final CloudExpansion.Version version;
if (params.size() < 2) { if (params.size() < 2) {
version = expansion.getVersion(expansion.getLatestVersion()); version = expansion.getVersion(expansion.getLatestVersion());
@@ -96,6 +88,37 @@ public final class CommandECloudDownload extends PlaceholderCommand {
return; return;
} }
plugin.getCloudExpansionManager().downloadExpansion(expansion, version)
.whenComplete((file, exception) -> {
if (exception != null) {
Msg.msg(sender,
"&cFailed to find an expansion named: &f" + params.get(0));
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;
if (params.size() < 2) {
version = expansion.getVersion(expansion.getLatestVersion());
if (version == null) {
Msg.msg(sender,
"&cCould not find latest version for expansion.");
return;
}
} else {
version = expansion.getVersion(params.get(1));
if (version == null) {
Msg.msg(sender,
"&cCould not find specified version: &f" + params.get(1),
"&7Available versions: &f" + expansion.getAvailableVersions());
return;
}
}
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
@@ -56,8 +56,6 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand {
return; return;
} }
final StringBuilder builder = new StringBuilder();
builder.append("&bExpansion: &f") builder.append("&bExpansion: &f")
.append(expansion.shouldUpdate() ? "&e" : "&a") .append(expansion.shouldUpdate() ? "&e" : "&a")
.append(expansion.getName()) .append(expansion.getName())
@@ -103,6 +101,17 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand {
.append('\n'); .append('\n');
} }
builder.append("&bVersion: &f")
.append(version.getVersion())
.append('\n')
.append("&bRelease Notes: &f")
.append(version.getReleaseNotes())
.append('\n')
.append("&bDownload URL: &f")
.append(version.getUrl())
.append('\n');
}
Msg.msg(sender, builder.toString()); Msg.msg(sender, builder.toString());
} }

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
@@ -170,19 +170,20 @@ 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("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE))
.toBuilder();
final TextComponent.Builder hoverText = text("Click to download this expansion!", AQUA)
.append(newline()).append(newline())
.append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE))
.append(newline()) .append(newline())
.append(text("Verified: ", AQUA)).append(text(expansion.getVersion().isVerified() ? "✔" : "❌", expansion.getVersion().isVerified() ? GREEN : RED, TextDecoration.BOLD)) .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();
Optional.ofNullable(expansion.getDescription())
.filter(description -> !description.isEmpty())
.ifPresent(description -> hoverText.append(newline()).append(newline())
.append(text(description.replace("\r", "").trim(), WHITE))
);
line.hoverEvent(HoverEvent.showText(hoverText.build())); line.hoverEvent(HoverEvent.showText(hoverText.build()));
if (index != expansions.size() - 1) { if (index != expansions.size() - 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

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

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
@@ -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,8 @@ 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() { public boolean detectMaliciousExpansions() {
return plugin.getConfig().getBoolean("detect_malicious_expansions", true); 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

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

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
@@ -182,7 +180,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 +430,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 +441,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 +452,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
@@ -195,6 +195,7 @@ 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() { public boolean isVerified() {
return verified; return 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
@@ -31,7 +31,6 @@ 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;
@@ -63,7 +62,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 = "https://ecloud.placeholderapi.com/api/v3/";
@NotNull @NotNull
private static final Gson GSON = new Gson(); private static final Gson GSON = new Gson();
@@ -116,10 +115,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 +197,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);

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
@@ -44,6 +44,8 @@ public final class CharsReplacer implements Replacer {
public String apply(@NotNull final String text, @Nullable final OfflinePlayer player, public String apply(@NotNull final String text, @Nullable final OfflinePlayer player,
@NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) { @NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) {
final char[] chars = text.toCharArray(); final char[] chars = text.toCharArray();
// Woo! Hlello %player_name%
// Woo! GHsda PiggyPiglet
final StringBuilder builder = new StringBuilder(text.length()); final StringBuilder builder = new StringBuilder(text.length());
final StringBuilder identifier = new StringBuilder(); final StringBuilder identifier = new StringBuilder();

View File

@@ -0,0 +1,171 @@
package me.clip.placeholderapi.replacer;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.kyori.adventure.text.*;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.Style;
import org.bukkit.OfflinePlayer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
public final class ComponentReplacer {
public Component replace(Component component, OfflinePlayer player, Function<String, PlaceholderExpansion> function) {
Component modified = component;
final List<Component> oldChildren = component.children();
final int oldChildrenSize = oldChildren.size();
List<Component> children = null;
if (component instanceof TextComponent) {
TextComponent tc = (TextComponent) component;
final String content = tc.content();
final char[] chars = content.toCharArray();
final StringBuilder identifier = new StringBuilder();
final StringBuilder parameters = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
final char l = chars[i];
if (l != '%' || i + 1 >= chars.length) {
continue;
}
final int start = i;
boolean identified = false;
boolean invalid = true;
while (++i < chars.length) {
final char p = chars[i];
if (p == ' ' && !identified) {
break;
}
if (p == '%') {
invalid = false;
break;
}
if (p == '_' && !identified) {
identified = true;
continue;
}
if (identified) {
parameters.append(p);
} else {
identifier.append(p);
}
}
final String identifierString = identifier.toString();
final String lowercaseIdentifierString = identifierString.toLowerCase(Locale.ROOT);
final String parametersString = parameters.toString();
identifier.setLength(0);
parameters.setLength(0);
if (invalid) {
continue;
}
final PlaceholderExpansion expansion = function.apply(lowercaseIdentifierString);
if (expansion == null) {
continue;
}
final String placeholderValue = expansion.onRequest(player, parametersString);
if (placeholderValue == null) {
continue;
}
if (start == 0) {
// if we're a full match, modify the component directly
if (i == content.length() - 1) {
final ComponentLike replacement = Component.text(placeholderValue).style(component.style());
modified = replacement.asComponent();
Style modStyle = modified.style();
if (modStyle.hoverEvent() != null) {
Object hoverValue = modStyle.hoverEvent().value();
if (hoverValue instanceof Component) {
final Object replacedValue = replace((Component) hoverValue, player, function);
if (replacedValue != hoverValue) {
((HoverEvent<Object>) modified.style().hoverEvent()).value(replacedValue);
}
}
}
if (modStyle.clickEvent() != null) {
final ClickEvent.Payload payload = modStyle.clickEvent().payload();
if (payload instanceof ClickEvent.Payload.Text) {
final ClickEvent.Payload.Text replacedPayload = ClickEvent.Payload.string(PlaceholderAPI.setPlaceholders(player, ((ClickEvent.Payload.Text) payload).value()));
modStyle.clickEvent(ClickEvent.clickEvent(modStyle.clickEvent().action(), replacedPayload));
} else if (payload instanceof ClickEvent.Payload.Dialog) {
final ClickEvent.Payload.Dialog replacedPayload;
// ((ClickEvent.Payload.Dialog) payload).dialog()
// apparently adventure doesn't have dialog support yet
}
}
if (children == null) {
children = new ArrayList<>(oldChildrenSize + modified.children().size());
children.addAll(modified.children());
}
} else {
modified = Component.text("", component.style());
// final ComponentLike child =
}
}
}
} else if (component instanceof TranslatableComponent) {
TranslatableComponent tc = (TranslatableComponent) component;
final List<TranslationArgument> args = tc.arguments();
List<TranslationArgument> newArgs = null;
for (int i = 0, size = args.size(); i < size; i++) {
final TranslationArgument original = args.get(i);
TranslationArgument replacement = original instanceof Component ? TranslationArgument.component(replace((Component) original, player, function)) : original;
if (original != replacement) {
if (newArgs == null) {
newArgs = new ArrayList<>(size);
if (i > 0) {
newArgs.addAll(args.subList(0, i));
}
}
}
if (newArgs != null) {
newArgs.add(replacement);
}
}
if (newArgs != null) {
modified = ((TranslatableComponent) modified).arguments(newArgs);
}
}
return modified;
}
private static <V> void test(HoverEvent<V> event, V value) {
event.value(value);
}
}

View File

@@ -1,23 +1,3 @@
/*
* 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; package me.clip.placeholderapi.replacer;
import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.PlaceholderExpansion;
@@ -28,17 +8,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public final class ExactReplacer implements Replacer { public class ExactReplacer implements Replacer {
private static final Pattern DELIMITER = Pattern.compile("_"); 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 @NotNull
@Override @Override
public String apply(@NotNull String text, @Nullable final OfflinePlayer player, public String apply(@NotNull String text, @Nullable final OfflinePlayer player,
@@ -54,7 +26,7 @@ public final class ExactReplacer implements Replacer {
} }
if (expansion == null) { if (expansion == null) {
return start + text + end; return text;
} }
final String params; final String params;
@@ -68,7 +40,7 @@ public final class ExactReplacer implements Replacer {
final String result = expansion.onRequest(player, params); final String result = expansion.onRequest(player, params);
if (result == null) { if (result == null) {
return start + text + end; return text;
} }
return result; 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

@@ -27,9 +27,7 @@ import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask; import me.clip.placeholderapi.scheduler.scheduling.tasks.MyScheduledTask;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
/** /** Just modified BukkitRunnable */
* Just modified BukkitRunnable
*/
public abstract class UniversalRunnable implements Runnable { public abstract class UniversalRunnable implements Runnable {
MyScheduledTask task; MyScheduledTask task;

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,9 +25,6 @@ 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.scheduler.scheduling.schedulers.TaskScheduler;
import me.clip.placeholderapi.util.Msg; import me.clip.placeholderapi.util.Msg;
@@ -38,13 +35,12 @@ 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 static final int RESOURCE_ID = 6245;
private final PlaceholderAPIPlugin plugin; private final PlaceholderAPIPlugin plugin;
private final TaskScheduler scheduler; 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 plugin) {
@@ -57,27 +53,27 @@ public class UpdateChecker implements Listener {
return updateAvailable; return updateAvailable;
} }
public String getModrinthVersion() { public String getSpigotVersion() {
return modrinthVersion; return spigotVersion;
} }
public void fetch() { public void fetch() {
scheduler.runTaskAsynchronously(() -> { scheduler.runTaskAsynchronously(() -> {
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;
@@ -85,21 +81,21 @@ public class UpdateChecker implements Listener {
scheduler.runTask(() -> { scheduler.runTask(() -> {
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 +118,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

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

View File

@@ -6,10 +6,10 @@
# 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
#
# CHANGE use_regex_component_replacer to true if you notice new minecraft text features not getting their placeholders replaced properly -- may cause performance issues
check_updates: true check_updates: true
cloud_enabled: true cloud_enabled: true
cloud_sorting: "name" cloud_sorting: "name"
@@ -17,6 +17,6 @@ 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
use_regex_component_replacer: false
detect_malicious_expansions: true detect_malicious_expansions: true
use_adventure_provided_replacer: false
debug: false debug: false

View File

@@ -12,6 +12,8 @@ commands:
placeholderapi: placeholderapi:
description: "PlaceholderAPI Command" description: "PlaceholderAPI Command"
aliases: ["papi"] aliases: ["papi"]
test:
description: "yes"
permissions: permissions:
placeholderapi.*: placeholderapi.*:

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,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