mirror of
https://github.com/PlaceholderAPI/PlaceholderAPI
synced 2026-02-08 00:42:47 +01:00
Compare commits
27 Commits
folia
...
feature/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d81cc443b | ||
|
|
2d686b679f | ||
|
|
5fbc5ee1cb | ||
|
|
4378a439fc | ||
|
|
85aa6ae8ae | ||
|
|
83aad38b09 | ||
|
|
b0fb784079 | ||
|
|
84948101f4 | ||
|
|
5dea70532c | ||
|
|
403adeb217 | ||
|
|
a81ed63c0f | ||
|
|
38da700168 | ||
|
|
4a085682dc | ||
|
|
cfed3ce31b | ||
|
|
4c62318338 | ||
|
|
7247cbb9f7 | ||
|
|
9ed7a7ae56 | ||
|
|
9a356ceecf | ||
|
|
e0ac7b1c66 | ||
|
|
82230d8156 | ||
|
|
cda55f20aa | ||
|
|
0df7a01fd8 | ||
|
|
b49668ddee | ||
|
|
f14b081f0b | ||
|
|
b51fbf4e13 | ||
|
|
e48b6fe702 | ||
|
|
984f944daf |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -38,7 +38,7 @@ PlaceholderAPI provides a feature to have expansions (separate jar files) for pl
|
|||||||
In those cases should you report the issue to the issue tracker of the expansion or plugin.
|
In those cases should you report the issue to the issue tracker of the expansion or plugin.
|
||||||
|
|
||||||
## Pull requests
|
## Pull requests
|
||||||
As an open source project are we welcoming all contributions to improve PlaceholderAPI, being it changes to its code, or contributions to its documentation such as the [Wiki] or the Javadocs.
|
As an open source project we are welcoming all contributions to improve PlaceholderAPI, being it changes to its code, or contributions to its documentation such as the [Wiki] or the Javadocs.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> When contributing, make sure to both base of and target the mentioned branch. Pull requests targeting the wrong branch may get closed without a warning.
|
> When contributing, make sure to both base of and target the mentioned branch. Pull requests targeting the wrong branch may get closed without a warning.
|
||||||
|
|||||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -21,7 +21,7 @@
|
|||||||
### Description
|
### Description
|
||||||
<!-- What does your Pull request change? -->
|
<!-- What does your Pull request change? -->
|
||||||
|
|
||||||
Closes N/A <!-- If your PR is based on an issue, change "N/A" the the issue ID (#id) -->
|
Closes N/A <!-- If your PR is based on an issue, change "N/A" to the issue ID (#id) -->
|
||||||
|
|
||||||
|
|
||||||
<!-- DO NOT ALTER ANYTHING BELOW THIS LINE! -->
|
<!-- DO NOT ALTER ANYTHING BELOW THIS LINE! -->
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
[discord]: https://helpch.at/discord
|
[discord]: https://helpch.at/discord
|
||||||
[spigot]: https://www.spigotmc.org/resources/6245/
|
[spigot]: https://www.spigotmc.org/resources/6245/
|
||||||
[hangar]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
|
[hangar]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
|
||||||
[bbb]: https://builtbybit.com/resources/placeholderapi.24306
|
[modrinth]: https://modrinth.com/plugin/placeholderapi
|
||||||
[Expansions cloud]: https://api.extendedclip.com/home
|
[Expansions cloud]: https://ecloud.placeholderapi.com
|
||||||
[placeholder list]: https://helpch.at/placeholders
|
[placeholder list]: https://helpch.at/placeholders
|
||||||
[statistics]: https://bstats.org/plugin/bukkit/PlaceholderAPI
|
[statistics]: https://bstats.org/plugin/bukkit/PlaceholderAPI
|
||||||
|
|
||||||
@@ -50,5 +50,5 @@ If you would like to create your own Placeholder Expansion for PlaceholderAPI, t
|
|||||||
- [Placeholder List]
|
- [Placeholder List]
|
||||||
- [Spigot Page][spigot]
|
- [Spigot Page][spigot]
|
||||||
- [Hangar Page][hangar]
|
- [Hangar Page][hangar]
|
||||||
- [BuiltByBit Page][bbb]
|
- [Modrinth Page][modrinth]
|
||||||
- [Plugin Statistics][statistics]
|
- [Plugin Statistics][statistics]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "me.clip"
|
group = "me.clip"
|
||||||
version = "2.11.7-DEV-${System.getProperty("BUILD_NUMBER")}"
|
version = "2.11.8-DEV-${System.getProperty("BUILD_NUMBER")}"
|
||||||
|
|
||||||
description = "An awesome placeholder provider!"
|
description = "An awesome placeholder provider!"
|
||||||
|
|
||||||
@@ -25,9 +25,10 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.bstats:bstats-bukkit:3.0.1")
|
implementation("org.bstats:bstats-bukkit:3.0.1")
|
||||||
implementation("net.kyori:adventure-platform-bukkit:4.3.3")
|
implementation("net.kyori:adventure-platform-bukkit:4.4.1")
|
||||||
|
|
||||||
//compileOnly("org.spigotmc:spigot-api:1.21-R0.1-SNAPSHOT")
|
//compileOnly("org.spigotmc:spigot-api:1.21-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.20.1-R0.1-SNAPSHOT")
|
||||||
compileOnlyApi("org.jetbrains:annotations:23.0.0")
|
compileOnlyApi("org.jetbrains:annotations:23.0.0")
|
||||||
|
|
||||||
@@ -45,6 +46,8 @@ java {
|
|||||||
|
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
|
|
||||||
|
disableAutoTargetJvm()
|
||||||
}
|
}
|
||||||
|
|
||||||
license {
|
license {
|
||||||
@@ -90,7 +93,12 @@ tasks {
|
|||||||
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/**")
|
||||||
}
|
}
|
||||||
|
|||||||
121
src/main/java/me/clip/placeholderapi/PAPIComponents.java
Normal file
121
src/main/java/me/clip/placeholderapi/PAPIComponents.java
Normal 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;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ 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;
|
||||||
@@ -46,11 +47,12 @@ public final class PlaceholderAPI {
|
|||||||
private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT);
|
private static final Replacer REPLACER_PERCENT = new CharsReplacer(Closure.PERCENT);
|
||||||
private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET);
|
private static final Replacer REPLACER_BRACKET = new CharsReplacer(Closure.BRACKET);
|
||||||
|
|
||||||
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
|
static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("[%]([^%]+)[%]");
|
||||||
private static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
|
static final Pattern BRACKET_PLACEHOLDER_PATTERN = Pattern.compile("[{]([^{}]+)[}]");
|
||||||
private 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() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@
|
|||||||
package me.clip.placeholderapi;
|
package me.clip.placeholderapi;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommandRouter;
|
import me.clip.placeholderapi.commands.PlaceholderCommandRouter;
|
||||||
|
import me.clip.placeholderapi.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;
|
||||||
@@ -34,6 +34,7 @@ import me.clip.placeholderapi.listeners.ServerLoadEventListener;
|
|||||||
import me.clip.placeholderapi.scheduler.UniversalScheduler;
|
import me.clip.placeholderapi.scheduler.UniversalScheduler;
|
||||||
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
import me.clip.placeholderapi.scheduler.scheduling.schedulers.TaskScheduler;
|
||||||
import me.clip.placeholderapi.updatechecker.UpdateChecker;
|
import me.clip.placeholderapi.updatechecker.UpdateChecker;
|
||||||
|
import me.clip.placeholderapi.util.ExpansionSafetyCheck;
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
import org.bstats.bukkit.Metrics;
|
import org.bstats.bukkit.Metrics;
|
||||||
@@ -93,6 +94,8 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
|
|||||||
|
|
||||||
private BukkitAudiences adventure;
|
private BukkitAudiences adventure;
|
||||||
|
|
||||||
|
private BukkitAudiences adventure;
|
||||||
|
private boolean safetyCheck = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API
|
* Gets the static instance of the main class for PlaceholderAPI. This class is not the actual API
|
||||||
@@ -152,17 +155,29 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
|
|||||||
public void onLoad() {
|
public void onLoad() {
|
||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
saveDefaultConfig();
|
saveDefaultConfig();
|
||||||
|
|
||||||
|
safetyCheck = new ExpansionSafetyCheck(this).runChecks();
|
||||||
|
|
||||||
|
if (safetyCheck) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
if (safetyCheck) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setupCommand();
|
setupCommand();
|
||||||
setupMetrics();
|
setupMetrics();
|
||||||
setupExpansions();
|
setupExpansions();
|
||||||
|
|
||||||
adventure = BukkitAudiences.create(this);
|
|
||||||
|
|
||||||
if (config.isCloudEnabled()) {
|
if (config.isCloudEnabled()) {
|
||||||
getCloudExpansionManager().load();
|
getCloudExpansionManager().load();
|
||||||
}
|
}
|
||||||
@@ -177,7 +192,14 @@ public final class PlaceholderAPIPlugin extends JavaPlugin {
|
|||||||
getCloudExpansionManager().kill();
|
getCloudExpansionManager().kill();
|
||||||
getLocalExpansionManager().kill();
|
getLocalExpansionManager().kill();
|
||||||
|
|
||||||
HandlerList.unregisterAll(this);
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
if (safetyCheck) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCloudExpansionManager().kill();
|
||||||
|
getLocalExpansionManager().kill();
|
||||||
|
|
||||||
scheduler.cancelTasks(this);
|
scheduler.cancelTasks(this);
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ package me.clip.placeholderapi.commands;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package me.clip.placeholderapi.commands;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -30,6 +31,7 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import 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;
|
||||||
|
|||||||
@@ -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)));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
package me.clip.placeholderapi.commands.impl.cloud;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
@@ -64,9 +65,32 @@ public final class CommandECloudDownload extends PlaceholderCommand {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final CloudExpansion expansion = plugin.getCloudExpansionManager()
|
final CloudExpansion.Version version;
|
||||||
.findCloudExpansionByName(params.get(0)).orElse(null);
|
if (params.size() < 2) {
|
||||||
if (expansion == null) {
|
version = expansion.getVersion(expansion.getLatestVersion());
|
||||||
|
if (version == null) {
|
||||||
|
Msg.msg(sender,
|
||||||
|
"&cCould not find latest version for expansion.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
version = expansion.getVersion(params.get(1));
|
||||||
|
if (version == null) {
|
||||||
|
Msg.msg(sender,
|
||||||
|
"&cCould not find specified version: &f" + params.get(1),
|
||||||
|
"&7Available versions: &f" + expansion.getAvailableVersions());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!version.isVerified()) {
|
||||||
|
Msg.msg(sender, "&cThe expansion '&f" + params.get(0) + "&c' is not verified and can only be downloaded manually from &fhttps://ecloud.placeholderapi.com");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getCloudExpansionManager().downloadExpansion(expansion, version)
|
||||||
|
.whenComplete((file, exception) -> {
|
||||||
|
if (exception != null) {
|
||||||
Msg.msg(sender,
|
Msg.msg(sender,
|
||||||
"&cFailed to find an expansion named: &f" + params.get(0));
|
"&cFailed to find an expansion named: &f" + params.get(0));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ package me.clip.placeholderapi.commands.impl.cloud;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
@@ -55,17 +56,12 @@ 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())
|
||||||
.append('\n')
|
.append('\n')
|
||||||
.append("&bAuthor: &f")
|
.append("&bAuthor: &f")
|
||||||
.append(expansion.getAuthor())
|
.append(expansion.getAuthor())
|
||||||
.append('\n')
|
|
||||||
.append("&bVerified: ")
|
|
||||||
.append(expansion.isVerified() ? "&a&l✔" : "&c&l❌")
|
|
||||||
.append('\n');
|
.append('\n');
|
||||||
|
|
||||||
if (params.size() < 2) {
|
if (params.size() < 2) {
|
||||||
@@ -76,6 +72,9 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand {
|
|||||||
.append(expansion.getTimeSinceLastUpdate())
|
.append(expansion.getTimeSinceLastUpdate())
|
||||||
.append(" ago")
|
.append(" ago")
|
||||||
.append('\n')
|
.append('\n')
|
||||||
|
.append("&bVerified: ")
|
||||||
|
.append(expansion.getVersion().isVerified() ? "&a&l✔" : "&c&l❌")
|
||||||
|
.append('\n')
|
||||||
.append("&bRelease Notes: &f")
|
.append("&bRelease Notes: &f")
|
||||||
.append(expansion.getVersion().getReleaseNotes())
|
.append(expansion.getVersion().getReleaseNotes())
|
||||||
.append('\n');
|
.append('\n');
|
||||||
@@ -88,6 +87,20 @@ public final class CommandECloudExpansionInfo extends PlaceholderCommand {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.append("&bVersion: &f")
|
||||||
|
.append(version.getVersion())
|
||||||
|
.append('\n')
|
||||||
|
.append("&bVerified: ")
|
||||||
|
.append(version.isVerified() ? "&a&l✔" : "&c&l❌")
|
||||||
|
.append('\n')
|
||||||
|
.append("&bRelease Notes: &f")
|
||||||
|
.append(version.getReleaseNotes())
|
||||||
|
.append('\n')
|
||||||
|
.append("&bDownload URL: &f")
|
||||||
|
.append(version.getUrl())
|
||||||
|
.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
builder.append("&bVersion: &f")
|
builder.append("&bVersion: &f")
|
||||||
.append(version.getVersion())
|
.append(version.getVersion())
|
||||||
.append('\n')
|
.append('\n')
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ import com.google.common.collect.ImmutableSet;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.configuration.ExpansionSort;
|
import me.clip.placeholderapi.configuration.ExpansionSort;
|
||||||
@@ -65,7 +67,7 @@ public final class CommandECloudExpansionList extends PlaceholderCommand {
|
|||||||
expansion -> "&f" + expansion.getAuthor();
|
expansion -> "&f" + expansion.getAuthor();
|
||||||
@NotNull
|
@NotNull
|
||||||
private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED =
|
private static final Function<CloudExpansion, Object> EXPANSION_VERIFIED =
|
||||||
expansion -> expansion.isVerified() ? "&aY" : "&cN";
|
expansion -> expansion.getVersion().isVerified() ? "&aY" : "&cN";
|
||||||
@NotNull
|
@NotNull
|
||||||
private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION =
|
private static final Function<CloudExpansion, Object> EXPANSION_LATEST_VERSION =
|
||||||
expansion -> "&f" + expansion.getLatestVersion();
|
expansion -> "&f" + expansion.getLatestVersion();
|
||||||
@@ -173,11 +175,14 @@ public final class CommandECloudExpansionList extends PlaceholderCommand {
|
|||||||
.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())
|
final TextComponent.Builder hoverText = text("Click to download this expansion!", AQUA)
|
||||||
.filter(description -> !description.isEmpty())
|
.append(newline()).append(newline())
|
||||||
.ifPresent(description -> hoverText.append(newline()).append(newline())
|
.append(text("Author: ", AQUA)).append(text(expansion.getAuthor(), WHITE))
|
||||||
.append(text(description.replace("\r", "").trim(), WHITE))
|
.append(newline())
|
||||||
);
|
.append(text("Verified: ", AQUA)).append(text(expansion.getVersion().isVerified() ? "✔" : "❌", expansion.getVersion().isVerified() ? GREEN : RED, TextDecoration.BOLD))
|
||||||
|
.append(newline())
|
||||||
|
.append(text("Released: ", AQUA)).append(text(format.format(expansion.getLastUpdate()), WHITE))
|
||||||
|
.toBuilder();
|
||||||
|
|
||||||
line.hoverEvent(HoverEvent.showText(hoverText.build()));
|
line.hoverEvent(HoverEvent.showText(hoverText.build()));
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,11 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
package me.clip.placeholderapi.commands.impl.cloud;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
package me.clip.placeholderapi.commands.impl.cloud;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
package me.clip.placeholderapi.commands.impl.cloud;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;
|
import me.clip.placeholderapi.expansion.manager.CloudExpansionManager;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.cloud;
|
package me.clip.placeholderapi.commands.impl.cloud;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -28,6 +29,7 @@ import java.util.Objects;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package me.clip.placeholderapi.commands.impl.local;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.local;
|
package me.clip.placeholderapi.commands.impl.local;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.local;
|
package me.clip.placeholderapi.commands.impl.local;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
|
|||||||
@@ -21,9 +21,11 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.local;
|
package me.clip.placeholderapi.commands.impl.local;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.util.List;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPI;
|
import me.clip.placeholderapi.PlaceholderAPI;
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
|
|||||||
@@ -21,8 +21,10 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.local;
|
package me.clip.placeholderapi.commands.impl.local;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
|
import me.clip.placeholderapi.util.ExpansionSafetyCheck;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
@@ -37,7 +39,9 @@ public final class CommandReload extends PlaceholderCommand {
|
|||||||
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
public void evaluate(@NotNull final PlaceholderAPIPlugin plugin,
|
||||||
@NotNull final CommandSender sender, @NotNull final String alias,
|
@NotNull final CommandSender sender, @NotNull final String alias,
|
||||||
@NotNull @Unmodifiable final List<String> params) {
|
@NotNull @Unmodifiable final List<String> params) {
|
||||||
|
if (!new ExpansionSafetyCheck(plugin).runChecks()) {
|
||||||
plugin.reloadConf(sender);
|
plugin.reloadConf(sender);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.commands.impl.local;
|
package me.clip.placeholderapi.commands.impl.local;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
import me.clip.placeholderapi.commands.PlaceholderCommand;
|
||||||
import me.clip.placeholderapi.util.Msg;
|
import me.clip.placeholderapi.util.Msg;
|
||||||
|
|||||||
@@ -86,4 +86,8 @@ public final class PlaceholderAPIConfig {
|
|||||||
return plugin.getConfig().getString("boolean.false", "false");
|
return plugin.getConfig().getString("boolean.false", "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean detectMaliciousExpansions() {
|
||||||
|
return plugin.getConfig().getBoolean("detect_malicious_expansions", true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ package me.clip.placeholderapi.events;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
|
|||||||
@@ -51,7 +51,12 @@ public enum NMSVersion {
|
|||||||
SPIGOT_1_20_R2("v1_20_R2"),
|
SPIGOT_1_20_R2("v1_20_R2"),
|
||||||
SPIGOT_1_20_R3("v1_20_R3"),
|
SPIGOT_1_20_R3("v1_20_R3"),
|
||||||
SPIGOT_1_20_R4("v1_20_R4"),
|
SPIGOT_1_20_R4("v1_20_R4"),
|
||||||
SPIGOT_1_21_R1("v1_21_R1");
|
SPIGOT_1_21_R1("v1_21_R1"),
|
||||||
|
SPIGOT_1_21_R2("V1_21_R2"),
|
||||||
|
SPIGOT_1_21_R3("V1_21_R3"),
|
||||||
|
SPIGOT_1_21_R4("V1_21_R4"),
|
||||||
|
SPIGOT_1_21_R5("V1_21_R5"),
|
||||||
|
SPIGOT_1_21_R6("V1_21_R6");
|
||||||
|
|
||||||
private final String version;
|
private final String version;
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ package me.clip.placeholderapi.expansion.cloud;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.clip.placeholderapi.util.TimeUtil;
|
import me.clip.placeholderapi.util.TimeUtil;
|
||||||
|
|
||||||
|
|
||||||
@@ -36,8 +37,7 @@ public class CloudExpansion {
|
|||||||
dependency_url;
|
dependency_url;
|
||||||
|
|
||||||
private boolean hasExpansion,
|
private boolean hasExpansion,
|
||||||
shouldUpdate,
|
shouldUpdate;
|
||||||
verified;
|
|
||||||
|
|
||||||
private long last_update,
|
private long last_update,
|
||||||
ratings_count;
|
ratings_count;
|
||||||
@@ -135,10 +135,6 @@ public class CloudExpansion {
|
|||||||
this.shouldUpdate = shouldUpdate;
|
this.shouldUpdate = shouldUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVerified() {
|
|
||||||
return verified;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastUpdate() {
|
public long getLastUpdate() {
|
||||||
return last_update;
|
return last_update;
|
||||||
}
|
}
|
||||||
@@ -174,6 +170,7 @@ public class CloudExpansion {
|
|||||||
public static class Version {
|
public static class Version {
|
||||||
|
|
||||||
private String url, version, release_notes;
|
private String url, version, release_notes;
|
||||||
|
private boolean verified;
|
||||||
|
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return url;
|
||||||
@@ -199,4 +196,13 @@ public class CloudExpansion {
|
|||||||
this.release_notes = release_notes;
|
this.release_notes = release_notes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isVerified() {
|
||||||
|
return verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVerified(boolean verified) {
|
||||||
|
this.verified = verified;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.google.common.io.Resources;
|
|||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -50,6 +51,7 @@ import java.util.function.Function;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collector;
|
import java.util.stream.Collector;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
import me.clip.placeholderapi.expansion.cloud.CloudExpansion;
|
||||||
@@ -60,7 +62,7 @@ import org.jetbrains.annotations.Unmodifiable;
|
|||||||
public final class CloudExpansionManager {
|
public final class CloudExpansionManager {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static final String API_URL = "http://api.extendedclip.com/v2/";
|
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();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package me.clip.placeholderapi.expansion.manager;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -38,6 +39,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import me.clip.placeholderapi.events.ExpansionRegisterEvent;
|
import me.clip.placeholderapi.events.ExpansionRegisterEvent;
|
||||||
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
|
import me.clip.placeholderapi.events.ExpansionUnregisterEvent;
|
||||||
@@ -213,6 +215,7 @@ public final class LocalExpansionManager implements Listener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to register a {@link PlaceholderExpansion}
|
* Attempt to register a {@link PlaceholderExpansion}
|
||||||
|
*
|
||||||
* @param expansion the expansion to register
|
* @param expansion the expansion to register
|
||||||
* @return if the expansion was registered
|
* @return if the expansion was registered
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package me.clip.placeholderapi.replacer;
|
|||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
@@ -43,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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package me.clip.placeholderapi.replacer;
|
||||||
|
|
||||||
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class ExactReplacer implements Replacer {
|
||||||
|
private static final Pattern DELIMITER = Pattern.compile("_");
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String apply(@NotNull String text, @Nullable final OfflinePlayer player,
|
||||||
|
@NotNull final Function<String, @Nullable PlaceholderExpansion> lookup) {
|
||||||
|
text = text.substring(1, text.length() - 1);
|
||||||
|
final String[] parts = DELIMITER.split(text);
|
||||||
|
final PlaceholderExpansion expansion;
|
||||||
|
|
||||||
|
if (parts.length == 0) {
|
||||||
|
expansion = lookup.apply(text);
|
||||||
|
} else {
|
||||||
|
expansion = lookup.apply(parts[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expansion == null) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String params;
|
||||||
|
|
||||||
|
if (text.endsWith("_")) {
|
||||||
|
params = "";
|
||||||
|
} else {
|
||||||
|
params = text.substring(text.indexOf('_') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String result = expansion.onRequest(player, params);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
package me.clip.placeholderapi.replacer;
|
package me.clip.placeholderapi.replacer;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public interface TaskScheduler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia</b>: Returns whether the current thread is ticking the global region <br>
|
* <b>Folia</b>: Returns whether the current thread is ticking the global region <br>
|
||||||
* <b>Paper & Bukkit</b>: Returns {@link org.bukkit.Server#isPrimaryThread}
|
* <b>Paper and Bukkit</b>: Returns {@link org.bukkit.Server#isPrimaryThread}
|
||||||
*/
|
*/
|
||||||
boolean isGlobalThread();
|
boolean isGlobalThread();
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ public interface TaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Returns whether the current thread is ticking a region and that the region
|
* <b>Folia and Paper</b>: Returns whether the current thread is ticking a region and that the region
|
||||||
* being ticked owns the specified entity. Note that this function is the only appropriate method of
|
* being ticked owns the specified entity. Note that this function is the only appropriate method of
|
||||||
* checking for ownership of an entity, as retrieving the entity's location is undefined unless the
|
* checking for ownership of an entity, as retrieving the entity's location is undefined unless the
|
||||||
* entity is owned by the current region
|
* entity is owned by the current region
|
||||||
@@ -61,7 +61,7 @@ public interface TaskScheduler {
|
|||||||
boolean isEntityThread(Entity entity);
|
boolean isEntityThread(Entity entity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Returns whether the current thread is ticking a region and that the region
|
* <b>Folia and Paper</b>: Returns whether the current thread is ticking a region and that the region
|
||||||
* being ticked owns the chunk at the specified world and block position as included in the specified location
|
* being ticked owns the chunk at the specified world and block position as included in the specified location
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Bukkit</b>: returns {@link org.bukkit.Server#isPrimaryThread}
|
* <b>Bukkit</b>: returns {@link org.bukkit.Server#isPrimaryThread}
|
||||||
@@ -72,7 +72,7 @@ public interface TaskScheduler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules a task to be executed on the next tick <br>
|
* Schedules a task to be executed on the next tick <br>
|
||||||
* <b>Folia & Paper</b>: ...on the global region <br>
|
* <b>Folia and Paper</b>: ...on the global region <br>
|
||||||
* <b>Bukkit</b>: ...on the main thread
|
* <b>Bukkit</b>: ...on the main thread
|
||||||
*
|
*
|
||||||
* @param runnable The task to execute
|
* @param runnable The task to execute
|
||||||
@@ -81,7 +81,7 @@ public interface TaskScheduler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules a task to be executed after the specified delay in ticks <br>
|
* Schedules a task to be executed after the specified delay in ticks <br>
|
||||||
* <b>Folia & Paper</b>: ...on the global region <br>
|
* <b>Folia and Paper</b>: ...on the global region <br>
|
||||||
* <b>Bukkit</b>: ...on the main thread
|
* <b>Bukkit</b>: ...on the main thread
|
||||||
*
|
*
|
||||||
* @param runnable The task to execute
|
* @param runnable The task to execute
|
||||||
@@ -91,7 +91,7 @@ public interface TaskScheduler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules a repeating task to be executed after the initial delay with the specified period <br>
|
* Schedules a repeating task to be executed after the initial delay with the specified period <br>
|
||||||
* <b>Folia & Paper</b>: ...on the global region <br>
|
* <b>Folia and Paper</b>: ...on the global region <br>
|
||||||
* <b>Bukkit</b>: ...on the main thread
|
* <b>Bukkit</b>: ...on the main thread
|
||||||
*
|
*
|
||||||
* @param runnable The task to execute
|
* @param runnable The task to execute
|
||||||
@@ -125,7 +125,7 @@ public interface TaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Schedules a task to be executed on the region which owns the location on the next tick
|
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location on the next tick
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Bukkit</b>: same as {@link #runTask(Runnable)}
|
* <b>Bukkit</b>: same as {@link #runTask(Runnable)}
|
||||||
*
|
*
|
||||||
@@ -137,7 +137,7 @@ public interface TaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Schedules a task to be executed on the region which owns the location after the
|
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location after the
|
||||||
* specified delay in ticks
|
* specified delay in ticks
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskLater(Runnable, long)}
|
* <b>Bukkit</b>: same as {@link #runTaskLater(Runnable, long)}
|
||||||
@@ -151,7 +151,7 @@ public interface TaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Schedules a repeating task to be executed on the region which owns the location
|
* <b>Folia and Paper</b>: Schedules a repeating task to be executed on the region which owns the location
|
||||||
* after the initial delay with the specified period
|
* after the initial delay with the specified period
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskTimer(Runnable, long, long)}
|
* <b>Bukkit</b>: same as {@link #runTaskTimer(Runnable, long, long)}
|
||||||
@@ -190,7 +190,7 @@ public interface TaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Schedules a task to be executed on the region which owns the location
|
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location
|
||||||
* of given entity on the next tick
|
* of given entity on the next tick
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Bukkit</b>: same as {@link #runTask(Runnable)}
|
* <b>Bukkit</b>: same as {@link #runTask(Runnable)}
|
||||||
@@ -203,7 +203,7 @@ public interface TaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Schedules a task to be executed on the region which owns the location
|
* <b>Folia and Paper</b>: Schedules a task to be executed on the region which owns the location
|
||||||
* of given entity after the specified delay in ticks
|
* of given entity after the specified delay in ticks
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskLater(Runnable, long)}
|
* <b>Bukkit</b>: same as {@link #runTaskLater(Runnable, long)}
|
||||||
@@ -217,7 +217,7 @@ public interface TaskScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Folia & Paper</b>: Schedules a repeating task to be executed on the region which owns the
|
* <b>Folia and Paper</b>: Schedules a repeating task to be executed on the region which owns the
|
||||||
* location of given entity after the initial delay with the specified period
|
* location of given entity after the initial delay with the specified period
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Bukkit</b>: same as {@link #runTaskTimer(Runnable, long, long)}
|
* <b>Bukkit</b>: same as {@link #runTaskTimer(Runnable, long, long)}
|
||||||
@@ -285,7 +285,7 @@ public interface TaskScheduler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls a method on the main thread and returns a Future object. This task will be executed
|
* Calls a method on the main thread and returns a Future object. This task will be executed
|
||||||
* by the main(Bukkit)/global(Folia&Paper) server thread.
|
* by the main(Bukkit)/global(FoliaandPaper) server thread.
|
||||||
* <p>
|
* <p>
|
||||||
* Note: The Future.get() methods must NOT be called from the main thread.
|
* Note: The Future.get() methods must NOT be called from the main thread.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package me.clip.placeholderapi.util;
|
||||||
|
|
||||||
|
import com.google.common.hash.Hashing;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public final class ExpansionSafetyCheck {
|
||||||
|
private static final String MESSAGE =
|
||||||
|
"\n###############################################\n" +
|
||||||
|
"###############################################\n" +
|
||||||
|
"PlaceholderAPI performs checks at startup and /papi reload for known malicious expansions. If you're seeing this message, there are the following malicious expansions in plugins/PlaceholderAPI/expansions.\n" +
|
||||||
|
"%s" +
|
||||||
|
"To prevent further infection PlaceholderAPI has stopped the server.\n" +
|
||||||
|
"If you're seeing this message after updating PAPI, your server may have been infected for some time, so best practice is a complete system wipe and reinstall of your server software and plugins to be safe.\n" +
|
||||||
|
"If you're seeing this after downloading an expansion however, PAPI hasn't loaded any of the malicious expansions above so you should be safe to simply delete the expansion in question.\n" +
|
||||||
|
"###############################################\n" +
|
||||||
|
"###############################################";
|
||||||
|
|
||||||
|
private final PlaceholderAPIPlugin main;
|
||||||
|
|
||||||
|
public ExpansionSafetyCheck(@NotNull final PlaceholderAPIPlugin main) {
|
||||||
|
this.main = main;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean runChecks() {
|
||||||
|
if (!main.getPlaceholderAPIConfig().detectMaliciousExpansions()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final File expansionsFolder = new File(main.getDataFolder(), "expansions");
|
||||||
|
|
||||||
|
if (!expansionsFolder.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<String> knownMaliciousExpansions;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String hashes = Resources.toString(new URL("https://check.placeholderapi.com"), StandardCharsets.UTF_8);
|
||||||
|
knownMaliciousExpansions = Arrays.stream(hashes.split("\n")).collect(Collectors.toSet());
|
||||||
|
} catch (Exception e) {
|
||||||
|
main.getLogger().log(Level.SEVERE, "Failed to download anti malware hash check list from https://check.placeholderapi.com", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<String> maliciousPaths = new HashSet<>();
|
||||||
|
|
||||||
|
for (File file : expansionsFolder.listFiles()) {
|
||||||
|
try {
|
||||||
|
final String hash = Hashing.sha256().hashBytes(Files.asByteSource(file).read()).toString();
|
||||||
|
|
||||||
|
if (knownMaliciousExpansions.contains(hash)) {
|
||||||
|
maliciousPaths.add(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
main.getLogger().log(Level.SEVERE, "Error occurred while trying to read " + file.getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maliciousPaths.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
main.getLogger().severe(String.format(MESSAGE, maliciousPaths.stream().map(p -> "HASH OF " + p + " MATCHES KNOWN MALICIOUS EXPANSION DELETE IMMEDIATELY\n").collect(Collectors.joining())));
|
||||||
|
|
||||||
|
main.getServer().shutdown();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import static java.util.stream.IntStream.range;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ package me.clip.placeholderapi.util;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
import me.clip.placeholderapi.PlaceholderAPIPlugin;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
# Discord: https://helpch.at/discord
|
# Discord: https://helpch.at/discord
|
||||||
# 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"
|
||||||
@@ -15,4 +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
|
||||||
debug: false
|
debug: false
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ commands:
|
|||||||
placeholderapi:
|
placeholderapi:
|
||||||
description: "PlaceholderAPI Command"
|
description: "PlaceholderAPI Command"
|
||||||
aliases: ["papi"]
|
aliases: ["papi"]
|
||||||
|
test:
|
||||||
|
description: "yes"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
placeholderapi.*:
|
placeholderapi.*:
|
||||||
|
|||||||
Reference in New Issue
Block a user