Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55fc6d762f | ||
|
|
b9c5eb2b4e | ||
|
|
37e271c96c | ||
|
|
3dad48e24d | ||
|
|
ae77e4810b | ||
|
|
3d50e37c37 | ||
|
|
421fd3bd04 | ||
|
|
5ecae0a366 | ||
|
|
5de4914fd7 | ||
|
|
0f9bf094ae | ||
|
|
e67680f397 | ||
|
|
73c0a5d655 | ||
|
|
220ed26f4a | ||
|
|
edf2ea41c7 | ||
|
|
16859b8ce5 | ||
|
|
10fe7d190a | ||
|
|
60a1f2429c | ||
|
|
cc6dc1e67c | ||
|
|
f4f5941691 | ||
|
|
f973281dd9 | ||
|
|
8acd76f363 | ||
|
|
4a165a86dc | ||
|
|
43b7c393b9 | ||
|
|
714952bc45 | ||
|
|
322e179b81 | ||
|
|
469be73ada | ||
|
|
7eac60146f | ||
|
|
ad0223e1bb | ||
|
|
430117f342 | ||
|
|
fa87cae81e | ||
|
|
5695750fc5 | ||
|
|
45e8a57880 | ||
|
|
17fcd2c1b5 | ||
|
|
0c1e17c351 | ||
|
|
9415515849 | ||
|
|
d0e957ea37 | ||
|
|
69514e2f85 | ||
|
|
259e35c978 | ||
|
|
40aec26f15 | ||
|
|
67b2fdd594 | ||
|
|
83f86983f6 | ||
|
|
3ba98a9a5e | ||
|
|
f19e565fbe | ||
|
|
ee3ecb643b | ||
|
|
3aefb0e481 | ||
|
|
d9eb1e1c26 | ||
|
|
70631e67c5 | ||
|
|
82797e7342 | ||
|
|
d2917341b1 | ||
|
|
760f42be0c | ||
|
|
bb01af2ab2 | ||
|
|
517d890c05 | ||
|
|
f02fc56778 | ||
|
|
4417b09c14 | ||
|
|
6b37fafa90 | ||
|
|
f8c5c9f06d | ||
|
|
0fd6cbaa08 | ||
|
|
81afa32eb0 | ||
|
|
7387fe2332 | ||
|
|
80fa05da98 | ||
|
|
77754249ad | ||
|
|
1843cf0f8a | ||
|
|
05eb5ee993 | ||
|
|
7bc11ee716 | ||
|
|
f566aec00e | ||
|
|
36d47c55a1 | ||
|
|
40463213ac | ||
|
|
6ec80d30ad | ||
|
|
7ccee60a0c | ||
|
|
0805b48763 | ||
|
|
d737322aaa | ||
|
|
4ddc150e1c | ||
|
|
0da119d89d | ||
|
|
fc0a07d1c5 | ||
|
|
4ce2850138 | ||
|
|
58316c2a06 | ||
|
|
d96ad10960 | ||
|
|
21283b0928 | ||
|
|
2797687f01 | ||
|
|
9c68d1fbc3 | ||
|
|
9371d9b88d | ||
|
|
14e2ead488 | ||
|
|
5473bb8ef8 | ||
|
|
90c55849ae | ||
|
|
9809140cf9 | ||
|
|
49a82dc005 | ||
|
|
92dec03b9a | ||
|
|
7453c70b87 | ||
|
|
3038ea43d0 | ||
|
|
3c6ddd8255 | ||
|
|
925ee04cc1 | ||
|
|
6f7de8716b | ||
|
|
a17b951a8b | ||
|
|
f003ed06a8 | ||
|
|
f864953da2 | ||
|
|
6ef31444ac | ||
|
|
99258116de | ||
|
|
a59c68102e | ||
|
|
2482525fe2 | ||
|
|
393d0031c7 |
15
.github/workflows/checkstyle.yml
vendored
15
.github/workflows/checkstyle.yml
vendored
@@ -1,15 +0,0 @@
|
||||
name: Check PR Codestyle
|
||||
on: [ pull_request ]
|
||||
|
||||
jobs:
|
||||
checkstyle:
|
||||
name: Checkstyle
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dbelyaev/action-checkstyle@v0.5.1
|
||||
with:
|
||||
github_token: ${{ secrets.github_token }}
|
||||
reporter: github-pr-review
|
||||
level: warning
|
||||
checkstyle_config: ../../config/checkstyle/checkstyle.xml
|
||||
@@ -82,6 +82,12 @@ allprojects {
|
||||
|
||||
// UltraEconomy
|
||||
maven("https://repo.techscode.com/repository/maven-releases/")
|
||||
|
||||
// PlayerPoints
|
||||
maven("https://repo.rosewooddev.io/repository/public/")
|
||||
|
||||
// Denizen
|
||||
maven("https://maven.citizensnpcs.co/repo")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -25,8 +25,8 @@ import com.willfp.eco.core.gui.menu.MenuType;
|
||||
import com.willfp.eco.core.gui.slot.SlotBuilder;
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
|
||||
import com.willfp.eco.core.items.TestableItem;
|
||||
import com.willfp.eco.core.math.MathContext;
|
||||
import com.willfp.eco.core.packet.Packet;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.core.proxy.ProxyFactory;
|
||||
import com.willfp.eco.core.scheduling.Scheduler;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
@@ -531,7 +531,7 @@ public interface Eco {
|
||||
* @return The value of the expression, or zero if invalid.
|
||||
*/
|
||||
double evaluate(@NotNull String expression,
|
||||
@NotNull MathContext context);
|
||||
@NotNull PlaceholderContext context);
|
||||
|
||||
/**
|
||||
* Get the menu a player currently has open.
|
||||
@@ -563,6 +563,30 @@ public interface Eco {
|
||||
void sendPacket(@NotNull Player player,
|
||||
@NotNull Packet packet);
|
||||
|
||||
/**
|
||||
* Translate placeholders in a string.
|
||||
*
|
||||
* @param text The text.
|
||||
* @param context The context.
|
||||
* @return The translated text.
|
||||
*/
|
||||
@NotNull
|
||||
String translatePlaceholders(@NotNull String text,
|
||||
@NotNull PlaceholderContext context);
|
||||
|
||||
/**
|
||||
* Get the value of a placeholder.
|
||||
*
|
||||
* @param plugin The plugin that owns the placeholder.
|
||||
* @param args The placeholder arguments.
|
||||
* @param context The context.
|
||||
* @return The value, or null if invalid.
|
||||
*/
|
||||
@Nullable
|
||||
String getPlaceholderValue(@Nullable EcoPlugin plugin,
|
||||
@NotNull String args,
|
||||
@NotNull PlaceholderContext context);
|
||||
|
||||
/**
|
||||
* Get the instance of eco; the bridge between the api frontend and the implementation backend.
|
||||
*
|
||||
|
||||
@@ -19,9 +19,10 @@ import com.willfp.eco.core.proxy.ProxyFactory;
|
||||
import com.willfp.eco.core.registry.Registrable;
|
||||
import com.willfp.eco.core.registry.Registry;
|
||||
import com.willfp.eco.core.scheduling.Scheduler;
|
||||
import com.willfp.eco.core.version.OutdatedEcoVersionError;
|
||||
import com.willfp.eco.core.version.Version;
|
||||
import com.willfp.eco.core.web.UpdateChecker;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
@@ -32,6 +33,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@@ -347,14 +349,14 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
they have an outdated version of eco installed.
|
||||
*/
|
||||
|
||||
DefaultArtifactVersion runningVersion = new DefaultArtifactVersion(Eco.get().getEcoPlugin().getDescription().getVersion());
|
||||
DefaultArtifactVersion requiredVersion = new DefaultArtifactVersion(this.getMinimumEcoVersion());
|
||||
Version runningVersion = new Version(Eco.get().getEcoPlugin().getDescription().getVersion());
|
||||
Version requiredVersion = new Version(this.getMinimumEcoVersion());
|
||||
if (!(runningVersion.compareTo(requiredVersion) > 0 || runningVersion.equals(requiredVersion))) {
|
||||
this.getLogger().severe("You are running an outdated version of eco!");
|
||||
this.getLogger().severe("You must be on at least" + this.getMinimumEcoVersion());
|
||||
this.getLogger().severe("Download the newest version here:");
|
||||
this.getLogger().severe("https://polymart.org/download/773/recent/JSpprMspkuyecf5y1wQ2Jn8OoLQSQ_IW");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
throw new OutdatedEcoVersionError("This plugin requires at least eco version " + this.getMinimumEcoVersion() + " to run.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,13 +367,12 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
public final void onEnable() {
|
||||
super.onEnable();
|
||||
|
||||
this.getLogger().info("");
|
||||
this.getLogger().info("Loading " + this.getColor() + this.getName());
|
||||
|
||||
if (this.getResourceId() != 0 && !Eco.get().getEcoPlugin().getConfigYml().getBool("no-update-checker")) {
|
||||
new UpdateChecker(this).getVersion(version -> {
|
||||
DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(this.getDescription().getVersion());
|
||||
DefaultArtifactVersion mostRecentVersion = new DefaultArtifactVersion(version);
|
||||
Version currentVersion = new Version(this.getDescription().getVersion());
|
||||
Version mostRecentVersion = new Version(version);
|
||||
if (!(currentVersion.compareTo(mostRecentVersion) > 0 || currentVersion.equals(mostRecentVersion))) {
|
||||
this.outdated = true;
|
||||
this.getLogger().warning(this.getName() + " is out of date! (Version " + this.getDescription().getVersion() + ")");
|
||||
@@ -405,7 +406,9 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
|
||||
this.loadedIntegrations.removeIf(pl -> pl.equalsIgnoreCase(this.getName()));
|
||||
|
||||
this.getLogger().info("Loaded integrations: " + String.join(", ", this.getLoadedIntegrations()));
|
||||
if (!this.getLoadedIntegrations().isEmpty()) {
|
||||
this.getLogger().info("Loaded integrations: " + String.join(", ", this.getLoadedIntegrations()));
|
||||
}
|
||||
|
||||
Prerequisite.update();
|
||||
|
||||
@@ -427,17 +430,19 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
if (this.isSupportingExtensions()) {
|
||||
this.getExtensionLoader().loadExtensions();
|
||||
|
||||
if (this.getExtensionLoader().getLoadedExtensions().isEmpty()) {
|
||||
this.getLogger().info("&cNo extensions found");
|
||||
} else {
|
||||
this.getLogger().info("Extensions Loaded:");
|
||||
this.getExtensionLoader().getLoadedExtensions().forEach(extension -> this.getLogger().info("- " + extension.getName() + " v" + extension.getVersion()));
|
||||
if (!this.getExtensionLoader().getLoadedExtensions().isEmpty()) {
|
||||
List<String> loadedExtensions = this.getExtensionLoader().getLoadedExtensions().stream().map(
|
||||
extension -> extension.getName() + " v" + extension.getVersion()
|
||||
).toList();
|
||||
|
||||
this.getLogger().info(
|
||||
"Loaded extensions: " +
|
||||
String.join(", ", loadedExtensions)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.handleLifecycle(this.onEnable, this::handleEnable);
|
||||
|
||||
this.getLogger().info("");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1081,7 +1086,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
*
|
||||
* @return The config handler.
|
||||
*/
|
||||
public ConfigHandler getConfigHandler() {
|
||||
public @NotNull ConfigHandler getConfigHandler() {
|
||||
return this.configHandler;
|
||||
}
|
||||
|
||||
@@ -1150,4 +1155,9 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
public final String getID() {
|
||||
return Registry.tryFitPattern(this.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull File getFile() {
|
||||
return super.getFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.willfp.eco.core;
|
||||
|
||||
import com.willfp.eco.core.config.updating.ConfigHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
@@ -13,12 +15,13 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public interface PluginLike {
|
||||
/**
|
||||
* Get the data folder of the object.
|
||||
* Get the data folder.
|
||||
* <p>
|
||||
* Returns the plugin data folder for a plugin, or the extension's parent plugin's folder
|
||||
*
|
||||
* @return The data folder.
|
||||
*/
|
||||
@NotNull
|
||||
File getDataFolder();
|
||||
|
||||
/**
|
||||
@@ -26,6 +29,7 @@ public interface PluginLike {
|
||||
*
|
||||
* @return The config handler.
|
||||
*/
|
||||
@NotNull
|
||||
ConfigHandler getConfigHandler();
|
||||
|
||||
/**
|
||||
@@ -33,5 +37,16 @@ public interface PluginLike {
|
||||
*
|
||||
* @return The logger.
|
||||
*/
|
||||
@NotNull
|
||||
Logger getLogger();
|
||||
|
||||
/**
|
||||
* Get the actual file.
|
||||
*
|
||||
* @return The file, i.e. the jar file.
|
||||
*/
|
||||
@Nullable
|
||||
default File getFile() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class Prerequisite {
|
||||
*/
|
||||
public static final Prerequisite HAS_PAPER = new Prerequisite(
|
||||
() -> ClassUtils.exists("com.destroystokyo.paper.event.block.BeaconEffectEvent"),
|
||||
"Requires server to be running paper (or a fork)"
|
||||
"Requires server to be running paper"
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -69,7 +69,7 @@ public class Prerequisite {
|
||||
@Deprecated(since = "6.49.0", forRemoval = true)
|
||||
public static final Prerequisite HAS_BUNGEECORD = new Prerequisite(
|
||||
() -> ClassUtils.exists("net.md_5.bungee.api.event.ServerConnectedEvent"),
|
||||
"Requires server to be running BungeeCord (or a fork)"
|
||||
"Requires server to be running BungeeCord"
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -80,7 +80,15 @@ public class Prerequisite {
|
||||
@Deprecated(since = "6.49.0", forRemoval = true)
|
||||
public static final Prerequisite HAS_VELOCITY = new Prerequisite(
|
||||
() -> ClassUtils.exists("com.velocitypowered.api.event.player.ServerConnectedEvent"),
|
||||
"Requires server to be running Velocity (or a fork)"
|
||||
"Requires server to be running Velocity"
|
||||
);
|
||||
|
||||
/**
|
||||
* Requires the server to be running an implementation of Folia.
|
||||
*/
|
||||
public static final Prerequisite HAS_FOLIA = new Prerequisite(
|
||||
() -> ClassUtils.exists("io.papermc.paper.threadedregions.scheduler.RegionisedScheduler"),
|
||||
"Requires server to be running Folia!"
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.willfp.eco.core.config.Configs;
|
||||
import com.willfp.eco.core.placeholder.AdditionalPlayer;
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
@@ -134,7 +135,7 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
* @return The computed value, or 0 if not found or invalid.
|
||||
*/
|
||||
default int getIntFromExpression(@NotNull String path) {
|
||||
return getIntFromExpression(path, null);
|
||||
return getIntFromExpression(path, PlaceholderContext.of(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,6 +164,18 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
return Double.valueOf(getDoubleFromExpression(path, player, additionalPlayers)).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a decimal value via a mathematical expression.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param context The placeholder context.
|
||||
* @return The computed value, or 0 if not found or invalid.
|
||||
*/
|
||||
default int getIntFromExpression(@NotNull String path,
|
||||
@NotNull PlaceholderContext context) {
|
||||
return Double.valueOf(getDoubleFromExpression(path, context)).intValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an integer from config.
|
||||
@@ -256,6 +269,22 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
return getString(path, true, option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a formatted string from config.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param context The placeholder context.
|
||||
* @return The found value, or an empty string if not found.
|
||||
*/
|
||||
@NotNull
|
||||
default String getFormattedString(@NotNull String path,
|
||||
@NotNull PlaceholderContext context) {
|
||||
return Objects.requireNonNullElse(
|
||||
getFormattedStringOrNull(path, context),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string from config.
|
||||
* <p>
|
||||
@@ -288,7 +317,7 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
* Get a formatted string from config.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @return The found value, or an empty string if not found.
|
||||
* @return The found value, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
default String getFormattedStringOrNull(@NotNull String path) {
|
||||
@@ -300,7 +329,7 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param option The format option.
|
||||
* @return The found value, or an empty string if not found.
|
||||
* @return The found value, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
default String getFormattedStringOrNull(@NotNull String path,
|
||||
@@ -308,6 +337,25 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
return getStringOrNull(path, true, option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a formatted string from config.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param context The placeholder context.
|
||||
* @return The found value, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
default String getFormattedStringOrNull(@NotNull String path,
|
||||
@NotNull PlaceholderContext context) {
|
||||
String nullable = getStringOrNull(path);
|
||||
|
||||
if (nullable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return StringUtils.format(nullable, context.withInjectableContext(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string from config.
|
||||
* <p>
|
||||
@@ -362,6 +410,24 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
return getStrings(path, true, option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of strings from config.
|
||||
* <p>
|
||||
* Formatted.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param context The placeholder context.
|
||||
* @return The found value, or a blank {@link java.util.ArrayList} if not found.
|
||||
*/
|
||||
@NotNull
|
||||
default List<String> getFormattedStrings(@NotNull String path,
|
||||
@NotNull PlaceholderContext context) {
|
||||
return Objects.requireNonNullElse(
|
||||
getFormattedStringsOrNull(path, context),
|
||||
new ArrayList<>()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of strings from config.
|
||||
* <p>
|
||||
@@ -418,6 +484,30 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
return getStringsOrNull(path, true, option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of strings from config.
|
||||
* <p>
|
||||
* Formatted.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param context The placeholder context.
|
||||
* @return The found value, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
default List<String> getFormattedStringsOrNull(@NotNull String path,
|
||||
@NotNull PlaceholderContext context) {
|
||||
List<String> nullable = getStringsOrNull(path);
|
||||
|
||||
if (nullable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return StringUtils.formatList(
|
||||
nullable,
|
||||
context.withInjectableContext(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of strings from config.
|
||||
* <p>
|
||||
@@ -463,7 +553,7 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
* @return The computed value, or 0 if not found or invalid.
|
||||
*/
|
||||
default double getDoubleFromExpression(@NotNull String path) {
|
||||
return getDoubleFromExpression(path, null);
|
||||
return getDoubleFromExpression(path, PlaceholderContext.of(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,21 +565,38 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
||||
*/
|
||||
default double getDoubleFromExpression(@NotNull String path,
|
||||
@Nullable Player player) {
|
||||
return NumberUtils.evaluateExpression(this.getString(path), player, this);
|
||||
return getDoubleFromExpression(path, player, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a decimal value via a mathematical expression.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param player The player to evaluate placeholders with respect to.
|
||||
* @param path The key to fetch the value from.
|
||||
* @param player The player to evaluate placeholders with respect to.
|
||||
* @param additionalPlayers The additional players to evaluate placeholders with respect to.
|
||||
* @return The computed value, or 0 if not found or invalid.
|
||||
*/
|
||||
default double getDoubleFromExpression(@NotNull String path,
|
||||
@Nullable Player player,
|
||||
@NotNull Collection<AdditionalPlayer> additionalPlayers) {
|
||||
return NumberUtils.evaluateExpression(this.getString(path), player, this, additionalPlayers);
|
||||
return getDoubleFromExpression(path, new PlaceholderContext(
|
||||
player,
|
||||
null,
|
||||
this,
|
||||
additionalPlayers
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a decimal value via a mathematical expression.
|
||||
*
|
||||
* @param path The key to fetch the value from.
|
||||
* @param context The placeholder context.
|
||||
* @return The computed value, or 0 if not found or invalid.
|
||||
*/
|
||||
default double getDoubleFromExpression(@NotNull String path,
|
||||
@NotNull PlaceholderContext context) {
|
||||
return NumberUtils.evaluateExpression(this.getString(path), context.withInjectableContext(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,17 +3,26 @@ package com.willfp.eco.core.data;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A simple store key-value store for data to be stored outside of plugins.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class ExternalDataStore {
|
||||
/**
|
||||
* The store.
|
||||
*/
|
||||
private static final HashMap<String, Object> data = new HashMap<>();
|
||||
private static final Map<String, Object> DATA = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The store adapters.
|
||||
*/
|
||||
private static final List<ExternalDataStoreObjectAdapter<?, ?>> STORE_ADAPTERS = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Put data into the store.
|
||||
@@ -23,7 +32,29 @@ public final class ExternalDataStore {
|
||||
*/
|
||||
public static void put(@NotNull final String key,
|
||||
@NotNull final Object value) {
|
||||
data.put(key, value);
|
||||
doPut(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put data into the store.
|
||||
*
|
||||
* @param key The key.
|
||||
* @param value The value.
|
||||
* @param <A> The stored type.
|
||||
*/
|
||||
private static <A> void doPut(@NotNull final String key,
|
||||
@NotNull final A value) {
|
||||
Object storedValue = value;
|
||||
|
||||
for (ExternalDataStoreObjectAdapter<?, ?> unknownAdapter : STORE_ADAPTERS) {
|
||||
if (unknownAdapter.getAccessedClass().isInstance(value)) {
|
||||
ExternalDataStoreObjectAdapter<A, ?> adapter = (ExternalDataStoreObjectAdapter<A, ?>) unknownAdapter;
|
||||
storedValue = adapter.toStoredObject(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DATA.put(key, storedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,7 +68,30 @@ public final class ExternalDataStore {
|
||||
@Nullable
|
||||
public static <T> T get(@NotNull final String key,
|
||||
@NotNull final Class<T> clazz) {
|
||||
Object value = data.get(key);
|
||||
return doGet(key, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data from the store.
|
||||
*
|
||||
* @param key The key.
|
||||
* @param clazz The class.
|
||||
* @param <A> The accessed type.
|
||||
* @param <S> The stored type.
|
||||
* @return The value.
|
||||
*/
|
||||
@Nullable
|
||||
private static <A, S> A doGet(@NotNull final String key,
|
||||
@NotNull final Class<A> clazz) {
|
||||
Object value = DATA.get(key);
|
||||
|
||||
for (ExternalDataStoreObjectAdapter<?, ?> unknownAdapter : STORE_ADAPTERS) {
|
||||
if (unknownAdapter.getStoredClass().isInstance(value) && unknownAdapter.getAccessedClass().equals(clazz)) {
|
||||
ExternalDataStoreObjectAdapter<A, S> adapter = (ExternalDataStoreObjectAdapter<A, S>) unknownAdapter;
|
||||
value = adapter.toAccessedObject((S) value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (clazz.isInstance(value)) {
|
||||
return clazz.cast(value);
|
||||
@@ -79,6 +133,15 @@ public final class ExternalDataStore {
|
||||
return get(key, clazz, defaultValue.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new adapter.
|
||||
*
|
||||
* @param adapter The adapter.
|
||||
*/
|
||||
public static void registerAdapter(@NotNull final ExternalDataStoreObjectAdapter<?, ?> adapter) {
|
||||
STORE_ADAPTERS.add(adapter);
|
||||
}
|
||||
|
||||
private ExternalDataStore() {
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.willfp.eco.core.data;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* An adapter for objects stored in {@link ExternalDataStore}.
|
||||
*
|
||||
* @param <A> The accessed class.
|
||||
* @param <S> The stored class.
|
||||
*/
|
||||
public abstract class ExternalDataStoreObjectAdapter<A, S> {
|
||||
/**
|
||||
* The class that is accessed (read / written).
|
||||
*/
|
||||
private final Class<? extends A> accessedClass;
|
||||
|
||||
/**
|
||||
* The class that is stored internally.
|
||||
*/
|
||||
private final Class<? extends S> storedClass;
|
||||
|
||||
/**
|
||||
* Create a new adapter.
|
||||
*
|
||||
* @param accessedClass The class that is accessed (read / written).
|
||||
* @param storedClass The class that is stored internally.
|
||||
*/
|
||||
protected ExternalDataStoreObjectAdapter(@NotNull final Class<? extends A> accessedClass,
|
||||
@NotNull final Class<? extends S> storedClass) {
|
||||
this.accessedClass = accessedClass;
|
||||
this.storedClass = storedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an object to the stored object.
|
||||
*
|
||||
* @param obj The object.
|
||||
* @return The stored object.
|
||||
*/
|
||||
@NotNull
|
||||
public abstract S toStoredObject(@NotNull final A obj);
|
||||
|
||||
/**
|
||||
* Convert an object to the accessed object.
|
||||
*
|
||||
* @param obj The object.
|
||||
* @return The accessed object.
|
||||
*/
|
||||
@NotNull
|
||||
public abstract A toAccessedObject(@NotNull final S obj);
|
||||
|
||||
/**
|
||||
* Get the class that is accessed (read / written).
|
||||
*
|
||||
* @return The class.
|
||||
*/
|
||||
public Class<? extends A> getAccessedClass() {
|
||||
return accessedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class that is stored internally.
|
||||
*
|
||||
* @return The class.
|
||||
*/
|
||||
public Class<? extends S> getStoredClass() {
|
||||
return storedClass;
|
||||
}
|
||||
}
|
||||
@@ -135,20 +135,26 @@ public abstract class Extension implements PluginLike {
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
public @NotNull File getDataFolder() {
|
||||
return this.plugin.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigHandler getConfigHandler() {
|
||||
public @NotNull ConfigHandler getConfigHandler() {
|
||||
return this.plugin.getConfigHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
public @NotNull Logger getLogger() {
|
||||
return this.plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull File getFile() {
|
||||
Validate.notNull(metadata, "Metadata cannot be null!");
|
||||
return this.metadata.file();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin for the extension.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.willfp.eco.core.extensions;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Generic exception in extension loading.
|
||||
*/
|
||||
public class ExtensionLoadException extends RuntimeException {
|
||||
/**
|
||||
* Create a new ExtensionLoadException.
|
||||
*
|
||||
* @param errorMessage The error message to show.
|
||||
*/
|
||||
public ExtensionLoadException(@NotNull final String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.willfp.eco.core.extensions;
|
||||
|
||||
import com.willfp.eco.core.version.Version;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* The extension's metadata.
|
||||
* <p>
|
||||
@@ -13,6 +16,23 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public record ExtensionMetadata(@NotNull String version,
|
||||
@NotNull String name,
|
||||
@NotNull String author) {
|
||||
|
||||
@NotNull String author,
|
||||
@NotNull File file,
|
||||
@NotNull Version minimumPluginVersion) {
|
||||
/**
|
||||
* Legacy constructor.
|
||||
*
|
||||
* @param version The extension version.
|
||||
* @param name The extension name.
|
||||
* @param author The extension's author.
|
||||
* @deprecated Use {@link ExtensionMetadata#ExtensionMetadata(String, String, String, File, Version)} instead.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Deprecated(since = "6.57.0", forRemoval = true)
|
||||
public ExtensionMetadata(@NotNull String version,
|
||||
@NotNull String name,
|
||||
@NotNull String author) {
|
||||
this(version, name, author, null, null);
|
||||
throw new UnsupportedOperationException("Legacy constructor is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Missing or invalid extension.yml.
|
||||
* Invalid filetype.
|
||||
*/
|
||||
public class MalformedExtensionException extends RuntimeException {
|
||||
public class MalformedExtensionException extends ExtensionLoadException {
|
||||
/**
|
||||
* Create a new MalformedExtensionException.
|
||||
*
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
package com.willfp.eco.core.integrations;
|
||||
|
||||
import com.willfp.eco.core.registry.Registrable;
|
||||
import com.willfp.eco.core.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Abstract class for integrations.
|
||||
*/
|
||||
public interface Integration {
|
||||
public interface Integration extends Registrable {
|
||||
/**
|
||||
* Get the name of integration.
|
||||
*
|
||||
* @return The name.
|
||||
*/
|
||||
String getPluginName();
|
||||
|
||||
@Override
|
||||
default @NotNull String getID() {
|
||||
return Registry.tryFitPattern(this.getPluginName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.willfp.eco.core.integrations;
|
||||
|
||||
import com.willfp.eco.core.Eco;
|
||||
import com.willfp.eco.core.registry.Registry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Registry for integrations.
|
||||
*
|
||||
* @param <T> The type of integration.
|
||||
*/
|
||||
public class IntegrationRegistry<T extends Integration> extends Registry<T> {
|
||||
@Override
|
||||
public @NotNull T register(@NotNull final T element) {
|
||||
return executeSafely(() -> super.register(element), element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all integrations, safely.
|
||||
*
|
||||
* @param action The action to perform.
|
||||
*/
|
||||
public void forEachSafely(@NotNull final Consumer<T> action) {
|
||||
for (T integration : new HashSet<>(this.values())) {
|
||||
executeSafely(() -> action.accept(integration), integration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If any integrations return true, safely.
|
||||
*
|
||||
* @param predicate The predicate to test.
|
||||
* @return If any integrations return true.
|
||||
*/
|
||||
public boolean anySafely(@NotNull final Predicate<T> predicate) {
|
||||
for (T integration : new HashSet<>(this.values())) {
|
||||
Boolean result = executeSafely(() -> predicate.test(integration), integration);
|
||||
if (result != null && result) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first integration that returns a value, safely.
|
||||
*
|
||||
* @param function The function to apply.
|
||||
* @param defaultValue The default value.
|
||||
* @param <R> The type of value.
|
||||
* @return The first value that returns a value.
|
||||
*/
|
||||
@NotNull
|
||||
public <R> R firstSafely(@NotNull final Function<T, R> function,
|
||||
@NotNull final R defaultValue) {
|
||||
if (this.isEmpty()) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
T integration = this.iterator().next();
|
||||
|
||||
return executeSafely(() -> function.apply(integration), integration, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given action safely, catching any exceptions and logging the issue.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param integration The integration to apply the action on.
|
||||
*/
|
||||
private void executeSafely(@NotNull final Runnable action,
|
||||
@NotNull final T integration) {
|
||||
executeSafely(() -> {
|
||||
action.run();
|
||||
return null;
|
||||
}, integration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given action safely, catching any exceptions and logging the issue.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param integration The integration to apply the action on.
|
||||
* @param <R> The return type of the action.
|
||||
* @return The result of the action, or null if an exception was thrown.
|
||||
*/
|
||||
private <R> R executeSafely(@NotNull final Supplier<R> action,
|
||||
@NotNull final T integration) {
|
||||
return executeSafely(action, integration, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given action safely, catching any exceptions and logging the issue.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param integration The integration to apply the action on.
|
||||
* @param defaultValue The default value to return if an exception is thrown.
|
||||
* @param <R> The return type of the action.
|
||||
* @return The result of the action, or the default value if an exception was thrown.
|
||||
*/
|
||||
private <R> R executeSafely(@NotNull final Supplier<R> action,
|
||||
@NotNull final T integration,
|
||||
@Nullable final R defaultValue) {
|
||||
try {
|
||||
return action.get();
|
||||
} catch (final Exception e) {
|
||||
Eco.get().getEcoPlugin().getLogger().warning("Integration for " + integration.getPluginName() + " threw an exception!");
|
||||
Eco.get().getEcoPlugin().getLogger().warning("The integration will be disabled.");
|
||||
e.printStackTrace();
|
||||
this.remove(integration);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If all integrations return true, safely.
|
||||
*
|
||||
* @param predicate The predicate to test.
|
||||
* @return If all integrations return true.
|
||||
*/
|
||||
public boolean allSafely(@NotNull final Predicate<T> predicate) {
|
||||
return !this.anySafely(predicate.negate());
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.willfp.eco.core.integrations.afk;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class to handle afk integrations.
|
||||
*/
|
||||
@@ -13,7 +11,7 @@ public final class AFKManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<AFKIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<AFKIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -21,8 +19,7 @@ public final class AFKManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final AFKIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTRY.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,13 +29,7 @@ public final class AFKManager {
|
||||
* @return If afk.
|
||||
*/
|
||||
public static boolean isAfk(@NotNull final Player player) {
|
||||
for (AFKIntegration integration : REGISTERED) {
|
||||
if (integration.isAfk(player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return REGISTRY.anySafely(integration -> integration.isAfk(player));
|
||||
}
|
||||
|
||||
private AFKManager() {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.willfp.eco.core.integrations.anticheat;
|
||||
|
||||
import com.willfp.eco.core.Eco;
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class to handle anticheat integrations.
|
||||
*/
|
||||
@@ -15,7 +13,7 @@ public final class AnticheatManager {
|
||||
/**
|
||||
* A set of all registered anticheats.
|
||||
*/
|
||||
private static final Set<AnticheatIntegration> ANTICHEATS = new HashSet<>();
|
||||
private static final IntegrationRegistry<AnticheatIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new anticheat.
|
||||
@@ -26,8 +24,7 @@ public final class AnticheatManager {
|
||||
if (anticheat instanceof Listener) {
|
||||
Eco.get().getEcoPlugin().getEventManager().registerListener((Listener) anticheat);
|
||||
}
|
||||
ANTICHEATS.removeIf(it -> it.getPluginName().equalsIgnoreCase(anticheat.getPluginName()));
|
||||
ANTICHEATS.add(anticheat);
|
||||
REGISTRY.register(anticheat);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,17 +33,16 @@ public final class AnticheatManager {
|
||||
* @param player The player to exempt.
|
||||
*/
|
||||
public static void exemptPlayer(@NotNull final Player player) {
|
||||
ANTICHEATS.forEach(anticheat -> anticheat.exempt(player));
|
||||
REGISTRY.forEachSafely(anticheat -> anticheat.exempt(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unexempt a player from triggering anticheats.
|
||||
* This is ran a tick after it is called to ensure that there are no event timing conflicts.
|
||||
*
|
||||
* @param player The player to remove the exemption.
|
||||
*/
|
||||
public static void unexemptPlayer(@NotNull final Player player) {
|
||||
ANTICHEATS.forEach(anticheat -> anticheat.unexempt(player));
|
||||
REGISTRY.forEachSafely(anticheat -> anticheat.unexempt(player));
|
||||
}
|
||||
|
||||
private AnticheatManager() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.core.integrations.antigrief;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@@ -16,7 +17,7 @@ public final class AntigriefManager {
|
||||
/**
|
||||
* Registered antigriefs.
|
||||
*/
|
||||
private static final Set<AntigriefIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<AntigriefIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new AntiGrief/Land Management integration.
|
||||
@@ -24,8 +25,7 @@ public final class AntigriefManager {
|
||||
* @param antigrief The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final AntigriefIntegration antigrief) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(antigrief.getPluginName()));
|
||||
REGISTERED.add(antigrief);
|
||||
REGISTRY.register(antigrief);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,8 +34,7 @@ public final class AntigriefManager {
|
||||
* @param antigrief The integration to unregister.
|
||||
*/
|
||||
public static void unregister(@NotNull final AntigriefIntegration antigrief) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(antigrief.getPluginName()));
|
||||
REGISTERED.remove(antigrief);
|
||||
REGISTRY.remove(antigrief);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +46,7 @@ public final class AntigriefManager {
|
||||
*/
|
||||
public static boolean canPickupItem(@NotNull final Player player,
|
||||
@NotNull final Location location) {
|
||||
return REGISTERED.stream().allMatch(antigriefIntegration -> antigriefIntegration.canPickupItem(player, location));
|
||||
return REGISTRY.allSafely(integration -> integration.canPickupItem(player, location));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +58,7 @@ public final class AntigriefManager {
|
||||
*/
|
||||
public static boolean canBreakBlock(@NotNull final Player player,
|
||||
@NotNull final Block block) {
|
||||
return REGISTERED.stream().allMatch(antigriefIntegration -> antigriefIntegration.canBreakBlock(player, block));
|
||||
return REGISTRY.allSafely(integration -> integration.canBreakBlock(player, block));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +70,7 @@ public final class AntigriefManager {
|
||||
*/
|
||||
public static boolean canCreateExplosion(@NotNull final Player player,
|
||||
@NotNull final Location location) {
|
||||
return REGISTERED.stream().allMatch(antigriefIntegration -> antigriefIntegration.canCreateExplosion(player, location));
|
||||
return REGISTRY.allSafely(integration -> integration.canCreateExplosion(player, location));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,7 +82,7 @@ public final class AntigriefManager {
|
||||
*/
|
||||
public static boolean canPlaceBlock(@NotNull final Player player,
|
||||
@NotNull final Block block) {
|
||||
return REGISTERED.stream().allMatch(antigriefIntegration -> antigriefIntegration.canPlaceBlock(player, block));
|
||||
return REGISTRY.allSafely(integration -> integration.canPlaceBlock(player, block));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +94,7 @@ public final class AntigriefManager {
|
||||
*/
|
||||
public static boolean canInjure(@NotNull final Player player,
|
||||
@NotNull final LivingEntity victim) {
|
||||
return REGISTERED.stream().allMatch(antigriefIntegration -> antigriefIntegration.canInjure(player, victim));
|
||||
return REGISTRY.allSafely(integration -> integration.canInjure(player, victim));
|
||||
}
|
||||
|
||||
private AntigriefManager() {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.willfp.eco.core.integrations.customentities;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class to handle custom entity integrations.
|
||||
*/
|
||||
@@ -12,7 +10,7 @@ public final class CustomEntitiesManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<CustomEntitiesIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<CustomEntitiesIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -20,8 +18,7 @@ public final class CustomEntitiesManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final CustomEntitiesIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTRY.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,9 +27,7 @@ public final class CustomEntitiesManager {
|
||||
* @see com.willfp.eco.core.entities.Entities
|
||||
*/
|
||||
public static void registerAllEntities() {
|
||||
for (CustomEntitiesIntegration integration : REGISTERED) {
|
||||
integration.registerAllEntities();
|
||||
}
|
||||
REGISTRY.forEachSafely(CustomEntitiesIntegration::registerAllEntities);
|
||||
}
|
||||
|
||||
private CustomEntitiesManager() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.core.integrations.customitems;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -12,7 +13,7 @@ public final class CustomItemsManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<CustomItemsIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<CustomItemsIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -20,8 +21,7 @@ public final class CustomItemsManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final CustomItemsIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTRY.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,9 +30,7 @@ public final class CustomItemsManager {
|
||||
* @see com.willfp.eco.core.items.Items
|
||||
*/
|
||||
public static void registerAllItems() {
|
||||
for (CustomItemsIntegration customItemsIntegration : REGISTERED) {
|
||||
customItemsIntegration.registerAllItems();
|
||||
}
|
||||
REGISTRY.forEachSafely(CustomItemsIntegration::registerAllItems);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,9 +39,7 @@ public final class CustomItemsManager {
|
||||
* @see com.willfp.eco.core.items.Items
|
||||
*/
|
||||
public static void registerProviders() {
|
||||
for (CustomItemsIntegration customItemsIntegration : REGISTERED) {
|
||||
customItemsIntegration.registerProvider();
|
||||
}
|
||||
REGISTRY.forEachSafely(CustomItemsIntegration::registerProvider);
|
||||
}
|
||||
|
||||
private CustomItemsManager() {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.willfp.eco.core.integrations.economy;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class to handle economy.
|
||||
@@ -14,7 +13,7 @@ public final class EconomyManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<EconomyIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<EconomyIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -22,8 +21,7 @@ public final class EconomyManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final EconomyIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTRY.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +30,7 @@ public final class EconomyManager {
|
||||
* @return If any economy.
|
||||
*/
|
||||
public static boolean hasRegistrations() {
|
||||
return !REGISTERED.isEmpty();
|
||||
return REGISTRY.isNotEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,11 +54,10 @@ public final class EconomyManager {
|
||||
*/
|
||||
public static boolean hasAmount(@NotNull final OfflinePlayer player,
|
||||
final BigDecimal amount) {
|
||||
for (EconomyIntegration integration : REGISTERED) {
|
||||
return integration.hasAmount(player, amount);
|
||||
}
|
||||
|
||||
return false;
|
||||
return REGISTRY.firstSafely(
|
||||
integration -> integration.hasAmount(player, amount),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,11 +81,10 @@ public final class EconomyManager {
|
||||
*/
|
||||
public static boolean giveMoney(@NotNull final OfflinePlayer player,
|
||||
@NotNull final BigDecimal amount) {
|
||||
for (EconomyIntegration integration : REGISTERED) {
|
||||
return integration.giveMoney(player, amount);
|
||||
}
|
||||
|
||||
return false;
|
||||
return REGISTRY.firstSafely(
|
||||
integration -> integration.giveMoney(player, amount),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,11 +108,10 @@ public final class EconomyManager {
|
||||
*/
|
||||
public static boolean removeMoney(@NotNull final OfflinePlayer player,
|
||||
@NotNull final BigDecimal amount) {
|
||||
for (EconomyIntegration integration : REGISTERED) {
|
||||
return integration.removeMoney(player, amount);
|
||||
}
|
||||
|
||||
return false;
|
||||
return REGISTRY.firstSafely(
|
||||
integration -> integration.removeMoney(player, amount),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,11 +131,10 @@ public final class EconomyManager {
|
||||
* @return The balance.
|
||||
*/
|
||||
public static BigDecimal getExactBalance(@NotNull final OfflinePlayer player) {
|
||||
for (EconomyIntegration integration : REGISTERED) {
|
||||
return integration.getExactBalance(player);
|
||||
}
|
||||
|
||||
return BigDecimal.ZERO;
|
||||
return REGISTRY.firstSafely(
|
||||
integration -> integration.getExactBalance(player),
|
||||
BigDecimal.ZERO
|
||||
);
|
||||
}
|
||||
|
||||
private EconomyManager() {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.willfp.eco.core.integrations.guidetection;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import com.willfp.eco.util.MenuUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class to handle GUI detection.
|
||||
*/
|
||||
@@ -14,7 +12,7 @@ public final class GUIDetectionManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<GUIDetectionIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<GUIDetectionIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -22,8 +20,7 @@ public final class GUIDetectionManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final GUIDetectionIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTRY.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,13 +34,7 @@ public final class GUIDetectionManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (GUIDetectionIntegration integration : REGISTERED) {
|
||||
if (integration.hasGUIOpen(player)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return REGISTRY.anySafely(integration -> integration.hasGUIOpen(player));
|
||||
}
|
||||
|
||||
private GUIDetectionManager() {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.willfp.eco.core.integrations.hologram;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class to handle hologram integrations.
|
||||
@@ -14,7 +13,7 @@ public final class HologramManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<HologramIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<HologramIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -22,8 +21,7 @@ public final class HologramManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final HologramIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTRY.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,11 +33,10 @@ public final class HologramManager {
|
||||
*/
|
||||
public static Hologram createHologram(@NotNull final Location location,
|
||||
@NotNull final List<String> contents) {
|
||||
for (HologramIntegration integration : REGISTERED) {
|
||||
return integration.createHologram(location, contents);
|
||||
}
|
||||
|
||||
return new DummyHologram();
|
||||
return REGISTRY.firstSafely(
|
||||
integration -> integration.createHologram(location, contents),
|
||||
new DummyHologram()
|
||||
);
|
||||
}
|
||||
|
||||
private HologramManager() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.core.integrations.mcmmo;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.Event;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -14,7 +15,7 @@ public final class McmmoManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<McmmoIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<McmmoIntegration> REGISTERED = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -22,8 +23,7 @@ public final class McmmoManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final McmmoIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTERED.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,13 +34,11 @@ public final class McmmoManager {
|
||||
*/
|
||||
public static int getBonusDropCount(@NotNull final Block block) {
|
||||
int finalValue = 0;
|
||||
|
||||
for (McmmoIntegration mcmmoIntegration : REGISTERED) {
|
||||
finalValue += mcmmoIntegration.getBonusDropCount(block);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return finalValue;
|
||||
}
|
||||
|
||||
@@ -51,13 +49,7 @@ public final class McmmoManager {
|
||||
* @return If the event is fake.
|
||||
*/
|
||||
public static boolean isFake(@NotNull final Event event) {
|
||||
for (McmmoIntegration mcmmoIntegration : REGISTERED) {
|
||||
if (mcmmoIntegration.isFake(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
return REGISTERED.anySafely(integration -> integration.isFake(event));
|
||||
}
|
||||
|
||||
private McmmoManager() {
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper class for placeholder integrations.
|
||||
* Wrapper class for arguments integrations.
|
||||
*/
|
||||
public interface PlaceholderIntegration extends Integration {
|
||||
/**
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
package com.willfp.eco.core.integrations.placeholder;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.willfp.eco.core.Eco;
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.map.DefaultMap;
|
||||
import com.willfp.eco.core.placeholder.AdditionalPlayer;
|
||||
import com.willfp.eco.core.placeholder.DynamicPlaceholder;
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||
import com.willfp.eco.core.placeholder.Placeholder;
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||
import com.willfp.eco.core.placeholder.PlayerDynamicPlaceholder;
|
||||
import com.willfp.eco.core.placeholder.PlayerPlaceholder;
|
||||
import com.willfp.eco.core.placeholder.PlayerStaticPlaceholder;
|
||||
import com.willfp.eco.core.placeholder.PlayerlessPlaceholder;
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import com.willfp.eco.core.placeholder.RegistrablePlaceholder;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -23,58 +17,34 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Class to handle placeholder integrations.
|
||||
* Class to handle arguments integrations.
|
||||
*/
|
||||
public final class PlaceholderManager {
|
||||
/**
|
||||
* All registered placeholders.
|
||||
*/
|
||||
private static final Map<EcoPlugin, Map<Pattern, Placeholder>> REGISTERED_PLACEHOLDERS = new HashMap<>();
|
||||
private static final DefaultMap<EcoPlugin, Set<Placeholder>> REGISTERED_PLACEHOLDERS = new DefaultMap<>(HashSet::new);
|
||||
|
||||
/**
|
||||
* All registered placeholder integrations.
|
||||
* All registered arguments integrations.
|
||||
*/
|
||||
private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Placeholder Lookup Cache.
|
||||
*/
|
||||
private static final Cache<PlaceholderLookup, Optional<Placeholder>> PLACEHOLDER_LOOKUP_CACHE = Caffeine.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Placeholder Cache.
|
||||
*/
|
||||
private static final LoadingCache<EntryWithPlayer, String> PLACEHOLDER_CACHE = Caffeine.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(key -> key.entry.getValue(key.player));
|
||||
|
||||
/**
|
||||
* Dynamic Placeholder Cache.
|
||||
*/
|
||||
private static final LoadingCache<DynamicEntryWithPlayer, String> DYNAMIC_PLACEHOLDER_CACHE = Caffeine.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(key -> key.entry.getValue(key.args, key.player));
|
||||
|
||||
/**
|
||||
* The default PlaceholderAPI pattern; brought in for compatibility.
|
||||
*/
|
||||
private static final Pattern PATTERN = Pattern.compile("%([^% ]+)%");
|
||||
|
||||
/**
|
||||
* Empty injectable object.
|
||||
* Empty injectableContext object.
|
||||
*/
|
||||
public static final PlaceholderInjectable EMPTY_INJECTABLE = new PlaceholderInjectable() {
|
||||
@Override
|
||||
@@ -105,97 +75,68 @@ public final class PlaceholderManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a placeholder.
|
||||
* Register a arguments.
|
||||
*
|
||||
* @param placeholder The placeholder to register.
|
||||
* @param placeholder The arguments to register.
|
||||
* @deprecated Use {@link #registerPlaceholder(RegistrablePlaceholder)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
public static void registerPlaceholder(@NotNull final Placeholder placeholder) {
|
||||
if (placeholder instanceof StaticPlaceholder || placeholder instanceof PlayerStaticPlaceholder) {
|
||||
throw new IllegalArgumentException("Static placeholders cannot be registered!");
|
||||
if (!(placeholder instanceof RegistrablePlaceholder)) {
|
||||
throw new IllegalArgumentException("Placeholder must be RegistrablePlaceholder!");
|
||||
}
|
||||
|
||||
Map<Pattern, Placeholder> pluginPlaceholders = REGISTERED_PLACEHOLDERS
|
||||
.getOrDefault(placeholder.getPlugin(), new HashMap<>());
|
||||
|
||||
pluginPlaceholders.put(placeholder.getPattern(), placeholder);
|
||||
|
||||
REGISTERED_PLACEHOLDERS.put(placeholder.getPlugin(), pluginPlaceholders);
|
||||
registerPlaceholder((RegistrablePlaceholder) placeholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of a placeholder with respect to a player.
|
||||
* Register a arguments.
|
||||
*
|
||||
* @param player The player to get the result from.
|
||||
* @param identifier The placeholder identifier.
|
||||
* @return The value of the placeholder.
|
||||
* @deprecated Specify a plugin to get the result from.
|
||||
* @param placeholder The arguments to register.
|
||||
*/
|
||||
@Deprecated(since = "6.52.2", forRemoval = true)
|
||||
@SuppressWarnings("unused")
|
||||
public static String getResult(@Nullable final Player player,
|
||||
@NotNull final String identifier) {
|
||||
throw new UnsupportedOperationException("Please specify a plugin to get the result from!");
|
||||
public static void registerPlaceholder(@NotNull final RegistrablePlaceholder placeholder) {
|
||||
// Storing as immutable set leads to slower times to register placeholders, but much
|
||||
// faster times to access registrations.
|
||||
Set<Placeholder> pluginPlaceholders = new HashSet<>(REGISTERED_PLACEHOLDERS.get(placeholder.getPlugin()));
|
||||
pluginPlaceholders.add(placeholder);
|
||||
REGISTERED_PLACEHOLDERS.put(placeholder.getPlugin(), ImmutableSet.copyOf(pluginPlaceholders));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result of a placeholder with respect to a player.
|
||||
*
|
||||
* @param player The player to get the result from.
|
||||
* @param identifier The placeholder identifier.
|
||||
* @param plugin The plugin for the placeholder.
|
||||
* @return The value of the placeholder.
|
||||
* @param identifier The placeholder args.
|
||||
* @param plugin The plugin for the arguments.
|
||||
* @return The value of the arguments.
|
||||
*/
|
||||
@NotNull
|
||||
public static String getResult(@Nullable final Player player,
|
||||
@NotNull final String identifier,
|
||||
@NotNull final EcoPlugin plugin) {
|
||||
Validate.notNull(plugin, "Plugin cannot be null!");
|
||||
@Nullable final EcoPlugin plugin) {
|
||||
return Objects.requireNonNullElse(
|
||||
getResult(
|
||||
plugin,
|
||||
identifier,
|
||||
new PlaceholderContext(player)
|
||||
),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
// This is really janky, and it sucks, but it works so?
|
||||
// Compensating for regex being slow so that's why we get it.
|
||||
Placeholder placeholder = PLACEHOLDER_LOOKUP_CACHE.get(
|
||||
new PlaceholderLookup(identifier, plugin),
|
||||
(it) -> {
|
||||
// I hate the streams API.
|
||||
return REGISTERED_PLACEHOLDERS
|
||||
.getOrDefault(plugin, new HashMap<>())
|
||||
.entrySet()
|
||||
.stream().filter(entry -> entry.getKey().matcher(identifier).matches())
|
||||
.map(Map.Entry::getValue)
|
||||
.findFirst();
|
||||
}
|
||||
).orElse(null);
|
||||
|
||||
if (placeholder == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
This code here is *really* not very good. It's mega externalized logic hacked
|
||||
together and made worse by the addition of dynamic placeholders. But it works,
|
||||
and it means I don't have to rewrite the whole placeholder system. So it's
|
||||
good enough for me.
|
||||
*/
|
||||
|
||||
if (placeholder instanceof PlayerPlaceholder playerPlaceholder) {
|
||||
if (player == null) {
|
||||
return "";
|
||||
} else {
|
||||
return PLACEHOLDER_CACHE.get(new EntryWithPlayer(playerPlaceholder, player));
|
||||
}
|
||||
} else if (placeholder instanceof PlayerlessPlaceholder playerlessPlaceholder) {
|
||||
return playerlessPlaceholder.getValue();
|
||||
} else if (placeholder instanceof PlayerDynamicPlaceholder playerDynamicPlaceholder) {
|
||||
if (player == null) {
|
||||
return "";
|
||||
} else {
|
||||
return DYNAMIC_PLACEHOLDER_CACHE.get(new DynamicEntryWithPlayer(playerDynamicPlaceholder, identifier, player));
|
||||
}
|
||||
} else if (placeholder instanceof DynamicPlaceholder dynamicPlaceholder) {
|
||||
return dynamicPlaceholder.getValue(identifier);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
/**
|
||||
* Get the result of a placeholder given a plugin and arguments.
|
||||
*
|
||||
* @param plugin The plugin for the placeholder.
|
||||
* @param args The arguments.
|
||||
* @param context The context.
|
||||
* @return The value of the arguments.
|
||||
*/
|
||||
@Nullable
|
||||
public static String getResult(@Nullable final EcoPlugin plugin,
|
||||
@NotNull final String args,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return Eco.get().getPlaceholderValue(plugin, args, context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,7 +145,10 @@ public final class PlaceholderManager {
|
||||
* @param text The text that may contain placeholders to translate.
|
||||
* @param player The player to translate the placeholders with respect to.
|
||||
* @return The text, translated.
|
||||
* @deprecated Use {@link #translatePlaceholders(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public static String translatePlaceholders(@NotNull final String text,
|
||||
@Nullable final Player player) {
|
||||
return translatePlaceholders(text, player, EMPTY_INJECTABLE);
|
||||
@@ -215,9 +159,12 @@ public final class PlaceholderManager {
|
||||
*
|
||||
* @param text The text that may contain placeholders to translate.
|
||||
* @param player The player to translate the placeholders with respect to.
|
||||
* @param context The injectable context.
|
||||
* @param context The injectableContext parseContext.
|
||||
* @return The text, translated.
|
||||
* @deprecated Use {@link #translatePlaceholders(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public static String translatePlaceholders(@NotNull final String text,
|
||||
@Nullable final Player player,
|
||||
@NotNull final PlaceholderInjectable context) {
|
||||
@@ -229,84 +176,50 @@ public final class PlaceholderManager {
|
||||
*
|
||||
* @param text The text that may contain placeholders to translate.
|
||||
* @param player The player to translate the placeholders with respect to.
|
||||
* @param context The injectable context.
|
||||
* @param context The injectableContext parseContext.
|
||||
* @param additionalPlayers Additional players to translate placeholders for.
|
||||
* @return The text, translated.
|
||||
* @deprecated Use {@link #translatePlaceholders(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public static String translatePlaceholders(@NotNull final String text,
|
||||
@Nullable final Player player,
|
||||
@NotNull final PlaceholderInjectable context,
|
||||
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
|
||||
String processed = text;
|
||||
return translatePlaceholders(
|
||||
text,
|
||||
new PlaceholderContext(
|
||||
player,
|
||||
null,
|
||||
context,
|
||||
additionalPlayers
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Translate all placeholders without a placeholder context.
|
||||
*
|
||||
* @param text The text that may contain placeholders to translate.
|
||||
* @return The text, translated.
|
||||
*/
|
||||
@NotNull
|
||||
public static String translatePlaceholders(@NotNull final String text) {
|
||||
return Eco.get().translatePlaceholders(text, PlaceholderContext.EMPTY);
|
||||
}
|
||||
|
||||
Why am I doing statics at the start, but player statics at the end?
|
||||
|
||||
Additional players let you use something like victim as a player to parse in relation to,
|
||||
for example doing %victim_player_health%, which would parse the health of the victim.
|
||||
|
||||
However, something like libreforge will also inject %victim_max_health%, which is unrelated
|
||||
to additional players, and instead holds a constant value. So, eco saw this, smartly thought
|
||||
"ah, it's an additional player, let's parse it", and then tried to parse %max_health% with
|
||||
relation to the victim, which resolved to zero. So, we have to parse statics and player statics
|
||||
that might include a prefix first, then additional players, then player statics with the support
|
||||
of additional players.
|
||||
|
||||
This was a massive headache and took so many reports before I clocked what was going on.
|
||||
|
||||
Oh well, at least it's fixed now.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
for (InjectablePlaceholder injection : context.getPlaceholderInjections()) {
|
||||
if (injection instanceof StaticPlaceholder placeholder) {
|
||||
processed = processed.replace("%" + placeholder.getIdentifier() + "%", placeholder.getValue());
|
||||
} else if (injection instanceof PlayerStaticPlaceholder placeholder && player != null) {
|
||||
processed = processed.replace("%" + placeholder.getIdentifier() + "%", placeholder.getValue(player));
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent running 2 scans if there are no additional players.
|
||||
if (!additionalPlayers.isEmpty()) {
|
||||
List<String> found = findPlaceholdersIn(text);
|
||||
|
||||
for (AdditionalPlayer additionalPlayer : additionalPlayers) {
|
||||
for (String placeholder : found) {
|
||||
String prefix = "%" + additionalPlayer.getIdentifier() + "_";
|
||||
|
||||
if (placeholder.startsWith(prefix)) {
|
||||
processed = processed.replace(
|
||||
placeholder,
|
||||
translatePlaceholders(
|
||||
"%" + StringUtils.removePrefix(prefix, placeholder),
|
||||
additionalPlayer.getPlayer()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only run jank code if there are no integrations.
|
||||
if (REGISTERED_INTEGRATIONS.isEmpty()) {
|
||||
processed = setWithoutIntegration(processed, player);
|
||||
}
|
||||
|
||||
for (PlaceholderIntegration integration : REGISTERED_INTEGRATIONS) {
|
||||
processed = integration.translate(processed, player);
|
||||
}
|
||||
|
||||
// DON'T REMOVE THIS, IT'S NOT DUPLICATE CODE.
|
||||
for (InjectablePlaceholder injection : context.getPlaceholderInjections()) {
|
||||
// Do I know this is a bad way of doing this? Yes.
|
||||
if (injection instanceof PlayerStaticPlaceholder placeholder && player != null) {
|
||||
processed = processed.replace("%" + placeholder.getIdentifier() + "%", placeholder.getValue(player));
|
||||
}
|
||||
}
|
||||
|
||||
return processed;
|
||||
/**
|
||||
* Translate all placeholders in a translation context.
|
||||
*
|
||||
* @param text The text that may contain placeholders to translate.
|
||||
* @param context The translation context.
|
||||
* @return The text, translated.
|
||||
*/
|
||||
@NotNull
|
||||
public static String translatePlaceholders(@NotNull final String text,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return Eco.get().translatePlaceholders(text, context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,108 +244,22 @@ public final class PlaceholderManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set placeholders without any integrations.
|
||||
* <p>
|
||||
* This is fallback if for some reason you don't have PAPI installed.
|
||||
* It's a cut-down version of the actual PAPI code, and I don't
|
||||
* really know how it works.
|
||||
* <p>
|
||||
* Original source
|
||||
* <a href="https://github.com/PlaceholderAPI/PlaceholderAPI/blob/master/src/main/java/me/clip/placeholderapi/replacer/CharsReplacer.java">here</a>.
|
||||
* Get all registered placeholder integrations.
|
||||
*
|
||||
* @param text The text.
|
||||
* @param player The player.
|
||||
* @return The text.
|
||||
* @return The integrations.
|
||||
*/
|
||||
private static String setWithoutIntegration(@NotNull final String text,
|
||||
@Nullable final Player player) {
|
||||
char[] chars = text.toCharArray();
|
||||
StringBuilder builder = new StringBuilder(text.length());
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
StringBuilder parameters = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char currentChar = chars[i];
|
||||
if (currentChar == '%' && i + 1 < chars.length) {
|
||||
boolean identified = false;
|
||||
boolean badPlaceholder = true;
|
||||
boolean hadSpace = false;
|
||||
|
||||
while (true) {
|
||||
i++;
|
||||
if (i >= chars.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
char p = chars[i];
|
||||
if (p == ' ' && !identified) {
|
||||
hadSpace = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == '%') {
|
||||
badPlaceholder = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == '_' && !identified) {
|
||||
identified = true;
|
||||
} else if (identified) {
|
||||
parameters.append(p);
|
||||
} else {
|
||||
identifier.append(p);
|
||||
}
|
||||
}
|
||||
|
||||
String pluginName = identifier.toString().toLowerCase();
|
||||
EcoPlugin plugin = EcoPlugin.getPlugin(pluginName);
|
||||
String placeholderIdentifier = parameters.toString();
|
||||
identifier.setLength(0);
|
||||
parameters.setLength(0);
|
||||
if (badPlaceholder) {
|
||||
builder.append('%').append(pluginName);
|
||||
if (identified) {
|
||||
builder.append('_').append(placeholderIdentifier);
|
||||
}
|
||||
|
||||
if (hadSpace) {
|
||||
builder.append(' ');
|
||||
}
|
||||
} else {
|
||||
if (plugin == null) {
|
||||
builder.append('%').append(pluginName);
|
||||
|
||||
if (identified) {
|
||||
builder.append('_');
|
||||
}
|
||||
|
||||
builder.append(placeholderIdentifier).append('%');
|
||||
} else {
|
||||
builder.append(getResult(player, placeholderIdentifier, plugin));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
builder.append(currentChar);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
public static Set<PlaceholderIntegration> getRegisteredIntegrations() {
|
||||
return Set.copyOf(REGISTERED_INTEGRATIONS);
|
||||
}
|
||||
|
||||
private record PlaceholderLookup(@NotNull String identifier,
|
||||
@Nullable EcoPlugin plugin) {
|
||||
|
||||
}
|
||||
|
||||
private record EntryWithPlayer(@NotNull PlayerPlaceholder entry,
|
||||
@NotNull Player player) {
|
||||
|
||||
}
|
||||
|
||||
private record DynamicEntryWithPlayer(@NotNull PlayerDynamicPlaceholder entry,
|
||||
@NotNull String args,
|
||||
@NotNull Player player) {
|
||||
|
||||
/**
|
||||
* Get all registered placeholders for a plugin.
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @return The placeholders.
|
||||
*/
|
||||
public static Set<Placeholder> getRegisteredPlaceholders(@NotNull final EcoPlugin plugin) {
|
||||
return REGISTERED_PLACEHOLDERS.get(plugin);
|
||||
}
|
||||
|
||||
private PlaceholderManager() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.core.integrations.shop;
|
||||
|
||||
import com.willfp.eco.core.integrations.IntegrationRegistry;
|
||||
import com.willfp.eco.core.price.Price;
|
||||
import com.willfp.eco.core.price.impl.PriceFree;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -13,11 +14,12 @@ import java.util.Set;
|
||||
/**
|
||||
* Class to handle shop integrations.
|
||||
*/
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
public final class ShopManager {
|
||||
/**
|
||||
* A set of all registered integrations.
|
||||
*/
|
||||
private static final Set<ShopIntegration> REGISTERED = new HashSet<>();
|
||||
private static final IntegrationRegistry<ShopIntegration> REGISTRY = new IntegrationRegistry<>();
|
||||
|
||||
/**
|
||||
* Register a new integration.
|
||||
@@ -25,17 +27,14 @@ public final class ShopManager {
|
||||
* @param integration The integration to register.
|
||||
*/
|
||||
public static void register(@NotNull final ShopIntegration integration) {
|
||||
REGISTERED.removeIf(it -> it.getPluginName().equalsIgnoreCase(integration.getPluginName()));
|
||||
REGISTERED.add(integration);
|
||||
REGISTRY.register(integration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register eco item provider for shop plugins.
|
||||
*/
|
||||
public static void registerEcoProvider() {
|
||||
for (ShopIntegration shopIntegration : REGISTERED) {
|
||||
shopIntegration.registerEcoProvider();
|
||||
}
|
||||
REGISTRY.forEachSafely(ShopIntegration::registerEcoProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,11 +50,7 @@ public final class ShopManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ShopIntegration integration : REGISTERED) {
|
||||
return integration.isSellable(itemStack, player);
|
||||
}
|
||||
|
||||
return false;
|
||||
return REGISTRY.anySafely(integration -> integration.isSellable(itemStack, player));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,11 +69,10 @@ public final class ShopManager {
|
||||
return new PriceFree();
|
||||
}
|
||||
|
||||
for (ShopIntegration integration : REGISTERED) {
|
||||
return integration.getUnitValue(itemStack, player);
|
||||
}
|
||||
|
||||
return new PriceFree();
|
||||
return REGISTRY.firstSafely(
|
||||
integration -> integration.getUnitValue(itemStack, player),
|
||||
new PriceFree()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,11 +102,10 @@ public final class ShopManager {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
for (ShopIntegration shopIntegration : REGISTERED) {
|
||||
return shopIntegration.getUnitValue(itemStack, player).getValue(player, itemStack.getAmount());
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
return REGISTRY.firstSafely(
|
||||
integration -> integration.getUnitValue(itemStack, player).getValue(player, itemStack.getAmount()),
|
||||
0.0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +114,7 @@ public final class ShopManager {
|
||||
* @return The integrations.
|
||||
*/
|
||||
public static Set<ShopIntegration> getRegisteredIntegrations() {
|
||||
return new HashSet<>(REGISTERED);
|
||||
return new HashSet<>(REGISTRY.values());
|
||||
}
|
||||
|
||||
private ShopManager() {
|
||||
|
||||
@@ -3,27 +3,25 @@ package com.willfp.eco.core.math;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import com.willfp.eco.core.placeholder.AdditionalPlayer;
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a context to do math in.
|
||||
* Represents a context to parse math in.
|
||||
*
|
||||
* @param injectableContext The PlaceholderInjectable context.
|
||||
* @param player The player.
|
||||
* @param additionalPlayers The additional players.
|
||||
* @deprecated Use {@link PlaceholderContext} instead.
|
||||
*/
|
||||
public record MathContext(
|
||||
@NotNull PlaceholderInjectable injectableContext,
|
||||
@Nullable Player player,
|
||||
@NotNull Collection<AdditionalPlayer> additionalPlayers
|
||||
) {
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
public class MathContext {
|
||||
/**
|
||||
* Empty math context.
|
||||
* Returns an empty math parseContext.
|
||||
*/
|
||||
public static final MathContext EMPTY = new MathContext(
|
||||
PlaceholderManager.EMPTY_INJECTABLE,
|
||||
@@ -32,9 +30,157 @@ public record MathContext(
|
||||
);
|
||||
|
||||
/**
|
||||
* Create MathContext of a PlaceholderInjectable context.
|
||||
* The PlaceholderInjectable parse context.
|
||||
*/
|
||||
@NotNull
|
||||
private final PlaceholderInjectable injectableContext;
|
||||
|
||||
/**
|
||||
* The player.
|
||||
*/
|
||||
@Nullable
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* The additional players.
|
||||
*/
|
||||
@NotNull
|
||||
private final Collection<AdditionalPlayer> additionalPlayers;
|
||||
|
||||
/**
|
||||
* Constructs a new MathContext with the given parameters.
|
||||
*
|
||||
* @param injectableContext The PlaceholderInjectable context.
|
||||
* @param injectableContext The PlaceholderInjectable parseContext.
|
||||
* @param player The player.
|
||||
* @param additionalPlayers The additional players.
|
||||
*/
|
||||
public MathContext(@NotNull PlaceholderInjectable injectableContext,
|
||||
@Nullable Player player,
|
||||
@NotNull Collection<AdditionalPlayer> additionalPlayers) {
|
||||
this.injectableContext = injectableContext;
|
||||
this.player = player;
|
||||
this.additionalPlayers = additionalPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PlaceholderInjectable parse context.
|
||||
* <p>
|
||||
* Duplicate method because MathContext used to be a record.
|
||||
*
|
||||
* @return The injectable context.
|
||||
* @deprecated Use {@link #getInjectableContext()} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
public PlaceholderInjectable injectableContext() {
|
||||
return injectableContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PlaceholderInjectable parse context.
|
||||
*
|
||||
* @return The injectable context.
|
||||
*/
|
||||
@NotNull
|
||||
public PlaceholderInjectable getInjectableContext() {
|
||||
return injectableContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the player.
|
||||
* <p>
|
||||
* Duplicate method because MathContext used to be a record.
|
||||
*
|
||||
* @return The player.
|
||||
* @deprecated Use {@link #getPlayer()} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@Nullable
|
||||
public Player player() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the player.
|
||||
*
|
||||
* @return The player.
|
||||
*/
|
||||
@Nullable
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional players.
|
||||
* <p>
|
||||
* Duplicate method because MathContext used to be a record.
|
||||
*
|
||||
* @return The additional players.
|
||||
* @deprecated Use {@link #getAdditionalPlayers()} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public Collection<AdditionalPlayer> additionalPlayers() {
|
||||
return additionalPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional players.
|
||||
*
|
||||
* @return The additional players.
|
||||
*/
|
||||
@NotNull
|
||||
public Collection<AdditionalPlayer> getAdditionalPlayers() {
|
||||
return additionalPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to PlaceholderContext.
|
||||
*
|
||||
* @return The PlaceholderContext.
|
||||
*/
|
||||
@NotNull
|
||||
public PlaceholderContext toPlaceholderContext() {
|
||||
return new PlaceholderContext(
|
||||
this.player,
|
||||
null,
|
||||
this.injectableContext,
|
||||
this.additionalPlayers
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MathContext{" +
|
||||
"injectableContext=" + injectableContext +
|
||||
", player=" + player +
|
||||
", additionalPlayers=" + additionalPlayers +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof MathContext that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return injectableContext.equals(that.injectableContext) &&
|
||||
Objects.equals(player, that.player) &&
|
||||
additionalPlayers.equals(that.additionalPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(injectableContext, player, additionalPlayers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create MathContext of a PlaceholderInjectable parseContext.
|
||||
*
|
||||
* @param injectableContext The PlaceholderInjectable parseContext.
|
||||
* @return The MathContext.
|
||||
*/
|
||||
public static MathContext of(@NotNull final PlaceholderInjectable injectableContext) {
|
||||
@@ -48,16 +194,16 @@ public record MathContext(
|
||||
/**
|
||||
* Copy a MathContext with a player.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param context The parseContext.
|
||||
* @param player The player.
|
||||
* @return The new MathContext.
|
||||
*/
|
||||
public static MathContext copyWithPlayer(@NotNull final MathContext context,
|
||||
@Nullable final Player player) {
|
||||
return new MathContext(
|
||||
context.injectableContext(),
|
||||
context.injectableContext,
|
||||
player,
|
||||
context.additionalPlayers()
|
||||
context.additionalPlayers
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -12,24 +12,24 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* A placeholder that does not require a player and supports dynamic styles.
|
||||
*/
|
||||
public final class DynamicPlaceholder implements Placeholder {
|
||||
public final class DynamicPlaceholder implements RegistrablePlaceholder {
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
* The arguments pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* The function to retrieve the output of the placeholder.
|
||||
* The function to retrieve the output of the arguments.
|
||||
*/
|
||||
private final Function<String, String> function;
|
||||
private final Function<@NotNull String, @Nullable String> function;
|
||||
|
||||
/**
|
||||
* The plugin for the placeholder.
|
||||
* The plugin for the arguments.
|
||||
*/
|
||||
private final EcoPlugin plugin;
|
||||
|
||||
/**
|
||||
* Create a new dynamic placeholder.
|
||||
* Create a new dynamic arguments.
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @param pattern The pattern.
|
||||
@@ -37,31 +37,33 @@ public final class DynamicPlaceholder implements Placeholder {
|
||||
*/
|
||||
public DynamicPlaceholder(@NotNull final EcoPlugin plugin,
|
||||
@NotNull final Pattern pattern,
|
||||
@NotNull final Function<String, String> function) {
|
||||
@NotNull final Function<@NotNull String, @Nullable String> function) {
|
||||
this.plugin = plugin;
|
||||
this.pattern = pattern;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the placeholder.
|
||||
*
|
||||
* @param args The args.
|
||||
* @return The value.
|
||||
*/
|
||||
@NotNull
|
||||
public String getValue(@NotNull final String args) {
|
||||
@Override
|
||||
@Nullable
|
||||
public String getValue(@NotNull final String args,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return function.apply(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the placeholder.
|
||||
* Get the value of the arguments.
|
||||
*
|
||||
* @return The placeholder.
|
||||
* @param args The args.
|
||||
* @return The value.
|
||||
* @deprecated Use {@link #getValue(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
public DynamicPlaceholder register() {
|
||||
PlaceholderManager.registerPlaceholder(this);
|
||||
return this;
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public String getValue(@NotNull final String args) {
|
||||
return Objects.requireNonNullElse(
|
||||
function.apply(args),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,18 +71,17 @@ public final class DynamicPlaceholder implements Placeholder {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public @NotNull String getIdentifier() {
|
||||
return "dynamic";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pattern getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull DynamicPlaceholder register() {
|
||||
return (DynamicPlaceholder) RegistrablePlaceholder.super.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (this == o) {
|
||||
@@ -97,6 +98,6 @@ public final class DynamicPlaceholder implements Placeholder {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
||||
return Objects.hash(this.getPattern(), this.getPlugin());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.Eco;
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Placeholders that can be injected into {@link PlaceholderInjectable} objects.
|
||||
*/
|
||||
public sealed interface InjectablePlaceholder extends Placeholder permits PlayerStaticPlaceholder, StaticPlaceholder {
|
||||
public interface InjectablePlaceholder extends Placeholder {
|
||||
/**
|
||||
* Get the plugin that holds the arguments.
|
||||
*
|
||||
* @return The plugin.
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
default @NotNull EcoPlugin getPlugin() {
|
||||
return Eco.get().getEcoPlugin();
|
||||
default EcoPlugin getPlugin() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,64 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A placeholder represents a string that can hold a value.
|
||||
*/
|
||||
public sealed interface Placeholder permits PlayerPlaceholder, PlayerlessPlaceholder,
|
||||
DynamicPlaceholder, PlayerDynamicPlaceholder, InjectablePlaceholder {
|
||||
public interface Placeholder {
|
||||
/**
|
||||
* Get the plugin that holds the placeholder.
|
||||
* Get the plugin that holds the arguments.
|
||||
*
|
||||
* @return The plugin.
|
||||
*/
|
||||
@NotNull
|
||||
@Nullable
|
||||
EcoPlugin getPlugin();
|
||||
|
||||
/**
|
||||
* Get the identifier for the placeholder.
|
||||
* Get the value of the arguments.
|
||||
*
|
||||
* @return The identifier.
|
||||
* @param args The args.
|
||||
* @param context The context.
|
||||
* @return The value.
|
||||
*/
|
||||
@NotNull
|
||||
String getIdentifier();
|
||||
@Nullable
|
||||
String getValue(@NotNull String args,
|
||||
@NotNull PlaceholderContext context);
|
||||
|
||||
/**
|
||||
* Get the pattern for the placeholder.
|
||||
* Get the pattern for the arguments.
|
||||
*
|
||||
* @return The pattern.
|
||||
*/
|
||||
@NotNull
|
||||
default Pattern getPattern() {
|
||||
return Pattern.compile(this.getIdentifier());
|
||||
Pattern getPattern();
|
||||
|
||||
/**
|
||||
* Try to translate all instances of this placeholder in text quickly.
|
||||
*
|
||||
* @param text The text to translate.
|
||||
* @param context The context.
|
||||
* @return The translated text.
|
||||
*/
|
||||
default String tryTranslateQuickly(@NotNull final String text,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the identifier for the arguments.
|
||||
*
|
||||
* @return The identifier.
|
||||
* @deprecated Some arguments may not have an identifier. Use {@link #getPattern()} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
default String getIdentifier() {
|
||||
return this.getPattern().pattern();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.List;
|
||||
*/
|
||||
public interface PlaceholderInjectable {
|
||||
/**
|
||||
* Inject placeholder.
|
||||
* Inject arguments.
|
||||
*
|
||||
* @param placeholders The placeholders.
|
||||
*/
|
||||
@@ -18,7 +18,7 @@ public interface PlaceholderInjectable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject placeholder.
|
||||
* Inject arguments.
|
||||
*
|
||||
* @param placeholders The placeholders.
|
||||
*/
|
||||
@@ -29,7 +29,7 @@ public interface PlaceholderInjectable {
|
||||
/**
|
||||
* Inject placeholders.
|
||||
* <p>
|
||||
* When implementing a PlaceholderInjectable object, override this method.
|
||||
* If a placeholder already has the same pattern, it should be replaced.
|
||||
*
|
||||
* @param placeholders The placeholders.
|
||||
*/
|
||||
@@ -43,7 +43,7 @@ public interface PlaceholderInjectable {
|
||||
/**
|
||||
* Get injected placeholders.
|
||||
* <p>
|
||||
* Override this method in implementations.
|
||||
* This method should always return an immutable list.
|
||||
*
|
||||
* @return Injected placeholders.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -11,26 +11,26 @@ import java.util.function.BiFunction;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A placeholder that does not require a player and supports dynamic styles.
|
||||
* A arguments that does not require a player and supports dynamic styles.
|
||||
*/
|
||||
public final class PlayerDynamicPlaceholder implements Placeholder {
|
||||
public final class PlayerDynamicPlaceholder implements RegistrablePlaceholder {
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
* The arguments pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* The function to retrieve the output of the placeholder.
|
||||
* The function to retrieve the output of the arguments.
|
||||
*/
|
||||
private final BiFunction<String, Player, String> function;
|
||||
private final BiFunction<@NotNull String, @NotNull Player, @Nullable String> function;
|
||||
|
||||
/**
|
||||
* The plugin for the placeholder.
|
||||
* The plugin for the arguments.
|
||||
*/
|
||||
private final EcoPlugin plugin;
|
||||
|
||||
/**
|
||||
* Create a new dynamic placeholder.
|
||||
* Create a new dynamic arguments.
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @param pattern The pattern.
|
||||
@@ -38,33 +38,40 @@ public final class PlayerDynamicPlaceholder implements Placeholder {
|
||||
*/
|
||||
public PlayerDynamicPlaceholder(@NotNull final EcoPlugin plugin,
|
||||
@NotNull final Pattern pattern,
|
||||
@NotNull final BiFunction<String, Player, String> function) {
|
||||
@NotNull final BiFunction<@NotNull String, @NotNull Player, @Nullable String> function) {
|
||||
this.plugin = plugin;
|
||||
this.pattern = pattern;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the placeholder.
|
||||
*
|
||||
* @param args The args.
|
||||
* @param player The player.
|
||||
* @return The value.
|
||||
*/
|
||||
@NotNull
|
||||
public String getValue(@NotNull final String args,
|
||||
@NotNull final Player player) {
|
||||
@Override
|
||||
public @Nullable String getValue(@NotNull final String args,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
Player player = context.getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return function.apply(args, player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the placeholder.
|
||||
* Get the value of the arguments.
|
||||
*
|
||||
* @return The placeholder.
|
||||
* @param args The args.
|
||||
* @param player The player.
|
||||
* @return The value.
|
||||
* @deprecated Use {@link #getValue(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
public PlayerDynamicPlaceholder register() {
|
||||
PlaceholderManager.registerPlaceholder(this);
|
||||
return this;
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public String getValue(@NotNull final String args,
|
||||
@NotNull final Player player) {
|
||||
return Objects.requireNonNullElse(
|
||||
function.apply(args, player),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,18 +79,17 @@ public final class PlayerDynamicPlaceholder implements Placeholder {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public @NotNull String getIdentifier() {
|
||||
return "dynamic";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pattern getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PlayerDynamicPlaceholder register() {
|
||||
return (PlayerDynamicPlaceholder) RegistrablePlaceholder.super.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (this == o) {
|
||||
@@ -100,6 +106,6 @@ public final class PlayerDynamicPlaceholder implements Placeholder {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
||||
return Objects.hash(this.getPattern(), this.getPlugin());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -11,31 +11,26 @@ import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A placeholder that requires a player.
|
||||
* A arguments that requires a player.
|
||||
*/
|
||||
public final class PlayerPlaceholder implements Placeholder {
|
||||
public final class PlayerPlaceholder implements RegistrablePlaceholder {
|
||||
/**
|
||||
* The name of the placeholder.
|
||||
*/
|
||||
private final String identifier;
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
* The arguments pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* The function to retrieve the output of the placeholder given a player.
|
||||
* The function to retrieve the output of the arguments given a player.
|
||||
*/
|
||||
private final Function<Player, String> function;
|
||||
private final Function<@NotNull Player, @Nullable String> function;
|
||||
|
||||
/**
|
||||
* The plugin for the placeholder.
|
||||
* The plugin for the arguments.
|
||||
*/
|
||||
private final EcoPlugin plugin;
|
||||
|
||||
/**
|
||||
* Create a new player placeholder.
|
||||
* Create a new player arguments.
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @param identifier The identifier.
|
||||
@@ -43,32 +38,38 @@ public final class PlayerPlaceholder implements Placeholder {
|
||||
*/
|
||||
public PlayerPlaceholder(@NotNull final EcoPlugin plugin,
|
||||
@NotNull final String identifier,
|
||||
@NotNull final Function<Player, String> function) {
|
||||
@NotNull final Function<@NotNull Player, @Nullable String> function) {
|
||||
this.plugin = plugin;
|
||||
this.identifier = identifier;
|
||||
this.pattern = Pattern.compile(identifier);
|
||||
this.pattern = Pattern.compile(identifier, Pattern.LITERAL);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the placeholder for a given player.
|
||||
*
|
||||
* @param player The player.
|
||||
* @return The value.
|
||||
*/
|
||||
@NotNull
|
||||
public String getValue(@NotNull final Player player) {
|
||||
@Override
|
||||
public @Nullable String getValue(@NotNull final String args,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
Player player = context.getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return function.apply(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the placeholder.
|
||||
* Get the value of the arguments for a given player.
|
||||
*
|
||||
* @return The placeholder.
|
||||
* @param player The player.
|
||||
* @return The value.
|
||||
* @deprecated Use {@link #getValue(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
public PlayerPlaceholder register() {
|
||||
PlaceholderManager.registerPlaceholder(this);
|
||||
return this;
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public String getValue(@NotNull final Player player) {
|
||||
return Objects.requireNonNullElse(
|
||||
function.apply(player),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,17 +77,17 @@ public final class PlayerPlaceholder implements Placeholder {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return this.identifier;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pattern getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PlayerPlaceholder register() {
|
||||
return (PlayerPlaceholder) RegistrablePlaceholder.super.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (this == o) {
|
||||
@@ -95,12 +96,12 @@ public final class PlayerPlaceholder implements Placeholder {
|
||||
if (!(o instanceof PlayerPlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(this.getIdentifier(), that.getIdentifier())
|
||||
return Objects.equals(this.getPattern(), that.getPattern())
|
||||
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
||||
return Objects.hash(this.getPattern(), this.getPlugin());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -13,47 +15,72 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
|
||||
/**
|
||||
* The name of the placeholder.
|
||||
* The identifier.
|
||||
*/
|
||||
private final String identifier;
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
* The arguments pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* The function to retrieve the output of the placeholder.
|
||||
* The function to retrieve the output of the arguments.
|
||||
*/
|
||||
private final Function<Player, String> function;
|
||||
private final Function<@NotNull Player, @Nullable String> function;
|
||||
|
||||
/**
|
||||
* Create a new player placeholder.
|
||||
* Create a new player arguments.
|
||||
*
|
||||
* @param identifier The identifier.
|
||||
* @param function The function to retrieve the value.
|
||||
*/
|
||||
public PlayerStaticPlaceholder(@NotNull final String identifier,
|
||||
@NotNull final Function<Player, String> function) {
|
||||
this.identifier = identifier;
|
||||
this.pattern = Pattern.compile(identifier);
|
||||
@NotNull final Function<@NotNull Player, @Nullable String> function) {
|
||||
this.identifier = "%" + identifier + "%";
|
||||
this.pattern = Pattern.compile(identifier, Pattern.LITERAL);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getValue(@NotNull final String args,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
Player player = context.getPlayer();
|
||||
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.getValue(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the placeholder.
|
||||
* Get the value of the arguments.
|
||||
*
|
||||
* @param player The player.
|
||||
* @return The value.
|
||||
* @deprecated Use {@link #getValue(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public String getValue(@NotNull final Player player) {
|
||||
return function.apply(player);
|
||||
return Objects.requireNonNullElse(
|
||||
function.apply(player),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return this.identifier;
|
||||
public String tryTranslateQuickly(@NotNull final String text,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return StringUtils.replaceQuickly(
|
||||
text,
|
||||
this.identifier,
|
||||
Objects.requireNonNullElse(
|
||||
this.getValue(identifier, context),
|
||||
""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -70,11 +97,11 @@ public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
|
||||
if (!(o instanceof PlayerStaticPlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(this.getIdentifier(), that.getIdentifier());
|
||||
return Objects.equals(this.getPattern(), that.getPattern());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getIdentifier());
|
||||
return Objects.hash(this.getPattern());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -10,31 +10,26 @@ import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A placeholder that does not require a player.
|
||||
* A arguments that does not require a player.
|
||||
*/
|
||||
public final class PlayerlessPlaceholder implements Placeholder {
|
||||
public final class PlayerlessPlaceholder implements RegistrablePlaceholder {
|
||||
/**
|
||||
* The placeholder identifier.
|
||||
*/
|
||||
private final String identifier;
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
* The arguments pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* The function to retrieve the output of the placeholder.
|
||||
* The function to retrieve the output of the arguments.
|
||||
*/
|
||||
private final Supplier<String> function;
|
||||
private final Supplier<@Nullable String> function;
|
||||
|
||||
/**
|
||||
* The plugin for the placeholder.
|
||||
* The plugin for the arguments.
|
||||
*/
|
||||
private final EcoPlugin plugin;
|
||||
|
||||
/**
|
||||
* Create a new player placeholder.
|
||||
* Create a new player arguments.
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @param identifier The identifier.
|
||||
@@ -42,30 +37,31 @@ public final class PlayerlessPlaceholder implements Placeholder {
|
||||
*/
|
||||
public PlayerlessPlaceholder(@NotNull final EcoPlugin plugin,
|
||||
@NotNull final String identifier,
|
||||
@NotNull final Supplier<String> function) {
|
||||
@NotNull final Supplier<@Nullable String> function) {
|
||||
this.plugin = plugin;
|
||||
this.identifier = identifier;
|
||||
this.pattern = Pattern.compile(identifier);
|
||||
this.pattern = Pattern.compile(identifier, Pattern.LITERAL);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the placeholder.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
public String getValue() {
|
||||
@Override
|
||||
public @Nullable String getValue(@NotNull final String args,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return function.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the placeholder.
|
||||
* Get the value of the arguments.
|
||||
*
|
||||
* @return The placeholder.
|
||||
* @return The value.
|
||||
* @deprecated Use {@link #getValue(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
public PlayerlessPlaceholder register() {
|
||||
PlaceholderManager.registerPlaceholder(this);
|
||||
return this;
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public String getValue() {
|
||||
return Objects.requireNonNullElse(
|
||||
this.function.get(),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,17 +69,17 @@ public final class PlayerlessPlaceholder implements Placeholder {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return this.identifier;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Pattern getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PlayerlessPlaceholder register() {
|
||||
return (PlayerlessPlaceholder) RegistrablePlaceholder.super.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (this == o) {
|
||||
@@ -92,12 +88,12 @@ public final class PlayerlessPlaceholder implements Placeholder {
|
||||
if (!(o instanceof PlayerlessPlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(this.getIdentifier(), that.getIdentifier())
|
||||
return Objects.equals(this.getPattern(), that.getPattern())
|
||||
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
||||
return Objects.hash(this.getPattern(), this.getPlugin());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Represents a placeholder that can be registered.
|
||||
*/
|
||||
public interface RegistrablePlaceholder extends Placeholder {
|
||||
/**
|
||||
* Get the plugin that holds the arguments.
|
||||
*
|
||||
* @return The plugin.
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
EcoPlugin getPlugin();
|
||||
|
||||
/**
|
||||
* Register the arguments.
|
||||
*
|
||||
* @return The arguments.
|
||||
*/
|
||||
@NotNull
|
||||
default RegistrablePlaceholder register() {
|
||||
PlaceholderManager.registerPlaceholder(this);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.willfp.eco.core.placeholder;
|
||||
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -8,50 +10,66 @@ import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A placeholder that cannot be registered, and exists purely in injection.
|
||||
* A arguments that cannot be registered, and exists purely in injection.
|
||||
*/
|
||||
public final class StaticPlaceholder implements InjectablePlaceholder {
|
||||
/**
|
||||
* The name of the placeholder.
|
||||
* The name of the arguments.
|
||||
*/
|
||||
private final String identifier;
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
* The arguments pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* The function to retrieve the output of the placeholder.
|
||||
* The function to retrieve the output of the arguments.
|
||||
*/
|
||||
private final Supplier<String> function;
|
||||
private final Supplier<@Nullable String> function;
|
||||
|
||||
/**
|
||||
* Create a new player placeholder.
|
||||
* Create a new player arguments.
|
||||
*
|
||||
* @param identifier The identifier.
|
||||
* @param function The function to retrieve the value.
|
||||
*/
|
||||
public StaticPlaceholder(@NotNull final String identifier,
|
||||
@NotNull final Supplier<String> function) {
|
||||
this.identifier = identifier;
|
||||
this.pattern = Pattern.compile(identifier);
|
||||
@NotNull final Supplier<@Nullable String> function) {
|
||||
this.identifier = "%" + identifier + "%";
|
||||
this.pattern = Pattern.compile(identifier, Pattern.LITERAL);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the placeholder.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
@NotNull
|
||||
public String getValue() {
|
||||
@Override
|
||||
public @Nullable String getValue(@NotNull final String args,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return function.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the arguments.
|
||||
*
|
||||
* @return The value.
|
||||
* @deprecated Use {@link #getValue(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@NotNull
|
||||
public String getValue() {
|
||||
return Objects.requireNonNullElse(
|
||||
function.get(),
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return this.identifier;
|
||||
public String tryTranslateQuickly(@NotNull final String text,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return StringUtils.replaceQuickly(
|
||||
text,
|
||||
this.identifier,
|
||||
Objects.requireNonNullElse(this.getValue(this.identifier, context), "")
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -68,11 +86,11 @@ public final class StaticPlaceholder implements InjectablePlaceholder {
|
||||
if (!(o instanceof StaticPlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(this.getIdentifier(), that.getIdentifier());
|
||||
return Objects.equals(this.getPattern(), that.getPattern());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getIdentifier());
|
||||
return Objects.hash(this.getPattern());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.willfp.eco.core.placeholder.context;
|
||||
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A merged injectable context.
|
||||
*/
|
||||
public class MergedInjectableContext implements PlaceholderInjectable {
|
||||
/**
|
||||
* The base context.
|
||||
*/
|
||||
private final PlaceholderInjectable baseContext;
|
||||
|
||||
/**
|
||||
* The additional context.
|
||||
*/
|
||||
private final PlaceholderInjectable additionalContext;
|
||||
|
||||
/**
|
||||
* Extra injections.
|
||||
*/
|
||||
private final Set<InjectablePlaceholder> extraInjections = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Create a new merged injectable context.
|
||||
*
|
||||
* @param baseContext The base context.
|
||||
* @param additionalContext The additional context.
|
||||
*/
|
||||
public MergedInjectableContext(@NotNull final PlaceholderInjectable baseContext,
|
||||
@NotNull final PlaceholderInjectable additionalContext) {
|
||||
this.baseContext = baseContext;
|
||||
this.additionalContext = additionalContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInjectablePlaceholder(@NotNull final Iterable<InjectablePlaceholder> placeholders) {
|
||||
for (InjectablePlaceholder placeholder : placeholders) {
|
||||
extraInjections.add(placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearInjectedPlaceholders() {
|
||||
baseContext.clearInjectedPlaceholders();
|
||||
additionalContext.clearInjectedPlaceholders();
|
||||
extraInjections.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<InjectablePlaceholder> getPlaceholderInjections() {
|
||||
List<InjectablePlaceholder> base = baseContext.getPlaceholderInjections();
|
||||
List<InjectablePlaceholder> additional = additionalContext.getPlaceholderInjections();
|
||||
|
||||
List<InjectablePlaceholder> injections = new ArrayList<>(base.size() + additional.size() + extraInjections.size());
|
||||
|
||||
injections.addAll(base);
|
||||
injections.addAll(additional);
|
||||
injections.addAll(extraInjections);
|
||||
|
||||
return injections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof MergedInjectableContext that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(baseContext, that.baseContext)
|
||||
&& Objects.equals(additionalContext, that.additionalContext)
|
||||
&& Objects.equals(extraInjections, that.extraInjections);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(baseContext, additionalContext, extraInjections);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
package com.willfp.eco.core.placeholder.context;
|
||||
|
||||
import com.willfp.eco.core.placeholder.AdditionalPlayer;
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a context to translate placeholders in.
|
||||
*/
|
||||
public class PlaceholderContext {
|
||||
/**
|
||||
* An empty injectable.
|
||||
*/
|
||||
private static final PlaceholderInjectable EMPTY_INJECTABLE = new PlaceholderInjectable() {
|
||||
@Override
|
||||
public void addInjectablePlaceholder(@NotNull final Iterable<InjectablePlaceholder> placeholders) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearInjectedPlaceholders() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<InjectablePlaceholder> getPlaceholderInjections() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An empty context.
|
||||
*/
|
||||
public static final PlaceholderContext EMPTY = new PlaceholderContext(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
Collections.emptyList()
|
||||
);
|
||||
|
||||
/**
|
||||
* The player.
|
||||
*/
|
||||
@Nullable
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* The ItemStack.
|
||||
*/
|
||||
@Nullable
|
||||
private final ItemStack itemStack;
|
||||
|
||||
/**
|
||||
* The PlaceholderInjectable context.
|
||||
*/
|
||||
@NotNull
|
||||
private final PlaceholderInjectable injectableContext;
|
||||
|
||||
/**
|
||||
* The additional players.
|
||||
*/
|
||||
@NotNull
|
||||
private final Collection<AdditionalPlayer> additionalPlayers;
|
||||
|
||||
/**
|
||||
* Create an empty PlaceholderContext.
|
||||
*/
|
||||
public PlaceholderContext() {
|
||||
this(null, null, null, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PlaceholderContext for a player.
|
||||
*
|
||||
* @param player The player.
|
||||
*/
|
||||
public PlaceholderContext(@Nullable final Player player) {
|
||||
this(player, null, null, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new PlaceholderContext with the given parameters.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param itemStack The ItemStack.
|
||||
* @param injectableContext The PlaceholderInjectable parseContext.
|
||||
* @param additionalPlayers The additional players.
|
||||
*/
|
||||
public PlaceholderContext(@Nullable final Player player,
|
||||
@Nullable final ItemStack itemStack,
|
||||
@Nullable final PlaceholderInjectable injectableContext,
|
||||
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
|
||||
this.player = player;
|
||||
this.itemStack = itemStack;
|
||||
this.injectableContext = Objects.requireNonNullElse(injectableContext, EMPTY_INJECTABLE);
|
||||
this.additionalPlayers = additionalPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the player.
|
||||
*
|
||||
* @return The player.
|
||||
*/
|
||||
@Nullable
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ItemStack.
|
||||
*
|
||||
* @return The ItemStack.
|
||||
*/
|
||||
@Nullable
|
||||
public ItemStack getItemStack() {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PlaceholderInjectable context.
|
||||
*
|
||||
* @return The PlaceholderInjectable context.
|
||||
*/
|
||||
@NotNull
|
||||
public PlaceholderInjectable getInjectableContext() {
|
||||
return injectableContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the additional players.
|
||||
*
|
||||
* @return The additional players.
|
||||
*/
|
||||
@NotNull
|
||||
public Collection<AdditionalPlayer> getAdditionalPlayers() {
|
||||
return additionalPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a {@link com.willfp.eco.core.math.MathContext}.
|
||||
*
|
||||
* @return The math context.
|
||||
* @deprecated MathContext is deprecated, use {@link PlaceholderContext} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@SuppressWarnings({"removal", "DeprecatedIsStillUsed"})
|
||||
public com.willfp.eco.core.math.MathContext toMathContext() {
|
||||
return new com.willfp.eco.core.math.MathContext(this.getInjectableContext(), this.getPlayer(), this.getAdditionalPlayers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy with a player.
|
||||
*
|
||||
* @param player The player.
|
||||
* @return The new context.
|
||||
*/
|
||||
public PlaceholderContext copyWithPlayer(@Nullable final Player player) {
|
||||
return new PlaceholderContext(
|
||||
player,
|
||||
this.getItemStack(),
|
||||
this.getInjectableContext(),
|
||||
this.getAdditionalPlayers()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy with an item.
|
||||
*
|
||||
* @param itemStack The ItemStack.
|
||||
* @return The new context.
|
||||
*/
|
||||
public PlaceholderContext copyWithItem(@Nullable final ItemStack itemStack) {
|
||||
return new PlaceholderContext(
|
||||
this.getPlayer(),
|
||||
itemStack,
|
||||
this.getInjectableContext(),
|
||||
this.getAdditionalPlayers()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy with an extra injectable context.
|
||||
*
|
||||
* @param injectableContext The injectable context to add.
|
||||
* @return The new context.
|
||||
*/
|
||||
public PlaceholderContext withInjectableContext(@NotNull final PlaceholderInjectable injectableContext) {
|
||||
return new PlaceholderContext(
|
||||
this.getPlayer(),
|
||||
this.getItemStack(),
|
||||
new MergedInjectableContext(this.getInjectableContext(), injectableContext),
|
||||
this.getAdditionalPlayers()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlaceholderContext{" +
|
||||
"player=" + player +
|
||||
", itemStack=" + itemStack +
|
||||
", injectableContext=" + injectableContext +
|
||||
", additionalPlayers=" + additionalPlayers +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof PlaceholderContext that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(
|
||||
getPlayer(), that.getPlayer())
|
||||
&& Objects.equals(getItemStack(), that.getItemStack())
|
||||
&& getInjectableContext().equals(that.getInjectableContext())
|
||||
&& getAdditionalPlayers().equals(that.getAdditionalPlayers()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getPlayer(), getItemStack(), getInjectableContext(), getAdditionalPlayers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PlaceholderContext of a PlaceholderInjectable parseContext.
|
||||
*
|
||||
* @param injectableContext The PlaceholderInjectable parseContext.
|
||||
* @return The context.
|
||||
*/
|
||||
public static PlaceholderContext of(@NotNull final PlaceholderInjectable injectableContext) {
|
||||
return new PlaceholderContext(
|
||||
null,
|
||||
null,
|
||||
injectableContext,
|
||||
Collections.emptyList()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.willfp.eco.core.placeholder.context;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A supplier that takes a {@link PlaceholderContext} and returns a value.
|
||||
*
|
||||
* @param <T> The type of value to return.
|
||||
*/
|
||||
public interface PlaceholderContextSupplier<T> {
|
||||
/**
|
||||
* Get the value.
|
||||
*
|
||||
* @param context The context.
|
||||
* @return The value.
|
||||
*/
|
||||
@NotNull
|
||||
T get(@NotNull PlaceholderContext context);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.willfp.eco.core.placeholder.templates;
|
||||
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A template class for dynamic placeholders.
|
||||
*/
|
||||
public abstract class DynamicInjectablePlaceholder implements InjectablePlaceholder {
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* Create a new dynamic injectable placeholder.
|
||||
*
|
||||
* @param pattern The pattern.
|
||||
*/
|
||||
protected DynamicInjectablePlaceholder(@NotNull final Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DynamicInjectablePlaceholder{" +
|
||||
"pattern='" + pattern + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@NotNull final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof DynamicInjectablePlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(pattern, that.getPattern());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pattern);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.willfp.eco.core.placeholder.templates;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.placeholder.RegistrablePlaceholder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A template class for dynamic placeholders.
|
||||
*/
|
||||
public abstract class DynamicPlaceholder implements RegistrablePlaceholder {
|
||||
/**
|
||||
* The plugin.
|
||||
*/
|
||||
private final EcoPlugin plugin;
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* Create a new dynamic placeholder.
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @param pattern The pattern.
|
||||
*/
|
||||
protected DynamicPlaceholder(@NotNull final EcoPlugin plugin,
|
||||
@NotNull final Pattern pattern) {
|
||||
this.plugin = plugin;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EcoPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DynamicPlaceholder{" +
|
||||
"plugin='" + plugin + '\'' +
|
||||
"pattern='" + pattern + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@NotNull final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof DynamicPlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(pattern, that.getPattern())
|
||||
&& Objects.equals(plugin, that.getPlugin());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(pattern, plugin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.willfp.eco.core.placeholder.templates;
|
||||
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A template class for simple placeholders.
|
||||
*/
|
||||
public abstract class SimpleInjectablePlaceholder implements InjectablePlaceholder {
|
||||
/**
|
||||
* The name of the placeholder.
|
||||
*/
|
||||
private final String identifier;
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* Create a new simple injectable placeholder.
|
||||
*
|
||||
* @param identifier The identifier.
|
||||
*/
|
||||
protected SimpleInjectablePlaceholder(@NotNull final String identifier) {
|
||||
this.identifier = identifier;
|
||||
this.pattern = Pattern.compile(identifier, Pattern.LITERAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tryTranslateQuickly(@NotNull final String text,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return text.replace(
|
||||
"%" + this.identifier + "%",
|
||||
Objects.requireNonNullElse(this.getValue(this.identifier, context), "")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SimpleInjectablePlaceholder{" +
|
||||
"identifier='" + identifier + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@NotNull final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof SimpleInjectablePlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(identifier, that.identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(identifier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.willfp.eco.core.placeholder.templates;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.placeholder.RegistrablePlaceholder;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A template class for simple placeholders.
|
||||
*/
|
||||
public abstract class SimplePlaceholder implements RegistrablePlaceholder {
|
||||
/**
|
||||
* The plugin.
|
||||
*/
|
||||
private final EcoPlugin plugin;
|
||||
|
||||
/**
|
||||
* The name of the placeholder.
|
||||
*/
|
||||
private final String identifier;
|
||||
|
||||
/**
|
||||
* The placeholder pattern.
|
||||
*/
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* Create a new simple placeholder.
|
||||
*
|
||||
* @param plugin The plugin.
|
||||
* @param identifier The identifier.
|
||||
*/
|
||||
protected SimplePlaceholder(@NotNull final EcoPlugin plugin,
|
||||
@NotNull final String identifier) {
|
||||
this.plugin = plugin;
|
||||
this.identifier = identifier;
|
||||
this.pattern = Pattern.compile(identifier, Pattern.LITERAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tryTranslateQuickly(@NotNull final String text,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return text.replace(
|
||||
"%" + this.identifier + "%",
|
||||
Objects.requireNonNullElse(this.getValue(this.identifier, context), "")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Pattern getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EcoPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SimplePlaceholder{" +
|
||||
"plugin='" + plugin + '\'' +
|
||||
"identifier='" + identifier + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@NotNull final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof SimplePlaceholder that)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Objects.equals(pattern, that.getPattern())
|
||||
&& Objects.equals(plugin, that.getPlugin());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(identifier, plugin);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.willfp.eco.core.price;
|
||||
|
||||
import com.willfp.eco.core.config.interfaces.Config;
|
||||
import com.willfp.eco.core.math.MathContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.core.price.impl.PriceFree;
|
||||
import com.willfp.eco.core.serialization.ConfigDeserializer;
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
@@ -168,7 +168,7 @@ public final class ConfiguredPrice implements Price {
|
||||
Price price = Prices.create(
|
||||
config.getString("value"),
|
||||
config.getString("type"),
|
||||
MathContext.of(config)
|
||||
PlaceholderContext.of(config)
|
||||
);
|
||||
|
||||
return new ConfiguredPrice(price, formatString);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.willfp.eco.core.price;
|
||||
|
||||
import com.willfp.eco.core.math.MathContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -10,7 +11,8 @@ import java.util.function.Function;
|
||||
/**
|
||||
* Create prices.
|
||||
* <p>
|
||||
* You must override one of the create methods.
|
||||
* Override create(PlaceholderContext, PlaceholderContextSupplier), other methods
|
||||
* are for backwards compatibility.
|
||||
*/
|
||||
public interface PriceFactory {
|
||||
/**
|
||||
@@ -27,20 +29,38 @@ public interface PriceFactory {
|
||||
*
|
||||
* @param value The value.
|
||||
* @return The price.
|
||||
* @deprecated Use {@link #create(PlaceholderContext, PlaceholderContextSupplier)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
default @NotNull Price create(final double value) {
|
||||
return create(MathContext.EMPTY, (ctx) -> value);
|
||||
return create(PlaceholderContext.EMPTY, (ctx) -> value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the price.
|
||||
*
|
||||
* @param baseContext The base MathContext.
|
||||
* @param function The function to use. Should use {@link MathContext#copyWithPlayer(MathContext, Player)} on calls.
|
||||
* @param function The function to use. Should use {@link com.willfp.eco.core.math.MathContext#copyWithPlayer(com.willfp.eco.core.math.MathContext, Player)} on calls.
|
||||
* @return The price.
|
||||
* @deprecated Use {@link #create(PlaceholderContext, PlaceholderContextSupplier)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
default @NotNull Price create(@NotNull final com.willfp.eco.core.math.MathContext baseContext,
|
||||
@NotNull final Function<com.willfp.eco.core.math.MathContext, Double> function) {
|
||||
return create(baseContext.toPlaceholderContext(), (PlaceholderContext ctx) -> function.apply(ctx.toMathContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the price.
|
||||
*
|
||||
* @param baseContext The base PlaceholderContext.
|
||||
* @param function The function to use. Should use {@link PlaceholderContext#copyWithPlayer(Player)} on calls.
|
||||
* @return The price.
|
||||
*/
|
||||
default @NotNull Price create(@NotNull final MathContext baseContext,
|
||||
@NotNull final Function<MathContext, Double> function) {
|
||||
return create(function.apply(baseContext));
|
||||
@SuppressWarnings("removal")
|
||||
default @NotNull Price create(@NotNull final PlaceholderContext baseContext,
|
||||
@NotNull final PlaceholderContextSupplier<Double> function) {
|
||||
return create(baseContext.toMathContext(), (com.willfp.eco.core.math.MathContext ctx) -> function.get(ctx.toPlaceholderContext()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ package com.willfp.eco.core.price;
|
||||
|
||||
import com.willfp.eco.core.items.Items;
|
||||
import com.willfp.eco.core.items.TestableItem;
|
||||
import com.willfp.eco.core.math.MathContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier;
|
||||
import com.willfp.eco.core.price.impl.PriceEconomy;
|
||||
import com.willfp.eco.core.price.impl.PriceFree;
|
||||
import com.willfp.eco.core.price.impl.PriceItem;
|
||||
@@ -13,7 +14,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Class to manage prices.
|
||||
@@ -48,7 +48,28 @@ public final class Prices {
|
||||
@NotNull
|
||||
public static Price create(@NotNull final String expression,
|
||||
@Nullable final String priceName) {
|
||||
return create(expression, priceName, MathContext.EMPTY);
|
||||
return create(expression, priceName, PlaceholderContext.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create price from an expression (representing the value),
|
||||
* and a price name. Uses a context to parse the expression.
|
||||
* <p>
|
||||
* Supports items as price names.
|
||||
*
|
||||
* @param expression The expression for the value.
|
||||
* @param priceName The price name.
|
||||
* @param context The math context to parse the expression.
|
||||
* @return The price, or free if invalid.
|
||||
* @deprecated Use {@link #create(String, String, PlaceholderContext)} instead.
|
||||
*/
|
||||
@NotNull
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public static Price create(@NotNull final String expression,
|
||||
@Nullable final String priceName,
|
||||
@NotNull final com.willfp.eco.core.math.MathContext context) {
|
||||
return create(expression, priceName, context.toPlaceholderContext());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,8 +86,8 @@ public final class Prices {
|
||||
@NotNull
|
||||
public static Price create(@NotNull final String expression,
|
||||
@Nullable final String priceName,
|
||||
@NotNull final MathContext context) {
|
||||
Function<MathContext, Double> function = (ctx) -> NumberUtils.evaluateExpression(
|
||||
@NotNull final PlaceholderContext context) {
|
||||
PlaceholderContextSupplier<Double> function = (ctx) -> NumberUtils.evaluateExpression(
|
||||
expression,
|
||||
ctx
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.willfp.eco.core.price.impl;
|
||||
|
||||
import com.willfp.eco.core.integrations.economy.EconomyManager;
|
||||
import com.willfp.eco.core.math.MathContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier;
|
||||
import com.willfp.eco.core.price.Price;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -18,12 +19,12 @@ public final class PriceEconomy implements Price {
|
||||
/**
|
||||
* The value of the price.
|
||||
*/
|
||||
private final Function<MathContext, Double> function;
|
||||
private final PlaceholderContextSupplier<Double> function;
|
||||
|
||||
/**
|
||||
* The base math context.
|
||||
* The base placeholder context.
|
||||
*/
|
||||
private final MathContext baseContext;
|
||||
private final PlaceholderContext baseContext;
|
||||
|
||||
/**
|
||||
* The multipliers.
|
||||
@@ -36,7 +37,21 @@ public final class PriceEconomy implements Price {
|
||||
* @param value The value.
|
||||
*/
|
||||
public PriceEconomy(final double value) {
|
||||
this(MathContext.EMPTY, ctx -> value);
|
||||
this(PlaceholderContext.EMPTY, (PlaceholderContext ctx) -> value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new economy-based price.
|
||||
*
|
||||
* @param baseContext The base context.
|
||||
* @param function The function.
|
||||
* @deprecated Use {@link #PriceEconomy(PlaceholderContext, PlaceholderContextSupplier)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public PriceEconomy(@NotNull final com.willfp.eco.core.math.MathContext baseContext,
|
||||
@NotNull final Function<com.willfp.eco.core.math.MathContext, Double> function) {
|
||||
this(baseContext.toPlaceholderContext(), (PlaceholderContext ctx) -> function.apply(ctx.toMathContext()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,8 +60,8 @@ public final class PriceEconomy implements Price {
|
||||
* @param baseContext The base context.
|
||||
* @param function The function.
|
||||
*/
|
||||
public PriceEconomy(@NotNull final MathContext baseContext,
|
||||
@NotNull final Function<MathContext, Double> function) {
|
||||
public PriceEconomy(@NotNull final PlaceholderContext baseContext,
|
||||
@NotNull final PlaceholderContextSupplier<Double> function) {
|
||||
this.baseContext = baseContext;
|
||||
this.function = function;
|
||||
}
|
||||
@@ -72,7 +87,7 @@ public final class PriceEconomy implements Price {
|
||||
@Override
|
||||
public double getValue(@NotNull final Player player,
|
||||
final double multiplier) {
|
||||
return this.function.apply(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player) * multiplier;
|
||||
return this.function.get(baseContext.copyWithPlayer(player)) * getMultiplier(player) * multiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,7 +3,8 @@ package com.willfp.eco.core.price.impl;
|
||||
import com.willfp.eco.core.drops.DropQueue;
|
||||
import com.willfp.eco.core.items.HashedItem;
|
||||
import com.willfp.eco.core.items.TestableItem;
|
||||
import com.willfp.eco.core.math.MathContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier;
|
||||
import com.willfp.eco.core.price.Price;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -20,14 +21,14 @@ import java.util.function.Function;
|
||||
*/
|
||||
public final class PriceItem implements Price {
|
||||
/**
|
||||
* The base MathContext.
|
||||
* The base PlaceholderContext.
|
||||
*/
|
||||
private final MathContext baseContext;
|
||||
private final PlaceholderContext baseContext;
|
||||
|
||||
/**
|
||||
* The amount of items.
|
||||
*/
|
||||
private final Function<MathContext, Double> function;
|
||||
private final PlaceholderContextSupplier<Double> function;
|
||||
|
||||
/**
|
||||
* The item.
|
||||
@@ -47,7 +48,23 @@ public final class PriceItem implements Price {
|
||||
*/
|
||||
public PriceItem(final int amount,
|
||||
@NotNull final TestableItem item) {
|
||||
this(MathContext.EMPTY, ctx -> (double) amount, item);
|
||||
this(PlaceholderContext.EMPTY, (PlaceholderContext ctx) -> (double) amount, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new item-based price.
|
||||
*
|
||||
* @param baseContext The base MathContext.
|
||||
* @param function The function to get the amount of items to remove.
|
||||
* @param item The item.
|
||||
* @deprecated Use {@link #PriceItem(PlaceholderContext, PlaceholderContextSupplier, TestableItem)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public PriceItem(@NotNull final com.willfp.eco.core.math.MathContext baseContext,
|
||||
@NotNull final Function<com.willfp.eco.core.math.MathContext, Double> function,
|
||||
@NotNull final TestableItem item) {
|
||||
this(baseContext.toPlaceholderContext(), (PlaceholderContext ctx) -> function.apply(ctx.toMathContext()), item);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +74,8 @@ public final class PriceItem implements Price {
|
||||
* @param function The function to get the amount of items to remove.
|
||||
* @param item The item.
|
||||
*/
|
||||
public PriceItem(@NotNull final MathContext baseContext,
|
||||
@NotNull final Function<MathContext, Double> function,
|
||||
public PriceItem(@NotNull final PlaceholderContext baseContext,
|
||||
@NotNull final PlaceholderContextSupplier<Double> function,
|
||||
@NotNull final TestableItem item) {
|
||||
this.baseContext = baseContext;
|
||||
this.function = function;
|
||||
@@ -137,7 +154,7 @@ public final class PriceItem implements Price {
|
||||
public double getValue(@NotNull final Player player,
|
||||
final double multiplier) {
|
||||
return Math.toIntExact(Math.round(
|
||||
this.function.apply(MathContext.copyWithPlayer(baseContext, player))
|
||||
this.function.get(baseContext.copyWithPlayer(player))
|
||||
* getMultiplier(player) * multiplier
|
||||
));
|
||||
}
|
||||
|
||||
@@ -127,8 +127,8 @@ public final class Recipes {
|
||||
}
|
||||
|
||||
if (builder.isAir()) {
|
||||
Bukkit.getLogger().warning("RECIPE ERROR! " + plugin.getName() + ":" + key + " consists only");
|
||||
Bukkit.getLogger().warning("of air or invalid items! Please change that or disable this recipe.");
|
||||
Bukkit.getLogger().warning("Crafting recipe " + plugin.getID() + ":" + key + " consists only");
|
||||
Bukkit.getLogger().warning("of air or invalid items! It will not be registered.");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -14,7 +16,7 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @param <T> The type of {@link Registrable}.
|
||||
*/
|
||||
public class Registry<T extends Registrable> {
|
||||
public class Registry<T extends Registrable> implements Iterable<T> {
|
||||
/**
|
||||
* The ID pattern.
|
||||
*/
|
||||
@@ -25,6 +27,17 @@ public class Registry<T extends Registrable> {
|
||||
*/
|
||||
private final Map<String, T> registry = new HashMap<>();
|
||||
|
||||
/**
|
||||
* If the registry is locked.
|
||||
*/
|
||||
private boolean isLocked = false;
|
||||
|
||||
/**
|
||||
* The locker, used to 'secure' registries and prevent random unlocking.
|
||||
*/
|
||||
@Nullable
|
||||
private Object locker = null;
|
||||
|
||||
/**
|
||||
* Instantiate a new registry.
|
||||
*/
|
||||
@@ -40,6 +53,10 @@ public class Registry<T extends Registrable> {
|
||||
*/
|
||||
@NotNull
|
||||
public T register(@NotNull final T element) {
|
||||
if (this.isLocked) {
|
||||
throw new IllegalStateException("Cannot add to locked registry! (ID: " + element.getID() + ")");
|
||||
}
|
||||
|
||||
Validate.isTrue(ID_PATTERN.matcher(element.getID()).matches(), "ID must match pattern: " + ID_PATTERN.pattern() + " (was " + element.getID() + ")");
|
||||
|
||||
registry.put(element.getID(), element);
|
||||
@@ -56,6 +73,10 @@ public class Registry<T extends Registrable> {
|
||||
* @return The element.
|
||||
*/
|
||||
public T remove(@NotNull final T element) {
|
||||
if (this.isLocked) {
|
||||
throw new IllegalStateException("Cannot remove from locked registry! (ID: " + element.getID() + ")");
|
||||
}
|
||||
|
||||
element.onRemove();
|
||||
|
||||
registry.remove(element.getID());
|
||||
@@ -71,6 +92,10 @@ public class Registry<T extends Registrable> {
|
||||
*/
|
||||
@Nullable
|
||||
public T remove(@NotNull final String id) {
|
||||
if (this.isLocked) {
|
||||
throw new IllegalStateException("Cannot remove from locked registry! (ID: " + id + ")");
|
||||
}
|
||||
|
||||
T element = registry.get(id);
|
||||
|
||||
if (element != null) {
|
||||
@@ -109,6 +134,61 @@ public class Registry<T extends Registrable> {
|
||||
return Set.copyOf(registry.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the registry is locked.
|
||||
*
|
||||
* @return If the registry is locked.
|
||||
*/
|
||||
public boolean isLocked() {
|
||||
return isLocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the registry.
|
||||
*
|
||||
* @param locker The locker.
|
||||
*/
|
||||
public void lock(@Nullable final Object locker) {
|
||||
this.locker = locker;
|
||||
isLocked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the registry.
|
||||
*
|
||||
* @param locker The locker.
|
||||
*/
|
||||
public void unlock(@Nullable final Object locker) {
|
||||
if (this.locker != locker) {
|
||||
throw new IllegalArgumentException("Cannot unlock registry!");
|
||||
}
|
||||
isLocked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the registry is empty.
|
||||
*
|
||||
* @return If the registry is empty.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return registry.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the registry is not empty.
|
||||
*
|
||||
* @return If the registry is not empty.
|
||||
*/
|
||||
public boolean isNotEmpty() {
|
||||
return !isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return values().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to fit a string to the ID pattern.
|
||||
*
|
||||
@@ -120,6 +200,6 @@ public class Registry<T extends Registrable> {
|
||||
return string.replace(" ", "_")
|
||||
.replace(".", "_")
|
||||
.replace("-", "_")
|
||||
.toLowerCase();
|
||||
.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.willfp.eco.core.scheduling;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -14,9 +16,13 @@ public interface Scheduler {
|
||||
* @param runnable The lambda to run.
|
||||
* @param ticksLater The amount of ticks to wait before execution.
|
||||
* @return The created {@link BukkitTask}.
|
||||
* @deprecated Does not work with Folia.
|
||||
*/
|
||||
BukkitTask runLater(@NotNull Runnable runnable,
|
||||
long ticksLater);
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default BukkitTask runLater(@NotNull Runnable runnable,
|
||||
long ticksLater) {
|
||||
return runLater(new Location(Bukkit.getWorlds().get(0), 0, 0, 0), (int) ticksLater, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task after a specified tick delay.
|
||||
@@ -26,10 +32,12 @@ public interface Scheduler {
|
||||
* @param runnable The lambda to run.
|
||||
* @param ticksLater The amount of ticks to wait before execution.
|
||||
* @return The created {@link BukkitTask}.
|
||||
* @deprecated Does not work with Folia.
|
||||
*/
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default BukkitTask runLater(long ticksLater,
|
||||
@NotNull Runnable runnable) {
|
||||
return runLater(runnable, ticksLater);
|
||||
return runLater(new Location(Bukkit.getWorlds().get(0), 0, 0, 0), (int) ticksLater, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,10 +47,14 @@ public interface Scheduler {
|
||||
* @param delay The amount of ticks to wait before the first execution.
|
||||
* @param repeat The amount of ticks to wait between executions.
|
||||
* @return The created {@link BukkitTask}.
|
||||
* @deprecated Does not work with Folia.
|
||||
*/
|
||||
BukkitTask runTimer(@NotNull Runnable runnable,
|
||||
long delay,
|
||||
long repeat);
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default BukkitTask runTimer(@NotNull Runnable runnable,
|
||||
long delay,
|
||||
long repeat) {
|
||||
return runTimer(new Location(Bukkit.getWorlds().get(0), 0, 0, 0), (int) delay, (int) repeat, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task repeatedly on a timer.
|
||||
@@ -53,11 +65,13 @@ public interface Scheduler {
|
||||
* @param delay The amount of ticks to wait before the first execution.
|
||||
* @param repeat The amount of ticks to wait between executions.
|
||||
* @return The created {@link BukkitTask}.
|
||||
* @deprecated Does not work with Folia.
|
||||
*/
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default BukkitTask runTimer(long delay,
|
||||
long repeat,
|
||||
@NotNull Runnable runnable) {
|
||||
return runTimer(runnable, delay, repeat);
|
||||
return runTimer(new Location(Bukkit.getWorlds().get(0), 0, 0, 0), (int) delay, (int) repeat, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,10 +81,14 @@ public interface Scheduler {
|
||||
* @param delay The amount of ticks to wait before the first execution.
|
||||
* @param repeat The amount of ticks to wait between executions.
|
||||
* @return The created {@link BukkitTask}.
|
||||
* @deprecated Does not work with Folia.
|
||||
*/
|
||||
BukkitTask runAsyncTimer(@NotNull Runnable runnable,
|
||||
long delay,
|
||||
long repeat);
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default BukkitTask runAsyncTimer(@NotNull Runnable runnable,
|
||||
long delay,
|
||||
long repeat) {
|
||||
return runTimerAsync((int) delay, (int) repeat, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task repeatedly and asynchronously on a timer.
|
||||
@@ -81,11 +99,13 @@ public interface Scheduler {
|
||||
* @param delay The amount of ticks to wait before the first execution.
|
||||
* @param repeat The amount of ticks to wait between executions.
|
||||
* @return The created {@link BukkitTask}.
|
||||
* @deprecated Does not work with Folia.
|
||||
*/
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default BukkitTask runAsyncTimer(long delay,
|
||||
long repeat,
|
||||
@NotNull Runnable runnable) {
|
||||
return runAsyncTimer(runnable, delay, repeat);
|
||||
return runTimerAsync((int) delay, (int) repeat, runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,28 +113,28 @@ public interface Scheduler {
|
||||
*
|
||||
* @param runnable The lambda to run.
|
||||
* @return The created {@link BukkitTask}.
|
||||
* @deprecated Does not work with Folia.
|
||||
*/
|
||||
BukkitTask run(@NotNull Runnable runnable);
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default BukkitTask run(@NotNull Runnable runnable) {
|
||||
return run(new Location(Bukkit.getWorlds().get(0), 0, 0, 0), runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the task asynchronously.
|
||||
*
|
||||
* @param runnable The lambda to run.
|
||||
* @return The created {@link BukkitTask}.
|
||||
*/
|
||||
BukkitTask runAsync(@NotNull Runnable runnable);
|
||||
|
||||
/**
|
||||
* Schedule the task to be ran repeatedly on a timer.
|
||||
* Schedule the task to be run repeatedly on a timer.
|
||||
*
|
||||
* @param runnable The lambda to run.
|
||||
* @param delay The amount of ticks to wait before the first execution.
|
||||
* @param repeat The amount of ticks to wait between executions.
|
||||
* @return The id of the task.
|
||||
* @deprecated Not needed.
|
||||
*/
|
||||
int syncRepeating(@NotNull Runnable runnable,
|
||||
long delay,
|
||||
long repeat);
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default int syncRepeating(@NotNull Runnable runnable,
|
||||
long delay,
|
||||
long repeat) {
|
||||
return runTimer(runnable, delay, repeat).getTaskId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the task to be ran repeatedly on a timer.
|
||||
@@ -125,15 +145,73 @@ public interface Scheduler {
|
||||
* @param delay The amount of ticks to wait before the first execution.
|
||||
* @param repeat The amount of ticks to wait between executions.
|
||||
* @return The id of the task.
|
||||
* @deprecated Not needed.
|
||||
*/
|
||||
@Deprecated(since = "6.53.0", forRemoval = true)
|
||||
default int syncRepeating(long delay,
|
||||
long repeat,
|
||||
@NotNull Runnable runnable) {
|
||||
return syncRepeating(runnable, delay, repeat);
|
||||
return runTimer(runnable, delay, repeat).getTaskId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all running tasks from the linked {@link EcoPlugin}.
|
||||
*/
|
||||
void cancelAll();
|
||||
|
||||
/**
|
||||
* Run a task asynchronously.
|
||||
*
|
||||
* @param task The lambda to run.
|
||||
* @return The created {@link BukkitTask}.
|
||||
*/
|
||||
BukkitTask runAsync(@NotNull Runnable task);
|
||||
|
||||
/**
|
||||
* Run a task.
|
||||
*
|
||||
* @param location The location.
|
||||
* @param task The task.
|
||||
* @return The created {@link BukkitTask}.
|
||||
*/
|
||||
BukkitTask run(@NotNull Location location,
|
||||
@NotNull Runnable task);
|
||||
|
||||
/**
|
||||
* Run a task after a delay.
|
||||
*
|
||||
* @param location The location.
|
||||
* @param ticksLater The delay.
|
||||
* @param task The task.
|
||||
* @return The created {@link BukkitTask}.
|
||||
*/
|
||||
BukkitTask runLater(@NotNull Location location,
|
||||
int ticksLater,
|
||||
@NotNull Runnable task);
|
||||
|
||||
/**
|
||||
* Run a task on a timer.
|
||||
*
|
||||
* @param location The location.
|
||||
* @param delay The delay.
|
||||
* @param repeat The repeat delay.
|
||||
* @param task The task.
|
||||
* @return The created {@link BukkitTask}.
|
||||
*/
|
||||
BukkitTask runTimer(@NotNull Location location,
|
||||
int delay,
|
||||
int repeat,
|
||||
@NotNull Runnable task);
|
||||
|
||||
/**
|
||||
* Run a task asynchronously on a timer.
|
||||
*
|
||||
* @param delay The delay.
|
||||
* @param repeat The repeat delay.
|
||||
* @param task The task.
|
||||
* @return The created {@link BukkitTask}.
|
||||
*/
|
||||
BukkitTask runTimerAsync(int delay,
|
||||
int repeat,
|
||||
@NotNull Runnable task);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.willfp.eco.core.version;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* An error thrown when eco is outdated.
|
||||
*/
|
||||
public class OutdatedEcoVersionError extends Error {
|
||||
/**
|
||||
* Create a new OutdatedEcoVersionError.
|
||||
*
|
||||
* @param message The message.
|
||||
*/
|
||||
public OutdatedEcoVersionError(@NotNull final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.willfp.eco.core.version;
|
||||
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A minimal class to represent a version, uses DefaultArtifactVersion under the hood.
|
||||
* <p>
|
||||
* This class exists to resolve issues where 1.17 doesn't include DefaultArtifactVersion.
|
||||
*/
|
||||
public class Version implements Comparable<Version> {
|
||||
/**
|
||||
* The version.
|
||||
*/
|
||||
private final DefaultArtifactVersion version;
|
||||
|
||||
/**
|
||||
* Create a new version.
|
||||
*
|
||||
* @param version The version.
|
||||
*/
|
||||
public Version(@NotNull final String version) {
|
||||
this.version = new DefaultArtifactVersion(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull final Version o) {
|
||||
return this.version.compareTo(o.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.version.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@NotNull final Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Version other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.version.equals(other.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.version.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -8,42 +8,15 @@ import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utilities / API methods for blocks.
|
||||
*/
|
||||
public final class BlockUtils {
|
||||
/**
|
||||
* Max blocks to mine (yes, this is to prevent a stack overflow).
|
||||
*/
|
||||
private static final int MAX_BLOCKS = 2500;
|
||||
|
||||
private static Set<Block> getNearbyBlocks(@NotNull final Block start,
|
||||
@NotNull final List<Material> allowedMaterials,
|
||||
@NotNull final Set<Block> blocks,
|
||||
final int limit) {
|
||||
for (BlockFace face : BlockFace.values()) {
|
||||
Block block = start.getRelative(face);
|
||||
if (blocks.contains(block)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (allowedMaterials.contains(block.getType())) {
|
||||
blocks.add(block);
|
||||
|
||||
if (blocks.size() > limit || blocks.size() > MAX_BLOCKS) {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
blocks.addAll(getNearbyBlocks(block, allowedMaterials, blocks, limit));
|
||||
}
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of all blocks in contact with each other of a specific type.
|
||||
*
|
||||
@@ -56,7 +29,32 @@ public final class BlockUtils {
|
||||
public static Set<Block> getVein(@NotNull final Block start,
|
||||
@NotNull final List<Material> allowedMaterials,
|
||||
final int limit) {
|
||||
return getNearbyBlocks(start, allowedMaterials, new HashSet<>(), limit);
|
||||
Set<Block> blocks = new HashSet<>();
|
||||
Queue<Block> toProcess = new LinkedList<>();
|
||||
|
||||
if (allowedMaterials.contains(start.getType())) {
|
||||
toProcess.add(start);
|
||||
}
|
||||
|
||||
while (!toProcess.isEmpty() && blocks.size() < limit) {
|
||||
Block currentBlock = toProcess.poll();
|
||||
|
||||
if (blocks.contains(currentBlock)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
blocks.add(currentBlock);
|
||||
|
||||
for (BlockFace face : BlockFace.values()) {
|
||||
Block adjacentBlock = currentBlock.getRelative(face);
|
||||
|
||||
if (!blocks.contains(adjacentBlock) && allowedMaterials.contains(adjacentBlock.getType())) {
|
||||
toProcess.add(adjacentBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package com.willfp.eco.util;
|
||||
|
||||
import com.willfp.eco.core.Eco;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import com.willfp.eco.core.math.MathContext;
|
||||
import com.willfp.eco.core.placeholder.AdditionalPlayer;
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -210,7 +209,7 @@ public final class NumberUtils {
|
||||
* @return The value of the expression, or zero if invalid.
|
||||
*/
|
||||
public static double evaluateExpression(@NotNull final String expression) {
|
||||
return evaluateExpression(expression, MathContext.EMPTY);
|
||||
return evaluateExpression(expression, PlaceholderContext.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,7 +221,7 @@ public final class NumberUtils {
|
||||
*/
|
||||
public static double evaluateExpression(@NotNull final String expression,
|
||||
@Nullable final Player player) {
|
||||
return evaluateExpression(expression, player, PlaceholderManager.EMPTY_INJECTABLE);
|
||||
return evaluateExpression(expression, player, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,12 +229,12 @@ public final class NumberUtils {
|
||||
*
|
||||
* @param expression The expression.
|
||||
* @param player The player.
|
||||
* @param context The injectable placeholders.
|
||||
* @param context The injectableContext placeholders.
|
||||
* @return The value of the expression, or zero if invalid.
|
||||
*/
|
||||
public static double evaluateExpression(@NotNull final String expression,
|
||||
@Nullable final Player player,
|
||||
@NotNull final PlaceholderInjectable context) {
|
||||
@Nullable final PlaceholderInjectable context) {
|
||||
return evaluateExpression(expression, player, context, new ArrayList<>());
|
||||
}
|
||||
|
||||
@@ -244,30 +243,46 @@ public final class NumberUtils {
|
||||
*
|
||||
* @param expression The expression.
|
||||
* @param player The player.
|
||||
* @param context The injectable placeholders.
|
||||
* @param context The injectableContext placeholders.
|
||||
* @param additionalPlayers Additional players to parse placeholders for.
|
||||
* @return The value of the expression, or zero if invalid.
|
||||
*/
|
||||
public static double evaluateExpression(@NotNull final String expression,
|
||||
@Nullable final Player player,
|
||||
@NotNull final PlaceholderInjectable context,
|
||||
@Nullable final PlaceholderInjectable context,
|
||||
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
|
||||
return Eco.get().evaluate(expression, new MathContext(
|
||||
context,
|
||||
return Eco.get().evaluate(expression, new PlaceholderContext(
|
||||
player,
|
||||
null,
|
||||
context,
|
||||
additionalPlayers
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate an expression with respect to a player (for placeholders).
|
||||
* Evaluate an expression in a context.
|
||||
*
|
||||
* @param expression The expression.
|
||||
* @param context The math context.
|
||||
* @param context The context.
|
||||
* @return The value of the expression, or zero if invalid.
|
||||
* @deprecated Use {@link #evaluateExpression(String, PlaceholderContext)} instead.
|
||||
*/
|
||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public static double evaluateExpression(@NotNull final String expression,
|
||||
@NotNull final com.willfp.eco.core.math.MathContext context) {
|
||||
return evaluateExpression(expression, context.toPlaceholderContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate an expression in a context.
|
||||
*
|
||||
* @param expression The expression.
|
||||
* @param context The context.
|
||||
* @return The value of the expression, or zero if invalid.
|
||||
*/
|
||||
public static double evaluateExpression(@NotNull final String expression,
|
||||
@NotNull final MathContext context) {
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return Eco.get().evaluate(expression, context);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.willfp.eco.core.Eco;
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
@@ -200,6 +201,26 @@ public final class StringUtils {
|
||||
return translated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a list of strings.
|
||||
* <p>
|
||||
* Coverts color codes and placeholders.
|
||||
*
|
||||
* @param list The messages to format.
|
||||
* @param context The context.
|
||||
* @return The message, format.
|
||||
*/
|
||||
@NotNull
|
||||
public static List<String> formatList(@NotNull final List<String> list,
|
||||
@NotNull PlaceholderContext context) {
|
||||
List<String> translated = new ArrayList<>();
|
||||
for (String string : list) {
|
||||
translated.add(format(string, context));
|
||||
}
|
||||
|
||||
return translated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string.
|
||||
* <p>
|
||||
@@ -242,7 +263,7 @@ public final class StringUtils {
|
||||
@NotNull
|
||||
public static String format(@NotNull final String message,
|
||||
@NotNull final FormatOption option) {
|
||||
return format(message, null, option);
|
||||
return format(message, (Player) null, option);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,7 +308,7 @@ public final class StringUtils {
|
||||
@NotNull
|
||||
public static Component formatToComponent(@NotNull final String message,
|
||||
@NotNull final FormatOption option) {
|
||||
return formatToComponent(message, null, option);
|
||||
return formatToComponent(message, (Player) null, option);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,10 +342,49 @@ public final class StringUtils {
|
||||
public static String format(@NotNull final String message,
|
||||
@Nullable final Player player,
|
||||
@NotNull final FormatOption option) {
|
||||
String processedMessage = message;
|
||||
if (option == FormatOption.WITH_PLACEHOLDERS) {
|
||||
processedMessage = PlaceholderManager.translatePlaceholders(processedMessage, player);
|
||||
return format(
|
||||
message,
|
||||
new PlaceholderContext(player)
|
||||
);
|
||||
}
|
||||
|
||||
return STRING_FORMAT_CACHE.get(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string to a component.
|
||||
* <p>
|
||||
* Converts color codes and placeholders if specified.
|
||||
*
|
||||
* @param message The message to translate.
|
||||
* @param context The placeholder context.
|
||||
* @return The message, formatted, as a component.
|
||||
* @see StringUtils#format(String, Player)
|
||||
*/
|
||||
@NotNull
|
||||
public static Component formatToComponent(@NotNull final String message,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
return toComponent(format(message, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a string.
|
||||
* <p>
|
||||
* Coverts color codes and placeholders if specified.
|
||||
*
|
||||
* @param message The message to format.
|
||||
* @param context The context to translate placeholders with respect to.
|
||||
* @return The message, formatted.
|
||||
*/
|
||||
@NotNull
|
||||
public static String format(@NotNull final String message,
|
||||
@NotNull final PlaceholderContext context) {
|
||||
String processedMessage = message;
|
||||
processedMessage = PlaceholderManager.translatePlaceholders(
|
||||
processedMessage,
|
||||
context
|
||||
);
|
||||
return STRING_FORMAT_CACHE.get(processedMessage);
|
||||
}
|
||||
|
||||
@@ -674,6 +734,56 @@ public final class StringUtils {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast implementation of {@link String#replace(CharSequence, CharSequence)}
|
||||
*
|
||||
* @param input The input string.
|
||||
* @param target The target string.
|
||||
* @param replacement The replacement string.
|
||||
* @return The replaced string.
|
||||
*/
|
||||
@NotNull
|
||||
public static String replaceQuickly(@NotNull final String input,
|
||||
@NotNull final String target,
|
||||
@NotNull final String replacement) {
|
||||
int targetLength = target.length();
|
||||
|
||||
// Count the number of original occurrences
|
||||
int count = 0;
|
||||
for (
|
||||
int index = input.indexOf(target);
|
||||
index != -1;
|
||||
index = input.indexOf(target, index + targetLength)
|
||||
) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return input;
|
||||
}
|
||||
|
||||
int replacementLength = replacement.length();
|
||||
int inputLength = input.length();
|
||||
|
||||
// Pre-calculate the final size of the StringBuilder
|
||||
int newSize = inputLength + (replacementLength - targetLength) * count;
|
||||
StringBuilder result = new StringBuilder(newSize);
|
||||
|
||||
int start = 0;
|
||||
for (
|
||||
int index = input.indexOf(target);
|
||||
index != -1;
|
||||
index = input.indexOf(target, start)
|
||||
) {
|
||||
result.append(input, start, index);
|
||||
result.append(replacement);
|
||||
start = index + targetLength;
|
||||
}
|
||||
|
||||
result.append(input, start, inputLength);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for formatting.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
@file:JvmName("PlaceholderContextExtensions")
|
||||
|
||||
package com.willfp.eco.core.placeholder.context
|
||||
|
||||
import com.willfp.eco.core.placeholder.AdditionalPlayer
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
/** @see PlaceholderContext */
|
||||
@JvmOverloads
|
||||
fun placeholderContext(
|
||||
player: Player? = null,
|
||||
item: ItemStack? = null,
|
||||
injectable: PlaceholderInjectable? = null,
|
||||
additionalPlayers: Collection<AdditionalPlayer> = emptyList()
|
||||
): PlaceholderContext = PlaceholderContext(player, item, injectable, additionalPlayers)
|
||||
|
||||
/** @see PlaceholderContext */
|
||||
fun PlaceholderContext.copy(
|
||||
player: Player? = this.player,
|
||||
item: ItemStack? = this.itemStack,
|
||||
injectable: PlaceholderInjectable? = this.injectableContext,
|
||||
additionalPlayers: Collection<AdditionalPlayer> = this.additionalPlayers
|
||||
): PlaceholderContext = PlaceholderContext(player, item, injectable, additionalPlayers)
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.willfp.eco.core.registry
|
||||
|
||||
/**
|
||||
* A registrable that has a string ID, for use with Kotlin.
|
||||
*/
|
||||
interface KRegistrable : Registrable {
|
||||
/**
|
||||
* The ID of the registrable.
|
||||
*/
|
||||
val id: String
|
||||
|
||||
override fun getID() = id
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
package com.willfp.eco.util
|
||||
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
@@ -31,6 +32,14 @@ fun String.formatEco(
|
||||
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
|
||||
)
|
||||
|
||||
/** @see StringUtils.format */
|
||||
fun String.formatEco(
|
||||
context: PlaceholderContext
|
||||
) = StringUtils.format(
|
||||
this,
|
||||
context
|
||||
)
|
||||
|
||||
/** @see StringUtils.formatList */
|
||||
fun List<String>.formatEco(
|
||||
player: Player? = null,
|
||||
@@ -41,6 +50,14 @@ fun List<String>.formatEco(
|
||||
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
|
||||
)
|
||||
|
||||
/** @see StringUtils.formatList */
|
||||
fun List<String>.formatEco(
|
||||
context: PlaceholderContext
|
||||
): List<String> = StringUtils.formatList(
|
||||
this,
|
||||
context
|
||||
)
|
||||
|
||||
/** @see StringUtils.splitAround */
|
||||
fun String.splitAround(separator: String): Array<String> =
|
||||
StringUtils.splitAround(this, separator)
|
||||
@@ -48,3 +65,7 @@ fun String.splitAround(separator: String): Array<String> =
|
||||
/** @see StringUtils.toNiceString */
|
||||
fun Any?.toNiceString(): String =
|
||||
StringUtils.toNiceString(this)
|
||||
|
||||
/** @see StringUtils.replaceQuickly */
|
||||
fun String.replaceQuickly(target: String, replacement: String): String =
|
||||
StringUtils.replaceQuickly(this, target, replacement)
|
||||
|
||||
@@ -3,7 +3,8 @@ package com.willfp.eco.internal.config
|
||||
import com.willfp.eco.core.config.ConfigType
|
||||
import com.willfp.eco.core.config.interfaces.Config
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.internal.fast.listView
|
||||
import com.willfp.eco.util.StringUtils
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -15,7 +16,7 @@ open class EcoConfig(
|
||||
private val values = ConcurrentHashMap<String, Any?>()
|
||||
|
||||
@Transient
|
||||
var injections = mutableListOf<InjectablePlaceholder>()
|
||||
var injections = ConcurrentHashMap<String, InjectablePlaceholder>()
|
||||
|
||||
fun init(values: Map<String, Any?>) {
|
||||
this.values.clear()
|
||||
@@ -104,12 +105,12 @@ open class EcoConfig(
|
||||
}
|
||||
|
||||
override fun getSubsectionOrNull(path: String): Config? {
|
||||
return (get(path) as? Config)?.apply { this.addInjectablePlaceholder(injections) }
|
||||
return (get(path) as? Config)?.apply { this.addInjectablePlaceholder(injections.values) }
|
||||
}
|
||||
|
||||
override fun getSubsectionsOrNull(path: String): List<Config>? {
|
||||
return getList<Config>(path)
|
||||
?.map { it.apply { this.addInjectablePlaceholder(injections) } }
|
||||
?.map { it.apply { this.addInjectablePlaceholder(injections.values) } }
|
||||
?.toList()
|
||||
}
|
||||
|
||||
@@ -141,9 +142,7 @@ open class EcoConfig(
|
||||
var string = get(path)?.toString() ?: return null
|
||||
if (format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
|
||||
for (injection in placeholderInjections) {
|
||||
if (injection is StaticPlaceholder) {
|
||||
string = string.replace("%${injection.identifier}%", injection.value)
|
||||
}
|
||||
string = injection.tryTranslateQuickly(string, PlaceholderContext.EMPTY)
|
||||
}
|
||||
}
|
||||
return if (format) StringUtils.format(string, option) else string
|
||||
@@ -161,9 +160,7 @@ open class EcoConfig(
|
||||
strings.replaceAll {
|
||||
var string = it
|
||||
for (injection in placeholderInjections) {
|
||||
if (injection is StaticPlaceholder) {
|
||||
string = string.replace("%${injection.identifier}%", injection.value)
|
||||
}
|
||||
string = injection.tryTranslateQuickly(string, PlaceholderContext.EMPTY)
|
||||
}
|
||||
string
|
||||
}
|
||||
@@ -180,12 +177,13 @@ open class EcoConfig(
|
||||
}
|
||||
|
||||
override fun addInjectablePlaceholder(placeholders: Iterable<InjectablePlaceholder>) {
|
||||
injections.removeIf { placeholders.any { placeholder -> it.identifier == placeholder.identifier } }
|
||||
injections.addAll(placeholders)
|
||||
for (placeholder in placeholders) {
|
||||
injections[placeholder.pattern.pattern()] = placeholder
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPlaceholderInjections(): List<InjectablePlaceholder> {
|
||||
return injections.toList()
|
||||
return injections.values.listView() // Faster than .toList()
|
||||
}
|
||||
|
||||
override fun clearInjectedPlaceholders() {
|
||||
@@ -208,14 +206,6 @@ open class EcoConfig(
|
||||
return bukkit
|
||||
}
|
||||
|
||||
override fun clone(): Config {
|
||||
return EcoConfigSection(type, this.values.toMutableMap(), injections)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return this.toPlaintext()
|
||||
}
|
||||
|
||||
private inline fun <reified T> getList(path: String): List<T>? {
|
||||
val asIterable = get(path) as? Iterable<*> ?: return null
|
||||
val asList = asIterable.toList()
|
||||
@@ -226,4 +216,44 @@ open class EcoConfig(
|
||||
|
||||
return asList as List<T>
|
||||
}
|
||||
|
||||
override fun clone(): Config {
|
||||
return EcoConfigSection(type, this.values.toMutableMap(), injections)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return this.toPlaintext()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (other !is EcoConfig) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Hey! Don't care. This works.
|
||||
return this.hashCode() == other.hashCode()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
/*
|
||||
The keys are completely redundant, as they are only used to prevent
|
||||
duplicate keys in the map. Therefore, we can ignore them and just
|
||||
hash the actual placeholder values.
|
||||
*/
|
||||
|
||||
var injectionHash = 0
|
||||
|
||||
injections.forEachValue(5) {
|
||||
injectionHash = injectionHash xor (it.hashCode() shl 5)
|
||||
}
|
||||
|
||||
// hashCode() has to compute extremely quickly, so we're using bitwise, because why not?
|
||||
// Fucking filthy to use identityHashCode here, but it should be extremely fast
|
||||
val identityHash = System.identityHashCode(this)
|
||||
return (identityHash shl 5) - (identityHash xor configType.hashCode()) + injectionHash
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@ package com.willfp.eco.internal.config
|
||||
|
||||
import com.willfp.eco.core.config.ConfigType
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class EcoConfigSection(
|
||||
type: ConfigType,
|
||||
values: Map<String, Any?> = emptyMap(),
|
||||
injections: Collection<InjectablePlaceholder> = emptyList()
|
||||
injections: Map<String, InjectablePlaceholder> = emptyMap()
|
||||
) : EcoConfig(type) {
|
||||
init {
|
||||
this.init(values)
|
||||
this.injections = injections.toMutableList()
|
||||
this.injections = ConcurrentHashMap(injections)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.willfp.eco.internal.data
|
||||
|
||||
import com.willfp.eco.core.data.ExternalDataStoreObjectAdapter
|
||||
import com.willfp.eco.core.version.Version
|
||||
|
||||
object VersionToStringAdapter: ExternalDataStoreObjectAdapter<Version, String>(
|
||||
Version::class.java,
|
||||
String::class.java
|
||||
) {
|
||||
override fun toAccessedObject(obj: String): Version = Version(obj)
|
||||
|
||||
override fun toStoredObject(obj: Version): String = obj.toString()
|
||||
}
|
||||
|
||||
class MavenVersionToStringAdapter(
|
||||
className: String
|
||||
): ExternalDataStoreObjectAdapter<Any, String>(
|
||||
Class.forName(className),
|
||||
String::class.java
|
||||
) {
|
||||
private val constructor = Class.forName(className)
|
||||
.getConstructor(String::class.java)
|
||||
|
||||
override fun toAccessedObject(obj: String): Any = constructor.newInstance(obj)
|
||||
|
||||
override fun toStoredObject(obj: Any): String = obj.toString()
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.config.toConfig
|
||||
import com.willfp.eco.core.extensions.Extension
|
||||
import com.willfp.eco.core.extensions.ExtensionLoadException
|
||||
import com.willfp.eco.core.extensions.ExtensionLoader
|
||||
import com.willfp.eco.core.extensions.ExtensionMetadata
|
||||
import com.willfp.eco.core.extensions.MalformedExtensionException
|
||||
import com.willfp.eco.core.version.Version
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
@@ -32,7 +34,7 @@ class EcoExtensionLoader(
|
||||
}
|
||||
|
||||
runCatching { loadExtension(extensionJar) }.onFailure {
|
||||
this.plugin.logger.warning(extensionJar.name + " caused an error!")
|
||||
this.plugin.logger.warning(extensionJar.name + " caused an error: ${it.message ?: "Unknown error"}")
|
||||
if (Eco.get().ecoPlugin.configYml.getBool("log-full-extension-errors")) {
|
||||
it.printStackTrace()
|
||||
}
|
||||
@@ -54,7 +56,12 @@ class EcoExtensionLoader(
|
||||
var name = extensionYml.getStringOrNull("name")
|
||||
var version = extensionYml.getStringOrNull("version")
|
||||
var author = extensionYml.getStringOrNull("author")
|
||||
val pluginVersion = Version(extensionYml.getStringOrNull("plugin-version") ?: "0.0.0")
|
||||
val pluginName = extensionYml.getStringOrNull("plugin")
|
||||
|
||||
if (pluginName != null && !pluginName.equals(this.plugin.description.name, ignoreCase = true)) {
|
||||
throw ExtensionLoadException("${extensionJar.name} is only compatible with $pluginName!")
|
||||
}
|
||||
|
||||
if (mainClass == null) {
|
||||
throw MalformedExtensionException("Invalid extension.yml found in " + extensionJar.name)
|
||||
@@ -75,7 +82,11 @@ class EcoExtensionLoader(
|
||||
author = "Unnamed Author"
|
||||
}
|
||||
|
||||
val metadata = ExtensionMetadata(version, name, author)
|
||||
if (Version(this.plugin.description.version) < pluginVersion) {
|
||||
throw ExtensionLoadException("Plugin version is too low for ${extensionJar.name}!")
|
||||
}
|
||||
|
||||
val metadata = ExtensionMetadata(version, name, author, extensionJar, pluginVersion)
|
||||
|
||||
val cls: Class<*> = classLoader.loadClass(mainClass)
|
||||
val extension: Extension = cls.getConstructor(EcoPlugin::class.java).newInstance(this.plugin) as Extension
|
||||
@@ -85,7 +96,7 @@ class EcoExtensionLoader(
|
||||
extensions[extension] = classLoader
|
||||
}
|
||||
|
||||
override fun getLoadedExtensions(): MutableSet<Extension> {
|
||||
override fun getLoadedExtensions(): Set<Extension> {
|
||||
return ImmutableSet.copyOf(extensions.keys)
|
||||
}
|
||||
|
||||
@@ -97,4 +108,4 @@ class EcoExtensionLoader(
|
||||
|
||||
extensions.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ class EcoRunnableFactory(private val plugin: EcoPlugin) : RunnableFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.willfp.eco.internal.fast
|
||||
|
||||
class ListViewOfCollection<T>(private val collection: Collection<T>) : List<T> {
|
||||
/*
|
||||
The backing list is lazy-loaded because it provides a performance hit
|
||||
to copy the contents of the contents of the collection into a list.
|
||||
|
||||
Since the only required operator for most use-cases is .iterator(),
|
||||
we can just use the collection's iterator.
|
||||
*/
|
||||
|
||||
private val backingList: List<T> by lazy { collection.toList() }
|
||||
|
||||
override val size: Int
|
||||
get() = collection.size
|
||||
|
||||
override fun containsAll(elements: Collection<T>) =
|
||||
collection.containsAll(elements)
|
||||
|
||||
override fun get(index: Int): T =
|
||||
backingList[index]
|
||||
|
||||
override fun indexOf(element: T): Int = backingList.indexOf(element)
|
||||
|
||||
override fun contains(element: T): Boolean = collection.contains(element)
|
||||
|
||||
override fun isEmpty() =
|
||||
collection.isEmpty()
|
||||
|
||||
override fun iterator() =
|
||||
collection.iterator()
|
||||
|
||||
override fun listIterator() =
|
||||
backingList.listIterator()
|
||||
|
||||
override fun listIterator(index: Int) =
|
||||
backingList.listIterator(index)
|
||||
|
||||
override fun subList(fromIndex: Int, toIndex: Int) =
|
||||
backingList.subList(fromIndex, toIndex)
|
||||
|
||||
override fun lastIndexOf(element: T) =
|
||||
backingList.lastIndexOf(element)
|
||||
}
|
||||
|
||||
inline fun <reified T> Collection<T>.listView(): List<T> {
|
||||
return ListViewOfCollection(this)
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.willfp.eco.internal.integrations
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
||||
import com.willfp.eco.core.placeholder.context.placeholderContext
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
@@ -33,7 +34,19 @@ class PAPIExpansion(private val plugin: EcoPlugin) : PlaceholderExpansion() {
|
||||
override fun onPlaceholderRequest(
|
||||
player: Player?,
|
||||
identifier: String
|
||||
): String {
|
||||
return PlaceholderManager.getResult(player, identifier, plugin)
|
||||
): String? {
|
||||
return PlaceholderManager.getResult(
|
||||
plugin,
|
||||
identifier,
|
||||
placeholderContext(
|
||||
player = player,
|
||||
item = player?.inventory?.itemInMainHand
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getPlaceholders(): List<String> {
|
||||
return PlaceholderManager.getRegisteredPlaceholders(plugin)
|
||||
.map { "%${this.plugin.name.lowercase()}_${it.pattern.pattern()}%" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.willfp.eco.internal.placeholder
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder
|
||||
import com.willfp.eco.core.placeholder.Placeholder
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class PlaceholderLookup(
|
||||
val args: String,
|
||||
val plugin: EcoPlugin?,
|
||||
private val injections: Collection<InjectablePlaceholder>?
|
||||
) {
|
||||
fun findMatchingPlaceholder(): Placeholder? {
|
||||
if (plugin != null) {
|
||||
val pluginPlaceholders = PlaceholderManager.getRegisteredPlaceholders(plugin)
|
||||
for (placeholder in pluginPlaceholders) {
|
||||
if (placeholder.matches(this)) {
|
||||
return placeholder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (injections != null) {
|
||||
for (placeholder in injections) {
|
||||
if (placeholder.matches(this)) {
|
||||
return placeholder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun Placeholder.matches(lookup: PlaceholderLookup): Boolean {
|
||||
val pattern = this.pattern
|
||||
val patternString = pattern.pattern()
|
||||
|
||||
val patternFlags = pattern.flags()
|
||||
val isLiteral = Pattern.LITERAL and patternFlags != 0
|
||||
|
||||
return if (isLiteral) lookup.args == patternString else pattern.matcher(lookup.args).matches()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package com.willfp.eco.internal.placeholder
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder
|
||||
import com.willfp.eco.core.placeholder.Placeholder
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.util.StringUtils
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/*
|
||||
|
||||
A lot of methods here are centered around minimising calls to getPlaceholderInjections,
|
||||
which tends to be slow for things like configs. This was optimised with ListViewOfCollection,
|
||||
but it's still best to minimise the memory overhead.
|
||||
|
||||
*/
|
||||
|
||||
class PlaceholderParser {
|
||||
private val placeholderRegex = Regex("%([^% ]+)%")
|
||||
|
||||
private val placeholderLookupCache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.SECONDS)
|
||||
.build<PlaceholderLookup, Optional<Placeholder>>()
|
||||
|
||||
fun translatePlacholders(text: String, context: PlaceholderContext): String {
|
||||
return translatePlacholders(text, context, context.injectableContext.placeholderInjections)
|
||||
}
|
||||
|
||||
private fun translatePlacholders(
|
||||
text: String,
|
||||
context: PlaceholderContext,
|
||||
injections: Collection<InjectablePlaceholder>,
|
||||
translateEcoPlaceholders: Boolean = true
|
||||
): String {
|
||||
/*
|
||||
|
||||
Why am I doing injections at the start, and again at the end?
|
||||
|
||||
Additional players let you use something like victim as a player to parse in relation to,
|
||||
for example doing %victim_player_health%, which would parse the health of the victim.
|
||||
|
||||
However, something like libreforge will also inject %victim_max_health%, which is unrelated
|
||||
to additional players, and instead holds a constant value. So, eco saw this, smartly thought
|
||||
"ah, it's an additional player, let's parse it", and then tried to parse %max_health% with
|
||||
relation to the victim, which resolved to zero. So, we have to parse statics and player statics
|
||||
that might include a prefix first, then additional players, then player statics with the support
|
||||
of additional players.
|
||||
|
||||
This was a massive headache and took so many reports before I clocked what was going on.
|
||||
|
||||
Oh well, at least it's fixed now.
|
||||
|
||||
*/
|
||||
|
||||
// Apply injections first
|
||||
var processed = injections.fold(text) { acc, injection ->
|
||||
injection.tryTranslateQuickly(acc, context)
|
||||
}
|
||||
|
||||
// Prevent running 2 scans if there are no additional players.
|
||||
if (context.additionalPlayers.isNotEmpty()) {
|
||||
val found = PlaceholderManager.findPlaceholdersIn(text)
|
||||
for (additionalPlayer in context.additionalPlayers) {
|
||||
val prefix = "%${additionalPlayer.identifier}_"
|
||||
processed = found.fold(processed) { acc, placeholder ->
|
||||
if (placeholder.startsWith(prefix)) {
|
||||
val newPlaceholder = "%${StringUtils.removePrefix(prefix, placeholder)}"
|
||||
val translation = translatePlacholders(
|
||||
newPlaceholder,
|
||||
context.copyWithPlayer(additionalPlayer.player),
|
||||
injections
|
||||
)
|
||||
acc.replace(placeholder, translation)
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Translate eco placeholders
|
||||
if (translateEcoPlaceholders) {
|
||||
processed = translateEcoPlaceholdersIn(processed, context, injections)
|
||||
}
|
||||
|
||||
// Apply registered integrations
|
||||
processed = PlaceholderManager.getRegisteredIntegrations().fold(processed) { acc, integration ->
|
||||
integration.translate(acc, context.player)
|
||||
}
|
||||
|
||||
// Apply injections again
|
||||
return injections.fold(processed) { acc, injection ->
|
||||
injection.tryTranslateQuickly(acc, context)
|
||||
}
|
||||
}
|
||||
|
||||
fun getPlaceholderResult(
|
||||
plugin: EcoPlugin?,
|
||||
args: String,
|
||||
context: PlaceholderContext
|
||||
): String? {
|
||||
// Only scan for injections if plugin is null.
|
||||
val injections = if (plugin == null) context.injectableContext.placeholderInjections else null
|
||||
|
||||
return doGetResult(plugin, args, injections, context)
|
||||
}
|
||||
|
||||
// Injections are sent separately here to prevent multiple calls to getPlaceholderInjections
|
||||
private fun doGetResult(
|
||||
plugin: EcoPlugin?,
|
||||
args: String?,
|
||||
injections: Collection<InjectablePlaceholder>?,
|
||||
context: PlaceholderContext
|
||||
): String? {
|
||||
if (args == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val lookup = PlaceholderLookup(args, plugin, injections)
|
||||
|
||||
val placeholder = placeholderLookupCache.get(lookup) {
|
||||
Optional.ofNullable(it.findMatchingPlaceholder())
|
||||
}.orElse(null) ?: return null
|
||||
|
||||
return placeholder.getValue(args, context)
|
||||
}
|
||||
|
||||
private fun translateEcoPlaceholdersIn(
|
||||
text: String,
|
||||
context: PlaceholderContext,
|
||||
injections: Collection<InjectablePlaceholder>
|
||||
): String {
|
||||
val output = StringBuilder()
|
||||
var lastAppendPosition = 0
|
||||
|
||||
for (matchResult in placeholderRegex.findAll(text)) {
|
||||
val placeholder = matchResult.groups[1]?.value ?: ""
|
||||
|
||||
val injectableResult = doGetResult(null, placeholder, injections, context)
|
||||
|
||||
val parts = placeholder.split("_", limit = 2)
|
||||
|
||||
var result: String? = null
|
||||
|
||||
if (injectableResult != null) {
|
||||
result = injectableResult
|
||||
} else if (parts.size == 2) {
|
||||
val plugin = EcoPlugin.getPlugin(parts[0])
|
||||
|
||||
if (plugin != null) {
|
||||
result = doGetResult(plugin, parts[1], null, context)
|
||||
}
|
||||
}
|
||||
|
||||
output.append(text.substring(lastAppendPosition, matchResult.range.first))
|
||||
|
||||
output.append(result ?: matchResult.value)
|
||||
|
||||
lastAppendPosition = matchResult.range.last + 1
|
||||
}
|
||||
|
||||
output.append(text.substring(lastAppendPosition))
|
||||
return output.toString()
|
||||
}
|
||||
|
||||
fun parseIndividualPlaceholders(strings: Collection<String>, context: PlaceholderContext): Collection<String> {
|
||||
val injections = context.injectableContext.placeholderInjections
|
||||
|
||||
return strings.map {
|
||||
parseIndividualEcoPlaceholder(it, context, injections)
|
||||
?: translatePlacholders(
|
||||
it,
|
||||
context,
|
||||
injections,
|
||||
translateEcoPlaceholders = false
|
||||
) // Default to slower translation
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseIndividualEcoPlaceholder(
|
||||
string: String,
|
||||
context: PlaceholderContext,
|
||||
injections: Collection<InjectablePlaceholder>
|
||||
): String? {
|
||||
val placeholder = string.substring(1, string.length - 1)
|
||||
|
||||
val injectableResult = doGetResult(null, placeholder, injections, context)
|
||||
|
||||
if (injectableResult != null) {
|
||||
return injectableResult
|
||||
}
|
||||
|
||||
val parts = placeholder.split("_", limit = 2)
|
||||
|
||||
if (parts.size == 2) {
|
||||
val plugin = EcoPlugin.getPlugin(parts[0])
|
||||
|
||||
if (plugin != null) {
|
||||
return doGetResult(plugin, parts[1], null, context)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.willfp.eco.internal.price
|
||||
|
||||
import com.willfp.eco.core.math.MathContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier
|
||||
import com.willfp.eco.core.price.Price
|
||||
import com.willfp.eco.core.price.PriceFactory
|
||||
import com.willfp.eco.core.price.impl.PriceEconomy
|
||||
import java.util.function.Function
|
||||
|
||||
object PriceFactoryEconomy : PriceFactory {
|
||||
override fun getNames() = listOf(
|
||||
@@ -12,7 +12,7 @@ object PriceFactoryEconomy : PriceFactory {
|
||||
"$"
|
||||
)
|
||||
|
||||
override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
|
||||
override fun create(baseContext: PlaceholderContext, function: PlaceholderContextSupplier<Double>): Price {
|
||||
return PriceEconomy(baseContext, function)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.willfp.eco.internal.price
|
||||
|
||||
import com.willfp.eco.core.math.MathContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier
|
||||
import com.willfp.eco.core.price.Price
|
||||
import com.willfp.eco.core.price.PriceFactory
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.UUID
|
||||
import java.util.function.Function
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object PriceFactoryXP : PriceFactory {
|
||||
@@ -15,13 +15,13 @@ object PriceFactoryXP : PriceFactory {
|
||||
"experience"
|
||||
)
|
||||
|
||||
override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
|
||||
return PriceXP(baseContext) { function.apply(it).roundToInt() }
|
||||
override fun create(baseContext: PlaceholderContext, function: PlaceholderContextSupplier<Double>): Price {
|
||||
return PriceXP(baseContext) { function.get(it).roundToInt() }
|
||||
}
|
||||
|
||||
private class PriceXP(
|
||||
private val baseContext: MathContext,
|
||||
private val xp: (MathContext) -> Int
|
||||
private val baseContext: PlaceholderContext,
|
||||
private val xp: (PlaceholderContext) -> Int
|
||||
) : Price {
|
||||
private val multipliers = mutableMapOf<UUID, Double>()
|
||||
|
||||
@@ -37,7 +37,7 @@ object PriceFactoryXP : PriceFactory {
|
||||
}
|
||||
|
||||
override fun getValue(player: Player, multiplier: Double): Double {
|
||||
return xp(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player) * multiplier
|
||||
return xp(baseContext.copyWithPlayer(player)) * getMultiplier(player) * multiplier
|
||||
}
|
||||
|
||||
override fun getMultiplier(player: Player): Double {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.willfp.eco.internal.price
|
||||
|
||||
import com.willfp.eco.core.math.MathContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier
|
||||
import com.willfp.eco.core.price.Price
|
||||
import com.willfp.eco.core.price.PriceFactory
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.UUID
|
||||
import java.util.function.Function
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object PriceFactoryXPLevels : PriceFactory {
|
||||
@@ -16,13 +16,13 @@ object PriceFactoryXPLevels : PriceFactory {
|
||||
"explevels",
|
||||
)
|
||||
|
||||
override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
|
||||
return PriceXPLevel(baseContext) { function.apply(it).roundToInt() }
|
||||
override fun create(baseContext: PlaceholderContext, function: PlaceholderContextSupplier<Double>): Price {
|
||||
return PriceXPLevel(baseContext) { function.get(it).roundToInt() }
|
||||
}
|
||||
|
||||
private class PriceXPLevel(
|
||||
private val baseContext: MathContext,
|
||||
private val level: (MathContext) -> Int
|
||||
private val baseContext: PlaceholderContext,
|
||||
private val level: (PlaceholderContext) -> Int
|
||||
) : Price {
|
||||
private val multipliers = mutableMapOf<UUID, Double>()
|
||||
|
||||
@@ -37,7 +37,7 @@ object PriceFactoryXPLevels : PriceFactory {
|
||||
}
|
||||
|
||||
override fun getValue(player: Player, multiplier: Double): Double {
|
||||
return level(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player) * multiplier
|
||||
return level(baseContext.copyWithPlayer(player)) * getMultiplier(player) * multiplier
|
||||
}
|
||||
|
||||
override fun getMultiplier(player: Player): Double {
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.willfp.eco.internal.scheduling
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.scheduling.Scheduler
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
|
||||
class EcoScheduler(private val plugin: EcoPlugin) : Scheduler {
|
||||
override fun runLater(
|
||||
runnable: Runnable,
|
||||
ticksLater: Long
|
||||
): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskLater(plugin, runnable, ticksLater)
|
||||
}
|
||||
|
||||
override fun runTimer(
|
||||
runnable: Runnable,
|
||||
delay: Long,
|
||||
repeat: Long
|
||||
): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, repeat)
|
||||
}
|
||||
|
||||
override fun runAsyncTimer(
|
||||
runnable: Runnable,
|
||||
delay: Long,
|
||||
repeat: Long
|
||||
): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, repeat)
|
||||
}
|
||||
|
||||
override fun run(runnable: Runnable): BukkitTask {
|
||||
return Bukkit.getScheduler().runTask(plugin, runnable)
|
||||
}
|
||||
|
||||
override fun runAsync(runnable: Runnable): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable)
|
||||
}
|
||||
|
||||
override fun syncRepeating(
|
||||
runnable: Runnable,
|
||||
delay: Long,
|
||||
repeat: Long
|
||||
): Int {
|
||||
return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, runnable, delay, repeat)
|
||||
}
|
||||
|
||||
override fun cancelAll() {
|
||||
Bukkit.getScheduler().cancelTasks(plugin)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.willfp.eco.internal.scheduling
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.scheduling.Scheduler
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
|
||||
class EcoSchedulerSpigot(private val plugin: EcoPlugin) : Scheduler {
|
||||
override fun runLater(location: Location, ticksLater: Int, task: Runnable): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskLater(plugin, task, ticksLater.toLong())
|
||||
}
|
||||
|
||||
override fun runTimer(location: Location, delay: Int, repeat: Int, task: Runnable): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskTimer(plugin, task, delay.toLong(), repeat.toLong())
|
||||
}
|
||||
|
||||
override fun run(location: Location, task: Runnable): BukkitTask {
|
||||
return Bukkit.getScheduler().runTask(plugin, task)
|
||||
}
|
||||
|
||||
override fun runAsync(task: Runnable): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskAsynchronously(plugin, task)
|
||||
}
|
||||
|
||||
override fun runTimerAsync(delay: Int, repeat: Int, task: Runnable): BukkitTask {
|
||||
return Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, task, delay.toLong(), repeat.toLong())
|
||||
}
|
||||
|
||||
override fun cancelAll() {
|
||||
Bukkit.getScheduler().cancelTasks(plugin)
|
||||
}
|
||||
}
|
||||
6
eco-core/core-folia/build.gradle.kts
Normal file
6
eco-core/core-folia/build.gradle.kts
Normal file
@@ -0,0 +1,6 @@
|
||||
group = "com.willfp"
|
||||
version = rootProject.version
|
||||
|
||||
dependencies {
|
||||
compileOnly("dev.folia:folia-api:1.19.4-R0.1-SNAPSHOT")
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.willfp.eco.internal.scheduling
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.scheduling.Scheduler
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class EcoSchedulerFolia(private val plugin: EcoPlugin) : Scheduler {
|
||||
override fun runLater(runnable: Runnable, ticksLater: Long): BukkitTask {
|
||||
Bukkit.getGlobalRegionScheduler().runDelayed(plugin, { runnable.run() }, ticksLater)
|
||||
}
|
||||
|
||||
override fun runLater(location: Location, ticksLater: Int, task: Runnable): BukkitTask {
|
||||
Bukkit.getRegionScheduler().runDelayed(plugin, location, { task.run() }, ticksLater.toLong())
|
||||
}
|
||||
|
||||
override fun runTimer(delay: Long, repeat: Long, runnable: Runnable): BukkitTask {
|
||||
Bukkit.getGlobalRegionScheduler().runAtFixedRate(plugin, { runnable.run() }, delay, repeat)
|
||||
}
|
||||
|
||||
override fun runTimer(location: Location, delay: Int, repeat: Int, task: Runnable): BukkitTask {
|
||||
Bukkit.getRegionScheduler().runAtFixedRate(plugin, location, { task.run() }, delay.toLong(), repeat.toLong())
|
||||
}
|
||||
|
||||
override fun run(runnable: Runnable): BukkitTask {
|
||||
Bukkit.getGlobalRegionScheduler().run(plugin) { runnable.run() }
|
||||
}
|
||||
|
||||
override fun run(location: Location, task: Runnable): BukkitTask {
|
||||
Bukkit.getRegionScheduler().run(plugin, location) { task.run() }
|
||||
}
|
||||
|
||||
override fun runAsync(task: Runnable): BukkitTask {
|
||||
Bukkit.getAsyncScheduler().runNow(plugin) { task.run() }
|
||||
}
|
||||
|
||||
override fun runTimerAsync(delay: Int, repeat: Int, task: Runnable): BukkitTask {
|
||||
Bukkit.getAsyncScheduler()
|
||||
.runAtFixedRate(plugin, { task.run() }, delay * 50L, repeat * 50L, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
override fun cancelAll() {
|
||||
Bukkit.getScheduler().cancelTasks(plugin)
|
||||
Bukkit.getAsyncScheduler().cancelTasks(plugin)
|
||||
Bukkit.getGlobalRegionScheduler().cancelTasks(plugin)
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class SNBTConverter : SNBTConverterProxy {
|
||||
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||
val nmsTag = nms.save(CompoundTag())
|
||||
nmsTag.remove("Count")
|
||||
return tag.copy().merge(nmsTag) == nmsTag
|
||||
return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
|
||||
}
|
||||
|
||||
override fun getItem(): ItemStack = item
|
||||
|
||||
@@ -45,7 +45,7 @@ class SNBTConverter : SNBTConverterProxy {
|
||||
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||
val nmsTag = nms.save(CompoundTag())
|
||||
nmsTag.remove("Count")
|
||||
return tag.copy().merge(nmsTag) == nmsTag
|
||||
return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
|
||||
}
|
||||
|
||||
override fun getItem(): ItemStack = item
|
||||
|
||||
@@ -45,7 +45,7 @@ class SNBTConverter : SNBTConverterProxy {
|
||||
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||
val nmsTag = nms.save(CompoundTag())
|
||||
nmsTag.remove("Count")
|
||||
return tag.copy().merge(nmsTag) == nmsTag
|
||||
return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
|
||||
}
|
||||
|
||||
override fun getItem(): ItemStack = item
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.willfp.eco.internal.spigot.proxy.v1_19_R1
|
||||
import com.willfp.eco.core.items.TestableItem
|
||||
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
|
||||
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.common.toMaterial
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.SnbtPrinterTagVisitor
|
||||
import net.minecraft.nbt.TagParser
|
||||
@@ -44,7 +45,7 @@ class SNBTConverter : SNBTConverterProxy {
|
||||
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||
val nmsTag = nms.save(CompoundTag())
|
||||
nmsTag.remove("Count")
|
||||
return tag.copy().merge(nmsTag) == nmsTag
|
||||
return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
|
||||
}
|
||||
|
||||
override fun getItem(): ItemStack = item
|
||||
|
||||
@@ -44,7 +44,7 @@ class SNBTConverter : SNBTConverterProxy {
|
||||
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||
val nmsTag = nms.save(CompoundTag())
|
||||
nmsTag.remove("Count")
|
||||
return tag.copy().merge(nmsTag) == nmsTag
|
||||
return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
|
||||
}
|
||||
|
||||
override fun getItem(): ItemStack = item
|
||||
|
||||
@@ -44,7 +44,7 @@ class SNBTConverter : SNBTConverterProxy {
|
||||
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||
val nmsTag = nms.save(CompoundTag())
|
||||
nmsTag.remove("Count")
|
||||
return tag.copy().merge(nmsTag) == nmsTag
|
||||
return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
|
||||
}
|
||||
|
||||
override fun getItem(): ItemStack = item
|
||||
|
||||
@@ -37,7 +37,7 @@ dependencies {
|
||||
compileOnly("com.github.jiangdashao:matrix-api-repo:317d4635fd")
|
||||
compileOnly("com.gmail.nossr50.mcMMO:mcMMO:2.1.202")
|
||||
compileOnly("me.clip:placeholderapi:2.10.10")
|
||||
compileOnly("com.github.oraxen:oraxen:bea381fb82")
|
||||
compileOnly("com.github.oraxen:oraxen:1.155.0")
|
||||
compileOnly("com.github.brcdev-minecraft:shopgui-api:3.0.0")
|
||||
compileOnly("com.github.LoneDev6:API-ItemsAdder:2.4.7")
|
||||
compileOnly("com.arcaniax:HeadDatabase-API:1.3.0")
|
||||
@@ -52,12 +52,16 @@ dependencies {
|
||||
compileOnly("com.github.N0RSKA:ScytherAPI:55a")
|
||||
compileOnly("com.ticxo.modelengine:api:R3.0.1")
|
||||
compileOnly("me.TechsCode:UltraEconomyAPI:1.0.0")
|
||||
compileOnly("org.black_ixx:playerpoints:3.2.5")
|
||||
compileOnly("com.github.Ssomar-Developement:SCore:3.4.7")
|
||||
compileOnly("io.lumine:Mythic:5.2.1")
|
||||
compileOnly("io.lumine:LumineUtils:1.19-SNAPSHOT")
|
||||
compileOnly("com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT")
|
||||
compileOnly("com.github.sirblobman.combatlogx:api:11.0.0.0-SNAPSHOT")
|
||||
compileOnly("LibsDisguises:LibsDisguises:10.0.26")
|
||||
compileOnly("com.denizenscript:denizen:1.2.7-SNAPSHOT") {
|
||||
exclude(group = "*", module = "*")
|
||||
}
|
||||
|
||||
compileOnly(fileTree("../../lib") {
|
||||
include("*.jar")
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.PluginLike
|
||||
import com.willfp.eco.core.PluginProps
|
||||
import com.willfp.eco.core.Prerequisite
|
||||
import com.willfp.eco.core.command.CommandBase
|
||||
import com.willfp.eco.core.command.PluginCommandBase
|
||||
import com.willfp.eco.core.config.ConfigType
|
||||
@@ -13,8 +14,8 @@ import com.willfp.eco.core.gui.menu.Menu
|
||||
import com.willfp.eco.core.gui.menu.MenuType
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotProvider
|
||||
import com.willfp.eco.core.items.Items
|
||||
import com.willfp.eco.core.math.MathContext
|
||||
import com.willfp.eco.core.packet.Packet
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.internal.EcoPropsParser
|
||||
import com.willfp.eco.internal.command.EcoPluginCommand
|
||||
import com.willfp.eco.internal.command.EcoSubcommand
|
||||
@@ -37,14 +38,18 @@ import com.willfp.eco.internal.gui.menu.renderedInventory
|
||||
import com.willfp.eco.internal.gui.slot.EcoSlotBuilder
|
||||
import com.willfp.eco.internal.integrations.PAPIExpansion
|
||||
import com.willfp.eco.internal.logging.EcoLogger
|
||||
import com.willfp.eco.internal.placeholder.PlaceholderParser
|
||||
import com.willfp.eco.internal.proxy.EcoProxyFactory
|
||||
import com.willfp.eco.internal.scheduling.EcoScheduler
|
||||
import com.willfp.eco.internal.scheduling.EcoSchedulerFolia
|
||||
import com.willfp.eco.internal.scheduling.EcoSchedulerSpigot
|
||||
import com.willfp.eco.internal.spigot.data.DataYml
|
||||
import com.willfp.eco.internal.spigot.data.KeyRegistry
|
||||
import com.willfp.eco.internal.spigot.data.ProfileHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.HandlerType
|
||||
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
|
||||
import com.willfp.eco.internal.spigot.math.evaluateExpression
|
||||
import com.willfp.eco.internal.spigot.math.DelegatedExpressionHandler
|
||||
import com.willfp.eco.internal.spigot.math.ImmediatePlaceholderTranslationExpressionHandler
|
||||
import com.willfp.eco.internal.spigot.math.LazyPlaceholderTranslationExpressionHandler
|
||||
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
|
||||
@@ -88,8 +93,17 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
||||
if (this.configYml.getBool("use-safer-namespacedkey-creation"))
|
||||
SafeInternalNamespacedKeyFactory() else FastInternalNamespacedKeyFactory()
|
||||
|
||||
private val placeholderParser = PlaceholderParser()
|
||||
|
||||
private val crunchHandler = DelegatedExpressionHandler(
|
||||
this,
|
||||
if (this.configYml.getBool("use-immediate-placeholder-translation-for-math"))
|
||||
ImmediatePlaceholderTranslationExpressionHandler(placeholderParser)
|
||||
else LazyPlaceholderTranslationExpressionHandler(placeholderParser),
|
||||
)
|
||||
|
||||
override fun createScheduler(plugin: EcoPlugin) =
|
||||
EcoScheduler(plugin)
|
||||
if (Prerequisite.HAS_FOLIA.isMet) EcoSchedulerFolia(plugin) else EcoSchedulerSpigot(plugin)
|
||||
|
||||
override fun createEventManager(plugin: EcoPlugin) =
|
||||
EcoEventManager(plugin)
|
||||
@@ -312,8 +326,8 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
||||
override fun getTPS() =
|
||||
getProxy(TPSProxy::class.java).getTPS()
|
||||
|
||||
override fun evaluate(expression: String, context: MathContext) =
|
||||
evaluateExpression(expression, context)
|
||||
override fun evaluate(expression: String, context: PlaceholderContext) =
|
||||
crunchHandler.evaluate(expression, context)
|
||||
|
||||
override fun getOpenMenu(player: Player) =
|
||||
player.renderedInventory?.menu
|
||||
@@ -326,4 +340,10 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
||||
|
||||
override fun sendPacket(player: Player, packet: Packet) =
|
||||
this.getProxy(PacketHandlerProxy::class.java).sendPacket(player, packet)
|
||||
|
||||
override fun translatePlaceholders(text: String, context: PlaceholderContext) =
|
||||
placeholderParser.translatePlacholders(text, context)
|
||||
|
||||
override fun getPlaceholderValue(plugin: EcoPlugin?, args: String, context: PlaceholderContext) =
|
||||
placeholderParser.getPlaceholderResult(plugin, args, context)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.willfp.eco.internal.spigot
|
||||
import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.Prerequisite
|
||||
import com.willfp.eco.core.data.ExternalDataStore
|
||||
import com.willfp.eco.core.entities.Entities
|
||||
import com.willfp.eco.core.integrations.IntegrationLoader
|
||||
import com.willfp.eco.core.integrations.afk.AFKManager
|
||||
@@ -19,6 +20,8 @@ import com.willfp.eco.core.items.Items
|
||||
import com.willfp.eco.core.packet.PacketListener
|
||||
import com.willfp.eco.core.particle.Particles
|
||||
import com.willfp.eco.core.price.Prices
|
||||
import com.willfp.eco.internal.data.MavenVersionToStringAdapter
|
||||
import com.willfp.eco.internal.data.VersionToStringAdapter
|
||||
import com.willfp.eco.internal.entities.EntityArgParserAdult
|
||||
import com.willfp.eco.internal.entities.EntityArgParserAttackDamage
|
||||
import com.willfp.eco.internal.entities.EntityArgParserAttackSpeed
|
||||
@@ -92,6 +95,7 @@ import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny
|
||||
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard
|
||||
import com.willfp.eco.internal.spigot.integrations.customentities.CustomEntitiesMythicMobs
|
||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsCustomCrafting
|
||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsDenizen
|
||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsExecutableItems
|
||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase
|
||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
|
||||
@@ -107,6 +111,7 @@ import com.willfp.eco.internal.spigot.integrations.hologram.HologramHolographicD
|
||||
import com.willfp.eco.internal.spigot.integrations.mcmmo.McmmoIntegrationImpl
|
||||
import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration
|
||||
import com.willfp.eco.internal.spigot.integrations.placeholder.PlaceholderIntegrationPAPI
|
||||
import com.willfp.eco.internal.spigot.integrations.price.PriceFactoryPlayerPoints
|
||||
import com.willfp.eco.internal.spigot.integrations.price.PriceFactoryUltraEconomy
|
||||
import com.willfp.eco.internal.spigot.integrations.shop.ShopDeluxeSellwands
|
||||
import com.willfp.eco.internal.spigot.integrations.shop.ShopEconomyShopGUI
|
||||
@@ -120,6 +125,7 @@ import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
|
||||
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla
|
||||
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapedCraftingRecipeStackHandler
|
||||
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapelessCraftingRecipeStackHandler
|
||||
import com.willfp.eco.util.ClassUtils
|
||||
import me.TechsCode.UltraEconomy.UltraEconomy
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences
|
||||
import net.milkbowl.vault.economy.Economy
|
||||
@@ -178,6 +184,20 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
SegmentParserUseIfPresent.register()
|
||||
|
||||
CustomItemsManager.registerProviders()
|
||||
|
||||
ExternalDataStore.registerAdapter(VersionToStringAdapter)
|
||||
// Handle with shadow.
|
||||
val className = listOf(
|
||||
"org",
|
||||
"apache",
|
||||
"maven",
|
||||
"artifact",
|
||||
"versioning",
|
||||
"DefaultArtifactVersion"
|
||||
).joinToString(".")
|
||||
if (ClassUtils.exists(className)) {
|
||||
ExternalDataStore.registerAdapter(MavenVersionToStringAdapter(className))
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleEnable() {
|
||||
@@ -270,6 +290,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
IntegrationLoader("CombatLogX") {
|
||||
val pluginManager = Bukkit.getPluginManager()
|
||||
val combatLogXPlugin = pluginManager.getPlugin("CombatLogX") ?: return@IntegrationLoader
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val pluginVersion = combatLogXPlugin.description.version
|
||||
if (pluginVersion.startsWith("10")) {
|
||||
@@ -294,7 +315,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
IntegrationLoader("MythicMobs") { CustomEntitiesManager.register(CustomEntitiesMythicMobs()) },
|
||||
|
||||
// Custom Items
|
||||
IntegrationLoader("Oraxen") { CustomItemsManager.register(CustomItemsOraxen()) },
|
||||
IntegrationLoader("Oraxen") { CustomItemsManager.register(CustomItemsOraxen(this)) },
|
||||
IntegrationLoader("ItemsAdder") { CustomItemsManager.register(CustomItemsItemsAdder()) },
|
||||
IntegrationLoader("HeadDatabase") { CustomItemsManager.register(CustomItemsHeadDatabase(this)) },
|
||||
IntegrationLoader("ExecutableItems") { CustomItemsManager.register(CustomItemsExecutableItems()) },
|
||||
@@ -304,6 +325,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
},
|
||||
IntegrationLoader("MythicMobs") { CustomItemsManager.register(CustomItemsMythicMobs(this)) },
|
||||
IntegrationLoader("Scyther") { CustomItemsManager.register(CustomItemsScyther()) },
|
||||
IntegrationLoader("Denizen") { CustomItemsManager.register(CustomItemsDenizen()) },
|
||||
|
||||
// Shop
|
||||
IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) },
|
||||
@@ -336,6 +358,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
Prices.registerPriceFactory(PriceFactoryUltraEconomy(currency))
|
||||
}
|
||||
},
|
||||
IntegrationLoader("PlayerPoints") { Prices.registerPriceFactory(PriceFactoryPlayerPoints()) },
|
||||
|
||||
// Placeholder
|
||||
IntegrationLoader("PlaceholderAPI") { PlaceholderManager.addIntegration(PlaceholderIntegrationPAPI()) },
|
||||
|
||||
@@ -16,9 +16,7 @@ abstract class EcoProfile(
|
||||
override fun <T : Any> write(key: PersistentDataKey<T>, value: T) {
|
||||
this.data[key] = value
|
||||
|
||||
val changedKeys = CHANGE_MAP[uuid] ?: mutableSetOf()
|
||||
changedKeys.add(key)
|
||||
CHANGE_MAP[uuid] = changedKeys
|
||||
CHANGE_MAP.add(uuid)
|
||||
}
|
||||
|
||||
override fun <T : Any> read(key: PersistentDataKey<T>): T {
|
||||
@@ -44,7 +42,7 @@ abstract class EcoProfile(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CHANGE_MAP: MutableMap<UUID, MutableSet<PersistentDataKey<*>>> = ConcurrentHashMap()
|
||||
val CHANGE_MAP: MutableSet<UUID> = ConcurrentHashMap.newKeySet()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
||||
import com.willfp.eco.internal.spigot.ServerLocking
|
||||
import com.willfp.eco.internal.spigot.data.storage.DataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.HandlerType
|
||||
import com.willfp.eco.internal.spigot.data.storage.LegacyMySQLDataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.MongoDataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
|
||||
@@ -22,24 +21,16 @@ class ProfileHandler(
|
||||
private val type: HandlerType,
|
||||
private val plugin: EcoSpigotPlugin
|
||||
) {
|
||||
private val loaded = mutableMapOf<UUID, Profile>()
|
||||
private val loaded = mutableMapOf<UUID, EcoProfile>()
|
||||
|
||||
val handler: DataHandler = when (type) {
|
||||
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
||||
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
||||
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
||||
HandlerType.LEGACY_MYSQL -> LegacyMySQLDataHandler(plugin, this)
|
||||
}
|
||||
|
||||
init {
|
||||
if (handler.type == HandlerType.LEGACY_MYSQL) {
|
||||
plugin.logger.warning("You're using the legacy MySQL handler!")
|
||||
plugin.logger.warning("Some features will not work and you may get unfixable errors.")
|
||||
plugin.logger.warning("Support cannot be given to data issues related to legacy MySQL.")
|
||||
plugin.logger.warning("Change your data handler to mysql, mongo, or yaml to fix this!")
|
||||
plugin.logger.warning("This can be done in /plugins/eco/config.yml")
|
||||
}
|
||||
}
|
||||
fun accessLoadedProfile(uuid: UUID): EcoProfile? =
|
||||
loaded[uuid]
|
||||
|
||||
fun loadGenericProfile(uuid: UUID): Profile {
|
||||
val found = loaded[uuid]
|
||||
@@ -87,11 +78,7 @@ class ProfileHandler(
|
||||
}
|
||||
|
||||
|
||||
var previousHandlerType = HandlerType.valueOf(plugin.dataYml.getString("previous-handler"))
|
||||
|
||||
if (previousHandlerType == HandlerType.MYSQL && !plugin.dataYml.has("new-mysql")) {
|
||||
previousHandlerType = HandlerType.LEGACY_MYSQL
|
||||
}
|
||||
val previousHandlerType = HandlerType.valueOf(plugin.dataYml.getString("previous-handler"))
|
||||
|
||||
if (previousHandlerType == type) {
|
||||
return
|
||||
@@ -101,7 +88,6 @@ class ProfileHandler(
|
||||
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
||||
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
||||
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
||||
HandlerType.LEGACY_MYSQL -> LegacyMySQLDataHandler(plugin, this)
|
||||
}
|
||||
|
||||
ServerLocking.lock("Migrating player data! Check console for more information.")
|
||||
|
||||
@@ -3,6 +3,5 @@ package com.willfp.eco.internal.spigot.data.storage
|
||||
enum class HandlerType {
|
||||
YAML,
|
||||
MYSQL,
|
||||
MONGO,
|
||||
LEGACY_MYSQL
|
||||
MONGO
|
||||
}
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
package com.willfp.eco.internal.spigot.data.storage
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||
import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKeyType
|
||||
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
||||
import com.willfp.eco.internal.spigot.data.ProfileHandler
|
||||
import com.willfp.eco.internal.spigot.data.serverProfileUUID
|
||||
import com.zaxxer.hikari.HikariConfig
|
||||
import com.zaxxer.hikari.HikariDataSource
|
||||
import org.jetbrains.exposed.dao.id.UUIDTable
|
||||
import org.jetbrains.exposed.sql.BooleanColumnType
|
||||
import org.jetbrains.exposed.sql.Column
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.DoubleColumnType
|
||||
import org.jetbrains.exposed.sql.IntegerColumnType
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.VarCharColumnType
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/*
|
||||
|
||||
The MySQL data handler is hot garbage for several reasons:
|
||||
- Using MySQL on unstructured data: it's being horrifically misused, but that's just how it has to be.
|
||||
- Can't remove un-needed keys, there's wasted space in the columns everywhere.
|
||||
- No native support for the STRING_LIST type, instead it 'serializes' the lists with semicolons as separators.
|
||||
- General lack of flexibility, it's too rigid.
|
||||
|
||||
That's why I added the MongoDB handler, it's far, far better suited for what eco does - use it over
|
||||
MySQL if you can.
|
||||
|
||||
Oh, also - I don't really know how this class works. I've rewritten it and hacked it together several ways
|
||||
in several sessions, and it's basically complete gibberish to me. Adding the STRING_LIST type is probably
|
||||
the worst bodge I've shipped in production.
|
||||
|
||||
*/
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class LegacyMySQLDataHandler(
|
||||
plugin: EcoSpigotPlugin,
|
||||
handler: ProfileHandler
|
||||
) : DataHandler(HandlerType.LEGACY_MYSQL) {
|
||||
private val database: Database
|
||||
private val playerHandler: ImplementedMySQLHandler
|
||||
private val serverHandler: ImplementedMySQLHandler
|
||||
|
||||
init {
|
||||
val config = HikariConfig()
|
||||
config.driverClassName = "com.mysql.cj.jdbc.Driver"
|
||||
config.username = plugin.configYml.getString("mysql.user")
|
||||
config.password = plugin.configYml.getString("mysql.password")
|
||||
config.jdbcUrl = "jdbc:mysql://" +
|
||||
"${plugin.configYml.getString("mysql.host")}:" +
|
||||
"${plugin.configYml.getString("mysql.port")}/" +
|
||||
plugin.configYml.getString("mysql.database")
|
||||
config.maximumPoolSize = plugin.configYml.getInt("mysql.connections")
|
||||
|
||||
database = Database.connect(HikariDataSource(config))
|
||||
|
||||
playerHandler = ImplementedMySQLHandler(
|
||||
handler,
|
||||
UUIDTable("eco_players"),
|
||||
plugin
|
||||
)
|
||||
|
||||
serverHandler = ImplementedMySQLHandler(
|
||||
handler,
|
||||
UUIDTable("eco_server"),
|
||||
plugin
|
||||
)
|
||||
}
|
||||
|
||||
override fun <T : Any> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
return applyFor(uuid) {
|
||||
it.read(uuid, key)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: T) {
|
||||
applyFor(uuid) {
|
||||
it.write(uuid, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
applyFor(uuid) {
|
||||
it.saveKeysForRow(uuid, keys)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <R> applyFor(uuid: UUID, function: (ImplementedMySQLHandler) -> R): R {
|
||||
return if (uuid == serverProfileUUID) {
|
||||
function(serverHandler)
|
||||
} else {
|
||||
function(playerHandler)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initialize() {
|
||||
playerHandler.initialize()
|
||||
serverHandler.initialize()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private inner class ImplementedMySQLHandler(
|
||||
private val handler: ProfileHandler,
|
||||
private val table: UUIDTable,
|
||||
private val plugin: EcoPlugin
|
||||
) {
|
||||
private val rows = Caffeine.newBuilder()
|
||||
.expireAfterWrite(3, TimeUnit.SECONDS)
|
||||
.build<UUID, ResultRow>()
|
||||
|
||||
private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-legacy-mysql-thread-%d").build()
|
||||
private val executor = Executors.newFixedThreadPool(plugin.configYml.getInt("mysql.threads"), threadFactory)
|
||||
val registeredKeys = mutableSetOf<PersistentDataKey<*>>()
|
||||
|
||||
init {
|
||||
transaction(database) {
|
||||
SchemaUtils.create(table)
|
||||
}
|
||||
}
|
||||
|
||||
fun initialize() {
|
||||
transaction(database) {
|
||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
||||
}
|
||||
}
|
||||
|
||||
fun ensureKeyRegistration(key: PersistentDataKey<*>) {
|
||||
if (table.columns.any { it.name == key.key.toString() }) {
|
||||
registeredKeys.add(key)
|
||||
return
|
||||
}
|
||||
|
||||
registerColumn(key)
|
||||
registeredKeys.add(key)
|
||||
}
|
||||
|
||||
fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: Any) {
|
||||
getRow(uuid)
|
||||
doWrite(uuid, key, key.type.constrainSQLTypes(value))
|
||||
}
|
||||
|
||||
private fun doWrite(uuid: UUID, key: PersistentDataKey<*>, constrainedValue: Any) {
|
||||
val column: Column<Any> = getColumn(key) as Column<Any>
|
||||
|
||||
executor.submit {
|
||||
transaction(database) {
|
||||
table.update({ table.id eq uuid }) {
|
||||
it[column] = constrainedValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun saveKeysForRow(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
saveRow(uuid, keys)
|
||||
}
|
||||
|
||||
private fun saveRow(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
val profile = handler.loadGenericProfile(uuid)
|
||||
|
||||
executor.submit {
|
||||
transaction(database) {
|
||||
getRow(uuid)
|
||||
|
||||
for (key in keys) {
|
||||
doWrite(uuid, key, key.type.constrainSQLTypes(profile.read(key)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
val doRead = Callable<T?> {
|
||||
transaction(database) {
|
||||
val row = getRow(uuid)
|
||||
val column = getColumn(key)
|
||||
val raw = row[column]
|
||||
key.type.fromConstrained(raw)
|
||||
}
|
||||
}
|
||||
|
||||
ensureKeyRegistration(key) // DON'T DELETE THIS LINE! I know it's covered in getColumn, but I need to do it here as well.
|
||||
|
||||
doRead.call()
|
||||
|
||||
return if (Eco.get().ecoPlugin.configYml.getBool("mysql.async-reads")) {
|
||||
executor.submit(doRead).get()
|
||||
} else {
|
||||
doRead.call()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> registerColumn(key: PersistentDataKey<T>) {
|
||||
try {
|
||||
transaction(database) {
|
||||
try {
|
||||
table.apply {
|
||||
if (table.columns.any { it.name == key.key.toString() }) {
|
||||
return@apply
|
||||
}
|
||||
|
||||
when (key.type) {
|
||||
PersistentDataKeyType.INT -> registerColumn<Int>(key.key.toString(), IntegerColumnType())
|
||||
.default(key.defaultValue as Int)
|
||||
|
||||
PersistentDataKeyType.DOUBLE -> registerColumn<Double>(
|
||||
key.key.toString(),
|
||||
DoubleColumnType()
|
||||
).default(key.defaultValue as Double)
|
||||
|
||||
PersistentDataKeyType.BOOLEAN -> registerColumn<Boolean>(
|
||||
key.key.toString(),
|
||||
BooleanColumnType()
|
||||
).default(key.defaultValue as Boolean)
|
||||
|
||||
PersistentDataKeyType.STRING -> registerColumn<String>(
|
||||
key.key.toString(),
|
||||
VarCharColumnType(512)
|
||||
).default(key.defaultValue as String)
|
||||
|
||||
PersistentDataKeyType.STRING_LIST -> registerColumn<String>(
|
||||
key.key.toString(),
|
||||
VarCharColumnType(8192)
|
||||
).default(PersistentDataKeyType.STRING_LIST.constrainSQLTypes(key.defaultValue as List<String>) as String)
|
||||
|
||||
PersistentDataKeyType.CONFIG -> throw IllegalArgumentException(
|
||||
"Config Persistent Data Keys are not supported by the legacy MySQL handler!"
|
||||
)
|
||||
|
||||
else -> throw NullPointerException("Null value found!")
|
||||
}
|
||||
}
|
||||
|
||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.info("MySQL Error 1!")
|
||||
e.printStackTrace()
|
||||
// What's that? Two enormous exception catches? That's right! This code sucks.
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
plugin.logger.info("MySQL Error 2!")
|
||||
e.printStackTrace()
|
||||
// It might fail. Who cares? This is legacy.
|
||||
}
|
||||
}
|
||||
|
||||
private fun getColumn(key: PersistentDataKey<*>): Column<*> {
|
||||
ensureKeyRegistration(key)
|
||||
|
||||
val name = key.key.toString()
|
||||
|
||||
return table.columns.first { it.name == name }
|
||||
}
|
||||
|
||||
private fun getRow(uuid: UUID): ResultRow {
|
||||
fun select(uuid: UUID): ResultRow? {
|
||||
return transaction(database) {
|
||||
table.select { table.id eq uuid }.limit(1).singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
return rows.get(uuid) {
|
||||
val row = select(uuid)
|
||||
|
||||
return@get if (row != null) {
|
||||
row
|
||||
} else {
|
||||
transaction(database) {
|
||||
table.insert { it[id] = uuid }
|
||||
}
|
||||
select(uuid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> PersistentDataKeyType<T>.constrainSQLTypes(value: Any): Any {
|
||||
return if (this == PersistentDataKeyType.STRING_LIST) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
value as List<String>
|
||||
value.joinToString(separator = ";")
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> PersistentDataKeyType<T>.fromConstrained(constrained: Any?): T? {
|
||||
if (constrained == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return if (this == PersistentDataKeyType.STRING_LIST) {
|
||||
constrained as String
|
||||
constrained.split(";").toList()
|
||||
} else {
|
||||
constrained
|
||||
} as T
|
||||
}
|
||||
@@ -34,7 +34,7 @@ Whatever. At least it works.
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class MySQLDataHandler(
|
||||
private val plugin: EcoSpigotPlugin,
|
||||
plugin: EcoSpigotPlugin,
|
||||
private val handler: ProfileHandler
|
||||
) : DataHandler(HandlerType.MYSQL) {
|
||||
private val database: Database
|
||||
@@ -149,9 +149,4 @@ class MySQLDataHandler(
|
||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun save() {
|
||||
plugin.dataYml.set("new-mysql", true)
|
||||
plugin.dataYml.save()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,16 @@ class ProfileSaver(
|
||||
val interval = plugin.configYml.getInt("save-interval").toLong()
|
||||
|
||||
plugin.scheduler.runTimer(20, interval) {
|
||||
for ((uuid, set) in EcoProfile.CHANGE_MAP) {
|
||||
handler.saveKeysFor(uuid, set)
|
||||
val iterator = EcoProfile.CHANGE_MAP.iterator()
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
val uuid = iterator.next()
|
||||
iterator.remove()
|
||||
|
||||
val profile = handler.accessLoadedProfile(uuid) ?: continue
|
||||
|
||||
handler.saveKeysFor(uuid, profile.data.keys)
|
||||
}
|
||||
EcoProfile.CHANGE_MAP.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.willfp.eco.internal.spigot.integrations.customitems
|
||||
|
||||
import com.willfp.eco.core.integrations.customitems.CustomItemsIntegration
|
||||
import com.willfp.eco.core.items.CustomItem
|
||||
import com.willfp.eco.core.items.TestableItem
|
||||
import com.willfp.eco.core.items.provider.ItemProvider
|
||||
import com.willfp.eco.util.NamespacedKeyUtils
|
||||
import com.denizenscript.denizen.objects.ItemTag
|
||||
import com.denizenscript.denizen.scripts.containers.core.ItemScriptHelper
|
||||
import com.willfp.eco.core.items.Items
|
||||
import org.bukkit.event.Listener
|
||||
|
||||
class CustomItemsDenizen : CustomItemsIntegration, Listener {
|
||||
|
||||
override fun registerProvider() {
|
||||
Items.registerItemProvider(DenizenProvider())
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "Denizen"
|
||||
}
|
||||
|
||||
private class DenizenProvider : ItemProvider("denizen") {
|
||||
override fun provideForKey(key: String): TestableItem? {
|
||||
val item = ItemTag.valueOf(key, false) ?: return null
|
||||
val id = item.scriptName
|
||||
val namespacedKey = NamespacedKeyUtils.create("denizen", id)
|
||||
val stack = item.itemStack
|
||||
return CustomItem(
|
||||
namespacedKey,
|
||||
{ id.equals(ItemScriptHelper.getItemScriptNameText(it), ignoreCase = true) },
|
||||
stack
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.internal.spigot.integrations.customitems
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.integrations.customitems.CustomItemsIntegration
|
||||
import com.willfp.eco.core.items.CustomItem
|
||||
import com.willfp.eco.core.items.Items
|
||||
@@ -7,16 +8,27 @@ import com.willfp.eco.core.items.TestableItem
|
||||
import com.willfp.eco.core.items.provider.ItemProvider
|
||||
import com.willfp.eco.util.NamespacedKeyUtils
|
||||
import io.th0rgal.oraxen.api.OraxenItems
|
||||
import io.th0rgal.oraxen.api.events.OraxenItemsLoadedEvent
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
|
||||
class CustomItemsOraxen : CustomItemsIntegration {
|
||||
class CustomItemsOraxen(
|
||||
private val plugin: EcoPlugin
|
||||
) : CustomItemsIntegration, Listener {
|
||||
override fun registerProvider() {
|
||||
Items.registerItemProvider(OraxenProvider())
|
||||
plugin.eventManager.registerListener(this)
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "Oraxen"
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun onItemRegister(event: OraxenItemsLoadedEvent) {
|
||||
Items.registerItemProvider(OraxenProvider())
|
||||
}
|
||||
|
||||
private class OraxenProvider : ItemProvider("oraxen") {
|
||||
override fun provideForKey(key: String): TestableItem? {
|
||||
val item = OraxenItems.getItemById(key) ?: return null
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.willfp.eco.internal.spigot.integrations.price
|
||||
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier
|
||||
import com.willfp.eco.core.price.Price
|
||||
import com.willfp.eco.core.price.PriceFactory
|
||||
import org.black_ixx.playerpoints.PlayerPoints
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.UUID
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class PriceFactoryPlayerPoints : PriceFactory {
|
||||
override fun getNames() = listOf(
|
||||
"player_points",
|
||||
"p_points"
|
||||
)
|
||||
|
||||
override fun create(baseContext: PlaceholderContext, function: PlaceholderContextSupplier<Double>): Price {
|
||||
return PricePlayerPoints(baseContext) { function.get(it).roundToInt() }
|
||||
}
|
||||
|
||||
private class PricePlayerPoints(
|
||||
private val baseContext: PlaceholderContext,
|
||||
private val function: (PlaceholderContext) -> Int
|
||||
) : Price {
|
||||
private val api = PlayerPoints.getInstance().api
|
||||
private val multipliers = mutableMapOf<UUID, Double>()
|
||||
|
||||
override fun canAfford(player: Player, multiplier: Double): Boolean {
|
||||
return api.look(player.uniqueId) >= getValue(player, multiplier)
|
||||
}
|
||||
|
||||
override fun pay(player: Player, multiplier: Double) {
|
||||
api.take(player.uniqueId, getValue(player, multiplier).roundToInt())
|
||||
}
|
||||
|
||||
override fun giveTo(player: Player, multiplier: Double) {
|
||||
api.give(player.uniqueId, getValue(player, multiplier).roundToInt())
|
||||
}
|
||||
|
||||
override fun getValue(player: Player, multiplier: Double): Double {
|
||||
return function(baseContext.copyWithPlayer(player)) * getMultiplier(player) * multiplier
|
||||
}
|
||||
|
||||
override fun getMultiplier(player: Player): Double {
|
||||
return multipliers[player.uniqueId] ?: 1.0
|
||||
}
|
||||
|
||||
override fun setMultiplier(player: Player, multiplier: Double) {
|
||||
multipliers[player.uniqueId] = multiplier
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.willfp.eco.internal.spigot.integrations.price
|
||||
|
||||
import com.willfp.eco.core.math.MathContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContextSupplier
|
||||
import com.willfp.eco.core.price.Price
|
||||
import com.willfp.eco.core.price.PriceFactory
|
||||
import com.willfp.eco.util.toSingletonList
|
||||
@@ -9,21 +10,20 @@ import me.TechsCode.UltraEconomy.objects.Account
|
||||
import me.TechsCode.UltraEconomy.objects.Currency
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.UUID
|
||||
import java.util.function.Function
|
||||
|
||||
class PriceFactoryUltraEconomy(private val currency: Currency) : PriceFactory {
|
||||
override fun getNames(): List<String> {
|
||||
return currency.name.lowercase().toSingletonList()
|
||||
}
|
||||
|
||||
override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
|
||||
return PriceUltraEconomy(currency, baseContext) { function.apply(it) }
|
||||
override fun create(baseContext: PlaceholderContext, function: PlaceholderContextSupplier<Double>): Price {
|
||||
return PriceUltraEconomy(currency, baseContext) { function.get(it) }
|
||||
}
|
||||
|
||||
private class PriceUltraEconomy(
|
||||
private val currency: Currency,
|
||||
private val baseContext: MathContext,
|
||||
private val function: (MathContext) -> Double
|
||||
private val baseContext: PlaceholderContext,
|
||||
private val function: (PlaceholderContext) -> Double
|
||||
) : Price {
|
||||
private val multipliers = mutableMapOf<UUID, Double>()
|
||||
private val api = UltraEconomy.getAPI()
|
||||
@@ -44,7 +44,7 @@ class PriceFactoryUltraEconomy(private val currency: Currency) : PriceFactory {
|
||||
}
|
||||
|
||||
override fun getValue(player: Player, multiplier: Double): Double {
|
||||
return function(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player) * multiplier
|
||||
return function(baseContext.copyWithPlayer(player)) * getMultiplier(player) * multiplier
|
||||
}
|
||||
|
||||
override fun getMultiplier(player: Player): Double {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.willfp.eco.internal.spigot.math
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
||||
import com.willfp.eco.core.math.MathContext
|
||||
import com.willfp.eco.core.placeholder.AdditionalPlayer
|
||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable
|
||||
import org.bukkit.entity.Player
|
||||
import redempt.crunch.CompiledExpression
|
||||
import redempt.crunch.Crunch
|
||||
import redempt.crunch.data.FastNumberParsing
|
||||
import redempt.crunch.functional.EvaluationEnvironment
|
||||
import redempt.crunch.functional.Function
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
private val cache: Cache<String, CompiledExpression> = Caffeine.newBuilder().build()
|
||||
private val goToZero = Crunch.compileExpression("0")
|
||||
|
||||
private val min = Function("min", 2) {
|
||||
min(it[0], it[1])
|
||||
}
|
||||
|
||||
private val max = Function("max", 2) {
|
||||
max(it[0], it[1])
|
||||
}
|
||||
|
||||
fun evaluateExpression(expression: String, context: MathContext) =
|
||||
evaluateExpression(expression, context.player, context.injectableContext, context.additionalPlayers)
|
||||
.let { if (!it.isFinite()) 0.0 else it } // Fixes NaN bug.
|
||||
|
||||
private fun evaluateExpression(
|
||||
expression: String,
|
||||
player: Player?,
|
||||
context: PlaceholderInjectable,
|
||||
additional: Collection<AdditionalPlayer>
|
||||
): Double {
|
||||
val placeholderValues = PlaceholderManager.findPlaceholdersIn(expression)
|
||||
.map { PlaceholderManager.translatePlaceholders(it, player, context, additional) }
|
||||
.map { runCatching { FastNumberParsing.parseDouble(it) }.getOrDefault(0.0) }
|
||||
.toDoubleArray()
|
||||
|
||||
val compiled = cache.get(expression) {
|
||||
val placeholders = PlaceholderManager.findPlaceholdersIn(it)
|
||||
val env = EvaluationEnvironment()
|
||||
env.setVariableNames(*placeholders.toTypedArray())
|
||||
env.addFunctions(min, max)
|
||||
runCatching { Crunch.compileExpression(expression, env) }.getOrDefault(goToZero)
|
||||
}
|
||||
|
||||
return runCatching { compiled.evaluate(*placeholderValues) }.getOrDefault(0.0)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.willfp.eco.internal.spigot.math
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class DelegatedExpressionHandler(
|
||||
plugin: EcoPlugin,
|
||||
private val handler: ExpressionHandler
|
||||
) : ExpressionHandler {
|
||||
private val evaluationCache: Cache<Int, Double> = Caffeine.newBuilder()
|
||||
.expireAfterWrite(plugin.configYml.getInt("math-cache-ttl").toLong(), TimeUnit.MILLISECONDS)
|
||||
.build()
|
||||
|
||||
override fun evaluate(expression: String, context: PlaceholderContext): Double {
|
||||
// Peak performance (totally not having fun with bitwise operators)
|
||||
val hash = (((expression.hashCode() shl 5) - expression.hashCode()) xor
|
||||
(context.player?.uniqueId?.hashCode() ?: 0)
|
||||
) xor context.injectableContext.hashCode()
|
||||
|
||||
return evaluationCache.get(hash) {
|
||||
handler.evaluate(expression, context)
|
||||
.let { if (!it.isFinite()) 0.0 else it } // Fixes NaN bug.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.willfp.eco.internal.spigot.math
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
import com.willfp.eco.internal.placeholder.PlaceholderParser
|
||||
import redempt.crunch.CompiledExpression
|
||||
import redempt.crunch.Crunch
|
||||
import redempt.crunch.functional.EvaluationEnvironment
|
||||
import redempt.crunch.functional.Function
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
|
||||
private val goToZero = Crunch.compileExpression("0")
|
||||
|
||||
private val min = Function("min", 2) {
|
||||
min(it[0], it[1])
|
||||
}
|
||||
|
||||
private val max = Function("max", 2) {
|
||||
max(it[0], it[1])
|
||||
}
|
||||
|
||||
interface ExpressionHandler {
|
||||
fun evaluate(expression: String, context: PlaceholderContext): Double
|
||||
}
|
||||
private fun String.fastToDoubleOrNull(): Double? {
|
||||
if (isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
var idx = 0
|
||||
val isNegative = this[0] == '-'
|
||||
if (isNegative) idx++
|
||||
|
||||
var integerPart = 0.0
|
||||
var decimalPart = 0.0
|
||||
var decimalIdx = -1
|
||||
|
||||
while (idx < length) {
|
||||
|
||||
when (val char = this[idx]) {
|
||||
'.' -> {
|
||||
if (decimalIdx != -1) return null
|
||||
decimalIdx = idx
|
||||
}
|
||||
in '0'..'9' -> {
|
||||
val number = (char.code - '0'.code).toDouble()
|
||||
if (decimalIdx != -1) {
|
||||
decimalPart = decimalPart * 10 + number
|
||||
} else {
|
||||
integerPart = integerPart * 10 + number
|
||||
}
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
idx++
|
||||
}
|
||||
|
||||
decimalPart /= 10.0.pow((length - decimalIdx - 1).toDouble())
|
||||
|
||||
return if (isNegative) -(integerPart + decimalPart) else integerPart + decimalPart
|
||||
}
|
||||
|
||||
|
||||
class ImmediatePlaceholderTranslationExpressionHandler(
|
||||
private val placeholderParser: PlaceholderParser
|
||||
) : ExpressionHandler {
|
||||
private val cache: Cache<String, CompiledExpression> = Caffeine.newBuilder()
|
||||
.expireAfterAccess(500, TimeUnit.MILLISECONDS)
|
||||
.build()
|
||||
|
||||
private val env = EvaluationEnvironment().apply {
|
||||
addFunctions(min, max)
|
||||
}
|
||||
|
||||
override fun evaluate(expression: String, context: PlaceholderContext): Double {
|
||||
val translatedExpression = placeholderParser.translatePlacholders(expression, context)
|
||||
|
||||
val compiled = cache.get(translatedExpression) {
|
||||
runCatching { Crunch.compileExpression(translatedExpression, env) }
|
||||
.getOrDefault(goToZero)
|
||||
}
|
||||
|
||||
return runCatching { compiled.evaluate() }.getOrDefault(0.0)
|
||||
}
|
||||
}
|
||||
|
||||
class LazyPlaceholderTranslationExpressionHandler(
|
||||
private val placeholderParser: PlaceholderParser
|
||||
) : ExpressionHandler {
|
||||
private val cache: Cache<String, CompiledExpression> = Caffeine.newBuilder()
|
||||
.build()
|
||||
|
||||
override fun evaluate(expression: String, context: PlaceholderContext): Double {
|
||||
val placeholders = PlaceholderManager.findPlaceholdersIn(expression)
|
||||
|
||||
val placeholderValues = placeholderParser.parseIndividualPlaceholders(placeholders, context)
|
||||
.map { it.fastToDoubleOrNull() ?: 0.0 }
|
||||
.toDoubleArray()
|
||||
|
||||
val compiled = cache.get(expression) {
|
||||
val env = EvaluationEnvironment()
|
||||
env.setVariableNames(*placeholders.toTypedArray())
|
||||
env.addFunctions(min, max)
|
||||
runCatching { Crunch.compileExpression(expression, env) }.getOrDefault(goToZero)
|
||||
}
|
||||
|
||||
return runCatching { compiled.evaluate(*placeholderValues) }.getOrDefault(0.0)
|
||||
}
|
||||
}
|
||||
@@ -46,11 +46,6 @@ conflicts:
|
||||
# Disable it if it changes drop mechanics too much for you.
|
||||
use-fast-collated-drops: true
|
||||
|
||||
# Some plugins use their own item display systems (eg Triton)
|
||||
# And must be run after eco. Don't enable this unless you run a conflicting plugin
|
||||
# and have been told to enable it.
|
||||
use-lower-protocollib-priority: false
|
||||
|
||||
# Display frames massively optimize PacketWindowItems, however some users have
|
||||
# reported display bugs by using it. If you have any problems with it, then you
|
||||
# should disable this option.
|
||||
@@ -82,4 +77,17 @@ displayed-recipes: true
|
||||
# If eco plugins should not check for updates; only enable this if you know what you're doing
|
||||
# as there can be urgent hotfixes that you are then not notified about. If you're confident
|
||||
# that you can manage updates on your own, turn this on.
|
||||
no-update-checker: false
|
||||
no-update-checker: false
|
||||
|
||||
# Math expressions are parsed using Crunch, which allows for variables to be used in expressions.
|
||||
# If this is false, variables will be used to represent placeholders, which leads to fewer
|
||||
# expression compilations at the expense of slower evaluation times. If this is true, variables
|
||||
# will instead be translated before compilation to reduce evaluation times at the expense of
|
||||
# longer compilation times. If your expressions usually contain many variables, then you
|
||||
# should enable this option as it may improve performance. If you're unsure, leave it disabled.
|
||||
use-immediate-placeholder-translation-for-math: false
|
||||
|
||||
# The time (in milliseconds) for math expressions to be cached for. Higher values will lead to
|
||||
# faster evaluation times (less CPU usage) at the expense of slightly more memory usage and
|
||||
# less reactive values.
|
||||
math-cache-ttl: 200
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user