From 18190c8b389e6181fd7a784f9c16a607aef9b9ef Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Feb 2026 20:29:17 +0800
Subject: [PATCH 1/8] don't create a new Function every time
Configurable#getConfig is called
---
.../configuration/PlaceholderAPIConfig.java | 2 +-
.../expansion/Configurable.java | 20 +++++++++++++++----
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/src/main/java/at/helpch/placeholderapi/configuration/PlaceholderAPIConfig.java b/src/main/java/at/helpch/placeholderapi/configuration/PlaceholderAPIConfig.java
index 3fcf999..21f98c8 100644
--- a/src/main/java/at/helpch/placeholderapi/configuration/PlaceholderAPIConfig.java
+++ b/src/main/java/at/helpch/placeholderapi/configuration/PlaceholderAPIConfig.java
@@ -98,7 +98,7 @@ public final class PlaceholderAPIConfig {
}
@NotNull
- public Map expansions() {
+ public ConcurrentHashMap expansions() {
return expansions;
}
diff --git a/src/main/java/at/helpch/placeholderapi/expansion/Configurable.java b/src/main/java/at/helpch/placeholderapi/expansion/Configurable.java
index df7dda1..20f358d 100644
--- a/src/main/java/at/helpch/placeholderapi/expansion/Configurable.java
+++ b/src/main/java/at/helpch/placeholderapi/expansion/Configurable.java
@@ -24,6 +24,7 @@ import at.helpch.placeholderapi.PlaceholderAPIPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Implementing this interface allows {@link at.helpch.placeholderapi.expansion.PlaceholderExpansion PlaceholderExpansions}
@@ -43,20 +44,31 @@ import java.util.Map;
* @author Ryan McCarthy
*/
public interface Configurable {
-
@NotNull
Class provideConfigType();
@NotNull
T provideDefault();
+ @SuppressWarnings("unchecked")
@NotNull
default T getConfig() {
- if (this instanceof PlaceholderExpansion exp) {
- return (T) PlaceholderAPIPlugin.instance().configManager().config().expansions().computeIfAbsent(exp.getIdentifier(), s -> provideDefault());
+ if (!(this instanceof PlaceholderExpansion exp)) {
+ return provideDefault();
}
- return provideDefault();
+ final ConcurrentHashMap expansionConfigs = PlaceholderAPIPlugin.instance().configManager().config().expansions();
+ final String key = exp.getIdentifier();
+
+ final Object existing = expansionConfigs.get(key);
+ if (existing != null) {
+ return (T) existing;
+ }
+
+ final T def = provideDefault();
+ final Object conf = expansionConfigs.putIfAbsent(key, def);
+
+ return (T) (conf != null ? conf : def);
}
// /**
From d338e49b2713093f3fbe08c8874def3a6aef0483 Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Feb 2026 20:30:58 +0800
Subject: [PATCH 2/8] 1.0.8 dev
---
build.gradle.kts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 55e1262..bc286c8 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -7,7 +7,7 @@ plugins {
}
group = "at.helpch"
-version = "1.0.7"
+version = "1.0.8-DEV-${System.getProperty("BUILD_NUMBER")}"
description = "An awesome placeholder provider!"
From ecfbd35784a336d73e49a0f18c412423f88cbb6f Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Mar 2026 18:21:08 +0800
Subject: [PATCH 3/8] set server version manually
---
src/main/resources/manifest.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/resources/manifest.json b/src/main/resources/manifest.json
index 1a03dda..c37510c 100644
--- a/src/main/resources/manifest.json
+++ b/src/main/resources/manifest.json
@@ -5,7 +5,7 @@
"Description": "An awesome placeholder provider",
"Authors": [{"Name": "HelpChat"}],
"Website": "https://placeholderapi.com",
- "ServerVersion": "*",
+ "ServerVersion": "2026.03.26-89796e57b",
"Dependencies": {},
"OptionalDependencies": {},
"DisabledByDefault": false,
From 79deb5f7d2f71293b938d09f4930d8c256a910a5 Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Mar 2026 18:23:15 +0800
Subject: [PATCH 4/8] pull new chars replacer from main papi
---
.../replacer/CharsReplacer.java | 160 ++++++++++--------
1 file changed, 87 insertions(+), 73 deletions(-)
diff --git a/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java b/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java
index 9c443e5..7e67215 100644
--- a/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java
+++ b/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java
@@ -24,7 +24,6 @@ import java.util.Locale;
import java.util.function.Function;
import at.helpch.placeholderapi.expansion.PlaceholderExpansion;
-import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,98 +37,113 @@ public final class CharsReplacer implements Replacer {
this.closure = closure;
}
-
+ /**
+ * Translates placeholders within the provided text using a high-performance
+ * character-scanning approach.
+ * * The method identifies placeholders delimited by the defined {@link Closure}
+ * (e.g., %identifier_params% or {identifier_params}). If a placeholder is
+ * successfully identified, the provided lookup function is used to fetch the
+ * corresponding {@link PlaceholderExpansion}.
+ *
+ * @param text The raw text containing potential placeholders to be replaced.
+ * @param player The {@link OfflinePlayer} to contextually parse the placeholders against.
+ * May be {@code null} if no player context is available.
+ * @param lookup A function that maps a lowercase identifier string to a registered
+ * {@link PlaceholderExpansion}.
+ * @return A string with all valid placeholders replaced by their respective values.
+ * Returns the original text if no placeholders are found.
+ */
@NotNull
@Override
public String apply(@NotNull final String text, @Nullable final PlayerRef player,
@NotNull final Function lookup) {
- final char[] chars = text.toCharArray();
- final StringBuilder builder = new StringBuilder(text.length());
+ final char head = closure.head;
+ int startPlaceholder = text.indexOf(head);
- final StringBuilder identifier = new StringBuilder();
- final StringBuilder parameters = new StringBuilder();
+ if (startPlaceholder == -1) {
+ return text;
+ }
- for (int i = 0; i < chars.length; i++) {
- final char l = chars[i];
+ final int length = text.length();
+ final StringBuilder builder = new StringBuilder(length + (length >> 3));
+ int cursor = 0;
- if (l != closure.head || i + 1 >= chars.length) {
- builder.append(l);
+ final char tail = closure.tail;
+
+ loop: do {
+ // Append plain text preceding the placeholder
+ if (startPlaceholder > cursor) {
+ builder.append(text, cursor, startPlaceholder);
+ }
+
+ final int endPlaceholder = text.indexOf(tail, startPlaceholder + 1);
+
+ if (endPlaceholder == -1) {
+ builder.append(text, startPlaceholder, length);
+ return builder.toString();
+ }
+
+ int underscoreIndex = -1;
+
+ for (int i = startPlaceholder + 1; i < endPlaceholder; i++) {
+ final char current = text.charAt(i);
+
+ if (current == ' ' && underscoreIndex == -1) {
+ // Invalid placeholder (contains space before _).
+ // Treat the opening symbol as literal text and search for the next one.
+ builder.append(head);
+ cursor = startPlaceholder + 1;
+ startPlaceholder = text.indexOf(head, cursor);
+
+ // Safety check: If no more placeholders exist, break to finalize
+ if (startPlaceholder == -1) {
+ break loop;
+ }
+ continue loop;
+ }
+
+ if (current == '_' && underscoreIndex == -1) {
+ underscoreIndex = i;
+ }
+ }
+
+ if (underscoreIndex == -1) {
+ builder.append(text, startPlaceholder, endPlaceholder + 1);
+ cursor = endPlaceholder + 1;
+ startPlaceholder = text.indexOf(head, cursor);
continue;
}
- boolean identified = false;
- boolean invalid = true;
- boolean hadSpace = false;
+ String identifier = text.substring(startPlaceholder + 1, underscoreIndex);
+ String parameters = "";
- while (++i < chars.length) {
- final char p = chars[i];
-
- if (p == ' ' && !identified) {
- hadSpace = true;
- break;
- }
- if (p == closure.tail) {
- invalid = false;
- break;
- }
-
- if (p == '_' && !identified) {
- identified = true;
- continue;
- }
-
- if (identified) {
- parameters.append(p);
- } else {
- identifier.append(p);
- }
+ if (underscoreIndex + 1 < endPlaceholder) {
+ parameters = text.substring(underscoreIndex + 1, endPlaceholder);
}
- final String identifierString = identifier.toString();
- final String lowercaseIdentifierString = identifierString.toLowerCase(Locale.ROOT);
- final String parametersString = parameters.toString();
+ final PlaceholderExpansion expansion = lookup.apply(identifier.toLowerCase(Locale.ROOT));
+ String replacement = null;
- identifier.setLength(0);
- parameters.setLength(0);
-
- if (invalid) {
- builder.append(closure.head).append(identifierString);
-
- if (identified) {
- builder.append('_').append(parametersString);
- }
-
- if (hadSpace) {
- builder.append(' ');
- }
- continue;
+ if (expansion != null) {
+ replacement = expansion.onPlaceholderRequest(player, parameters);
}
- final PlaceholderExpansion placeholder = lookup.apply(lowercaseIdentifierString);
- if (placeholder == null) {
- builder.append(closure.head).append(identifierString);
-
- if (identified) {
- builder.append('_');
- }
-
- builder.append(parametersString).append(closure.tail);
- continue;
+ if (replacement != null) {
+ builder.append(replacement);
+ } else {
+ // Fallback: Restore original placeholder format
+ builder.append(head).append(identifier);
+ builder.append('_').append(parameters);
+ builder.append(tail);
}
- final String replacement = placeholder.onPlaceholderRequest(player, parametersString);
- if (replacement == null) {
- builder.append(closure.head).append(identifierString);
+ cursor = endPlaceholder + 1;
+ startPlaceholder = text.indexOf(head, cursor);
- if (identified) {
- builder.append('_');
- }
+ } while (startPlaceholder != -1);
- builder.append(parametersString).append(closure.tail);
- continue;
- }
-
- builder.append(replacement);
+ if (cursor < length) {
+ builder.append(text, cursor, length);
}
return builder.toString();
From 683815679fee282428c7427357c78efcf3c29af0 Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Mar 2026 18:29:25 +0800
Subject: [PATCH 5/8] don't fail when javadocs are missing smh
---
build.gradle.kts | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index bc286c8..461a6b3 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -42,6 +42,10 @@ tasks {
eachFile { expand("version" to project.version) }
}
+ withType.configureEach {
+ isFailOnError = false
+ }
+
withType {
archiveClassifier.set("hytale")
@@ -75,4 +79,4 @@ tasks {
}
publish.get().setDependsOn(listOf(build.get()))
-}
\ No newline at end of file
+}
From 453f93da75d512aadd19b1df8119dde14e0cbfba Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Mar 2026 18:30:08 +0800
Subject: [PATCH 6/8] remove .configureEach from javadoc task
---
build.gradle.kts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 461a6b3..1034042 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -42,7 +42,7 @@ tasks {
eachFile { expand("version" to project.version) }
}
- withType.configureEach {
+ withType {
isFailOnError = false
}
From c14c1145e47102266eea05eefb09ce61c95ea34e Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Mar 2026 18:30:41 +0800
Subject: [PATCH 7/8] update bukkit javadoc -> hytale
---
.../java/at/helpch/placeholderapi/replacer/CharsReplacer.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java b/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java
index 7e67215..9a79ac9 100644
--- a/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java
+++ b/src/main/java/at/helpch/placeholderapi/replacer/CharsReplacer.java
@@ -46,7 +46,7 @@ public final class CharsReplacer implements Replacer {
* corresponding {@link PlaceholderExpansion}.
*
* @param text The raw text containing potential placeholders to be replaced.
- * @param player The {@link OfflinePlayer} to contextually parse the placeholders against.
+ * @param player The {@link PlayerRef} to contextually parse the placeholders against.
* May be {@code null} if no player context is available.
* @param lookup A function that maps a lowercase identifier string to a registered
* {@link PlaceholderExpansion}.
From 7313622a8ab583d602aaea9cb69e8c5b96c59f89 Mon Sep 17 00:00:00 2001
From: PiggyPiglet
Date: Fri, 27 Mar 2026 18:44:51 +0800
Subject: [PATCH 8/8] 1.0.8 release
---
build.gradle.kts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 1034042..6378995 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -7,7 +7,7 @@ plugins {
}
group = "at.helpch"
-version = "1.0.8-DEV-${System.getProperty("BUILD_NUMBER")}"
+version = "1.0.8"
description = "An awesome placeholder provider!"