Compare commits
134 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eddf240f0c | ||
|
|
4f406353ba | ||
|
|
095494dd2e | ||
|
|
fd92645500 | ||
|
|
1a6ac29083 | ||
|
|
7edc00d459 | ||
|
|
a51bad058f | ||
|
|
89ebb8ba59 | ||
|
|
f0ae8f4f84 | ||
|
|
7d6cf78442 | ||
|
|
780d8f3b86 | ||
|
|
146a0130f9 | ||
|
|
df8c3411cb | ||
|
|
4fc3c22a7d | ||
|
|
cfc4808bb8 | ||
|
|
4ac6325a41 | ||
|
|
4aed33751d | ||
|
|
3fe1c2c69f | ||
|
|
5feaa84b2c | ||
|
|
d8793bc2bb | ||
|
|
15c512f3ca | ||
|
|
15ff2fb1d6 | ||
|
|
862b588c8d | ||
|
|
3c2a99b5f4 | ||
|
|
2d23c05c47 | ||
|
|
8fc55d3393 | ||
|
|
5900a756e4 | ||
|
|
c18b85f223 | ||
|
|
85116108c2 | ||
|
|
044f141bd0 | ||
|
|
9ca7f99fdb | ||
|
|
7aa7770a3e | ||
|
|
10202917fa | ||
|
|
43df79e3b1 | ||
|
|
5ef244f0bc | ||
|
|
861f076c11 | ||
|
|
7bed43059f | ||
|
|
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 |
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;
|
||||
@@ -135,6 +135,14 @@ public interface Eco {
|
||||
@NotNull
|
||||
Logger createLogger(@NotNull EcoPlugin plugin);
|
||||
|
||||
/**
|
||||
* Get NOOP logger.
|
||||
*
|
||||
* @return The logger.
|
||||
*/
|
||||
@NotNull
|
||||
Logger getNOOPLogger();
|
||||
|
||||
/**
|
||||
* Create a PAPI integration.
|
||||
*
|
||||
@@ -170,7 +178,7 @@ public interface Eco {
|
||||
* @return The PluginCommandBase implementation
|
||||
*/
|
||||
@NotNull
|
||||
PluginCommandBase createPluginCommand(@NotNull CommandBase parentDelegate,
|
||||
PluginCommandBase createPluginCommand(@NotNull PluginCommandBase parentDelegate,
|
||||
@NotNull EcoPlugin plugin,
|
||||
@NotNull String name,
|
||||
@NotNull String permission,
|
||||
@@ -393,15 +401,6 @@ public interface Eco {
|
||||
@NotNull
|
||||
ServerProfile getServerProfile();
|
||||
|
||||
/**
|
||||
* Unload a player profile from memory.
|
||||
* <p>
|
||||
* This will not save the profile first.
|
||||
*
|
||||
* @param uuid The uuid.
|
||||
*/
|
||||
void unloadPlayerProfile(@NotNull UUID uuid);
|
||||
|
||||
/**
|
||||
* Create dummy entity - never spawned, exists purely in code.
|
||||
*
|
||||
@@ -531,7 +530,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 +562,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;
|
||||
@@ -124,7 +126,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
/**
|
||||
* The logger for the plugin.
|
||||
*/
|
||||
private final Logger logger;
|
||||
private Logger logger;
|
||||
|
||||
/**
|
||||
* If the server is running an outdated version of the plugin.
|
||||
@@ -162,6 +164,11 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
*/
|
||||
private final ListMap<LifecyclePosition, Runnable> afterLoad = new ListMap<>();
|
||||
|
||||
/**
|
||||
* The tasks to run on task creation.
|
||||
*/
|
||||
private final ListMap<LifecyclePosition, Runnable> createTasks = new ListMap<>();
|
||||
|
||||
/**
|
||||
* Create a new plugin.
|
||||
* <p>
|
||||
@@ -347,14 +354,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 +372,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 +411,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();
|
||||
|
||||
@@ -422,22 +430,35 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
|
||||
this.loadPluginCommands().forEach(PluginCommand::register);
|
||||
|
||||
this.getScheduler().runLater(this::afterLoad, 1);
|
||||
// Run preliminary reload to resolve load order issues
|
||||
this.getScheduler().runLater(() -> {
|
||||
Logger before = this.getLogger();
|
||||
// Temporary silence logger.
|
||||
this.logger = Eco.get().getNOOPLogger();
|
||||
|
||||
this.reload(false);
|
||||
|
||||
this.logger = before;
|
||||
}, 1);
|
||||
|
||||
this.getScheduler().runLater(this::afterLoad, 2);
|
||||
|
||||
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("");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -596,14 +617,30 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
* Reload the plugin.
|
||||
*/
|
||||
public final void reload() {
|
||||
this.reload(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the plugin.
|
||||
*
|
||||
* @param cancelTasks If tasks should be cancelled.
|
||||
*/
|
||||
public final void reload(final boolean cancelTasks) {
|
||||
this.getConfigHandler().updateConfigs();
|
||||
|
||||
this.getScheduler().cancelAll();
|
||||
if (cancelTasks) {
|
||||
this.getScheduler().cancelAll();
|
||||
}
|
||||
|
||||
this.getConfigHandler().callUpdate();
|
||||
this.getConfigHandler().callUpdate(); // Call twice to fix issues
|
||||
|
||||
this.handleLifecycle(this.onReload, this::handleReload);
|
||||
|
||||
if (cancelTasks) {
|
||||
this.handleLifecycle(this.createTasks, this::createTasks);
|
||||
}
|
||||
|
||||
for (Extension extension : this.extensionLoader.getLoadedExtensions()) {
|
||||
extension.handleReload();
|
||||
}
|
||||
@@ -717,6 +754,15 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The plugin-specific code to create tasks.
|
||||
* <p>
|
||||
* Override when needed.
|
||||
*/
|
||||
protected void createTasks() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The plugin-specific code to be executed after the server is up.
|
||||
* <p>
|
||||
@@ -1081,7 +1127,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
*
|
||||
* @return The config handler.
|
||||
*/
|
||||
public ConfigHandler getConfigHandler() {
|
||||
public @NotNull ConfigHandler getConfigHandler() {
|
||||
return this.configHandler;
|
||||
}
|
||||
|
||||
@@ -1145,9 +1191,24 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
||||
return this.getMetadataValueFactory().create(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if all {@link com.willfp.eco.core.data.keys.PersistentDataKey}'s for this
|
||||
* plugin should be saved locally (via data.yml.) even if eco is using a database.
|
||||
*
|
||||
* @return If using local storage.
|
||||
*/
|
||||
public boolean isUsingLocalStorage() {
|
||||
return this.configYml.isUsingLocalStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
* Default plugin config.yml.
|
||||
*/
|
||||
public class ConfigYml extends BaseConfig {
|
||||
/**
|
||||
* The use local storage key.
|
||||
*/
|
||||
public static final String KEY_USES_LOCAL_STORAGE = "use-local-storage";
|
||||
|
||||
/**
|
||||
* Config.yml.
|
||||
*
|
||||
@@ -52,4 +57,13 @@ public class ConfigYml extends BaseConfig {
|
||||
final boolean removeUnused) {
|
||||
super(name, plugin, removeUnused, ConfigType.YAML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the plugin is using local storage.
|
||||
*
|
||||
* @return The prefix.
|
||||
*/
|
||||
public boolean isUsingLocalStorage() {
|
||||
return this.getBool(KEY_USES_LOCAL_STORAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.willfp.eco.core.config.interfaces.Config;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -49,6 +50,11 @@ public final class PersistentDataKeyType<T> {
|
||||
*/
|
||||
public static final PersistentDataKeyType<Config> CONFIG = new PersistentDataKeyType<>("CONFIG");
|
||||
|
||||
/**
|
||||
* Big Decimal.
|
||||
*/
|
||||
public static final PersistentDataKeyType<BigDecimal> BIG_DECIMAL = new PersistentDataKeyType<>("BIG_DECIMAL");
|
||||
|
||||
/**
|
||||
* The name of the key type.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -142,6 +142,26 @@ public interface MenuBuilder extends PageBuilder {
|
||||
return this.onRender((player, menu) -> menu.setState(player, Page.MAX_PAGE_KEY, pages.apply(player)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default page.
|
||||
*
|
||||
* @param page The page.
|
||||
* @return The builder.
|
||||
*/
|
||||
default MenuBuilder defaultPage(final int page) {
|
||||
return this.maxPages(player -> page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default page dynamically for a player.
|
||||
*
|
||||
* @param page The default page.
|
||||
* @return The builder.
|
||||
*/
|
||||
default MenuBuilder defaultPage(@NotNull final Function<Player, Integer> page) {
|
||||
return this.onOpen((player, menu) -> menu.setState(player, Page.PAGE_KEY, page.apply(player)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a menu close handler.
|
||||
*
|
||||
|
||||
@@ -76,6 +76,15 @@ public abstract class CustomSlot implements Slot {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderOnClick() {
|
||||
if (delegate == null) {
|
||||
throw new IllegalStateException("Custom Slot was not initialized!");
|
||||
}
|
||||
|
||||
return delegate.shouldRenderOnClick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getRows() {
|
||||
return Slot.super.getRows();
|
||||
|
||||
@@ -92,6 +92,15 @@ public interface Slot extends GUIComponent {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the slot should re-render the menu if clicked.
|
||||
*
|
||||
* @return If the slot should re-render.
|
||||
*/
|
||||
default boolean shouldRenderOnClick() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getRows() {
|
||||
return 1;
|
||||
|
||||
@@ -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,138 @@
|
||||
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> {
|
||||
/**
|
||||
* Create a new integration registry.
|
||||
*/
|
||||
public IntegrationRegistry() {
|
||||
super();
|
||||
}
|
||||
|
||||
@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() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.willfp.eco.core.items;
|
||||
|
||||
import com.willfp.eco.core.Eco;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -55,7 +54,7 @@ public class CustomItem implements TestableItem {
|
||||
*/
|
||||
Eco.get().getEcoPlugin().getScheduler().runLater(() -> {
|
||||
if (!matches(getItem())) {
|
||||
Bukkit.getLogger().severe("Item with key " + key + " is invalid!");
|
||||
Eco.get().getEcoPlugin().getLogger().severe("Item with key " + key + " is invalid!");
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ public class DefaultMap<K, V> implements Map<K, V> {
|
||||
*/
|
||||
@NotNull
|
||||
public static <K, K1, V> DefaultMap<K, Map<K1, V>> createNestedMap() {
|
||||
return new DefaultMap<>(new HashMap<>());
|
||||
return new DefaultMap<>(HashMap::new);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,6 +163,6 @@ public class DefaultMap<K, V> implements Map<K, V> {
|
||||
*/
|
||||
@NotNull
|
||||
public static <K, K1, V> DefaultMap<K, ListMap<K1, V>> createNestedListMap() {
|
||||
return new DefaultMap<>(new ListMap<>());
|
||||
return new DefaultMap<>(ListMap::new);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
));
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.willfp.eco.core.items.Items;
|
||||
import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
|
||||
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
|
||||
import com.willfp.eco.util.NamespacedKeyUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -127,8 +126,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.");
|
||||
plugin.getLogger().warning("Crafting recipe " + plugin.getID() + ":" + key + " consists only");
|
||||
plugin.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,67 @@ 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) {
|
||||
if (this.isLocked && this.locker != locker) {
|
||||
throw new IllegalArgumentException("Registry is already locked with a different 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!");
|
||||
}
|
||||
|
||||
this.locker = null;
|
||||
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 +206,6 @@ public class Registry<T extends Registrable> {
|
||||
return string.replace(" ", "_")
|
||||
.replace(".", "_")
|
||||
.replace("-", "_")
|
||||
.toLowerCase();
|
||||
.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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", "DeprecatedIsStillUsed"})
|
||||
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,7 +8,10 @@ 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.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
@@ -200,6 +203,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 +265,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 +310,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 +344,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 +736,177 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Line wrap a list of strings while preserving formatting.
|
||||
*
|
||||
* @param input The input list.
|
||||
* @param lineLength The length of each line.
|
||||
* @return The wrapped list.
|
||||
*/
|
||||
@NotNull
|
||||
public static List<String> lineWrap(@NotNull final List<String> input,
|
||||
final int lineLength) {
|
||||
return lineWrap(input, lineLength, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Line wrap a list of strings while preserving formatting.
|
||||
*
|
||||
* @param input The input list.
|
||||
* @param lineLength The length of each line.
|
||||
* @param preserveMargin If the string has a margin, add it to the next line.
|
||||
* @return The wrapped list.
|
||||
*/
|
||||
@NotNull
|
||||
public static List<String> lineWrap(@NotNull final List<String> input,
|
||||
final int lineLength,
|
||||
final boolean preserveMargin) {
|
||||
return input.stream()
|
||||
.flatMap(line -> lineWrap(line, lineLength, preserveMargin).stream())
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Line wrap a string while preserving formatting.
|
||||
*
|
||||
* @param input The input list.
|
||||
* @param lineLength The length of each line.
|
||||
* @return The wrapped list.
|
||||
*/
|
||||
@NotNull
|
||||
public static List<String> lineWrap(@NotNull final String input,
|
||||
final int lineLength) {
|
||||
return lineWrap(input, lineLength, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Line wrap a string while preserving formatting.
|
||||
*
|
||||
* @param input The input string.
|
||||
* @param lineLength The length of each line.
|
||||
* @param preserveMargin If the string has a margin, add it to the start of each line.
|
||||
* @return The wrapped string.
|
||||
*/
|
||||
@NotNull
|
||||
public static List<String> lineWrap(@NotNull final String input,
|
||||
final int lineLength,
|
||||
final boolean preserveMargin) {
|
||||
int margin = preserveMargin ? getMargin(input) : 0;
|
||||
TextComponent space = Component.text(" ");
|
||||
|
||||
Component asComponent = toComponent(input);
|
||||
|
||||
// The component contains the text as its children, so the child components
|
||||
// are accessed like this:
|
||||
List<TextComponent> children = new ArrayList<>();
|
||||
|
||||
if (asComponent instanceof TextComponent) {
|
||||
children.add((TextComponent) asComponent);
|
||||
}
|
||||
|
||||
for (Component child : asComponent.children()) {
|
||||
children.add((TextComponent) child);
|
||||
}
|
||||
|
||||
// Start by splitting the component into individual characters.
|
||||
List<TextComponent> letters = new ArrayList<>();
|
||||
for (TextComponent child : children) {
|
||||
for (char c : child.content().toCharArray()) {
|
||||
letters.add(Component.text(c).mergeStyle(child));
|
||||
}
|
||||
}
|
||||
|
||||
List<Component> lines = new ArrayList<>();
|
||||
List<TextComponent> currentLine = new ArrayList<>();
|
||||
boolean isFirstLine = true;
|
||||
|
||||
for (TextComponent letter : letters) {
|
||||
if (currentLine.size() > lineLength && letter.content().isBlank()) {
|
||||
lines.add(Component.join(JoinConfiguration.noSeparators(), currentLine));
|
||||
currentLine.clear();
|
||||
isFirstLine = false;
|
||||
} else {
|
||||
// Add margin if starting a new line.
|
||||
if (currentLine.isEmpty() && !isFirstLine) {
|
||||
if (preserveMargin) {
|
||||
for (int i = 0; i < margin; i++) {
|
||||
currentLine.add(space);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentLine.add(letter);
|
||||
}
|
||||
}
|
||||
|
||||
// Push last line.
|
||||
lines.add(Component.join(JoinConfiguration.noSeparators(), currentLine));
|
||||
|
||||
// Convert back to legacy strings.
|
||||
return lines.stream().map(StringUtils::toLegacy)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string's margin.
|
||||
*
|
||||
* @param input The input string.
|
||||
* @return The margin.
|
||||
*/
|
||||
public static int getMargin(@NotNull final String input) {
|
||||
return input.indexOf(input.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for formatting.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@ package com.willfp.eco.core.map
|
||||
* @see ListMap
|
||||
*/
|
||||
@Suppress("RedundantOverride")
|
||||
class MutableListMap<K : Any, V : Any> : ListMap<K, V>() {
|
||||
class MutableListMap<K : Any, V> : ListMap<K, V>() {
|
||||
/**
|
||||
* Override with enforced MutableList type.
|
||||
*/
|
||||
@@ -18,7 +18,7 @@ class MutableListMap<K : Any, V : Any> : ListMap<K, V>() {
|
||||
/**
|
||||
* Override with enforced MutableList type.
|
||||
*/
|
||||
override fun getOrDefault(key: K, defaultValue: MutableList<V>?): MutableList<V> {
|
||||
override fun getOrDefault(key: K, defaultValue: MutableList<V>): MutableList<V> {
|
||||
return super.getOrDefault(key, defaultValue)
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,12 @@ class MutableListMap<K : Any, V : Any> : ListMap<K, V>() {
|
||||
fun <K : Any, V : Any> defaultMap(defaultValue: V) =
|
||||
DefaultMap<K, V>(defaultValue)
|
||||
|
||||
/**
|
||||
* @see DefaultMap
|
||||
*/
|
||||
fun <K : Any, V : Any> defaultMap(defaultValue: () -> V) =
|
||||
DefaultMap<K, V>(defaultValue())
|
||||
|
||||
/**
|
||||
* @see ListMap
|
||||
*/
|
||||
@@ -38,11 +44,13 @@ fun <K : Any, V : Any> listMap() =
|
||||
/**
|
||||
* @see DefaultMap.createNestedMap
|
||||
*/
|
||||
fun <K : Any, K1 : Any, V : Any> nestedMap() =
|
||||
fun <K : Any, K1 : Any, V> nestedMap() =
|
||||
DefaultMap.createNestedMap<K, K1, V>()
|
||||
|
||||
/**
|
||||
* @see DefaultMap.createNestedListMap
|
||||
*/
|
||||
fun <K : Any, K1 : Any, V : Any> nestedListMap() =
|
||||
DefaultMap<K, MutableListMap<K1, V>>(MutableListMap())
|
||||
fun <K : Any, K1 : Any, V> nestedListMap() =
|
||||
DefaultMap<K, MutableListMap<K1, V>>() {
|
||||
MutableListMap()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -15,5 +15,5 @@ fun <T> create2DList(rows: Int, columns: Int): MutableList<MutableList<T>> =
|
||||
ListUtils.create2DList(rows, columns)
|
||||
|
||||
/** @see ListUtils.toSingletonList */
|
||||
fun <T> T.toSingletonList(): List<T> =
|
||||
fun <T> T?.toSingletonList(): List<T> =
|
||||
ListUtils.toSingletonList(this)
|
||||
|
||||
@@ -2,6 +2,32 @@
|
||||
|
||||
package com.willfp.eco.util
|
||||
|
||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||
|
||||
/** @see NumberUtils.toNumeral */
|
||||
fun Number.toNumeral(): String =
|
||||
NumberUtils.toNumeral(this.toInt())
|
||||
|
||||
/** @see NumberUtils.fromNumeral */
|
||||
fun String.parseNumeral(): Int =
|
||||
NumberUtils.fromNumeral(this)
|
||||
|
||||
/** @see NumberUtils.randInt */
|
||||
fun randInt(min: Int, max: Int) =
|
||||
NumberUtils.randInt(min, max)
|
||||
|
||||
/** @see NumberUtils.randFloat */
|
||||
fun randDouble(min: Double, max: Double) =
|
||||
NumberUtils.randFloat(min, max)
|
||||
|
||||
/** @see NumberUtils.randFloat */
|
||||
fun randFloat(min: Float, max: Float) =
|
||||
NumberUtils.randFloat(min.toDouble(), max.toDouble()).toFloat()
|
||||
|
||||
/** @see NumberUtils.evaluateExpression */
|
||||
fun evaluateExpression(expression: String) =
|
||||
NumberUtils.evaluateExpression(expression)
|
||||
|
||||
/** @see NumberUtils.evaluateExpression */
|
||||
fun evaluateExpression(expression: String, context: PlaceholderContext) =
|
||||
NumberUtils.evaluateExpression(expression, context)
|
||||
|
||||
@@ -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,19 @@ 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)
|
||||
|
||||
/** @see StringUtils.lineWrap */
|
||||
fun String.lineWrap(width: Int, preserveMargin: Boolean = true): List<String> =
|
||||
StringUtils.lineWrap(this, width, preserveMargin)
|
||||
|
||||
/** @see StringUtils.lineWrap */
|
||||
fun List<String>.lineWrap(width: Int, preserveMargin: Boolean = true): List<String> =
|
||||
StringUtils.lineWrap(this, width, preserveMargin)
|
||||
|
||||
/** @see StringUtils.getMargin */
|
||||
val String.margin: Int
|
||||
get() = StringUtils.getMargin(this)
|
||||
|
||||
@@ -8,10 +8,12 @@ import org.bukkit.command.TabCompleter
|
||||
|
||||
class DelegatedBukkitCommand(
|
||||
private val delegate: EcoPluginCommand
|
||||
) : Command(delegate.name), TabCompleter, PluginIdentifiableCommand {
|
||||
private var _aliases: List<String>? = null
|
||||
private var _description: String? = null
|
||||
|
||||
) : Command(
|
||||
delegate.name,
|
||||
delegate.description ?: "",
|
||||
"/${delegate.name}",
|
||||
delegate.aliases
|
||||
), TabCompleter, PluginIdentifiableCommand {
|
||||
override fun execute(sender: CommandSender, label: String, args: Array<out String>?): Boolean {
|
||||
return delegate.onCommand(sender, this, label, args)
|
||||
}
|
||||
@@ -36,16 +38,4 @@ class DelegatedBukkitCommand(
|
||||
|
||||
override fun getPlugin() = delegate.plugin
|
||||
override fun getPermission() = delegate.permission
|
||||
override fun getDescription() = _description ?: delegate.description ?: ""
|
||||
override fun getAliases(): List<String> = _aliases ?: delegate.aliases
|
||||
|
||||
override fun setDescription(description: String): Command {
|
||||
this._description = description
|
||||
return this
|
||||
}
|
||||
|
||||
override fun setAliases(aliases: List<String>): Command {
|
||||
this._aliases = aliases
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.willfp.eco.core.command.PluginCommandBase
|
||||
import org.bukkit.Bukkit
|
||||
|
||||
class EcoPluginCommand(
|
||||
parentDelegate: CommandBase,
|
||||
private val parentDelegate: PluginCommandBase,
|
||||
plugin: EcoPlugin,
|
||||
name: String,
|
||||
permission: String,
|
||||
@@ -39,6 +39,9 @@ class EcoPluginCommand(
|
||||
|
||||
Eco.get().syncCommands()
|
||||
}
|
||||
|
||||
override fun getAliases(): List<String> = parentDelegate.aliases
|
||||
override fun getDescription(): String? = parentDelegate.description
|
||||
}
|
||||
|
||||
class EcoSubcommand(
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -34,4 +34,6 @@ open class EcoSlot(
|
||||
}
|
||||
|
||||
override fun getActionableSlot(player: Player, menu: Menu): EcoSlot = this
|
||||
|
||||
override fun shouldRenderOnClick() = handlers.values.any { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.willfp.eco.core.gui.slot.functional.CaptiveFilter
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotHandler
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotProvider
|
||||
import com.willfp.eco.core.gui.slot.functional.SlotUpdater
|
||||
import com.willfp.eco.core.map.listMap
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.inventory.ClickType
|
||||
import java.util.function.Predicate
|
||||
@@ -15,14 +16,14 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
|
||||
private var captiveFromEmpty = false
|
||||
private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) }
|
||||
|
||||
private val handlers = mutableMapOf<ClickType, MutableList<SlotHandler>>()
|
||||
private val handlers = listMap<ClickType, SlotHandler>()
|
||||
|
||||
private var captiveFilter =
|
||||
CaptiveFilter { _, _, _ -> true }
|
||||
private var notCaptiveFor: (Player) -> Boolean = { _ -> false}
|
||||
|
||||
override fun onClick(type: ClickType, action: SlotHandler): SlotBuilder {
|
||||
handlers.computeIfAbsent(type) { mutableListOf() } += action
|
||||
handlers[type] += action
|
||||
return 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,10 @@
|
||||
package com.willfp.eco.internal.logging
|
||||
|
||||
import java.util.logging.LogRecord
|
||||
import java.util.logging.Logger
|
||||
|
||||
object NOOPLogger : Logger("eco_noop", null as String?) {
|
||||
override fun log(record: LogRecord?) {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -13,8 +13,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,6 +37,8 @@ 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.logging.NOOPLogger
|
||||
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.spigot.data.DataYml
|
||||
@@ -44,7 +46,9 @@ 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,6 +92,15 @@ 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)
|
||||
|
||||
@@ -113,6 +126,9 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
||||
override fun createLogger(plugin: EcoPlugin) =
|
||||
EcoLogger(plugin)
|
||||
|
||||
override fun getNOOPLogger() =
|
||||
NOOPLogger
|
||||
|
||||
override fun createPAPIIntegration(plugin: EcoPlugin) {
|
||||
PAPIExpansion(plugin)
|
||||
}
|
||||
@@ -172,7 +188,7 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
||||
}
|
||||
|
||||
override fun createPluginCommand(
|
||||
parentDelegate: CommandBase,
|
||||
parentDelegate: PluginCommandBase,
|
||||
plugin: EcoPlugin,
|
||||
name: String,
|
||||
permission: String,
|
||||
@@ -246,6 +262,7 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
||||
|
||||
override fun addNewPlugin(plugin: EcoPlugin) {
|
||||
loadedEcoPlugins[plugin.name.lowercase()] = plugin
|
||||
loadedEcoPlugins[plugin.id] = plugin
|
||||
}
|
||||
|
||||
override fun getLoadedPlugins(): List<String> =
|
||||
@@ -269,9 +286,6 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
||||
override fun loadPlayerProfile(uuid: UUID) =
|
||||
profileHandler.load(uuid)
|
||||
|
||||
override fun unloadPlayerProfile(uuid: UUID) =
|
||||
profileHandler.unloadPlayer(uuid)
|
||||
|
||||
override fun createDummyEntity(location: Location): Entity =
|
||||
getProxy(DummyEntityFactoryProxy::class.java).createDummyEntity(location)
|
||||
|
||||
@@ -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() {
|
||||
@@ -199,8 +219,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
this.logger.info("No conflicts found!")
|
||||
}
|
||||
|
||||
|
||||
CollatedRunnable(this)
|
||||
CustomItemsManager.registerProviders() // Do it again here
|
||||
|
||||
// Register events for ShopSellEvent
|
||||
@@ -231,14 +249,15 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
Eco.get().adventure?.close()
|
||||
}
|
||||
|
||||
override fun handleReload() {
|
||||
override fun createTasks() {
|
||||
CollatedRunnable(this)
|
||||
|
||||
this.scheduler.runLater(3) {
|
||||
profileHandler.migrateIfNeeded()
|
||||
}
|
||||
|
||||
ProfileSaver(this, profileHandler)
|
||||
ProfileSaver(this, profileHandler).startTicking()
|
||||
|
||||
this.scheduler.runTimer(
|
||||
{ getProxy(PacketHandlerProxy::class.java).clearDisplayFrames() },
|
||||
this.configYml.getInt("display-frame-ttl").toLong(),
|
||||
@@ -270,6 +289,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 +314,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 +324,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 +357,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
Prices.registerPriceFactory(PriceFactoryUltraEconomy(currency))
|
||||
}
|
||||
},
|
||||
IntegrationLoader("PlayerPoints") { Prices.registerPriceFactory(PriceFactoryPlayerPoints()) },
|
||||
|
||||
// Placeholder
|
||||
IntegrationLoader("PlaceholderAPI") { PlaceholderManager.addIntegration(PlaceholderIntegrationPAPI()) },
|
||||
@@ -360,7 +382,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
GUIListener(this),
|
||||
ArrowDataListener(this),
|
||||
ArmorChangeEventListeners(this),
|
||||
DataListener(this),
|
||||
DataListener(this, profileHandler),
|
||||
PlayerBlockListener(this),
|
||||
ServerLocking
|
||||
)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.willfp.eco.internal.spigot.data
|
||||
|
||||
import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.util.PlayerUtils
|
||||
import org.bukkit.event.EventHandler
|
||||
@@ -11,11 +10,14 @@ import org.bukkit.event.player.PlayerLoginEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
|
||||
class DataListener(
|
||||
private val plugin: EcoPlugin
|
||||
private val plugin: EcoPlugin,
|
||||
private val handler: ProfileHandler
|
||||
) : Listener {
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
fun onLeave(event: PlayerQuitEvent) {
|
||||
Eco.get().unloadPlayerProfile(event.player.uniqueId)
|
||||
val profile = handler.accessLoadedProfile(event.player.uniqueId) ?: return
|
||||
handler.saveKeysFor(event.player.uniqueId, profile.data.keys)
|
||||
handler.unloadPlayer(event.player.uniqueId)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -27,6 +29,6 @@ class DataListener(
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
fun onLogin(event: PlayerLoginEvent) {
|
||||
Eco.get().unloadPlayerProfile(event.player.uniqueId)
|
||||
handler.unloadPlayer(event.player.uniqueId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.internal.spigot.data
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.data.PlayerProfile
|
||||
import com.willfp.eco.core.data.Profile
|
||||
import com.willfp.eco.core.data.ServerProfile
|
||||
@@ -11,14 +12,13 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
abstract class EcoProfile(
|
||||
val data: MutableMap<PersistentDataKey<*>, Any>,
|
||||
val uuid: UUID,
|
||||
private val handler: DataHandler
|
||||
private val handler: DataHandler,
|
||||
private val localHandler: DataHandler
|
||||
) : Profile {
|
||||
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 {
|
||||
@@ -27,7 +27,12 @@ abstract class EcoProfile(
|
||||
return this.data[key] as T
|
||||
}
|
||||
|
||||
this.data[key] = handler.read(uuid, key) ?: key.defaultValue
|
||||
this.data[key] = if (key.isLocal) {
|
||||
localHandler.read(uuid, key)
|
||||
} else {
|
||||
handler.read(uuid, key)
|
||||
} ?: key.defaultValue
|
||||
|
||||
return read(key)
|
||||
}
|
||||
|
||||
@@ -44,15 +49,16 @@ abstract class EcoProfile(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CHANGE_MAP: MutableMap<UUID, MutableSet<PersistentDataKey<*>>> = ConcurrentHashMap()
|
||||
val CHANGE_MAP: MutableSet<UUID> = ConcurrentHashMap.newKeySet()
|
||||
}
|
||||
}
|
||||
|
||||
class EcoPlayerProfile(
|
||||
data: MutableMap<PersistentDataKey<*>, Any>,
|
||||
uuid: UUID,
|
||||
handler: DataHandler
|
||||
) : EcoProfile(data, uuid, handler), PlayerProfile {
|
||||
handler: DataHandler,
|
||||
localHandler: DataHandler
|
||||
) : EcoProfile(data, uuid, handler, localHandler), PlayerProfile {
|
||||
override fun toString(): String {
|
||||
return "EcoPlayerProfile{uuid=$uuid}"
|
||||
}
|
||||
@@ -60,9 +66,13 @@ class EcoPlayerProfile(
|
||||
|
||||
class EcoServerProfile(
|
||||
data: MutableMap<PersistentDataKey<*>, Any>,
|
||||
handler: DataHandler
|
||||
) : EcoProfile(data, serverProfileUUID, handler), ServerProfile {
|
||||
handler: DataHandler,
|
||||
localHandler: DataHandler
|
||||
) : EcoProfile(data, serverProfileUUID, handler, localHandler), ServerProfile {
|
||||
override fun toString(): String {
|
||||
return "EcoServerProfile"
|
||||
}
|
||||
}
|
||||
|
||||
private val PersistentDataKey<*>.isLocal: Boolean
|
||||
get() = EcoPlugin.getPlugin(this.key.namespace)?.isUsingLocalStorage == true
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.willfp.eco.core.config.interfaces.Config
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKeyType
|
||||
import org.bukkit.NamespacedKey
|
||||
import java.math.BigDecimal
|
||||
|
||||
object KeyRegistry {
|
||||
private val registry = mutableMapOf<NamespacedKey, PersistentDataKey<*>>()
|
||||
@@ -44,6 +45,9 @@ object KeyRegistry {
|
||||
PersistentDataKeyType.CONFIG -> if (default !is Config) {
|
||||
throw IllegalArgumentException("Invalid Data Type! Should be Config")
|
||||
}
|
||||
PersistentDataKeyType.BIG_DECIMAL -> if (default !is BigDecimal) {
|
||||
throw IllegalArgumentException("Invalid Data Type! Should be BigDecimal")
|
||||
}
|
||||
|
||||
else -> throw NullPointerException("Null value found!")
|
||||
}
|
||||
|
||||
@@ -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,18 @@ class ProfileHandler(
|
||||
private val type: HandlerType,
|
||||
private val plugin: EcoSpigotPlugin
|
||||
) {
|
||||
private val loaded = mutableMapOf<UUID, Profile>()
|
||||
private val loaded = mutableMapOf<UUID, EcoProfile>()
|
||||
|
||||
private val localHandler = YamlDataHandler(plugin, this)
|
||||
|
||||
val handler: DataHandler = when (type) {
|
||||
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
||||
HandlerType.YAML -> localHandler
|
||||
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]
|
||||
@@ -50,7 +43,7 @@ class ProfileHandler(
|
||||
val data = mutableMapOf<PersistentDataKey<*>, Any>()
|
||||
|
||||
val profile = if (uuid == serverProfileUUID)
|
||||
EcoServerProfile(data, handler) else EcoPlayerProfile(data, uuid, handler)
|
||||
EcoServerProfile(data, handler, localHandler) else EcoPlayerProfile(data, uuid, handler, localHandler)
|
||||
|
||||
loaded[uuid] = profile
|
||||
return profile
|
||||
@@ -65,7 +58,19 @@ class ProfileHandler(
|
||||
}
|
||||
|
||||
fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
handler.saveKeysFor(uuid, keys)
|
||||
val profile = accessLoadedProfile(uuid) ?: return
|
||||
val map = mutableMapOf<PersistentDataKey<*>, Any>()
|
||||
|
||||
for (key in keys) {
|
||||
map[key] = profile.data[key] ?: continue
|
||||
}
|
||||
|
||||
handler.saveKeysFor(uuid, map)
|
||||
|
||||
// Don't save to local handler if it's the same handler.
|
||||
if (localHandler != handler) {
|
||||
localHandler.saveKeysFor(uuid, map)
|
||||
}
|
||||
}
|
||||
|
||||
fun unloadPlayer(uuid: UUID) {
|
||||
@@ -74,6 +79,10 @@ class ProfileHandler(
|
||||
|
||||
fun save() {
|
||||
handler.save()
|
||||
|
||||
if (localHandler != handler) {
|
||||
localHandler.save()
|
||||
}
|
||||
}
|
||||
|
||||
fun migrateIfNeeded() {
|
||||
@@ -87,11 +96,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 +106,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.")
|
||||
@@ -161,5 +165,8 @@ class ProfileHandler(
|
||||
|
||||
fun initialize() {
|
||||
handler.initialize()
|
||||
if (localHandler != handler) {
|
||||
localHandler.initialize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ abstract class DataHandler(
|
||||
/**
|
||||
* Save a set of keys for a given UUID.
|
||||
*/
|
||||
abstract fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>)
|
||||
abstract fun saveKeysFor(uuid: UUID, keys: Map<PersistentDataKey<*>, Any>)
|
||||
|
||||
// Everything below this are methods that are only needed for certain implementations.
|
||||
|
||||
|
||||
@@ -3,6 +3,5 @@ package com.willfp.eco.internal.spigot.data.storage
|
||||
enum class HandlerType {
|
||||
YAML,
|
||||
MYSQL,
|
||||
MONGO,
|
||||
LEGACY_MYSQL
|
||||
MONGO
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user