Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8f710161d | ||
|
|
f840a55734 | ||
|
|
36677fe503 | ||
|
|
7e74223352 | ||
|
|
b6f2b9d4ea | ||
|
|
f320e77008 | ||
|
|
c8b255b358 | ||
|
|
5b5e161062 | ||
|
|
ffa511176f | ||
|
|
8515ff2b7b | ||
|
|
74aeaec257 | ||
|
|
0ce3d294d1 | ||
|
|
7c7052f5b9 | ||
|
|
a6b7dda82d | ||
|
|
04aaefb9ea | ||
|
|
d2fdb4f8e0 | ||
|
|
87f90d8b26 | ||
|
|
899d5cc054 | ||
|
|
c1ed771eb3 | ||
|
|
08a4d9d6b1 | ||
|
|
7ef8dcfd64 | ||
|
|
5bedf88b4c | ||
|
|
1d241651b5 | ||
|
|
3ff2bfa412 | ||
|
|
3a508c693b | ||
|
|
a4c5ff921e | ||
|
|
137e9dc7d6 | ||
|
|
710cec4bc1 | ||
|
|
fa0ec7d6b0 | ||
|
|
5093799775 | ||
|
|
8535f23ede | ||
|
|
8e09ae7f4c | ||
|
|
bbc2513b40 | ||
|
|
c7f8063a3a | ||
|
|
14b0f1be0c | ||
|
|
af20bb315b | ||
|
|
6645e216d5 | ||
|
|
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 | ||
|
|
4ce2850138 |
@@ -27,6 +27,7 @@ dependencies {
|
|||||||
implementation(project(path = ":eco-core:core-nms:v1_19_R1", configuration = "reobf"))
|
implementation(project(path = ":eco-core:core-nms:v1_19_R1", configuration = "reobf"))
|
||||||
implementation(project(path = ":eco-core:core-nms:v1_19_R2", configuration = "reobf"))
|
implementation(project(path = ":eco-core:core-nms:v1_19_R2", configuration = "reobf"))
|
||||||
implementation(project(path = ":eco-core:core-nms:v1_19_R3", configuration = "reobf"))
|
implementation(project(path = ":eco-core:core-nms:v1_19_R3", configuration = "reobf"))
|
||||||
|
implementation(project(path = ":eco-core:core-nms:v1_20_R1", configuration = "reobf"))
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@@ -82,6 +83,12 @@ allprojects {
|
|||||||
|
|
||||||
// UltraEconomy
|
// UltraEconomy
|
||||||
maven("https://repo.techscode.com/repository/maven-releases/")
|
maven("https://repo.techscode.com/repository/maven-releases/")
|
||||||
|
|
||||||
|
// PlayerPoints
|
||||||
|
maven("https://repo.rosewooddev.io/repository/public/")
|
||||||
|
|
||||||
|
// Denizen
|
||||||
|
maven("https://maven.citizensnpcs.co/repo")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
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.SlotBuilder;
|
||||||
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
|
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
|
||||||
import com.willfp.eco.core.items.TestableItem;
|
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.packet.Packet;
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
import com.willfp.eco.core.proxy.ProxyFactory;
|
import com.willfp.eco.core.proxy.ProxyFactory;
|
||||||
import com.willfp.eco.core.scheduling.Scheduler;
|
import com.willfp.eco.core.scheduling.Scheduler;
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
@@ -135,6 +135,14 @@ public interface Eco {
|
|||||||
@NotNull
|
@NotNull
|
||||||
Logger createLogger(@NotNull EcoPlugin plugin);
|
Logger createLogger(@NotNull EcoPlugin plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get NOOP logger.
|
||||||
|
*
|
||||||
|
* @return The logger.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
Logger getNOOPLogger();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a PAPI integration.
|
* Create a PAPI integration.
|
||||||
*
|
*
|
||||||
@@ -170,7 +178,7 @@ public interface Eco {
|
|||||||
* @return The PluginCommandBase implementation
|
* @return The PluginCommandBase implementation
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
PluginCommandBase createPluginCommand(@NotNull CommandBase parentDelegate,
|
PluginCommandBase createPluginCommand(@NotNull PluginCommandBase parentDelegate,
|
||||||
@NotNull EcoPlugin plugin,
|
@NotNull EcoPlugin plugin,
|
||||||
@NotNull String name,
|
@NotNull String name,
|
||||||
@NotNull String permission,
|
@NotNull String permission,
|
||||||
@@ -393,15 +401,6 @@ public interface Eco {
|
|||||||
@NotNull
|
@NotNull
|
||||||
ServerProfile getServerProfile();
|
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.
|
* Create dummy entity - never spawned, exists purely in code.
|
||||||
*
|
*
|
||||||
@@ -528,10 +527,11 @@ public interface Eco {
|
|||||||
*
|
*
|
||||||
* @param expression The expression.
|
* @param expression The expression.
|
||||||
* @param context The context.
|
* @param context The context.
|
||||||
* @return The value of the expression, or zero if invalid.
|
* @return The value of the expression, or null if invalid.
|
||||||
*/
|
*/
|
||||||
double evaluate(@NotNull String expression,
|
@Nullable
|
||||||
@NotNull MathContext context);
|
Double evaluate(@NotNull String expression,
|
||||||
|
@NotNull PlaceholderContext context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the menu a player currently has open.
|
* Get the menu a player currently has open.
|
||||||
@@ -563,6 +563,30 @@ public interface Eco {
|
|||||||
void sendPacket(@NotNull Player player,
|
void sendPacket(@NotNull Player player,
|
||||||
@NotNull Packet packet);
|
@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.
|
* Get the instance of eco; the bridge between the api frontend and the implementation backend.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -125,7 +126,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
/**
|
/**
|
||||||
* The logger for the plugin.
|
* The logger for the plugin.
|
||||||
*/
|
*/
|
||||||
private final Logger logger;
|
private Logger logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the server is running an outdated version of the plugin.
|
* If the server is running an outdated version of the plugin.
|
||||||
@@ -163,6 +164,11 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
*/
|
*/
|
||||||
private final ListMap<LifecyclePosition, Runnable> afterLoad = new ListMap<>();
|
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.
|
* Create a new plugin.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -366,7 +372,6 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
public final void onEnable() {
|
public final void onEnable() {
|
||||||
super.onEnable();
|
super.onEnable();
|
||||||
|
|
||||||
this.getLogger().info("");
|
|
||||||
this.getLogger().info("Loading " + this.getColor() + this.getName());
|
this.getLogger().info("Loading " + this.getColor() + this.getName());
|
||||||
|
|
||||||
if (this.getResourceId() != 0 && !Eco.get().getEcoPlugin().getConfigYml().getBool("no-update-checker")) {
|
if (this.getResourceId() != 0 && !Eco.get().getEcoPlugin().getConfigYml().getBool("no-update-checker")) {
|
||||||
@@ -406,7 +411,9 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
|
|
||||||
this.loadedIntegrations.removeIf(pl -> pl.equalsIgnoreCase(this.getName()));
|
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();
|
Prerequisite.update();
|
||||||
|
|
||||||
@@ -423,22 +430,35 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
|
|
||||||
this.loadPluginCommands().forEach(PluginCommand::register);
|
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()) {
|
if (this.isSupportingExtensions()) {
|
||||||
this.getExtensionLoader().loadExtensions();
|
this.getExtensionLoader().loadExtensions();
|
||||||
|
|
||||||
if (this.getExtensionLoader().getLoadedExtensions().isEmpty()) {
|
if (!this.getExtensionLoader().getLoadedExtensions().isEmpty()) {
|
||||||
this.getLogger().info("&cNo extensions found");
|
List<String> loadedExtensions = this.getExtensionLoader().getLoadedExtensions().stream().map(
|
||||||
} else {
|
extension -> extension.getName() + " v" + extension.getVersion()
|
||||||
this.getLogger().info("Extensions Loaded:");
|
).toList();
|
||||||
this.getExtensionLoader().getLoadedExtensions().forEach(extension -> this.getLogger().info("- " + extension.getName() + " v" + extension.getVersion()));
|
|
||||||
|
this.getLogger().info(
|
||||||
|
"Loaded extensions: " +
|
||||||
|
String.join(", ", loadedExtensions)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.handleLifecycle(this.onEnable, this::handleEnable);
|
this.handleLifecycle(this.onEnable, this::handleEnable);
|
||||||
|
|
||||||
this.getLogger().info("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -597,14 +617,30 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
* Reload the plugin.
|
* Reload the plugin.
|
||||||
*/
|
*/
|
||||||
public final void reload() {
|
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.getConfigHandler().updateConfigs();
|
||||||
|
|
||||||
this.getScheduler().cancelAll();
|
if (cancelTasks) {
|
||||||
|
this.getScheduler().cancelAll();
|
||||||
|
}
|
||||||
|
|
||||||
this.getConfigHandler().callUpdate();
|
this.getConfigHandler().callUpdate();
|
||||||
this.getConfigHandler().callUpdate(); // Call twice to fix issues
|
this.getConfigHandler().callUpdate(); // Call twice to fix issues
|
||||||
|
|
||||||
this.handleLifecycle(this.onReload, this::handleReload);
|
this.handleLifecycle(this.onReload, this::handleReload);
|
||||||
|
|
||||||
|
if (cancelTasks) {
|
||||||
|
this.handleLifecycle(this.createTasks, this::createTasks);
|
||||||
|
}
|
||||||
|
|
||||||
for (Extension extension : this.extensionLoader.getLoadedExtensions()) {
|
for (Extension extension : this.extensionLoader.getLoadedExtensions()) {
|
||||||
extension.handleReload();
|
extension.handleReload();
|
||||||
}
|
}
|
||||||
@@ -718,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.
|
* The plugin-specific code to be executed after the server is up.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -1082,7 +1127,7 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
*
|
*
|
||||||
* @return The config handler.
|
* @return The config handler.
|
||||||
*/
|
*/
|
||||||
public ConfigHandler getConfigHandler() {
|
public @NotNull ConfigHandler getConfigHandler() {
|
||||||
return this.configHandler;
|
return this.configHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1146,9 +1191,24 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
|
|||||||
return this.getMetadataValueFactory().create(value);
|
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
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public final String getID() {
|
public final String getID() {
|
||||||
return Registry.tryFitPattern(this.getName());
|
return Registry.tryFitPattern(this.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull File getFile() {
|
||||||
|
return super.getFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.willfp.eco.core;
|
package com.willfp.eco.core;
|
||||||
|
|
||||||
import com.willfp.eco.core.config.updating.ConfigHandler;
|
import com.willfp.eco.core.config.updating.ConfigHandler;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -13,12 +15,13 @@ import java.util.logging.Logger;
|
|||||||
*/
|
*/
|
||||||
public interface PluginLike {
|
public interface PluginLike {
|
||||||
/**
|
/**
|
||||||
* Get the data folder of the object.
|
* Get the data folder.
|
||||||
* <p>
|
* <p>
|
||||||
* Returns the plugin data folder for a plugin, or the extension's parent plugin's folder
|
* Returns the plugin data folder for a plugin, or the extension's parent plugin's folder
|
||||||
*
|
*
|
||||||
* @return The data folder.
|
* @return The data folder.
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
File getDataFolder();
|
File getDataFolder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,6 +29,7 @@ public interface PluginLike {
|
|||||||
*
|
*
|
||||||
* @return The config handler.
|
* @return The config handler.
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
ConfigHandler getConfigHandler();
|
ConfigHandler getConfigHandler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,5 +37,16 @@ public interface PluginLike {
|
|||||||
*
|
*
|
||||||
* @return The logger.
|
* @return The logger.
|
||||||
*/
|
*/
|
||||||
|
@NotNull
|
||||||
Logger getLogger();
|
Logger getLogger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the actual file.
|
||||||
|
*
|
||||||
|
* @return The file, i.e. the jar file.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default File getFile() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,11 +37,19 @@ public class Prerequisite {
|
|||||||
"Requires server to have ProtocolLib"
|
"Requires server to have ProtocolLib"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires the server to be running 1.20.
|
||||||
|
*/
|
||||||
|
public static final Prerequisite HAS_1_20 = new Prerequisite(
|
||||||
|
() -> ProxyConstants.NMS_VERSION.contains("20"),
|
||||||
|
"Requires server to be running 1.20+"
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requires the server to be running 1.19.4.
|
* Requires the server to be running 1.19.4.
|
||||||
*/
|
*/
|
||||||
public static final Prerequisite HAS_1_19_4 = new Prerequisite(
|
public static final Prerequisite HAS_1_19_4 = new Prerequisite(
|
||||||
() -> ProxyConstants.NMS_VERSION.contains("19_R3"),
|
() -> ProxyConstants.NMS_VERSION.contains("19_R3") || HAS_1_20.isMet(),
|
||||||
"Requires server to be running 1.19.4+"
|
"Requires server to be running 1.19.4+"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -49,7 +57,7 @@ public class Prerequisite {
|
|||||||
* Requires the server to be running 1.19.
|
* Requires the server to be running 1.19.
|
||||||
*/
|
*/
|
||||||
public static final Prerequisite HAS_1_19 = new Prerequisite(
|
public static final Prerequisite HAS_1_19 = new Prerequisite(
|
||||||
() -> ProxyConstants.NMS_VERSION.contains("19"),
|
() -> ProxyConstants.NMS_VERSION.contains("19") || HAS_1_20.isMet(),
|
||||||
"Requires server to be running 1.19+"
|
"Requires server to be running 1.19+"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* Default plugin config.yml.
|
* Default plugin config.yml.
|
||||||
*/
|
*/
|
||||||
public class ConfigYml extends BaseConfig {
|
public class ConfigYml extends BaseConfig {
|
||||||
|
/**
|
||||||
|
* The use local storage key.
|
||||||
|
*/
|
||||||
|
public static final String KEY_USES_LOCAL_STORAGE = "use-local-storage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Config.yml.
|
* Config.yml.
|
||||||
*
|
*
|
||||||
@@ -52,4 +57,13 @@ public class ConfigYml extends BaseConfig {
|
|||||||
final boolean removeUnused) {
|
final boolean removeUnused) {
|
||||||
super(name, plugin, removeUnused, ConfigType.YAML);
|
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.AdditionalPlayer;
|
||||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
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.NumberUtils;
|
||||||
import com.willfp.eco.util.StringUtils;
|
import com.willfp.eco.util.StringUtils;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
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.
|
* @return The computed value, or 0 if not found or invalid.
|
||||||
*/
|
*/
|
||||||
default int getIntFromExpression(@NotNull String path) {
|
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();
|
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.
|
* Get an integer from config.
|
||||||
@@ -256,6 +269,22 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
|||||||
return getString(path, true, option);
|
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.
|
* Get a string from config.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -288,7 +317,7 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
|||||||
* Get a formatted string from config.
|
* Get a formatted string from config.
|
||||||
*
|
*
|
||||||
* @param path The key to fetch the value from.
|
* @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
|
@Nullable
|
||||||
default String getFormattedStringOrNull(@NotNull String path) {
|
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 path The key to fetch the value from.
|
||||||
* @param option The format option.
|
* @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
|
@Nullable
|
||||||
default String getFormattedStringOrNull(@NotNull String path,
|
default String getFormattedStringOrNull(@NotNull String path,
|
||||||
@@ -308,6 +337,25 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
|||||||
return getStringOrNull(path, true, option);
|
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.
|
* Get a string from config.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -362,6 +410,24 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
|||||||
return getStrings(path, true, option);
|
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.
|
* Get a list of strings from config.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -418,6 +484,30 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
|||||||
return getStringsOrNull(path, true, option);
|
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.
|
* Get a list of strings from config.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -463,7 +553,7 @@ public interface Config extends Cloneable, PlaceholderInjectable {
|
|||||||
* @return The computed value, or 0 if not found or invalid.
|
* @return The computed value, or 0 if not found or invalid.
|
||||||
*/
|
*/
|
||||||
default double getDoubleFromExpression(@NotNull String path) {
|
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,
|
default double getDoubleFromExpression(@NotNull String path,
|
||||||
@Nullable Player player) {
|
@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.
|
* Get a decimal value via a mathematical expression.
|
||||||
*
|
*
|
||||||
* @param path The key to fetch the value from.
|
* @param path The key to fetch the value from.
|
||||||
* @param player The player to evaluate placeholders with respect to.
|
* @param player The player to evaluate placeholders with respect to.
|
||||||
* @param additionalPlayers The additional players 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.
|
* @return The computed value, or 0 if not found or invalid.
|
||||||
*/
|
*/
|
||||||
default double getDoubleFromExpression(@NotNull String path,
|
default double getDoubleFromExpression(@NotNull String path,
|
||||||
@Nullable Player player,
|
@Nullable Player player,
|
||||||
@NotNull Collection<AdditionalPlayer> additionalPlayers) {
|
@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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,6 +9,22 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* Profiles save automatically, so there is no need to save after changes.
|
* Profiles save automatically, so there is no need to save after changes.
|
||||||
*/
|
*/
|
||||||
public interface ServerProfile extends Profile {
|
public interface ServerProfile extends Profile {
|
||||||
|
/**
|
||||||
|
* Get the server ID.
|
||||||
|
*
|
||||||
|
* @return The server ID.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String getServerID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the local server ID.
|
||||||
|
*
|
||||||
|
* @return The local server ID.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String getLocalServerID();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the server profile.
|
* Load the server profile.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.willfp.eco.core.config.interfaces.Config;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -49,6 +50,11 @@ public final class PersistentDataKeyType<T> {
|
|||||||
*/
|
*/
|
||||||
public static final PersistentDataKeyType<Config> CONFIG = new PersistentDataKeyType<>("CONFIG");
|
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.
|
* The name of the key type.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -135,20 +135,26 @@ public abstract class Extension implements PluginLike {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getDataFolder() {
|
public @NotNull File getDataFolder() {
|
||||||
return this.plugin.getDataFolder();
|
return this.plugin.getDataFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigHandler getConfigHandler() {
|
public @NotNull ConfigHandler getConfigHandler() {
|
||||||
return this.plugin.getConfigHandler();
|
return this.plugin.getConfigHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Logger getLogger() {
|
public @NotNull Logger getLogger() {
|
||||||
return this.plugin.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.
|
* 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;
|
package com.willfp.eco.core.extensions;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.version.Version;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The extension's metadata.
|
* The extension's metadata.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -13,6 +16,23 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
*/
|
*/
|
||||||
public record ExtensionMetadata(@NotNull String version,
|
public record ExtensionMetadata(@NotNull String version,
|
||||||
@NotNull String name,
|
@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.
|
* Missing or invalid extension.yml.
|
||||||
* Invalid filetype.
|
* Invalid filetype.
|
||||||
*/
|
*/
|
||||||
public class MalformedExtensionException extends RuntimeException {
|
public class MalformedExtensionException extends ExtensionLoadException {
|
||||||
/**
|
/**
|
||||||
* Create a new MalformedExtensionException.
|
* 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)));
|
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.
|
* Add a menu close handler.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -76,6 +76,15 @@ public abstract class CustomSlot implements Slot {
|
|||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRenderOnClick() {
|
||||||
|
if (delegate == null) {
|
||||||
|
throw new IllegalStateException("Custom Slot was not initialized!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return delegate.shouldRenderOnClick();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int getRows() {
|
public final int getRows() {
|
||||||
return Slot.super.getRows();
|
return Slot.super.getRows();
|
||||||
|
|||||||
@@ -92,6 +92,15 @@ public interface Slot extends GUIComponent {
|
|||||||
return false;
|
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
|
@Override
|
||||||
default int getRows() {
|
default int getRows() {
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ import java.util.function.Supplier;
|
|||||||
* @param <T> The type of integration.
|
* @param <T> The type of integration.
|
||||||
*/
|
*/
|
||||||
public class IntegrationRegistry<T extends Integration> extends Registry<T> {
|
public class IntegrationRegistry<T extends Integration> extends Registry<T> {
|
||||||
|
/**
|
||||||
|
* Create a new integration registry.
|
||||||
|
*/
|
||||||
|
public IntegrationRegistry() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull T register(@NotNull final T element) {
|
public @NotNull T register(@NotNull final T element) {
|
||||||
return executeSafely(() -> super.register(element), element);
|
return executeSafely(() -> super.register(element), element);
|
||||||
@@ -114,7 +121,7 @@ public class IntegrationRegistry<T extends Integration> extends Registry<T> {
|
|||||||
Eco.get().getEcoPlugin().getLogger().warning("Integration for " + integration.getPluginName() + " threw an exception!");
|
Eco.get().getEcoPlugin().getLogger().warning("Integration for " + integration.getPluginName() + " threw an exception!");
|
||||||
Eco.get().getEcoPlugin().getLogger().warning("The integration will be disabled.");
|
Eco.get().getEcoPlugin().getLogger().warning("The integration will be disabled.");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
this.remove(integration.getPluginName());
|
this.remove(integration);
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class for placeholder integrations.
|
* Wrapper class for arguments integrations.
|
||||||
*/
|
*/
|
||||||
public interface PlaceholderIntegration extends Integration {
|
public interface PlaceholderIntegration extends Integration {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
package com.willfp.eco.core.integrations.placeholder;
|
package com.willfp.eco.core.integrations.placeholder;
|
||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.willfp.eco.core.Eco;
|
||||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
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.AdditionalPlayer;
|
||||||
import com.willfp.eco.core.placeholder.DynamicPlaceholder;
|
|
||||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||||
import com.willfp.eco.core.placeholder.Placeholder;
|
import com.willfp.eco.core.placeholder.Placeholder;
|
||||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||||
import com.willfp.eco.core.placeholder.PlayerDynamicPlaceholder;
|
import com.willfp.eco.core.placeholder.RegistrablePlaceholder;
|
||||||
import com.willfp.eco.core.placeholder.PlayerPlaceholder;
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
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 org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -23,58 +17,34 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to handle placeholder integrations.
|
* Class to handle arguments integrations.
|
||||||
*/
|
*/
|
||||||
public final class PlaceholderManager {
|
public final class PlaceholderManager {
|
||||||
/**
|
/**
|
||||||
* All registered placeholders.
|
* 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<>();
|
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.
|
* The default PlaceholderAPI pattern; brought in for compatibility.
|
||||||
*/
|
*/
|
||||||
private static final Pattern PATTERN = Pattern.compile("%([^% ]+)%");
|
private static final Pattern PATTERN = Pattern.compile("%([^% ]+)%");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty injectable object.
|
* Empty injectableContext object.
|
||||||
*/
|
*/
|
||||||
public static final PlaceholderInjectable EMPTY_INJECTABLE = new PlaceholderInjectable() {
|
public static final PlaceholderInjectable EMPTY_INJECTABLE = new PlaceholderInjectable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -105,97 +75,69 @@ 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) {
|
public static void registerPlaceholder(@NotNull final Placeholder placeholder) {
|
||||||
if (placeholder instanceof StaticPlaceholder || placeholder instanceof PlayerStaticPlaceholder) {
|
if (!(placeholder instanceof RegistrablePlaceholder)) {
|
||||||
throw new IllegalArgumentException("Static placeholders cannot be registered!");
|
throw new IllegalArgumentException("Placeholder must be RegistrablePlaceholder!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Pattern, Placeholder> pluginPlaceholders = REGISTERED_PLACEHOLDERS
|
registerPlaceholder((RegistrablePlaceholder) placeholder);
|
||||||
.getOrDefault(placeholder.getPlugin(), new HashMap<>());
|
|
||||||
|
|
||||||
pluginPlaceholders.put(placeholder.getPattern(), placeholder);
|
|
||||||
|
|
||||||
REGISTERED_PLACEHOLDERS.put(placeholder.getPlugin(), pluginPlaceholders);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the result of a placeholder with respect to a player.
|
* Register a arguments.
|
||||||
*
|
*
|
||||||
* @param player The player to get the result from.
|
* @param placeholder The arguments to register.
|
||||||
* @param identifier The placeholder identifier.
|
|
||||||
* @return The value of the placeholder.
|
|
||||||
* @deprecated Specify a plugin to get the result from.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.52.2", forRemoval = true)
|
public static void registerPlaceholder(@NotNull final RegistrablePlaceholder placeholder) {
|
||||||
@SuppressWarnings("unused")
|
// Storing as immutable set leads to slower times to register placeholders, but much
|
||||||
public static String getResult(@Nullable final Player player,
|
// faster times to access registrations.
|
||||||
@NotNull final String identifier) {
|
Set<Placeholder> pluginPlaceholders = new HashSet<>(REGISTERED_PLACEHOLDERS.get(placeholder.getPlugin()));
|
||||||
throw new UnsupportedOperationException("Please specify a plugin to get the result from!");
|
pluginPlaceholders.removeIf(p -> p.getPattern().equals(placeholder.getPattern()));
|
||||||
|
pluginPlaceholders.add(placeholder);
|
||||||
|
REGISTERED_PLACEHOLDERS.put(placeholder.getPlugin(), ImmutableSet.copyOf(pluginPlaceholders));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the result of a placeholder with respect to a player.
|
* Get the result of a placeholder with respect to a player.
|
||||||
*
|
*
|
||||||
* @param player The player to get the result from.
|
* @param player The player to get the result from.
|
||||||
* @param identifier The placeholder identifier.
|
* @param identifier The placeholder args.
|
||||||
* @param plugin The plugin for the placeholder.
|
* @param plugin The plugin for the arguments.
|
||||||
* @return The value of the placeholder.
|
* @return The value of the arguments.
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String getResult(@Nullable final Player player,
|
public static String getResult(@Nullable final Player player,
|
||||||
@NotNull final String identifier,
|
@NotNull final String identifier,
|
||||||
@NotNull final EcoPlugin plugin) {
|
@Nullable final EcoPlugin plugin) {
|
||||||
Validate.notNull(plugin, "Plugin cannot be null!");
|
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.
|
* Get the result of a placeholder given a plugin and arguments.
|
||||||
Placeholder placeholder = PLACEHOLDER_LOOKUP_CACHE.get(
|
*
|
||||||
new PlaceholderLookup(identifier, plugin),
|
* @param plugin The plugin for the placeholder.
|
||||||
(it) -> {
|
* @param args The arguments.
|
||||||
// I hate the streams API.
|
* @param context The context.
|
||||||
return REGISTERED_PLACEHOLDERS
|
* @return The value of the arguments.
|
||||||
.getOrDefault(plugin, new HashMap<>())
|
*/
|
||||||
.entrySet()
|
@Nullable
|
||||||
.stream().filter(entry -> entry.getKey().matcher(identifier).matches())
|
public static String getResult(@Nullable final EcoPlugin plugin,
|
||||||
.map(Map.Entry::getValue)
|
@NotNull final String args,
|
||||||
.findFirst();
|
@NotNull final PlaceholderContext context) {
|
||||||
}
|
return Eco.get().getPlaceholderValue(plugin, args, context);
|
||||||
).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 "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,7 +146,10 @@ public final class PlaceholderManager {
|
|||||||
* @param text The text that may contain placeholders to translate.
|
* @param text The text that may contain placeholders to translate.
|
||||||
* @param player The player to translate the placeholders with respect to.
|
* @param player The player to translate the placeholders with respect to.
|
||||||
* @return The text, translated.
|
* @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,
|
public static String translatePlaceholders(@NotNull final String text,
|
||||||
@Nullable final Player player) {
|
@Nullable final Player player) {
|
||||||
return translatePlaceholders(text, player, EMPTY_INJECTABLE);
|
return translatePlaceholders(text, player, EMPTY_INJECTABLE);
|
||||||
@@ -215,9 +160,12 @@ public final class PlaceholderManager {
|
|||||||
*
|
*
|
||||||
* @param text The text that may contain placeholders to translate.
|
* @param text The text that may contain placeholders to translate.
|
||||||
* @param player The player to translate the placeholders with respect to.
|
* @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.
|
* @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,
|
public static String translatePlaceholders(@NotNull final String text,
|
||||||
@Nullable final Player player,
|
@Nullable final Player player,
|
||||||
@NotNull final PlaceholderInjectable context) {
|
@NotNull final PlaceholderInjectable context) {
|
||||||
@@ -229,84 +177,50 @@ public final class PlaceholderManager {
|
|||||||
*
|
*
|
||||||
* @param text The text that may contain placeholders to translate.
|
* @param text The text that may contain placeholders to translate.
|
||||||
* @param player The player to translate the placeholders with respect to.
|
* @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.
|
* @param additionalPlayers Additional players to translate placeholders for.
|
||||||
* @return The text, translated.
|
* @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,
|
public static String translatePlaceholders(@NotNull final String text,
|
||||||
@Nullable final Player player,
|
@Nullable final Player player,
|
||||||
@NotNull final PlaceholderInjectable context,
|
@NotNull final PlaceholderInjectable context,
|
||||||
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
|
@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?
|
/**
|
||||||
|
* Translate all placeholders in a translation context.
|
||||||
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.
|
* @param text The text that may contain placeholders to translate.
|
||||||
|
* @param context The translation context.
|
||||||
However, something like libreforge will also inject %victim_max_health%, which is unrelated
|
* @return The text, translated.
|
||||||
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
|
@NotNull
|
||||||
relation to the victim, which resolved to zero. So, we have to parse statics and player statics
|
public static String translatePlaceholders(@NotNull final String text,
|
||||||
that might include a prefix first, then additional players, then player statics with the support
|
@NotNull final PlaceholderContext context) {
|
||||||
of additional players.
|
return Eco.get().translatePlaceholders(text, context);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -331,108 +245,22 @@ public final class PlaceholderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set placeholders without any integrations.
|
* Get all registered placeholder 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>.
|
|
||||||
*
|
*
|
||||||
* @param text The text.
|
* @return The integrations.
|
||||||
* @param player The player.
|
|
||||||
* @return The text.
|
|
||||||
*/
|
*/
|
||||||
private static String setWithoutIntegration(@NotNull final String text,
|
public static Set<PlaceholderIntegration> getRegisteredIntegrations() {
|
||||||
@Nullable final Player player) {
|
return Set.copyOf(REGISTERED_INTEGRATIONS);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private record PlaceholderLookup(@NotNull String identifier,
|
/**
|
||||||
@Nullable EcoPlugin plugin) {
|
* Get all registered placeholders for a plugin.
|
||||||
|
*
|
||||||
}
|
* @param plugin The plugin.
|
||||||
|
* @return The placeholders.
|
||||||
private record EntryWithPlayer(@NotNull PlayerPlaceholder entry,
|
*/
|
||||||
@NotNull Player player) {
|
public static Set<Placeholder> getRegisteredPlaceholders(@NotNull final EcoPlugin plugin) {
|
||||||
|
return REGISTERED_PLACEHOLDERS.get(plugin);
|
||||||
}
|
|
||||||
|
|
||||||
private record DynamicEntryWithPlayer(@NotNull PlayerDynamicPlaceholder entry,
|
|
||||||
@NotNull String args,
|
|
||||||
@NotNull Player player) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlaceholderManager() {
|
private PlaceholderManager() {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.willfp.eco.core.items;
|
package com.willfp.eco.core.items;
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
import com.willfp.eco.core.Eco;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -55,7 +54,7 @@ public class CustomItem implements TestableItem {
|
|||||||
*/
|
*/
|
||||||
Eco.get().getEcoPlugin().getScheduler().runLater(() -> {
|
Eco.get().getEcoPlugin().getScheduler().runLater(() -> {
|
||||||
if (!matches(getItem())) {
|
if (!matches(getItem())) {
|
||||||
Bukkit.getLogger().severe("Item with key " + key + " is invalid!");
|
Eco.get().getEcoPlugin().getLogger().severe("Item with key " + key + " is invalid!");
|
||||||
}
|
}
|
||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ public class DefaultMap<K, V> implements Map<K, V> {
|
|||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static <K, K1, V> DefaultMap<K, Map<K1, V>> createNestedMap() {
|
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
|
@NotNull
|
||||||
public static <K, K1, V> DefaultMap<K, ListMap<K1, V>> createNestedListMap() {
|
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.integrations.placeholder.PlaceholderManager;
|
||||||
import com.willfp.eco.core.placeholder.AdditionalPlayer;
|
import com.willfp.eco.core.placeholder.AdditionalPlayer;
|
||||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
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.
|
* @deprecated Use {@link PlaceholderContext} instead.
|
||||||
* @param player The player.
|
|
||||||
* @param additionalPlayers The additional players.
|
|
||||||
*/
|
*/
|
||||||
public record MathContext(
|
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||||
@NotNull PlaceholderInjectable injectableContext,
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
@Nullable Player player,
|
public class MathContext {
|
||||||
@NotNull Collection<AdditionalPlayer> additionalPlayers
|
|
||||||
) {
|
|
||||||
/**
|
/**
|
||||||
* Empty math context.
|
* Returns an empty math parseContext.
|
||||||
*/
|
*/
|
||||||
public static final MathContext EMPTY = new MathContext(
|
public static final MathContext EMPTY = new MathContext(
|
||||||
PlaceholderManager.EMPTY_INJECTABLE,
|
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.
|
* @return The MathContext.
|
||||||
*/
|
*/
|
||||||
public static MathContext of(@NotNull final PlaceholderInjectable injectableContext) {
|
public static MathContext of(@NotNull final PlaceholderInjectable injectableContext) {
|
||||||
@@ -48,16 +194,16 @@ public record MathContext(
|
|||||||
/**
|
/**
|
||||||
* Copy a MathContext with a player.
|
* Copy a MathContext with a player.
|
||||||
*
|
*
|
||||||
* @param context The context.
|
* @param context The parseContext.
|
||||||
* @param player The player.
|
* @param player The player.
|
||||||
* @return The new MathContext.
|
* @return The new MathContext.
|
||||||
*/
|
*/
|
||||||
public static MathContext copyWithPlayer(@NotNull final MathContext context,
|
public static MathContext copyWithPlayer(@NotNull final MathContext context,
|
||||||
@Nullable final Player player) {
|
@Nullable final Player player) {
|
||||||
return new MathContext(
|
return new MathContext(
|
||||||
context.injectableContext(),
|
context.injectableContext,
|
||||||
player,
|
player,
|
||||||
context.additionalPlayers()
|
context.additionalPlayers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.willfp.eco.core.placeholder;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.
|
* 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;
|
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;
|
private final EcoPlugin plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new dynamic placeholder.
|
* Create a new dynamic arguments.
|
||||||
*
|
*
|
||||||
* @param plugin The plugin.
|
* @param plugin The plugin.
|
||||||
* @param pattern The pattern.
|
* @param pattern The pattern.
|
||||||
@@ -37,31 +37,33 @@ public final class DynamicPlaceholder implements Placeholder {
|
|||||||
*/
|
*/
|
||||||
public DynamicPlaceholder(@NotNull final EcoPlugin plugin,
|
public DynamicPlaceholder(@NotNull final EcoPlugin plugin,
|
||||||
@NotNull final Pattern pattern,
|
@NotNull final Pattern pattern,
|
||||||
@NotNull final Function<String, String> function) {
|
@NotNull final Function<@NotNull String, @Nullable String> function) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.pattern = pattern;
|
this.pattern = pattern;
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the value of the placeholder.
|
@Nullable
|
||||||
*
|
public String getValue(@NotNull final String args,
|
||||||
* @param args The args.
|
@NotNull final PlaceholderContext context) {
|
||||||
* @return The value.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public String getValue(@NotNull final String args) {
|
|
||||||
return function.apply(args);
|
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() {
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
PlaceholderManager.registerPlaceholder(this);
|
@NotNull
|
||||||
return this;
|
public String getValue(@NotNull final String args) {
|
||||||
|
return Objects.requireNonNullElse(
|
||||||
|
function.apply(args),
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,18 +71,17 @@ public final class DynamicPlaceholder implements Placeholder {
|
|||||||
return this.plugin;
|
return this.plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public @NotNull String getIdentifier() {
|
|
||||||
return "dynamic";
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Pattern getPattern() {
|
public Pattern getPattern() {
|
||||||
return this.pattern;
|
return this.pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull DynamicPlaceholder register() {
|
||||||
|
return (DynamicPlaceholder) RegistrablePlaceholder.super.register();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable final Object o) {
|
public boolean equals(@Nullable final Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
@@ -97,6 +98,6 @@ public final class DynamicPlaceholder implements Placeholder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
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;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
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.
|
* 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
|
@Override
|
||||||
default @NotNull EcoPlugin getPlugin() {
|
default EcoPlugin getPlugin() {
|
||||||
return Eco.get().getEcoPlugin();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,64 @@
|
|||||||
package com.willfp.eco.core.placeholder;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A placeholder represents a string that can hold a value.
|
* A placeholder represents a string that can hold a value.
|
||||||
*/
|
*/
|
||||||
public sealed interface Placeholder permits PlayerPlaceholder, PlayerlessPlaceholder,
|
public interface Placeholder {
|
||||||
DynamicPlaceholder, PlayerDynamicPlaceholder, InjectablePlaceholder {
|
|
||||||
/**
|
/**
|
||||||
* Get the plugin that holds the placeholder.
|
* Get the plugin that holds the arguments.
|
||||||
*
|
*
|
||||||
* @return The plugin.
|
* @return The plugin.
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@Nullable
|
||||||
EcoPlugin getPlugin();
|
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
|
@Nullable
|
||||||
String getIdentifier();
|
String getValue(@NotNull String args,
|
||||||
|
@NotNull PlaceholderContext context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the pattern for the placeholder.
|
* Get the pattern for the arguments.
|
||||||
*
|
*
|
||||||
* @return The pattern.
|
* @return The pattern.
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
default Pattern getPattern() {
|
Pattern getPattern();
|
||||||
return Pattern.compile(this.getIdentifier());
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
public interface PlaceholderInjectable {
|
||||||
/**
|
/**
|
||||||
* Inject placeholder.
|
* Inject arguments.
|
||||||
*
|
*
|
||||||
* @param placeholders The placeholders.
|
* @param placeholders The placeholders.
|
||||||
*/
|
*/
|
||||||
@@ -18,7 +18,7 @@ public interface PlaceholderInjectable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject placeholder.
|
* Inject arguments.
|
||||||
*
|
*
|
||||||
* @param placeholders The placeholders.
|
* @param placeholders The placeholders.
|
||||||
*/
|
*/
|
||||||
@@ -29,7 +29,7 @@ public interface PlaceholderInjectable {
|
|||||||
/**
|
/**
|
||||||
* Inject placeholders.
|
* Inject placeholders.
|
||||||
* <p>
|
* <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.
|
* @param placeholders The placeholders.
|
||||||
*/
|
*/
|
||||||
@@ -43,7 +43,7 @@ public interface PlaceholderInjectable {
|
|||||||
/**
|
/**
|
||||||
* Get injected placeholders.
|
* Get injected placeholders.
|
||||||
* <p>
|
* <p>
|
||||||
* Override this method in implementations.
|
* This method should always return an immutable list.
|
||||||
*
|
*
|
||||||
* @return Injected placeholders.
|
* @return Injected placeholders.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.willfp.eco.core.placeholder;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
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.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -11,26 +11,26 @@ import java.util.function.BiFunction;
|
|||||||
import java.util.regex.Pattern;
|
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;
|
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;
|
private final EcoPlugin plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new dynamic placeholder.
|
* Create a new dynamic arguments.
|
||||||
*
|
*
|
||||||
* @param plugin The plugin.
|
* @param plugin The plugin.
|
||||||
* @param pattern The pattern.
|
* @param pattern The pattern.
|
||||||
@@ -38,33 +38,40 @@ public final class PlayerDynamicPlaceholder implements Placeholder {
|
|||||||
*/
|
*/
|
||||||
public PlayerDynamicPlaceholder(@NotNull final EcoPlugin plugin,
|
public PlayerDynamicPlaceholder(@NotNull final EcoPlugin plugin,
|
||||||
@NotNull final Pattern pattern,
|
@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.plugin = plugin;
|
||||||
this.pattern = pattern;
|
this.pattern = pattern;
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the value of the placeholder.
|
public @Nullable String getValue(@NotNull final String args,
|
||||||
*
|
@NotNull final PlaceholderContext context) {
|
||||||
* @param args The args.
|
Player player = context.getPlayer();
|
||||||
* @param player The player.
|
|
||||||
* @return The value.
|
if (player == null) {
|
||||||
*/
|
return null;
|
||||||
@NotNull
|
}
|
||||||
public String getValue(@NotNull final String args,
|
|
||||||
@NotNull final Player player) {
|
|
||||||
return function.apply(args, player);
|
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() {
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
PlaceholderManager.registerPlaceholder(this);
|
@NotNull
|
||||||
return this;
|
public String getValue(@NotNull final String args,
|
||||||
|
@NotNull final Player player) {
|
||||||
|
return Objects.requireNonNullElse(
|
||||||
|
function.apply(args, player),
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,18 +79,17 @@ public final class PlayerDynamicPlaceholder implements Placeholder {
|
|||||||
return this.plugin;
|
return this.plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public @NotNull String getIdentifier() {
|
|
||||||
return "dynamic";
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Pattern getPattern() {
|
public Pattern getPattern() {
|
||||||
return this.pattern;
|
return this.pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull PlayerDynamicPlaceholder register() {
|
||||||
|
return (PlayerDynamicPlaceholder) RegistrablePlaceholder.super.register();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable final Object o) {
|
public boolean equals(@Nullable final Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
@@ -100,6 +106,6 @@ public final class PlayerDynamicPlaceholder implements Placeholder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
return Objects.hash(this.getPattern(), this.getPlugin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.willfp.eco.core.placeholder;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
|
import com.willfp.eco.util.PatternUtils;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -11,31 +12,26 @@ import java.util.function.Function;
|
|||||||
import java.util.regex.Pattern;
|
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.
|
* The arguments pattern.
|
||||||
*/
|
|
||||||
private final String identifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholder pattern.
|
|
||||||
*/
|
*/
|
||||||
private final Pattern 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;
|
private final EcoPlugin plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new player placeholder.
|
* Create a new player arguments.
|
||||||
*
|
*
|
||||||
* @param plugin The plugin.
|
* @param plugin The plugin.
|
||||||
* @param identifier The identifier.
|
* @param identifier The identifier.
|
||||||
@@ -43,32 +39,38 @@ public final class PlayerPlaceholder implements Placeholder {
|
|||||||
*/
|
*/
|
||||||
public PlayerPlaceholder(@NotNull final EcoPlugin plugin,
|
public PlayerPlaceholder(@NotNull final EcoPlugin plugin,
|
||||||
@NotNull final String identifier,
|
@NotNull final String identifier,
|
||||||
@NotNull final Function<Player, String> function) {
|
@NotNull final Function<@NotNull Player, @Nullable String> function) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.identifier = identifier;
|
this.pattern = PatternUtils.compileLiteral(identifier);
|
||||||
this.pattern = Pattern.compile(identifier);
|
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the value of the placeholder for a given player.
|
public @Nullable String getValue(@NotNull final String args,
|
||||||
*
|
@NotNull final PlaceholderContext context) {
|
||||||
* @param player The player.
|
Player player = context.getPlayer();
|
||||||
* @return The value.
|
|
||||||
*/
|
if (player == null) {
|
||||||
@NotNull
|
return null;
|
||||||
public String getValue(@NotNull final Player player) {
|
}
|
||||||
|
|
||||||
return function.apply(player);
|
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() {
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
PlaceholderManager.registerPlaceholder(this);
|
@NotNull
|
||||||
return this;
|
public String getValue(@NotNull final Player player) {
|
||||||
|
return Objects.requireNonNullElse(
|
||||||
|
function.apply(player),
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,17 +78,17 @@ public final class PlayerPlaceholder implements Placeholder {
|
|||||||
return this.plugin;
|
return this.plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull String getIdentifier() {
|
|
||||||
return this.identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Pattern getPattern() {
|
public Pattern getPattern() {
|
||||||
return this.pattern;
|
return this.pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull PlayerPlaceholder register() {
|
||||||
|
return (PlayerPlaceholder) RegistrablePlaceholder.super.register();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable final Object o) {
|
public boolean equals(@Nullable final Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
@@ -95,12 +97,12 @@ public final class PlayerPlaceholder implements Placeholder {
|
|||||||
if (!(o instanceof PlayerPlaceholder that)) {
|
if (!(o instanceof PlayerPlaceholder that)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Objects.equals(this.getIdentifier(), that.getIdentifier())
|
return Objects.equals(this.getPattern(), that.getPattern())
|
||||||
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(this.getIdentifier(), this.getPlugin());
|
return Objects.hash(this.getPattern(), this.getPlugin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.willfp.eco.core.placeholder;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
|
import com.willfp.eco.util.PatternUtils;
|
||||||
|
import com.willfp.eco.util.StringUtils;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -13,47 +16,72 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
|
public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
|
||||||
/**
|
/**
|
||||||
* The name of the placeholder.
|
* The identifier.
|
||||||
*/
|
*/
|
||||||
private final String identifier;
|
private final String identifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The placeholder pattern.
|
* The arguments pattern.
|
||||||
*/
|
*/
|
||||||
private final Pattern 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 identifier The identifier.
|
||||||
* @param function The function to retrieve the value.
|
* @param function The function to retrieve the value.
|
||||||
*/
|
*/
|
||||||
public PlayerStaticPlaceholder(@NotNull final String identifier,
|
public PlayerStaticPlaceholder(@NotNull final String identifier,
|
||||||
@NotNull final Function<Player, String> function) {
|
@NotNull final Function<@NotNull Player, @Nullable String> function) {
|
||||||
this.identifier = identifier;
|
this.identifier = "%" + identifier + "%";
|
||||||
this.pattern = Pattern.compile(identifier);
|
this.pattern = PatternUtils.compileLiteral(identifier);
|
||||||
this.function = function;
|
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.
|
* @param player The player.
|
||||||
* @return The value.
|
* @return The value.
|
||||||
|
* @deprecated Use {@link #getValue(String, PlaceholderContext)} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getValue(@NotNull final Player player) {
|
public String getValue(@NotNull final Player player) {
|
||||||
return function.apply(player);
|
return Objects.requireNonNullElse(
|
||||||
|
function.apply(player),
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull String getIdentifier() {
|
public String tryTranslateQuickly(@NotNull final String text,
|
||||||
return this.identifier;
|
@NotNull final PlaceholderContext context) {
|
||||||
|
return StringUtils.replaceQuickly(
|
||||||
|
text,
|
||||||
|
this.identifier,
|
||||||
|
Objects.requireNonNullElse(
|
||||||
|
this.getValue(identifier, context),
|
||||||
|
""
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -70,11 +98,11 @@ public final class PlayerStaticPlaceholder implements InjectablePlaceholder {
|
|||||||
if (!(o instanceof PlayerStaticPlaceholder that)) {
|
if (!(o instanceof PlayerStaticPlaceholder that)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Objects.equals(this.getIdentifier(), that.getIdentifier());
|
return Objects.equals(this.getPattern(), that.getPattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(this.getIdentifier());
|
return Objects.hash(this.getPattern());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.willfp.eco.core.placeholder;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
import com.willfp.eco.core.EcoPlugin;
|
import com.willfp.eco.core.EcoPlugin;
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
|
import com.willfp.eco.util.PatternUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -10,31 +11,26 @@ import java.util.function.Supplier;
|
|||||||
import java.util.regex.Pattern;
|
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.
|
* The arguments pattern.
|
||||||
*/
|
|
||||||
private final String identifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The placeholder pattern.
|
|
||||||
*/
|
*/
|
||||||
private final Pattern 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;
|
private final EcoPlugin plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new player placeholder.
|
* Create a new player arguments.
|
||||||
*
|
*
|
||||||
* @param plugin The plugin.
|
* @param plugin The plugin.
|
||||||
* @param identifier The identifier.
|
* @param identifier The identifier.
|
||||||
@@ -42,30 +38,31 @@ public final class PlayerlessPlaceholder implements Placeholder {
|
|||||||
*/
|
*/
|
||||||
public PlayerlessPlaceholder(@NotNull final EcoPlugin plugin,
|
public PlayerlessPlaceholder(@NotNull final EcoPlugin plugin,
|
||||||
@NotNull final String identifier,
|
@NotNull final String identifier,
|
||||||
@NotNull final Supplier<String> function) {
|
@NotNull final Supplier<@Nullable String> function) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.identifier = identifier;
|
this.pattern = PatternUtils.compileLiteral(identifier);
|
||||||
this.pattern = Pattern.compile(identifier);
|
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the value of the placeholder.
|
public @Nullable String getValue(@NotNull final String args,
|
||||||
*
|
@NotNull final PlaceholderContext context) {
|
||||||
* @return The value.
|
|
||||||
*/
|
|
||||||
public String getValue() {
|
|
||||||
return function.get();
|
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() {
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
PlaceholderManager.registerPlaceholder(this);
|
@NotNull
|
||||||
return this;
|
public String getValue() {
|
||||||
|
return Objects.requireNonNullElse(
|
||||||
|
this.function.get(),
|
||||||
|
""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,17 +70,17 @@ public final class PlayerlessPlaceholder implements Placeholder {
|
|||||||
return this.plugin;
|
return this.plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull String getIdentifier() {
|
|
||||||
return this.identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Pattern getPattern() {
|
public Pattern getPattern() {
|
||||||
return this.pattern;
|
return this.pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull PlayerlessPlaceholder register() {
|
||||||
|
return (PlayerlessPlaceholder) RegistrablePlaceholder.super.register();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable final Object o) {
|
public boolean equals(@Nullable final Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
@@ -92,12 +89,12 @@ public final class PlayerlessPlaceholder implements Placeholder {
|
|||||||
if (!(o instanceof PlayerlessPlaceholder that)) {
|
if (!(o instanceof PlayerlessPlaceholder that)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Objects.equals(this.getIdentifier(), that.getIdentifier())
|
return Objects.equals(this.getPattern(), that.getPattern())
|
||||||
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
&& Objects.equals(this.getPlugin(), that.getPlugin());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
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,8 @@
|
|||||||
package com.willfp.eco.core.placeholder;
|
package com.willfp.eco.core.placeholder;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
|
import com.willfp.eco.util.PatternUtils;
|
||||||
|
import com.willfp.eco.util.StringUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -8,50 +11,66 @@ import java.util.function.Supplier;
|
|||||||
import java.util.regex.Pattern;
|
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 {
|
public final class StaticPlaceholder implements InjectablePlaceholder {
|
||||||
/**
|
/**
|
||||||
* The name of the placeholder.
|
* The name of the arguments.
|
||||||
*/
|
*/
|
||||||
private final String identifier;
|
private final String identifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The placeholder pattern.
|
* The arguments pattern.
|
||||||
*/
|
*/
|
||||||
private final Pattern 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 identifier The identifier.
|
||||||
* @param function The function to retrieve the value.
|
* @param function The function to retrieve the value.
|
||||||
*/
|
*/
|
||||||
public StaticPlaceholder(@NotNull final String identifier,
|
public StaticPlaceholder(@NotNull final String identifier,
|
||||||
@NotNull final Supplier<String> function) {
|
@NotNull final Supplier<@Nullable String> function) {
|
||||||
this.identifier = identifier;
|
this.identifier = "%" + identifier + "%";
|
||||||
this.pattern = Pattern.compile(identifier);
|
this.pattern = PatternUtils.compileLiteral(identifier);
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Get the value of the placeholder.
|
public @Nullable String getValue(@NotNull final String args,
|
||||||
*
|
@NotNull final PlaceholderContext context) {
|
||||||
* @return The value.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
public String getValue() {
|
|
||||||
return function.get();
|
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
|
@Override
|
||||||
public @NotNull String getIdentifier() {
|
public String tryTranslateQuickly(@NotNull final String text,
|
||||||
return this.identifier;
|
@NotNull final PlaceholderContext context) {
|
||||||
|
return StringUtils.replaceQuickly(
|
||||||
|
text,
|
||||||
|
this.identifier,
|
||||||
|
Objects.requireNonNullElse(this.getValue(this.identifier, context), "")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -68,11 +87,11 @@ public final class StaticPlaceholder implements InjectablePlaceholder {
|
|||||||
if (!(o instanceof StaticPlaceholder that)) {
|
if (!(o instanceof StaticPlaceholder that)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Objects.equals(this.getIdentifier(), that.getIdentifier());
|
return Objects.equals(this.getPattern(), that.getPattern());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
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,73 @@
|
|||||||
|
package com.willfp.eco.core.placeholder.templates;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.InjectablePlaceholder;
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
|
import com.willfp.eco.util.PatternUtils;
|
||||||
|
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 = PatternUtils.compileLiteral(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,90 @@
|
|||||||
|
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 com.willfp.eco.util.PatternUtils;
|
||||||
|
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 = PatternUtils.compileLiteral(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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,8 @@
|
|||||||
package com.willfp.eco.core.price;
|
package com.willfp.eco.core.price;
|
||||||
|
|
||||||
|
import com.willfp.eco.core.Eco;
|
||||||
import com.willfp.eco.core.config.interfaces.Config;
|
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.price.impl.PriceFree;
|
||||||
import com.willfp.eco.core.serialization.ConfigDeserializer;
|
import com.willfp.eco.core.serialization.ConfigDeserializer;
|
||||||
import com.willfp.eco.util.NumberUtils;
|
import com.willfp.eco.util.NumberUtils;
|
||||||
@@ -158,17 +159,32 @@ public final class ConfiguredPrice implements Price {
|
|||||||
if (!(
|
if (!(
|
||||||
config.has("value")
|
config.has("value")
|
||||||
&& config.has("type")
|
&& config.has("type")
|
||||||
&& config.has("display")
|
|
||||||
)) {
|
)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String formatString = config.getString("display");
|
String formatString;
|
||||||
|
|
||||||
|
String langConfig = Eco.get().getEcoPlugin().getLangYml()
|
||||||
|
.getSubsections("price-display")
|
||||||
|
.stream()
|
||||||
|
.filter(section -> section.getString("type").equalsIgnoreCase(config.getString("type")))
|
||||||
|
.findFirst()
|
||||||
|
.map(section -> section.getString("display"))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (langConfig != null) {
|
||||||
|
formatString = langConfig;
|
||||||
|
} else if (config.has("display")) {
|
||||||
|
formatString = config.getString("display");
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Price price = Prices.create(
|
Price price = Prices.create(
|
||||||
config.getString("value"),
|
config.getString("value"),
|
||||||
config.getString("type"),
|
config.getString("type"),
|
||||||
MathContext.of(config)
|
PlaceholderContext.of(config)
|
||||||
);
|
);
|
||||||
|
|
||||||
return new ConfiguredPrice(price, formatString);
|
return new ConfiguredPrice(price, formatString);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.willfp.eco.core.price;
|
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.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@@ -10,7 +11,8 @@ import java.util.function.Function;
|
|||||||
/**
|
/**
|
||||||
* Create prices.
|
* Create prices.
|
||||||
* <p>
|
* <p>
|
||||||
* You must override one of the create methods.
|
* Override create(PlaceholderContext, PlaceholderContextSupplier), other methods
|
||||||
|
* are for backwards compatibility.
|
||||||
*/
|
*/
|
||||||
public interface PriceFactory {
|
public interface PriceFactory {
|
||||||
/**
|
/**
|
||||||
@@ -27,20 +29,38 @@ public interface PriceFactory {
|
|||||||
*
|
*
|
||||||
* @param value The value.
|
* @param value The value.
|
||||||
* @return The price.
|
* @return The price.
|
||||||
|
* @deprecated Use {@link #create(PlaceholderContext, PlaceholderContextSupplier)} instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
default @NotNull Price create(final double value) {
|
default @NotNull Price create(final double value) {
|
||||||
return create(MathContext.EMPTY, (ctx) -> value);
|
return create(PlaceholderContext.EMPTY, (ctx) -> value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the price.
|
* Create the price.
|
||||||
*
|
*
|
||||||
* @param baseContext The base MathContext.
|
* @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.
|
* @return The price.
|
||||||
*/
|
*/
|
||||||
default @NotNull Price create(@NotNull final MathContext baseContext,
|
@SuppressWarnings("removal")
|
||||||
@NotNull final Function<MathContext, Double> function) {
|
default @NotNull Price create(@NotNull final PlaceholderContext baseContext,
|
||||||
return create(function.apply(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.Items;
|
||||||
import com.willfp.eco.core.items.TestableItem;
|
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.PriceEconomy;
|
||||||
import com.willfp.eco.core.price.impl.PriceFree;
|
import com.willfp.eco.core.price.impl.PriceFree;
|
||||||
import com.willfp.eco.core.price.impl.PriceItem;
|
import com.willfp.eco.core.price.impl.PriceItem;
|
||||||
@@ -13,7 +14,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage prices.
|
* Class to manage prices.
|
||||||
@@ -48,7 +48,28 @@ public final class Prices {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static Price create(@NotNull final String expression,
|
public static Price create(@NotNull final String expression,
|
||||||
@Nullable final String priceName) {
|
@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
|
@NotNull
|
||||||
public static Price create(@NotNull final String expression,
|
public static Price create(@NotNull final String expression,
|
||||||
@Nullable final String priceName,
|
@Nullable final String priceName,
|
||||||
@NotNull final MathContext context) {
|
@NotNull final PlaceholderContext context) {
|
||||||
Function<MathContext, Double> function = (ctx) -> NumberUtils.evaluateExpression(
|
PlaceholderContextSupplier<Double> function = (ctx) -> NumberUtils.evaluateExpression(
|
||||||
expression,
|
expression,
|
||||||
ctx
|
ctx
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.willfp.eco.core.price.impl;
|
package com.willfp.eco.core.price.impl;
|
||||||
|
|
||||||
import com.willfp.eco.core.integrations.economy.EconomyManager;
|
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 com.willfp.eco.core.price.Price;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -18,12 +19,12 @@ public final class PriceEconomy implements Price {
|
|||||||
/**
|
/**
|
||||||
* The value of the 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.
|
* The multipliers.
|
||||||
@@ -36,7 +37,21 @@ public final class PriceEconomy implements Price {
|
|||||||
* @param value The value.
|
* @param value The value.
|
||||||
*/
|
*/
|
||||||
public PriceEconomy(final double 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 baseContext The base context.
|
||||||
* @param function The function.
|
* @param function The function.
|
||||||
*/
|
*/
|
||||||
public PriceEconomy(@NotNull final MathContext baseContext,
|
public PriceEconomy(@NotNull final PlaceholderContext baseContext,
|
||||||
@NotNull final Function<MathContext, Double> function) {
|
@NotNull final PlaceholderContextSupplier<Double> function) {
|
||||||
this.baseContext = baseContext;
|
this.baseContext = baseContext;
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
@@ -72,7 +87,7 @@ public final class PriceEconomy implements Price {
|
|||||||
@Override
|
@Override
|
||||||
public double getValue(@NotNull final Player player,
|
public double getValue(@NotNull final Player player,
|
||||||
final double multiplier) {
|
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
|
@Override
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package com.willfp.eco.core.price.impl;
|
|||||||
import com.willfp.eco.core.drops.DropQueue;
|
import com.willfp.eco.core.drops.DropQueue;
|
||||||
import com.willfp.eco.core.items.HashedItem;
|
import com.willfp.eco.core.items.HashedItem;
|
||||||
import com.willfp.eco.core.items.TestableItem;
|
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 com.willfp.eco.core.price.Price;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -20,14 +21,14 @@ import java.util.function.Function;
|
|||||||
*/
|
*/
|
||||||
public final class PriceItem implements Price {
|
public final class PriceItem implements Price {
|
||||||
/**
|
/**
|
||||||
* The base MathContext.
|
* The base PlaceholderContext.
|
||||||
*/
|
*/
|
||||||
private final MathContext baseContext;
|
private final PlaceholderContext baseContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of items.
|
* The amount of items.
|
||||||
*/
|
*/
|
||||||
private final Function<MathContext, Double> function;
|
private final PlaceholderContextSupplier<Double> function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The item.
|
* The item.
|
||||||
@@ -47,7 +48,23 @@ public final class PriceItem implements Price {
|
|||||||
*/
|
*/
|
||||||
public PriceItem(final int amount,
|
public PriceItem(final int amount,
|
||||||
@NotNull final TestableItem item) {
|
@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 function The function to get the amount of items to remove.
|
||||||
* @param item The item.
|
* @param item The item.
|
||||||
*/
|
*/
|
||||||
public PriceItem(@NotNull final MathContext baseContext,
|
public PriceItem(@NotNull final PlaceholderContext baseContext,
|
||||||
@NotNull final Function<MathContext, Double> function,
|
@NotNull final PlaceholderContextSupplier<Double> function,
|
||||||
@NotNull final TestableItem item) {
|
@NotNull final TestableItem item) {
|
||||||
this.baseContext = baseContext;
|
this.baseContext = baseContext;
|
||||||
this.function = function;
|
this.function = function;
|
||||||
@@ -137,7 +154,7 @@ public final class PriceItem implements Price {
|
|||||||
public double getValue(@NotNull final Player player,
|
public double getValue(@NotNull final Player player,
|
||||||
final double multiplier) {
|
final double multiplier) {
|
||||||
return Math.toIntExact(Math.round(
|
return Math.toIntExact(Math.round(
|
||||||
this.function.apply(MathContext.copyWithPlayer(baseContext, player))
|
this.function.get(baseContext.copyWithPlayer(player))
|
||||||
* getMultiplier(player) * multiplier
|
* getMultiplier(player) * multiplier
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ public final class ProxyConstants {
|
|||||||
"v1_18_R2",
|
"v1_18_R2",
|
||||||
"v1_19_R1",
|
"v1_19_R1",
|
||||||
"v1_19_R2",
|
"v1_19_R2",
|
||||||
"v1_19_R3"
|
"v1_19_R3",
|
||||||
|
"v1_20_R1"
|
||||||
);
|
);
|
||||||
|
|
||||||
private ProxyConstants() {
|
private ProxyConstants() {
|
||||||
|
|||||||
@@ -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.CraftingRecipe;
|
||||||
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
|
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
|
||||||
import com.willfp.eco.util.NamespacedKeyUtils;
|
import com.willfp.eco.util.NamespacedKeyUtils;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -127,8 +126,8 @@ public final class Recipes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (builder.isAir()) {
|
if (builder.isAir()) {
|
||||||
Bukkit.getLogger().warning("RECIPE ERROR! " + plugin.getName() + ":" + key + " consists only");
|
plugin.getLogger().warning("Crafting recipe " + plugin.getID() + ":" + key + " consists only");
|
||||||
Bukkit.getLogger().warning("of air or invalid items! Please change that or disable this recipe.");
|
plugin.getLogger().warning("of air or invalid items! It will not be registered.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,10 @@ public class Registry<T extends Registrable> implements Iterable<T> {
|
|||||||
* @param locker The locker.
|
* @param locker The locker.
|
||||||
*/
|
*/
|
||||||
public void lock(@Nullable final Object 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;
|
this.locker = locker;
|
||||||
isLocked = true;
|
isLocked = true;
|
||||||
}
|
}
|
||||||
@@ -162,6 +166,8 @@ public class Registry<T extends Registrable> implements Iterable<T> {
|
|||||||
if (this.locker != locker) {
|
if (this.locker != locker) {
|
||||||
throw new IllegalArgumentException("Cannot unlock registry!");
|
throw new IllegalArgumentException("Cannot unlock registry!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.locker = null;
|
||||||
isLocked = false;
|
isLocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.willfp.eco.util;
|
package com.willfp.eco.util;
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco;
|
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.AdditionalPlayer;
|
||||||
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
import com.willfp.eco.core.placeholder.PlaceholderInjectable;
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -13,6 +12,7 @@ import java.text.DecimalFormat;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ public final class NumberUtils {
|
|||||||
* @return The value of the expression, or zero if invalid.
|
* @return The value of the expression, or zero if invalid.
|
||||||
*/
|
*/
|
||||||
public static double evaluateExpression(@NotNull final String expression) {
|
public static double evaluateExpression(@NotNull final String expression) {
|
||||||
return evaluateExpression(expression, MathContext.EMPTY);
|
return evaluateExpression(expression, PlaceholderContext.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,7 +222,7 @@ public final class NumberUtils {
|
|||||||
*/
|
*/
|
||||||
public static double evaluateExpression(@NotNull final String expression,
|
public static double evaluateExpression(@NotNull final String expression,
|
||||||
@Nullable final Player player) {
|
@Nullable final Player player) {
|
||||||
return evaluateExpression(expression, player, PlaceholderManager.EMPTY_INJECTABLE);
|
return evaluateExpression(expression, player, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -230,12 +230,12 @@ public final class NumberUtils {
|
|||||||
*
|
*
|
||||||
* @param expression The expression.
|
* @param expression The expression.
|
||||||
* @param player The player.
|
* @param player The player.
|
||||||
* @param context The injectable placeholders.
|
* @param context The injectableContext placeholders.
|
||||||
* @return The value of the expression, or zero if invalid.
|
* @return The value of the expression, or zero if invalid.
|
||||||
*/
|
*/
|
||||||
public static double evaluateExpression(@NotNull final String expression,
|
public static double evaluateExpression(@NotNull final String expression,
|
||||||
@Nullable final Player player,
|
@Nullable final Player player,
|
||||||
@NotNull final PlaceholderInjectable context) {
|
@Nullable final PlaceholderInjectable context) {
|
||||||
return evaluateExpression(expression, player, context, new ArrayList<>());
|
return evaluateExpression(expression, player, context, new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,30 +244,65 @@ public final class NumberUtils {
|
|||||||
*
|
*
|
||||||
* @param expression The expression.
|
* @param expression The expression.
|
||||||
* @param player The player.
|
* @param player The player.
|
||||||
* @param context The injectable placeholders.
|
* @param context The injectableContext placeholders.
|
||||||
* @param additionalPlayers Additional players to parse placeholders for.
|
* @param additionalPlayers Additional players to parse placeholders for.
|
||||||
* @return The value of the expression, or zero if invalid.
|
* @return The value of the expression, or zero if invalid.
|
||||||
*/
|
*/
|
||||||
public static double evaluateExpression(@NotNull final String expression,
|
public static double evaluateExpression(@NotNull final String expression,
|
||||||
@Nullable final Player player,
|
@Nullable final Player player,
|
||||||
@NotNull final PlaceholderInjectable context,
|
@Nullable final PlaceholderInjectable context,
|
||||||
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
|
@NotNull final Collection<AdditionalPlayer> additionalPlayers) {
|
||||||
return Eco.get().evaluate(expression, new MathContext(
|
return evaluateExpression(
|
||||||
context,
|
expression,
|
||||||
player,
|
new PlaceholderContext(
|
||||||
additionalPlayers
|
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 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.
|
* @return The value of the expression, or zero if invalid.
|
||||||
*/
|
*/
|
||||||
public static double evaluateExpression(@NotNull final String expression,
|
public static double evaluateExpression(@NotNull final String expression,
|
||||||
@NotNull final MathContext context) {
|
@NotNull final PlaceholderContext context) {
|
||||||
|
return Objects.requireNonNullElse(
|
||||||
|
evaluateExpressionOrNull(expression, context),
|
||||||
|
0.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate an expression in a context.
|
||||||
|
*
|
||||||
|
* @param expression The expression.
|
||||||
|
* @param context The context.
|
||||||
|
* @return The value of the expression, or zero if invalid.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static Double evaluateExpressionOrNull(@NotNull final String expression,
|
||||||
|
@NotNull final PlaceholderContext context) {
|
||||||
return Eco.get().evaluate(expression, context);
|
return Eco.get().evaluate(expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
eco-api/src/main/java/com/willfp/eco/util/PatternUtils.java
Normal file
35
eco-api/src/main/java/com/willfp/eco/util/PatternUtils.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.util;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities / API methods for patterns.
|
||||||
|
*/
|
||||||
|
public final class PatternUtils {
|
||||||
|
/**
|
||||||
|
* Cache of compiled literal patterns.
|
||||||
|
*/
|
||||||
|
private static final Cache<String, Pattern> LITERAL_PATTERN_CACHE = Caffeine.newBuilder()
|
||||||
|
.expireAfterAccess(1, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile a literal pattern.
|
||||||
|
*
|
||||||
|
* @param pattern The pattern.
|
||||||
|
* @return The compiled pattern.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static Pattern compileLiteral(@NotNull final String pattern) {
|
||||||
|
return LITERAL_PATTERN_CACHE.get(pattern, (it) -> Pattern.compile(it, Pattern.LITERAL));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PatternUtils() {
|
||||||
|
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,10 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
import com.willfp.eco.core.Eco;
|
import com.willfp.eco.core.Eco;
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager;
|
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.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.format.TextDecoration;
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
@@ -200,6 +203,26 @@ public final class StringUtils {
|
|||||||
return translated;
|
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.
|
* Format a string.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -242,7 +265,7 @@ public final class StringUtils {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static String format(@NotNull final String message,
|
public static String format(@NotNull final String message,
|
||||||
@NotNull final FormatOption option) {
|
@NotNull final FormatOption option) {
|
||||||
return format(message, null, option);
|
return format(message, (Player) null, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -287,7 +310,7 @@ public final class StringUtils {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static Component formatToComponent(@NotNull final String message,
|
public static Component formatToComponent(@NotNull final String message,
|
||||||
@NotNull final FormatOption option) {
|
@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,
|
public static String format(@NotNull final String message,
|
||||||
@Nullable final Player player,
|
@Nullable final Player player,
|
||||||
@NotNull final FormatOption option) {
|
@NotNull final FormatOption option) {
|
||||||
String processedMessage = message;
|
|
||||||
if (option == FormatOption.WITH_PLACEHOLDERS) {
|
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);
|
return STRING_FORMAT_CACHE.get(processedMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,6 +736,177 @@ public final class StringUtils {
|
|||||||
return builder.toString();
|
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.
|
* Options for formatting.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package com.willfp.eco.core.map
|
|||||||
* @see ListMap
|
* @see ListMap
|
||||||
*/
|
*/
|
||||||
@Suppress("RedundantOverride")
|
@Suppress("RedundantOverride")
|
||||||
class MutableListMap<K : Any, V : Any> : ListMap<K, V>() {
|
class MutableListMap<K : Any, V> : ListMap<K, V>() {
|
||||||
/**
|
/**
|
||||||
* Override with enforced MutableList type.
|
* Override with enforced MutableList type.
|
||||||
*/
|
*/
|
||||||
@@ -18,7 +18,7 @@ class MutableListMap<K : Any, V : Any> : ListMap<K, V>() {
|
|||||||
/**
|
/**
|
||||||
* Override with enforced MutableList type.
|
* 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)
|
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) =
|
fun <K : Any, V : Any> defaultMap(defaultValue: V) =
|
||||||
DefaultMap<K, V>(defaultValue)
|
DefaultMap<K, V>(defaultValue)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see DefaultMap
|
||||||
|
*/
|
||||||
|
fun <K : Any, V : Any> defaultMap(defaultValue: () -> V) =
|
||||||
|
DefaultMap<K, V>(defaultValue())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ListMap
|
* @see ListMap
|
||||||
*/
|
*/
|
||||||
@@ -38,11 +44,13 @@ fun <K : Any, V : Any> listMap() =
|
|||||||
/**
|
/**
|
||||||
* @see DefaultMap.createNestedMap
|
* @see DefaultMap.createNestedMap
|
||||||
*/
|
*/
|
||||||
fun <K : Any, K1 : Any, V : Any> nestedMap() =
|
fun <K : Any, K1 : Any, V> nestedMap() =
|
||||||
DefaultMap.createNestedMap<K, K1, V>()
|
DefaultMap.createNestedMap<K, K1, V>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see DefaultMap.createNestedListMap
|
* @see DefaultMap.createNestedListMap
|
||||||
*/
|
*/
|
||||||
fun <K : Any, K1 : Any, V : Any> nestedListMap() =
|
fun <K : Any, K1 : Any, V> nestedListMap() =
|
||||||
DefaultMap<K, MutableListMap<K1, V>>(MutableListMap())
|
DefaultMap<K, MutableListMap<K1, V>>() {
|
||||||
|
MutableListMap()
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
@file:JvmName("PlaceholderExtensions")
|
||||||
|
|
||||||
|
package com.willfp.eco.core.placeholder
|
||||||
|
|
||||||
|
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||||
|
|
||||||
|
/** @see PlaceholderManager.translatePlaceholders */
|
||||||
|
fun String.translatePlaceholders(context: PlaceholderContext) =
|
||||||
|
PlaceholderManager.translatePlaceholders(this, context)
|
||||||
|
|
||||||
|
/** @see PlaceholderManager.findPlaceholdersIn */
|
||||||
|
fun String.findPlaceholders(): List<String> =
|
||||||
|
PlaceholderManager.findPlaceholdersIn(this)
|
||||||
@@ -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)
|
||||||
@@ -15,5 +15,5 @@ fun <T> create2DList(rows: Int, columns: Int): MutableList<MutableList<T>> =
|
|||||||
ListUtils.create2DList(rows, columns)
|
ListUtils.create2DList(rows, columns)
|
||||||
|
|
||||||
/** @see ListUtils.toSingletonList */
|
/** @see ListUtils.toSingletonList */
|
||||||
fun <T> T.toSingletonList(): List<T> =
|
fun <T> T?.toSingletonList(): List<T> =
|
||||||
ListUtils.toSingletonList(this)
|
ListUtils.toSingletonList(this)
|
||||||
|
|||||||
@@ -2,6 +2,36 @@
|
|||||||
|
|
||||||
package com.willfp.eco.util
|
package com.willfp.eco.util
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||||
|
|
||||||
/** @see NumberUtils.toNumeral */
|
/** @see NumberUtils.toNumeral */
|
||||||
fun Number.toNumeral(): String =
|
fun Number.toNumeral(): String =
|
||||||
NumberUtils.toNumeral(this.toInt())
|
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)
|
||||||
|
|
||||||
|
/** @see NumberUtils.evaluateExpressionOrNull */
|
||||||
|
fun evaluateExpressionOrNull(expression: String, context: PlaceholderContext) =
|
||||||
|
NumberUtils.evaluateExpressionOrNull(expression, context)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
package com.willfp.eco.util
|
package com.willfp.eco.util
|
||||||
|
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
@@ -31,6 +32,14 @@ fun String.formatEco(
|
|||||||
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
|
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 */
|
/** @see StringUtils.formatList */
|
||||||
fun List<String>.formatEco(
|
fun List<String>.formatEco(
|
||||||
player: Player? = null,
|
player: Player? = null,
|
||||||
@@ -41,6 +50,14 @@ fun List<String>.formatEco(
|
|||||||
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
|
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 */
|
/** @see StringUtils.splitAround */
|
||||||
fun String.splitAround(separator: String): Array<String> =
|
fun String.splitAround(separator: String): Array<String> =
|
||||||
StringUtils.splitAround(this, separator)
|
StringUtils.splitAround(this, separator)
|
||||||
@@ -48,3 +65,19 @@ fun String.splitAround(separator: String): Array<String> =
|
|||||||
/** @see StringUtils.toNiceString */
|
/** @see StringUtils.toNiceString */
|
||||||
fun Any?.toNiceString(): String =
|
fun Any?.toNiceString(): String =
|
||||||
StringUtils.toNiceString(this)
|
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(
|
class DelegatedBukkitCommand(
|
||||||
private val delegate: EcoPluginCommand
|
private val delegate: EcoPluginCommand
|
||||||
) : Command(delegate.name), TabCompleter, PluginIdentifiableCommand {
|
) : Command(
|
||||||
private var _aliases: List<String>? = null
|
delegate.name,
|
||||||
private var _description: String? = null
|
delegate.description ?: "",
|
||||||
|
"/${delegate.name}",
|
||||||
|
delegate.aliases
|
||||||
|
), TabCompleter, PluginIdentifiableCommand {
|
||||||
override fun execute(sender: CommandSender, label: String, args: Array<out String>?): Boolean {
|
override fun execute(sender: CommandSender, label: String, args: Array<out String>?): Boolean {
|
||||||
return delegate.onCommand(sender, this, label, args)
|
return delegate.onCommand(sender, this, label, args)
|
||||||
}
|
}
|
||||||
@@ -36,16 +38,4 @@ class DelegatedBukkitCommand(
|
|||||||
|
|
||||||
override fun getPlugin() = delegate.plugin
|
override fun getPlugin() = delegate.plugin
|
||||||
override fun getPermission() = delegate.permission
|
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
|
import org.bukkit.Bukkit
|
||||||
|
|
||||||
class EcoPluginCommand(
|
class EcoPluginCommand(
|
||||||
parentDelegate: CommandBase,
|
private val parentDelegate: PluginCommandBase,
|
||||||
plugin: EcoPlugin,
|
plugin: EcoPlugin,
|
||||||
name: String,
|
name: String,
|
||||||
permission: String,
|
permission: String,
|
||||||
@@ -39,6 +39,9 @@ class EcoPluginCommand(
|
|||||||
|
|
||||||
Eco.get().syncCommands()
|
Eco.get().syncCommands()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAliases(): List<String> = parentDelegate.aliases
|
||||||
|
override fun getDescription(): String? = parentDelegate.description
|
||||||
}
|
}
|
||||||
|
|
||||||
class EcoSubcommand(
|
class EcoSubcommand(
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ internal fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
|
|||||||
this.toMutableList()
|
this.toMutableList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is Float -> this.toDouble() // Should prevent !!float from being written
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package com.willfp.eco.internal.config
|
|||||||
import com.willfp.eco.core.config.ConfigType
|
import com.willfp.eco.core.config.ConfigType
|
||||||
import com.willfp.eco.core.config.interfaces.Config
|
import com.willfp.eco.core.config.interfaces.Config
|
||||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder
|
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 com.willfp.eco.util.StringUtils
|
||||||
import org.bukkit.configuration.file.YamlConfiguration
|
import org.bukkit.configuration.file.YamlConfiguration
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@@ -141,9 +142,7 @@ open class EcoConfig(
|
|||||||
var string = get(path)?.toString() ?: return null
|
var string = get(path)?.toString() ?: return null
|
||||||
if (format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
|
if (format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
|
||||||
for (injection in placeholderInjections) {
|
for (injection in placeholderInjections) {
|
||||||
if (injection is StaticPlaceholder) {
|
string = injection.tryTranslateQuickly(string, PlaceholderContext.EMPTY)
|
||||||
string = string.replace("%${injection.identifier}%", injection.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return if (format) StringUtils.format(string, option) else string
|
return if (format) StringUtils.format(string, option) else string
|
||||||
@@ -161,9 +160,7 @@ open class EcoConfig(
|
|||||||
strings.replaceAll {
|
strings.replaceAll {
|
||||||
var string = it
|
var string = it
|
||||||
for (injection in placeholderInjections) {
|
for (injection in placeholderInjections) {
|
||||||
if (injection is StaticPlaceholder) {
|
string = injection.tryTranslateQuickly(string, PlaceholderContext.EMPTY)
|
||||||
string = string.replace("%${injection.identifier}%", injection.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
string
|
string
|
||||||
}
|
}
|
||||||
@@ -181,12 +178,12 @@ open class EcoConfig(
|
|||||||
|
|
||||||
override fun addInjectablePlaceholder(placeholders: Iterable<InjectablePlaceholder>) {
|
override fun addInjectablePlaceholder(placeholders: Iterable<InjectablePlaceholder>) {
|
||||||
for (placeholder in placeholders) {
|
for (placeholder in placeholders) {
|
||||||
injections[placeholder.identifier] = placeholder
|
injections[placeholder.pattern.pattern()] = placeholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPlaceholderInjections(): List<InjectablePlaceholder> {
|
override fun getPlaceholderInjections(): List<InjectablePlaceholder> {
|
||||||
return injections.values.toList()
|
return injections.values.listView() // Faster than .toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearInjectedPlaceholders() {
|
override fun clearInjectedPlaceholders() {
|
||||||
@@ -209,14 +206,6 @@ open class EcoConfig(
|
|||||||
return bukkit
|
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>? {
|
private inline fun <reified T> getList(path: String): List<T>? {
|
||||||
val asIterable = get(path) as? Iterable<*> ?: return null
|
val asIterable = get(path) as? Iterable<*> ?: return null
|
||||||
val asList = asIterable.toList()
|
val asList = asIterable.toList()
|
||||||
@@ -227,4 +216,44 @@ open class EcoConfig(
|
|||||||
|
|
||||||
return asList as List<T>
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap
|
|||||||
class EcoConfigSection(
|
class EcoConfigSection(
|
||||||
type: ConfigType,
|
type: ConfigType,
|
||||||
values: Map<String, Any?> = emptyMap(),
|
values: Map<String, Any?> = emptyMap(),
|
||||||
injections: MutableMap<String, InjectablePlaceholder> = mutableMapOf()
|
injections: Map<String, InjectablePlaceholder> = emptyMap()
|
||||||
) : EcoConfig(type) {
|
) : EcoConfig(type) {
|
||||||
init {
|
init {
|
||||||
this.init(values)
|
this.init(values)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.willfp.eco.internal.config
|
package com.willfp.eco.internal.config
|
||||||
|
|
||||||
import com.willfp.eco.core.config.interfaces.Config
|
import com.willfp.eco.core.config.interfaces.Config
|
||||||
|
import org.yaml.snakeyaml.DumperOptions
|
||||||
import org.yaml.snakeyaml.nodes.Node
|
import org.yaml.snakeyaml.nodes.Node
|
||||||
import org.yaml.snakeyaml.representer.Represent
|
import org.yaml.snakeyaml.representer.Represent
|
||||||
import org.yaml.snakeyaml.representer.Representer
|
import org.yaml.snakeyaml.representer.Representer
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
class EcoRepresenter : Representer(DumperOptions()) {
|
||||||
class EcoRepresenter : Representer() {
|
|
||||||
init {
|
init {
|
||||||
multiRepresenters[Config::class.java] = RepresentConfig(multiRepresenters[Map::class.java]!!)
|
multiRepresenters[Config::class.java] = RepresentConfig(multiRepresenters[Map::class.java]!!)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,15 @@ private val listeners = mutableMapOf<PacketPriority, MutableList<RegisteredPacke
|
|||||||
fun PacketEvent.handleSend() {
|
fun PacketEvent.handleSend() {
|
||||||
for (priority in PacketPriority.values()) {
|
for (priority in PacketPriority.values()) {
|
||||||
for (listener in listeners[priority] ?: continue) {
|
for (listener in listeners[priority] ?: continue) {
|
||||||
listener.listener.onSend(this)
|
try {
|
||||||
|
listener.listener.onSend(this)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
listener.plugin.logger.warning(
|
||||||
|
"Exception in packet listener ${listener.listener.javaClass.name}" +
|
||||||
|
" for packet ${packet.handle.javaClass.name}!"
|
||||||
|
)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +36,15 @@ fun PacketEvent.handleSend() {
|
|||||||
fun PacketEvent.handleReceive() {
|
fun PacketEvent.handleReceive() {
|
||||||
for (priority in PacketPriority.values()) {
|
for (priority in PacketPriority.values()) {
|
||||||
for (listener in listeners[priority] ?: continue) {
|
for (listener in listeners[priority] ?: continue) {
|
||||||
listener.listener.onReceive(this)
|
try {
|
||||||
|
listener.listener.onReceive(this)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
listener.plugin.logger.warning(
|
||||||
|
"Exception in packet listener ${listener.listener.javaClass.name}" +
|
||||||
|
" for packet ${packet.handle.javaClass.name}!"
|
||||||
|
)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import com.willfp.eco.core.Eco
|
|||||||
import com.willfp.eco.core.EcoPlugin
|
import com.willfp.eco.core.EcoPlugin
|
||||||
import com.willfp.eco.core.config.toConfig
|
import com.willfp.eco.core.config.toConfig
|
||||||
import com.willfp.eco.core.extensions.Extension
|
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.ExtensionLoader
|
||||||
import com.willfp.eco.core.extensions.ExtensionMetadata
|
import com.willfp.eco.core.extensions.ExtensionMetadata
|
||||||
import com.willfp.eco.core.extensions.MalformedExtensionException
|
import com.willfp.eco.core.extensions.MalformedExtensionException
|
||||||
|
import com.willfp.eco.core.version.Version
|
||||||
import org.bukkit.configuration.file.YamlConfiguration
|
import org.bukkit.configuration.file.YamlConfiguration
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
@@ -32,7 +34,7 @@ class EcoExtensionLoader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
runCatching { loadExtension(extensionJar) }.onFailure {
|
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")) {
|
if (Eco.get().ecoPlugin.configYml.getBool("log-full-extension-errors")) {
|
||||||
it.printStackTrace()
|
it.printStackTrace()
|
||||||
}
|
}
|
||||||
@@ -54,7 +56,12 @@ class EcoExtensionLoader(
|
|||||||
var name = extensionYml.getStringOrNull("name")
|
var name = extensionYml.getStringOrNull("name")
|
||||||
var version = extensionYml.getStringOrNull("version")
|
var version = extensionYml.getStringOrNull("version")
|
||||||
var author = extensionYml.getStringOrNull("author")
|
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) {
|
if (mainClass == null) {
|
||||||
throw MalformedExtensionException("Invalid extension.yml found in " + extensionJar.name)
|
throw MalformedExtensionException("Invalid extension.yml found in " + extensionJar.name)
|
||||||
@@ -75,7 +82,11 @@ class EcoExtensionLoader(
|
|||||||
author = "Unnamed Author"
|
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 cls: Class<*> = classLoader.loadClass(mainClass)
|
||||||
val extension: Extension = cls.getConstructor(EcoPlugin::class.java).newInstance(this.plugin) as Extension
|
val extension: Extension = cls.getConstructor(EcoPlugin::class.java).newInstance(this.plugin) as Extension
|
||||||
@@ -85,7 +96,7 @@ class EcoExtensionLoader(
|
|||||||
extensions[extension] = classLoader
|
extensions[extension] = classLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLoadedExtensions(): MutableSet<Extension> {
|
override fun getLoadedExtensions(): Set<Extension> {
|
||||||
return ImmutableSet.copyOf(extensions.keys)
|
return ImmutableSet.copyOf(extensions.keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,4 +108,4 @@ class EcoExtensionLoader(
|
|||||||
|
|
||||||
extensions.clear()
|
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 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.SlotHandler
|
||||||
import com.willfp.eco.core.gui.slot.functional.SlotProvider
|
import com.willfp.eco.core.gui.slot.functional.SlotProvider
|
||||||
import com.willfp.eco.core.gui.slot.functional.SlotUpdater
|
import com.willfp.eco.core.gui.slot.functional.SlotUpdater
|
||||||
|
import com.willfp.eco.core.map.listMap
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.inventory.ClickType
|
import org.bukkit.event.inventory.ClickType
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
@@ -15,14 +16,14 @@ class EcoSlotBuilder(private val provider: SlotProvider) : SlotBuilder {
|
|||||||
private var captiveFromEmpty = false
|
private var captiveFromEmpty = false
|
||||||
private var updater: SlotUpdater = SlotUpdater { player, menu, _ -> provider.provide(player, menu) }
|
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 =
|
private var captiveFilter =
|
||||||
CaptiveFilter { _, _, _ -> true }
|
CaptiveFilter { _, _, _ -> true }
|
||||||
private var notCaptiveFor: (Player) -> Boolean = { _ -> false}
|
private var notCaptiveFor: (Player) -> Boolean = { _ -> false}
|
||||||
|
|
||||||
override fun onClick(type: ClickType, action: SlotHandler): SlotBuilder {
|
override fun onClick(type: ClickType, action: SlotHandler): SlotBuilder {
|
||||||
handlers.computeIfAbsent(type) { mutableListOf() } += action
|
handlers[type] += action
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.willfp.eco.internal.integrations
|
|||||||
|
|
||||||
import com.willfp.eco.core.EcoPlugin
|
import com.willfp.eco.core.EcoPlugin
|
||||||
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
|
||||||
|
import com.willfp.eco.core.placeholder.context.placeholderContext
|
||||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion
|
import me.clip.placeholderapi.expansion.PlaceholderExpansion
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
@@ -33,7 +34,19 @@ class PAPIExpansion(private val plugin: EcoPlugin) : PlaceholderExpansion() {
|
|||||||
override fun onPlaceholderRequest(
|
override fun onPlaceholderRequest(
|
||||||
player: Player?,
|
player: Player?,
|
||||||
identifier: String
|
identifier: String
|
||||||
): String {
|
): String? {
|
||||||
return PlaceholderManager.getResult(player, identifier, plugin)
|
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,53 @@
|
|||||||
|
package com.willfp.eco.internal.items
|
||||||
|
|
||||||
|
import com.willfp.eco.core.items.args.LookupArgParser
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta
|
||||||
|
import java.util.function.Predicate
|
||||||
|
|
||||||
|
object ArgParserHead : LookupArgParser {
|
||||||
|
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
|
||||||
|
if (meta !is SkullMeta) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
var playerName: String? = null
|
||||||
|
|
||||||
|
for (arg in args) {
|
||||||
|
val argSplit = arg.split(":")
|
||||||
|
if (!argSplit[0].equals("head", ignoreCase = true)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (argSplit.size < 2) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
playerName = argSplit[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
playerName ?: return null
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val player = Bukkit.getOfflinePlayer(playerName)
|
||||||
|
|
||||||
|
meta.owningPlayer = player
|
||||||
|
|
||||||
|
return Predicate {
|
||||||
|
val testMeta = it.itemMeta as? SkullMeta ?: return@Predicate false
|
||||||
|
testMeta.owningPlayer?.uniqueId == player.uniqueId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serializeBack(meta: ItemMeta): String? {
|
||||||
|
if (meta !is SkullMeta) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta.owningPlayer == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return "head:${meta.owningPlayer?.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,65 @@
|
|||||||
|
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 com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||||
|
import com.willfp.eco.core.placeholder.templates.SimpleInjectablePlaceholder
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
A set of global placeholders that are always available.
|
||||||
|
|
||||||
|
*/
|
||||||
|
private val globalPlaceholders = setOf<Placeholder>(
|
||||||
|
object : SimpleInjectablePlaceholder("player") {
|
||||||
|
override fun getValue(args: String, context: PlaceholderContext): String? {
|
||||||
|
return context.player?.name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (placeholder in globalPlaceholders) {
|
||||||
|
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,207 @@
|
|||||||
|
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.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, 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) {
|
||||||
|
it.findMatchingPlaceholder()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
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.Price
|
||||||
import com.willfp.eco.core.price.PriceFactory
|
import com.willfp.eco.core.price.PriceFactory
|
||||||
import com.willfp.eco.core.price.impl.PriceEconomy
|
import com.willfp.eco.core.price.impl.PriceEconomy
|
||||||
import java.util.function.Function
|
|
||||||
|
|
||||||
object PriceFactoryEconomy : PriceFactory {
|
object PriceFactoryEconomy : PriceFactory {
|
||||||
override fun getNames() = listOf(
|
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)
|
return PriceEconomy(baseContext, function)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.willfp.eco.internal.price
|
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.Price
|
||||||
import com.willfp.eco.core.price.PriceFactory
|
import com.willfp.eco.core.price.PriceFactory
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.function.Function
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
object PriceFactoryXP : PriceFactory {
|
object PriceFactoryXP : PriceFactory {
|
||||||
@@ -15,13 +15,13 @@ object PriceFactoryXP : PriceFactory {
|
|||||||
"experience"
|
"experience"
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
|
override fun create(baseContext: PlaceholderContext, function: PlaceholderContextSupplier<Double>): Price {
|
||||||
return PriceXP(baseContext) { function.apply(it).roundToInt() }
|
return PriceXP(baseContext) { function.get(it).roundToInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PriceXP(
|
private class PriceXP(
|
||||||
private val baseContext: MathContext,
|
private val baseContext: PlaceholderContext,
|
||||||
private val xp: (MathContext) -> Int
|
private val xp: (PlaceholderContext) -> Int
|
||||||
) : Price {
|
) : Price {
|
||||||
private val multipliers = mutableMapOf<UUID, Double>()
|
private val multipliers = mutableMapOf<UUID, Double>()
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ object PriceFactoryXP : PriceFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getValue(player: Player, multiplier: Double): Double {
|
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 {
|
override fun getMultiplier(player: Player): Double {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.willfp.eco.internal.price
|
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.Price
|
||||||
import com.willfp.eco.core.price.PriceFactory
|
import com.willfp.eco.core.price.PriceFactory
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.function.Function
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
object PriceFactoryXPLevels : PriceFactory {
|
object PriceFactoryXPLevels : PriceFactory {
|
||||||
@@ -16,13 +16,13 @@ object PriceFactoryXPLevels : PriceFactory {
|
|||||||
"explevels",
|
"explevels",
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
|
override fun create(baseContext: PlaceholderContext, function: PlaceholderContextSupplier<Double>): Price {
|
||||||
return PriceXPLevel(baseContext) { function.apply(it).roundToInt() }
|
return PriceXPLevel(baseContext) { function.get(it).roundToInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PriceXPLevel(
|
private class PriceXPLevel(
|
||||||
private val baseContext: MathContext,
|
private val baseContext: PlaceholderContext,
|
||||||
private val level: (MathContext) -> Int
|
private val level: (PlaceholderContext) -> Int
|
||||||
) : Price {
|
) : Price {
|
||||||
private val multipliers = mutableMapOf<UUID, Double>()
|
private val multipliers = mutableMapOf<UUID, Double>()
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ object PriceFactoryXPLevels : PriceFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getValue(player: Player, multiplier: Double): Double {
|
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 {
|
override fun getMultiplier(player: Player): Double {
|
||||||
|
|||||||
39
eco-core/core-nms/v1_20_R1/build.gradle.kts
Normal file
39
eco-core/core-nms/v1_20_R1/build.gradle.kts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
plugins {
|
||||||
|
id("io.papermc.paperweight.userdev")
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "com.willfp"
|
||||||
|
version = rootProject.version
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":eco-core:core-nms:nms-common"))
|
||||||
|
paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
|
implementation("net.kyori:adventure-text-minimessage:4.11.0") {
|
||||||
|
version {
|
||||||
|
strictly("4.11.0")
|
||||||
|
}
|
||||||
|
exclude(group = "net.kyori", module = "adventure-api")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
build {
|
||||||
|
dependsOn(reobfJar)
|
||||||
|
}
|
||||||
|
|
||||||
|
reobfJar {
|
||||||
|
mustRunAfter(shadowJar)
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
relocate(
|
||||||
|
"com.willfp.eco.internal.spigot.proxy.common",
|
||||||
|
"com.willfp.eco.internal.spigot.proxy.v1_20_R1.common"
|
||||||
|
)
|
||||||
|
relocate(
|
||||||
|
"net.kyori.adventure.text.minimessage",
|
||||||
|
"com.willfp.eco.internal.spigot.proxy.v1_20_R1.minimessage"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.core.command.PluginCommandBase
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.BukkitCommandsProxy
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.command.Command
|
||||||
|
import org.bukkit.command.SimpleCommandMap
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.CraftServer
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
|
class BukkitCommands : BukkitCommandsProxy {
|
||||||
|
private val knownCommandsField: Field by lazy {
|
||||||
|
SimpleCommandMap::class.java.getDeclaredField("knownCommands")
|
||||||
|
.apply {
|
||||||
|
isAccessible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private val knownCommands: MutableMap<String, Command>
|
||||||
|
get() = knownCommandsField.get(getCommandMap()) as MutableMap<String, Command>
|
||||||
|
|
||||||
|
override fun getCommandMap(): SimpleCommandMap {
|
||||||
|
return (Bukkit.getServer() as CraftServer).commandMap
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun syncCommands() {
|
||||||
|
(Bukkit.getServer() as CraftServer).syncCommands()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unregisterCommand(command: PluginCommandBase) {
|
||||||
|
knownCommands.remove(command.name)
|
||||||
|
knownCommands.remove("${command.plugin.name.lowercase()}:${command.name}")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.core.EcoPlugin
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.CommonsProvider
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.PacketInjectorListener
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.toResourceLocation
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.nbt.Tag
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import net.minecraft.server.level.ServerPlayer
|
||||||
|
import net.minecraft.world.entity.PathfinderMob
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.CraftServer
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftMob
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.persistence.CraftPersistentDataContainer
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.persistence.CraftPersistentDataTypeRegistry
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.util.CraftMagicNumbers
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.util.CraftNamespacedKey
|
||||||
|
import org.bukkit.entity.LivingEntity
|
||||||
|
import org.bukkit.entity.Mob
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
|
class CommonsInitializer : CommonsInitializerProxy {
|
||||||
|
override fun init(plugin: EcoPlugin) {
|
||||||
|
CommonsProvider.setIfNeeded(CommonsProviderImpl)
|
||||||
|
plugin.onEnable {
|
||||||
|
plugin.eventManager.registerListener(PacketInjectorListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CommonsProviderImpl : CommonsProvider {
|
||||||
|
private val cisHandle: Field = CraftItemStack::class.java.getDeclaredField("handle").apply {
|
||||||
|
isAccessible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_20_R1.inventory.CraftMetaItem")
|
||||||
|
.getDeclaredField("DATA_TYPE_REGISTRY")
|
||||||
|
.apply { isAccessible = true }
|
||||||
|
.get(null) as CraftPersistentDataTypeRegistry
|
||||||
|
|
||||||
|
override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING
|
||||||
|
|
||||||
|
override fun toPathfinderMob(mob: Mob): PathfinderMob? {
|
||||||
|
val craft = mob as? CraftMob ?: return null
|
||||||
|
return craft.handle as? PathfinderMob
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toResourceLocation(namespacedKey: NamespacedKey): ResourceLocation =
|
||||||
|
CraftNamespacedKey.toMinecraft(namespacedKey)
|
||||||
|
|
||||||
|
override fun asNMSStack(itemStack: ItemStack): net.minecraft.world.item.ItemStack {
|
||||||
|
return if (itemStack !is CraftItemStack) {
|
||||||
|
CraftItemStack.asNMSCopy(itemStack)
|
||||||
|
} else {
|
||||||
|
cisHandle[itemStack] as net.minecraft.world.item.ItemStack? ?: CraftItemStack.asNMSCopy(itemStack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun asBukkitStack(itemStack: net.minecraft.world.item.ItemStack): ItemStack {
|
||||||
|
return CraftItemStack.asCraftMirror(itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mergeIfNeeded(itemStack: ItemStack, nmsStack: net.minecraft.world.item.ItemStack) {
|
||||||
|
if (itemStack !is CraftItemStack) {
|
||||||
|
itemStack.itemMeta = CraftItemStack.asCraftMirror(nmsStack).itemMeta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? =
|
||||||
|
CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity
|
||||||
|
|
||||||
|
override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer {
|
||||||
|
fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry)
|
||||||
|
|
||||||
|
fun CompoundTag?.toPdc(): PersistentDataContainer {
|
||||||
|
val pdc = emptyPdc()
|
||||||
|
this ?: return pdc
|
||||||
|
val keys = this.allKeys
|
||||||
|
for (key in keys) {
|
||||||
|
pdc.put(key, this[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdc
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (base) {
|
||||||
|
tag.toPdc()
|
||||||
|
} else {
|
||||||
|
if (tag.contains("PublicBukkitValues")) {
|
||||||
|
tag.getCompound("PublicBukkitValues").toPdc()
|
||||||
|
} else {
|
||||||
|
emptyPdc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setPdc(
|
||||||
|
tag: CompoundTag,
|
||||||
|
pdc: PersistentDataContainer?,
|
||||||
|
item: net.minecraft.world.item.ItemStack?
|
||||||
|
) {
|
||||||
|
fun CraftPersistentDataContainer.toTag(): CompoundTag {
|
||||||
|
val compound = CompoundTag()
|
||||||
|
val rawPublicMap: Map<String, Tag> = this.raw
|
||||||
|
for ((key, value) in rawPublicMap) {
|
||||||
|
compound.put(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return compound
|
||||||
|
}
|
||||||
|
|
||||||
|
val container = when (pdc) {
|
||||||
|
is CraftPersistentDataContainer? -> pdc
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
if (container != null && !container.isEmpty) {
|
||||||
|
for (key in tag.allKeys.toSet()) {
|
||||||
|
tag.remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.merge(container.toTag())
|
||||||
|
} else {
|
||||||
|
item.tag = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (container != null && !container.isEmpty) {
|
||||||
|
tag.put("PublicBukkitValues", container.toTag())
|
||||||
|
} else {
|
||||||
|
tag.remove("PublicBukkitValues")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun materialToItem(material: Material): Item =
|
||||||
|
BuiltInRegistries.ITEM.getOptional(material.key.toResourceLocation())
|
||||||
|
.orElseThrow { IllegalArgumentException("Material is not item!") }
|
||||||
|
|
||||||
|
override fun itemToMaterial(item: Item) =
|
||||||
|
Material.getMaterial(BuiltInRegistries.ITEM.getKey(item).path.uppercase())
|
||||||
|
?: throw IllegalArgumentException("Invalid material!")
|
||||||
|
|
||||||
|
override fun toNMS(player: Player): ServerPlayer {
|
||||||
|
return (player as CraftPlayer).handle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.internal.entities.EcoDummyEntity
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld
|
||||||
|
import org.bukkit.entity.Entity
|
||||||
|
import org.bukkit.entity.EntityType
|
||||||
|
|
||||||
|
class DummyEntityFactory : DummyEntityFactoryProxy {
|
||||||
|
override fun createDummyEntity(location: Location): Entity {
|
||||||
|
val world = location.world as CraftWorld
|
||||||
|
@Suppress("UsePropertyAccessSyntax")
|
||||||
|
return EcoDummyEntity(world.createEntity(location, EntityType.ZOMBIE.entityClass).getBukkitEntity())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityController
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.v1_20_R1.entity.EcoEntityController
|
||||||
|
import org.bukkit.entity.Mob
|
||||||
|
|
||||||
|
class EntityControllerFactory : EntityControllerFactoryProxy {
|
||||||
|
override fun <T : Mob> createEntityController(entity: T): EntityController<T> {
|
||||||
|
return EcoEntityController(entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.core.data.ExtendedPersistentDataContainer
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy
|
||||||
|
import net.minecraft.nbt.Tag
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.persistence.CraftPersistentDataContainer
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.persistence.CraftPersistentDataTypeRegistry
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
|
||||||
|
class ExtendedPersistentDataContainerFactory : ExtendedPersistentDataContainerFactoryProxy {
|
||||||
|
private val registry: CraftPersistentDataTypeRegistry
|
||||||
|
|
||||||
|
init {
|
||||||
|
/*
|
||||||
|
Can't grab actual instance since it's in CraftMetaItem (which is package-private)
|
||||||
|
And getting it would mean more janky reflection
|
||||||
|
*/
|
||||||
|
val item = CraftItemStack.asCraftCopy(ItemStack(Material.STONE))
|
||||||
|
val pdc = item.itemMeta!!.persistentDataContainer
|
||||||
|
this.registry = CraftPersistentDataContainer::class.java.getDeclaredField("registry")
|
||||||
|
.apply { isAccessible = true }.get(pdc) as CraftPersistentDataTypeRegistry
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer {
|
||||||
|
return when (pdc) {
|
||||||
|
is CraftPersistentDataContainer -> EcoPersistentDataContainer(pdc)
|
||||||
|
else -> throw IllegalArgumentException("Custom PDC instance ims not supported!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newPdc(): PersistentDataContainer {
|
||||||
|
return CraftPersistentDataContainer(registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class EcoPersistentDataContainer(
|
||||||
|
private val handle: CraftPersistentDataContainer
|
||||||
|
) : ExtendedPersistentDataContainer {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private val customDataTags: MutableMap<String, Tag> =
|
||||||
|
CraftPersistentDataContainer::class.java.getDeclaredField("customDataTags")
|
||||||
|
.apply { isAccessible = true }.get(handle) as MutableMap<String, Tag>
|
||||||
|
|
||||||
|
override fun <T : Any, Z : Any> set(key: String, dataType: PersistentDataType<T, Z>, value: Z) {
|
||||||
|
customDataTags[key] =
|
||||||
|
registry.wrap(dataType.primitiveType, dataType.toPrimitive(value, handle.adapterContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any, Z : Any> has(key: String, dataType: PersistentDataType<T, Z>): Boolean {
|
||||||
|
val value = customDataTags[key] ?: return false
|
||||||
|
return registry.isInstanceOf(dataType.primitiveType, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any, Z : Any> get(key: String, dataType: PersistentDataType<T, Z>): Z? {
|
||||||
|
val value = customDataTags[key] ?: return null
|
||||||
|
return dataType.fromPrimitive(registry.extract(dataType.primitiveType, value), handle.adapterContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any, Z : Any> getOrDefault(
|
||||||
|
key: String,
|
||||||
|
dataType: PersistentDataType<T, Z>,
|
||||||
|
defaultValue: Z
|
||||||
|
): Z {
|
||||||
|
return get(key, dataType) ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(key: String) {
|
||||||
|
customDataTags.remove(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAllKeys(): MutableSet<String> {
|
||||||
|
return customDataTags.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getBase(): PersistentDataContainer {
|
||||||
|
return handle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.core.fast.FastItemStack
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.item.EcoFastItemStack
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
|
class FastItemStackFactory : FastItemStackFactoryProxy {
|
||||||
|
override fun create(itemStack: ItemStack): FastItemStack {
|
||||||
|
return EcoFastItemStack(itemStack)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.core.display.Display
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy
|
||||||
|
import com.willfp.eco.util.toLegacy
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage
|
||||||
|
|
||||||
|
class MiniMessageTranslator : MiniMessageTranslatorProxy {
|
||||||
|
override fun format(message: String): String {
|
||||||
|
var mut = message
|
||||||
|
|
||||||
|
val startsWithPrefix = mut.startsWith(Display.PREFIX)
|
||||||
|
if (startsWithPrefix) {
|
||||||
|
mut = mut.substring(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
mut = mut.replace('§', '&')
|
||||||
|
|
||||||
|
val miniMessage = runCatching {
|
||||||
|
MiniMessage.miniMessage().deserialize(
|
||||||
|
mut
|
||||||
|
).toLegacy()
|
||||||
|
}.getOrNull() ?: mut
|
||||||
|
|
||||||
|
mut = if (startsWithPrefix) {
|
||||||
|
Display.PREFIX + miniMessage
|
||||||
|
} else {
|
||||||
|
miniMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
return mut
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.core.EcoPlugin
|
||||||
|
import com.willfp.eco.core.packet.PacketListener
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketAutoRecipe
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketHeldItemSlot
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketOpenWindowMerchant
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetCreativeSlot
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketSetSlot
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.display.PacketWindowItems
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.packet.display.frame.clearFrames
|
||||||
|
import net.minecraft.network.protocol.Packet
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class PacketHandler : PacketHandlerProxy {
|
||||||
|
override fun sendPacket(player: Player, packet: com.willfp.eco.core.packet.Packet) {
|
||||||
|
if (player !is CraftPlayer) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val handle = packet.handle
|
||||||
|
|
||||||
|
if (handle !is Packet<*>) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
player.handle.connection.send(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearDisplayFrames() {
|
||||||
|
clearFrames()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPacketListeners(plugin: EcoPlugin): List<PacketListener> {
|
||||||
|
return listOf(
|
||||||
|
PacketAutoRecipe(plugin),
|
||||||
|
PacketHeldItemSlot,
|
||||||
|
PacketOpenWindowMerchant,
|
||||||
|
PacketSetCreativeSlot,
|
||||||
|
PacketSetSlot,
|
||||||
|
PacketWindowItems(plugin)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_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 net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.nbt.SnbtPrinterTagVisitor
|
||||||
|
import net.minecraft.nbt.TagParser
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
|
class SNBTConverter : SNBTConverterProxy {
|
||||||
|
override fun fromSNBT(snbt: String): ItemStack? {
|
||||||
|
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return null
|
||||||
|
val nms = net.minecraft.world.item.ItemStack.of(nbt)
|
||||||
|
return CraftItemStack.asBukkitCopy(nms)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toSNBT(itemStack: ItemStack): String {
|
||||||
|
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||||
|
return SnbtPrinterTagVisitor().visit(nms.save(CompoundTag()))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun makeSNBTTestable(snbt: String): TestableItem {
|
||||||
|
val nbt = runCatching { TagParser.parseTag(snbt) }.getOrNull() ?: return EmptyTestableItem()
|
||||||
|
val nms = net.minecraft.world.item.ItemStack.of(nbt)
|
||||||
|
if (nms == net.minecraft.world.item.ItemStack.EMPTY) {
|
||||||
|
return EmptyTestableItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
nbt.remove("Count")
|
||||||
|
return SNBTTestableItem(CraftItemStack.asBukkitCopy(nms), nbt)
|
||||||
|
}
|
||||||
|
|
||||||
|
class SNBTTestableItem(
|
||||||
|
private val item: ItemStack,
|
||||||
|
private val tag: CompoundTag
|
||||||
|
) : TestableItem {
|
||||||
|
override fun matches(itemStack: ItemStack?): Boolean {
|
||||||
|
if (itemStack == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val nms = CraftItemStack.asNMSCopy(itemStack)
|
||||||
|
val nmsTag = nms.save(CompoundTag())
|
||||||
|
nmsTag.remove("Count")
|
||||||
|
return tag.copy().merge(nmsTag) == nmsTag && itemStack.type == item.type
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItem(): ItemStack = item
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.SkullProxy
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.texture
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta
|
||||||
|
|
||||||
|
class Skull : SkullProxy {
|
||||||
|
override fun setSkullTexture(
|
||||||
|
meta: SkullMeta,
|
||||||
|
base64: String
|
||||||
|
) {
|
||||||
|
meta.texture = base64
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSkullTexture(
|
||||||
|
meta: SkullMeta
|
||||||
|
): String? = meta.texture
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
|
||||||
|
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.TPSProxy
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.CraftServer
|
||||||
|
|
||||||
|
class TPS : TPSProxy {
|
||||||
|
override fun getTPS(): Double {
|
||||||
|
return (Bukkit.getServer() as CraftServer).handle.server.recentTps[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package com.willfp.eco.internal.spigot.proxy.v1_20_R1.entity
|
||||||
|
|
||||||
|
import com.willfp.eco.core.entities.ai.CustomGoal
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityController
|
||||||
|
import com.willfp.eco.core.entities.ai.EntityGoal
|
||||||
|
import com.willfp.eco.core.entities.ai.TargetGoal
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.ai.CustomGoalFactory
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.ai.getGoalFactory
|
||||||
|
import com.willfp.eco.internal.spigot.proxy.common.toPathfinderMob
|
||||||
|
import net.minecraft.world.entity.PathfinderMob
|
||||||
|
import net.minecraft.world.entity.ai.goal.Goal
|
||||||
|
import org.bukkit.entity.Mob
|
||||||
|
|
||||||
|
class EcoEntityController<T : Mob>(
|
||||||
|
private val handle: T
|
||||||
|
) : EntityController<T> {
|
||||||
|
override fun addEntityGoal(priority: Int, goal: EntityGoal<in T>): EntityController<T> {
|
||||||
|
val nms = getNms() ?: return this
|
||||||
|
|
||||||
|
nms.goalSelector.addGoal(
|
||||||
|
priority,
|
||||||
|
goal.getGoalFactory()?.create(goal, nms) ?: return this
|
||||||
|
)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeEntityGoal(goal: EntityGoal<in T>): EntityController<T> {
|
||||||
|
val nms = getNms() ?: return this
|
||||||
|
|
||||||
|
val predicate: (Goal) -> Boolean = if (goal is CustomGoal<*>) {
|
||||||
|
{ CustomGoalFactory.isGoalOfType(it, goal) }
|
||||||
|
} else {
|
||||||
|
{ goal.getGoalFactory()?.isGoalOfType(it) == true }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (wrapped in nms.goalSelector.availableGoals.toSet()) {
|
||||||
|
if (predicate(wrapped.goal)) {
|
||||||
|
nms.goalSelector.removeGoal(wrapped.goal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearEntityGoals(): EntityController<T> {
|
||||||
|
val nms = getNms() ?: return this
|
||||||
|
nms.goalSelector.availableGoals.clear()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addTargetGoal(priority: Int, goal: TargetGoal<in T>): EntityController<T> {
|
||||||
|
val nms = getNms() ?: return this
|
||||||
|
|
||||||
|
nms.targetSelector.addGoal(
|
||||||
|
priority, goal.getGoalFactory()?.create(goal, nms) ?: return this
|
||||||
|
)
|
||||||
|
|
||||||
|
nms.targetSelector
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeTargetGoal(goal: TargetGoal<in T>): EntityController<T> {
|
||||||
|
val nms = getNms() ?: return this
|
||||||
|
|
||||||
|
val predicate: (Goal) -> Boolean = if (goal is CustomGoal<*>) {
|
||||||
|
{ CustomGoalFactory.isGoalOfType(it, goal) }
|
||||||
|
} else {
|
||||||
|
{ goal.getGoalFactory()?.isGoalOfType(it) == true }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (wrapped in nms.targetSelector.availableGoals.toSet()) {
|
||||||
|
if (predicate(wrapped.goal)) {
|
||||||
|
nms.targetSelector.removeGoal(wrapped.goal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearTargetGoals(): EntityController<T> {
|
||||||
|
val nms = getNms() ?: return this
|
||||||
|
nms.targetSelector.availableGoals.clear()
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNms(): PathfinderMob? {
|
||||||
|
return handle.toPathfinderMob()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEntity(): T {
|
||||||
|
return handle
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,12 +52,16 @@ dependencies {
|
|||||||
compileOnly("com.github.N0RSKA:ScytherAPI:55a")
|
compileOnly("com.github.N0RSKA:ScytherAPI:55a")
|
||||||
compileOnly("com.ticxo.modelengine:api:R3.0.1")
|
compileOnly("com.ticxo.modelengine:api:R3.0.1")
|
||||||
compileOnly("me.TechsCode:UltraEconomyAPI:1.0.0")
|
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("com.github.Ssomar-Developement:SCore:3.4.7")
|
||||||
compileOnly("io.lumine:Mythic:5.2.1")
|
compileOnly("io.lumine:Mythic:5.2.1")
|
||||||
compileOnly("io.lumine:LumineUtils:1.19-SNAPSHOT")
|
compileOnly("io.lumine:LumineUtils:1.19-SNAPSHOT")
|
||||||
compileOnly("com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT")
|
compileOnly("com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT")
|
||||||
compileOnly("com.github.sirblobman.combatlogx:api:11.0.0.0-SNAPSHOT")
|
compileOnly("com.github.sirblobman.combatlogx:api:11.0.0.0-SNAPSHOT")
|
||||||
compileOnly("LibsDisguises:LibsDisguises:10.0.26")
|
compileOnly("LibsDisguises:LibsDisguises:10.0.26")
|
||||||
|
compileOnly("com.denizenscript:denizen:1.2.7-SNAPSHOT") {
|
||||||
|
exclude(group = "*", module = "*")
|
||||||
|
}
|
||||||
|
|
||||||
compileOnly(fileTree("../../lib") {
|
compileOnly(fileTree("../../lib") {
|
||||||
include("*.jar")
|
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.menu.MenuType
|
||||||
import com.willfp.eco.core.gui.slot.functional.SlotProvider
|
import com.willfp.eco.core.gui.slot.functional.SlotProvider
|
||||||
import com.willfp.eco.core.items.Items
|
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.packet.Packet
|
||||||
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||||
import com.willfp.eco.internal.EcoPropsParser
|
import com.willfp.eco.internal.EcoPropsParser
|
||||||
import com.willfp.eco.internal.command.EcoPluginCommand
|
import com.willfp.eco.internal.command.EcoPluginCommand
|
||||||
import com.willfp.eco.internal.command.EcoSubcommand
|
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.gui.slot.EcoSlotBuilder
|
||||||
import com.willfp.eco.internal.integrations.PAPIExpansion
|
import com.willfp.eco.internal.integrations.PAPIExpansion
|
||||||
import com.willfp.eco.internal.logging.EcoLogger
|
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.proxy.EcoProxyFactory
|
||||||
import com.willfp.eco.internal.scheduling.EcoScheduler
|
import com.willfp.eco.internal.scheduling.EcoScheduler
|
||||||
import com.willfp.eco.internal.spigot.data.DataYml
|
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.ProfileHandler
|
||||||
import com.willfp.eco.internal.spigot.data.storage.HandlerType
|
import com.willfp.eco.internal.spigot.data.storage.HandlerType
|
||||||
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
|
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.BukkitCommandsProxy
|
||||||
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
|
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
|
||||||
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
|
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
|
||||||
@@ -88,6 +92,15 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
|||||||
if (this.configYml.getBool("use-safer-namespacedkey-creation"))
|
if (this.configYml.getBool("use-safer-namespacedkey-creation"))
|
||||||
SafeInternalNamespacedKeyFactory() else FastInternalNamespacedKeyFactory()
|
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) =
|
override fun createScheduler(plugin: EcoPlugin) =
|
||||||
EcoScheduler(plugin)
|
EcoScheduler(plugin)
|
||||||
|
|
||||||
@@ -113,6 +126,9 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
|||||||
override fun createLogger(plugin: EcoPlugin) =
|
override fun createLogger(plugin: EcoPlugin) =
|
||||||
EcoLogger(plugin)
|
EcoLogger(plugin)
|
||||||
|
|
||||||
|
override fun getNOOPLogger() =
|
||||||
|
NOOPLogger
|
||||||
|
|
||||||
override fun createPAPIIntegration(plugin: EcoPlugin) {
|
override fun createPAPIIntegration(plugin: EcoPlugin) {
|
||||||
PAPIExpansion(plugin)
|
PAPIExpansion(plugin)
|
||||||
}
|
}
|
||||||
@@ -172,7 +188,7 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createPluginCommand(
|
override fun createPluginCommand(
|
||||||
parentDelegate: CommandBase,
|
parentDelegate: PluginCommandBase,
|
||||||
plugin: EcoPlugin,
|
plugin: EcoPlugin,
|
||||||
name: String,
|
name: String,
|
||||||
permission: String,
|
permission: String,
|
||||||
@@ -246,6 +262,7 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
|||||||
|
|
||||||
override fun addNewPlugin(plugin: EcoPlugin) {
|
override fun addNewPlugin(plugin: EcoPlugin) {
|
||||||
loadedEcoPlugins[plugin.name.lowercase()] = plugin
|
loadedEcoPlugins[plugin.name.lowercase()] = plugin
|
||||||
|
loadedEcoPlugins[plugin.id] = plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLoadedPlugins(): List<String> =
|
override fun getLoadedPlugins(): List<String> =
|
||||||
@@ -269,9 +286,6 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
|||||||
override fun loadPlayerProfile(uuid: UUID) =
|
override fun loadPlayerProfile(uuid: UUID) =
|
||||||
profileHandler.load(uuid)
|
profileHandler.load(uuid)
|
||||||
|
|
||||||
override fun unloadPlayerProfile(uuid: UUID) =
|
|
||||||
profileHandler.unloadPlayer(uuid)
|
|
||||||
|
|
||||||
override fun createDummyEntity(location: Location): Entity =
|
override fun createDummyEntity(location: Location): Entity =
|
||||||
getProxy(DummyEntityFactoryProxy::class.java).createDummyEntity(location)
|
getProxy(DummyEntityFactoryProxy::class.java).createDummyEntity(location)
|
||||||
|
|
||||||
@@ -312,8 +326,8 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
|||||||
override fun getTPS() =
|
override fun getTPS() =
|
||||||
getProxy(TPSProxy::class.java).getTPS()
|
getProxy(TPSProxy::class.java).getTPS()
|
||||||
|
|
||||||
override fun evaluate(expression: String, context: MathContext) =
|
override fun evaluate(expression: String, context: PlaceholderContext) =
|
||||||
evaluateExpression(expression, context)
|
crunchHandler.evaluate(expression, context)
|
||||||
|
|
||||||
override fun getOpenMenu(player: Player) =
|
override fun getOpenMenu(player: Player) =
|
||||||
player.renderedInventory?.menu
|
player.renderedInventory?.menu
|
||||||
@@ -326,4 +340,10 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
|
|||||||
|
|
||||||
override fun sendPacket(player: Player, packet: Packet) =
|
override fun sendPacket(player: Player, packet: Packet) =
|
||||||
this.getProxy(PacketHandlerProxy::class.java).sendPacket(player, 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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import com.willfp.eco.internal.items.ArgParserColor
|
|||||||
import com.willfp.eco.internal.items.ArgParserCustomModelData
|
import com.willfp.eco.internal.items.ArgParserCustomModelData
|
||||||
import com.willfp.eco.internal.items.ArgParserEnchantment
|
import com.willfp.eco.internal.items.ArgParserEnchantment
|
||||||
import com.willfp.eco.internal.items.ArgParserFlag
|
import com.willfp.eco.internal.items.ArgParserFlag
|
||||||
|
import com.willfp.eco.internal.items.ArgParserHead
|
||||||
import com.willfp.eco.internal.items.ArgParserName
|
import com.willfp.eco.internal.items.ArgParserName
|
||||||
import com.willfp.eco.internal.items.ArgParserTexture
|
import com.willfp.eco.internal.items.ArgParserTexture
|
||||||
import com.willfp.eco.internal.items.ArgParserUnbreakable
|
import com.willfp.eco.internal.items.ArgParserUnbreakable
|
||||||
@@ -95,6 +96,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.antigrief.AntigriefWorldGuard
|
||||||
import com.willfp.eco.internal.spigot.integrations.customentities.CustomEntitiesMythicMobs
|
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.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.CustomItemsExecutableItems
|
||||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase
|
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase
|
||||||
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
|
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
|
||||||
@@ -110,11 +112,14 @@ 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.mcmmo.McmmoIntegrationImpl
|
||||||
import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration
|
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.placeholder.PlaceholderIntegrationPAPI
|
||||||
|
import com.willfp.eco.internal.spigot.integrations.price.PriceFactoryPlayerPoints
|
||||||
|
import com.willfp.eco.internal.spigot.integrations.price.PriceFactoryRoyaleEconomy
|
||||||
import com.willfp.eco.internal.spigot.integrations.price.PriceFactoryUltraEconomy
|
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.ShopDeluxeSellwands
|
||||||
import com.willfp.eco.internal.spigot.integrations.shop.ShopEconomyShopGUI
|
import com.willfp.eco.internal.spigot.integrations.shop.ShopEconomyShopGUI
|
||||||
import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus
|
import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus
|
||||||
import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop
|
import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop
|
||||||
|
import com.willfp.eco.internal.spigot.metrics.PlayerflowHandler
|
||||||
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
|
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
|
||||||
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
|
import com.willfp.eco.internal.spigot.proxy.PacketHandlerProxy
|
||||||
import com.willfp.eco.internal.spigot.recipes.CraftingRecipeListener
|
import com.willfp.eco.internal.spigot.recipes.CraftingRecipeListener
|
||||||
@@ -125,6 +130,7 @@ import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapedCraftingRecipe
|
|||||||
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapelessCraftingRecipeStackHandler
|
import com.willfp.eco.internal.spigot.recipes.stackhandlers.ShapelessCraftingRecipeStackHandler
|
||||||
import com.willfp.eco.util.ClassUtils
|
import com.willfp.eco.util.ClassUtils
|
||||||
import me.TechsCode.UltraEconomy.UltraEconomy
|
import me.TechsCode.UltraEconomy.UltraEconomy
|
||||||
|
import me.qKing12.RoyaleEconomy.MultiCurrency.MultiCurrencyHandler
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences
|
||||||
import net.milkbowl.vault.economy.Economy
|
import net.milkbowl.vault.economy.Economy
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
@@ -145,6 +151,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
|||||||
Items.registerArgParser(ArgParserFlag)
|
Items.registerArgParser(ArgParserFlag)
|
||||||
Items.registerArgParser(ArgParserUnbreakable)
|
Items.registerArgParser(ArgParserUnbreakable)
|
||||||
Items.registerArgParser(ArgParserName)
|
Items.registerArgParser(ArgParserName)
|
||||||
|
Items.registerArgParser(ArgParserHead)
|
||||||
|
|
||||||
Entities.registerArgParser(EntityArgParserName)
|
Entities.registerArgParser(EntityArgParserName)
|
||||||
Entities.registerArgParser(EntityArgParserNoAI)
|
Entities.registerArgParser(EntityArgParserNoAI)
|
||||||
@@ -217,8 +224,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
|||||||
this.logger.info("No conflicts found!")
|
this.logger.info("No conflicts found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CollatedRunnable(this)
|
|
||||||
CustomItemsManager.registerProviders() // Do it again here
|
CustomItemsManager.registerProviders() // Do it again here
|
||||||
|
|
||||||
// Register events for ShopSellEvent
|
// Register events for ShopSellEvent
|
||||||
@@ -249,19 +254,23 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
|||||||
Eco.get().adventure?.close()
|
Eco.get().adventure?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleReload() {
|
override fun createTasks() {
|
||||||
CollatedRunnable(this)
|
CollatedRunnable(this)
|
||||||
|
|
||||||
this.scheduler.runLater(3) {
|
this.scheduler.runLater(3) {
|
||||||
profileHandler.migrateIfNeeded()
|
profileHandler.migrateIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileSaver(this, profileHandler)
|
ProfileSaver(this, profileHandler).startTicking()
|
||||||
|
|
||||||
this.scheduler.runTimer(
|
this.scheduler.runTimer(
|
||||||
{ getProxy(PacketHandlerProxy::class.java).clearDisplayFrames() },
|
|
||||||
this.configYml.getInt("display-frame-ttl").toLong(),
|
this.configYml.getInt("display-frame-ttl").toLong(),
|
||||||
this.configYml.getInt("display-frame-ttl").toLong()
|
this.configYml.getInt("display-frame-ttl").toLong(),
|
||||||
)
|
) { getProxy(PacketHandlerProxy::class.java).clearDisplayFrames() }
|
||||||
|
|
||||||
|
if (this.configYml.getBool("playerflow")) {
|
||||||
|
PlayerflowHandler(this.scheduler).startTicking()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAfterLoad() {
|
override fun handleAfterLoad() {
|
||||||
@@ -323,6 +332,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
|||||||
},
|
},
|
||||||
IntegrationLoader("MythicMobs") { CustomItemsManager.register(CustomItemsMythicMobs(this)) },
|
IntegrationLoader("MythicMobs") { CustomItemsManager.register(CustomItemsMythicMobs(this)) },
|
||||||
IntegrationLoader("Scyther") { CustomItemsManager.register(CustomItemsScyther()) },
|
IntegrationLoader("Scyther") { CustomItemsManager.register(CustomItemsScyther()) },
|
||||||
|
IntegrationLoader("Denizen") { CustomItemsManager.register(CustomItemsDenizen()) },
|
||||||
|
|
||||||
// Shop
|
// Shop
|
||||||
IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) },
|
IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) },
|
||||||
@@ -355,6 +365,12 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
|||||||
Prices.registerPriceFactory(PriceFactoryUltraEconomy(currency))
|
Prices.registerPriceFactory(PriceFactoryUltraEconomy(currency))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
IntegrationLoader("PlayerPoints") { Prices.registerPriceFactory(PriceFactoryPlayerPoints()) },
|
||||||
|
IntegrationLoader("RoyaleEconomy") {
|
||||||
|
for (currency in MultiCurrencyHandler.getCurrencies()) {
|
||||||
|
Prices.registerPriceFactory(PriceFactoryRoyaleEconomy(currency))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Placeholder
|
// Placeholder
|
||||||
IntegrationLoader("PlaceholderAPI") { PlaceholderManager.addIntegration(PlaceholderIntegrationPAPI()) },
|
IntegrationLoader("PlaceholderAPI") { PlaceholderManager.addIntegration(PlaceholderIntegrationPAPI()) },
|
||||||
@@ -379,7 +395,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
|||||||
GUIListener(this),
|
GUIListener(this),
|
||||||
ArrowDataListener(this),
|
ArrowDataListener(this),
|
||||||
ArmorChangeEventListeners(this),
|
ArmorChangeEventListeners(this),
|
||||||
DataListener(this),
|
DataListener(this, profileHandler),
|
||||||
PlayerBlockListener(this),
|
PlayerBlockListener(this),
|
||||||
ServerLocking
|
ServerLocking
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.willfp.eco.internal.spigot.data
|
package com.willfp.eco.internal.spigot.data
|
||||||
|
|
||||||
import com.willfp.eco.core.Eco
|
|
||||||
import com.willfp.eco.core.EcoPlugin
|
import com.willfp.eco.core.EcoPlugin
|
||||||
import com.willfp.eco.util.PlayerUtils
|
import com.willfp.eco.util.PlayerUtils
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
@@ -11,11 +10,14 @@ import org.bukkit.event.player.PlayerLoginEvent
|
|||||||
import org.bukkit.event.player.PlayerQuitEvent
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
|
||||||
class DataListener(
|
class DataListener(
|
||||||
private val plugin: EcoPlugin
|
private val plugin: EcoPlugin,
|
||||||
|
private val handler: ProfileHandler
|
||||||
) : Listener {
|
) : Listener {
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
fun onLeave(event: PlayerQuitEvent) {
|
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
|
@EventHandler
|
||||||
@@ -27,6 +29,6 @@ class DataListener(
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
fun onLogin(event: PlayerLoginEvent) {
|
fun onLogin(event: PlayerLoginEvent) {
|
||||||
Eco.get().unloadPlayerProfile(event.player.uniqueId)
|
handler.unloadPlayer(event.player.uniqueId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
package com.willfp.eco.internal.spigot.data
|
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.PlayerProfile
|
||||||
import com.willfp.eco.core.data.Profile
|
import com.willfp.eco.core.data.Profile
|
||||||
import com.willfp.eco.core.data.ServerProfile
|
import com.willfp.eco.core.data.ServerProfile
|
||||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||||
|
import com.willfp.eco.core.data.keys.PersistentDataKeyType
|
||||||
import com.willfp.eco.internal.spigot.data.storage.DataHandler
|
import com.willfp.eco.internal.spigot.data.storage.DataHandler
|
||||||
|
import com.willfp.eco.util.namespacedKeyOf
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
abstract class EcoProfile(
|
abstract class EcoProfile(
|
||||||
val data: MutableMap<PersistentDataKey<*>, Any>,
|
val data: MutableMap<PersistentDataKey<*>, Any>,
|
||||||
val uuid: UUID,
|
val uuid: UUID,
|
||||||
private val handler: DataHandler
|
private val handler: DataHandler,
|
||||||
|
private val localHandler: DataHandler
|
||||||
) : Profile {
|
) : Profile {
|
||||||
override fun <T : Any> write(key: PersistentDataKey<T>, value: T) {
|
override fun <T : Any> write(key: PersistentDataKey<T>, value: T) {
|
||||||
this.data[key] = value
|
this.data[key] = value
|
||||||
|
|
||||||
val changedKeys = CHANGE_MAP[uuid] ?: mutableSetOf()
|
CHANGE_MAP.add(uuid)
|
||||||
changedKeys.add(key)
|
|
||||||
CHANGE_MAP[uuid] = changedKeys
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> read(key: PersistentDataKey<T>): T {
|
override fun <T : Any> read(key: PersistentDataKey<T>): T {
|
||||||
@@ -27,7 +29,12 @@ abstract class EcoProfile(
|
|||||||
return this.data[key] as T
|
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)
|
return read(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,25 +51,58 @@ abstract class EcoProfile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val CHANGE_MAP: MutableMap<UUID, MutableSet<PersistentDataKey<*>>> = ConcurrentHashMap()
|
val CHANGE_MAP: MutableSet<UUID> = ConcurrentHashMap.newKeySet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EcoPlayerProfile(
|
class EcoPlayerProfile(
|
||||||
data: MutableMap<PersistentDataKey<*>, Any>,
|
data: MutableMap<PersistentDataKey<*>, Any>,
|
||||||
uuid: UUID,
|
uuid: UUID,
|
||||||
handler: DataHandler
|
handler: DataHandler,
|
||||||
) : EcoProfile(data, uuid, handler), PlayerProfile {
|
localHandler: DataHandler
|
||||||
|
) : EcoProfile(data, uuid, handler, localHandler), PlayerProfile {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "EcoPlayerProfile{uuid=$uuid}"
|
return "EcoPlayerProfile{uuid=$uuid}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val serverIDKey = PersistentDataKey(
|
||||||
|
namespacedKeyOf("eco", "server_id"),
|
||||||
|
PersistentDataKeyType.STRING,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
|
private val localServerIDKey = PersistentDataKey(
|
||||||
|
namespacedKeyOf("eco", "local_server_id"),
|
||||||
|
PersistentDataKeyType.STRING,
|
||||||
|
""
|
||||||
|
)
|
||||||
|
|
||||||
class EcoServerProfile(
|
class EcoServerProfile(
|
||||||
data: MutableMap<PersistentDataKey<*>, Any>,
|
data: MutableMap<PersistentDataKey<*>, Any>,
|
||||||
handler: DataHandler
|
handler: DataHandler,
|
||||||
) : EcoProfile(data, serverProfileUUID, handler), ServerProfile {
|
localHandler: DataHandler
|
||||||
|
) : EcoProfile(data, serverProfileUUID, handler, localHandler), ServerProfile {
|
||||||
|
override fun getServerID(): String {
|
||||||
|
if (this.read(serverIDKey).isBlank()) {
|
||||||
|
this.write(serverIDKey, UUID.randomUUID().toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.read(serverIDKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLocalServerID(): String {
|
||||||
|
if (this.read(localServerIDKey).isBlank()) {
|
||||||
|
this.write(localServerIDKey, UUID.randomUUID().toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.read(localServerIDKey)
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "EcoServerProfile"
|
return "EcoServerProfile"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val PersistentDataKey<*>.isLocal: Boolean
|
||||||
|
get() = this == localServerIDKey || 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.PersistentDataKey
|
||||||
import com.willfp.eco.core.data.keys.PersistentDataKeyType
|
import com.willfp.eco.core.data.keys.PersistentDataKeyType
|
||||||
import org.bukkit.NamespacedKey
|
import org.bukkit.NamespacedKey
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
object KeyRegistry {
|
object KeyRegistry {
|
||||||
private val registry = mutableMapOf<NamespacedKey, PersistentDataKey<*>>()
|
private val registry = mutableMapOf<NamespacedKey, PersistentDataKey<*>>()
|
||||||
@@ -44,6 +45,9 @@ object KeyRegistry {
|
|||||||
PersistentDataKeyType.CONFIG -> if (default !is Config) {
|
PersistentDataKeyType.CONFIG -> if (default !is Config) {
|
||||||
throw IllegalArgumentException("Invalid Data Type! Should be 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!")
|
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.ServerLocking
|
||||||
import com.willfp.eco.internal.spigot.data.storage.DataHandler
|
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.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.MongoDataHandler
|
||||||
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
|
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
|
||||||
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
|
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
|
||||||
@@ -22,24 +21,18 @@ class ProfileHandler(
|
|||||||
private val type: HandlerType,
|
private val type: HandlerType,
|
||||||
private val plugin: EcoSpigotPlugin
|
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) {
|
val handler: DataHandler = when (type) {
|
||||||
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
HandlerType.YAML -> localHandler
|
||||||
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
||||||
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
||||||
HandlerType.LEGACY_MYSQL -> LegacyMySQLDataHandler(plugin, this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
fun accessLoadedProfile(uuid: UUID): EcoProfile? =
|
||||||
if (handler.type == HandlerType.LEGACY_MYSQL) {
|
loaded[uuid]
|
||||||
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 loadGenericProfile(uuid: UUID): Profile {
|
fun loadGenericProfile(uuid: UUID): Profile {
|
||||||
val found = loaded[uuid]
|
val found = loaded[uuid]
|
||||||
@@ -50,7 +43,7 @@ class ProfileHandler(
|
|||||||
val data = mutableMapOf<PersistentDataKey<*>, Any>()
|
val data = mutableMapOf<PersistentDataKey<*>, Any>()
|
||||||
|
|
||||||
val profile = if (uuid == serverProfileUUID)
|
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
|
loaded[uuid] = profile
|
||||||
return profile
|
return profile
|
||||||
@@ -65,7 +58,19 @@ class ProfileHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
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) {
|
fun unloadPlayer(uuid: UUID) {
|
||||||
@@ -74,6 +79,10 @@ class ProfileHandler(
|
|||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
handler.save()
|
handler.save()
|
||||||
|
|
||||||
|
if (localHandler != handler) {
|
||||||
|
localHandler.save()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun migrateIfNeeded() {
|
fun migrateIfNeeded() {
|
||||||
@@ -87,11 +96,7 @@ class ProfileHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var previousHandlerType = HandlerType.valueOf(plugin.dataYml.getString("previous-handler"))
|
val previousHandlerType = HandlerType.valueOf(plugin.dataYml.getString("previous-handler"))
|
||||||
|
|
||||||
if (previousHandlerType == HandlerType.MYSQL && !plugin.dataYml.has("new-mysql")) {
|
|
||||||
previousHandlerType = HandlerType.LEGACY_MYSQL
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousHandlerType == type) {
|
if (previousHandlerType == type) {
|
||||||
return
|
return
|
||||||
@@ -101,7 +106,6 @@ class ProfileHandler(
|
|||||||
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
||||||
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
||||||
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
||||||
HandlerType.LEGACY_MYSQL -> LegacyMySQLDataHandler(plugin, this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerLocking.lock("Migrating player data! Check console for more information.")
|
ServerLocking.lock("Migrating player data! Check console for more information.")
|
||||||
@@ -161,5 +165,8 @@ class ProfileHandler(
|
|||||||
|
|
||||||
fun initialize() {
|
fun initialize() {
|
||||||
handler.initialize()
|
handler.initialize()
|
||||||
|
if (localHandler != handler) {
|
||||||
|
localHandler.initialize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ abstract class DataHandler(
|
|||||||
/**
|
/**
|
||||||
* Save a set of keys for a given UUID.
|
* 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.
|
// 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 {
|
enum class HandlerType {
|
||||||
YAML,
|
YAML,
|
||||||
MYSQL,
|
MYSQL,
|
||||||
MONGO,
|
MONGO
|
||||||
LEGACY_MYSQL
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,315 +0,0 @@
|
|||||||
package com.willfp.eco.internal.spigot.data.storage
|
|
||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
|
||||||
import com.willfp.eco.core.Eco
|
|
||||||
import com.willfp.eco.core.EcoPlugin
|
|
||||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
|
||||||
import com.willfp.eco.core.data.keys.PersistentDataKeyType
|
|
||||||
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
|
||||||
import com.willfp.eco.internal.spigot.data.ProfileHandler
|
|
||||||
import com.willfp.eco.internal.spigot.data.serverProfileUUID
|
|
||||||
import com.zaxxer.hikari.HikariConfig
|
|
||||||
import com.zaxxer.hikari.HikariDataSource
|
|
||||||
import org.jetbrains.exposed.dao.id.UUIDTable
|
|
||||||
import org.jetbrains.exposed.sql.BooleanColumnType
|
|
||||||
import org.jetbrains.exposed.sql.Column
|
|
||||||
import org.jetbrains.exposed.sql.Database
|
|
||||||
import org.jetbrains.exposed.sql.DoubleColumnType
|
|
||||||
import org.jetbrains.exposed.sql.IntegerColumnType
|
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
|
||||||
import org.jetbrains.exposed.sql.SchemaUtils
|
|
||||||
import org.jetbrains.exposed.sql.VarCharColumnType
|
|
||||||
import org.jetbrains.exposed.sql.insert
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
|
||||||
import org.jetbrains.exposed.sql.update
|
|
||||||
import java.util.UUID
|
|
||||||
import java.util.concurrent.Callable
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
The MySQL data handler is hot garbage for several reasons:
|
|
||||||
- Using MySQL on unstructured data: it's being horrifically misused, but that's just how it has to be.
|
|
||||||
- Can't remove un-needed keys, there's wasted space in the columns everywhere.
|
|
||||||
- No native support for the STRING_LIST type, instead it 'serializes' the lists with semicolons as separators.
|
|
||||||
- General lack of flexibility, it's too rigid.
|
|
||||||
|
|
||||||
That's why I added the MongoDB handler, it's far, far better suited for what eco does - use it over
|
|
||||||
MySQL if you can.
|
|
||||||
|
|
||||||
Oh, also - I don't really know how this class works. I've rewritten it and hacked it together several ways
|
|
||||||
in several sessions, and it's basically complete gibberish to me. Adding the STRING_LIST type is probably
|
|
||||||
the worst bodge I've shipped in production.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
class LegacyMySQLDataHandler(
|
|
||||||
plugin: EcoSpigotPlugin,
|
|
||||||
handler: ProfileHandler
|
|
||||||
) : DataHandler(HandlerType.LEGACY_MYSQL) {
|
|
||||||
private val database: Database
|
|
||||||
private val playerHandler: ImplementedMySQLHandler
|
|
||||||
private val serverHandler: ImplementedMySQLHandler
|
|
||||||
|
|
||||||
init {
|
|
||||||
val config = HikariConfig()
|
|
||||||
config.driverClassName = "com.mysql.cj.jdbc.Driver"
|
|
||||||
config.username = plugin.configYml.getString("mysql.user")
|
|
||||||
config.password = plugin.configYml.getString("mysql.password")
|
|
||||||
config.jdbcUrl = "jdbc:mysql://" +
|
|
||||||
"${plugin.configYml.getString("mysql.host")}:" +
|
|
||||||
"${plugin.configYml.getString("mysql.port")}/" +
|
|
||||||
plugin.configYml.getString("mysql.database")
|
|
||||||
config.maximumPoolSize = plugin.configYml.getInt("mysql.connections")
|
|
||||||
|
|
||||||
database = Database.connect(HikariDataSource(config))
|
|
||||||
|
|
||||||
playerHandler = ImplementedMySQLHandler(
|
|
||||||
handler,
|
|
||||||
UUIDTable("eco_players"),
|
|
||||||
plugin
|
|
||||||
)
|
|
||||||
|
|
||||||
serverHandler = ImplementedMySQLHandler(
|
|
||||||
handler,
|
|
||||||
UUIDTable("eco_server"),
|
|
||||||
plugin
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
|
||||||
return applyFor(uuid) {
|
|
||||||
it.read(uuid, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: T) {
|
|
||||||
applyFor(uuid) {
|
|
||||||
it.write(uuid, key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
|
||||||
applyFor(uuid) {
|
|
||||||
it.saveKeysForRow(uuid, keys)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <R> applyFor(uuid: UUID, function: (ImplementedMySQLHandler) -> R): R {
|
|
||||||
return if (uuid == serverProfileUUID) {
|
|
||||||
function(serverHandler)
|
|
||||||
} else {
|
|
||||||
function(playerHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun initialize() {
|
|
||||||
playerHandler.initialize()
|
|
||||||
serverHandler.initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
private inner class ImplementedMySQLHandler(
|
|
||||||
private val handler: ProfileHandler,
|
|
||||||
private val table: UUIDTable,
|
|
||||||
private val plugin: EcoPlugin
|
|
||||||
) {
|
|
||||||
private val rows = Caffeine.newBuilder()
|
|
||||||
.expireAfterWrite(3, TimeUnit.SECONDS)
|
|
||||||
.build<UUID, ResultRow>()
|
|
||||||
|
|
||||||
private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-legacy-mysql-thread-%d").build()
|
|
||||||
private val executor = Executors.newFixedThreadPool(plugin.configYml.getInt("mysql.threads"), threadFactory)
|
|
||||||
val registeredKeys = mutableSetOf<PersistentDataKey<*>>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
transaction(database) {
|
|
||||||
SchemaUtils.create(table)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun initialize() {
|
|
||||||
transaction(database) {
|
|
||||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ensureKeyRegistration(key: PersistentDataKey<*>) {
|
|
||||||
if (table.columns.any { it.name == key.key.toString() }) {
|
|
||||||
registeredKeys.add(key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
registerColumn(key)
|
|
||||||
registeredKeys.add(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: Any) {
|
|
||||||
getRow(uuid)
|
|
||||||
doWrite(uuid, key, key.type.constrainSQLTypes(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doWrite(uuid: UUID, key: PersistentDataKey<*>, constrainedValue: Any) {
|
|
||||||
val column: Column<Any> = getColumn(key) as Column<Any>
|
|
||||||
|
|
||||||
executor.submit {
|
|
||||||
transaction(database) {
|
|
||||||
table.update({ table.id eq uuid }) {
|
|
||||||
it[column] = constrainedValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveKeysForRow(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
|
||||||
saveRow(uuid, keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveRow(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
|
||||||
val profile = handler.loadGenericProfile(uuid)
|
|
||||||
|
|
||||||
executor.submit {
|
|
||||||
transaction(database) {
|
|
||||||
getRow(uuid)
|
|
||||||
|
|
||||||
for (key in keys) {
|
|
||||||
doWrite(uuid, key, key.type.constrainSQLTypes(profile.read(key)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
|
||||||
val doRead = Callable<T?> {
|
|
||||||
transaction(database) {
|
|
||||||
val row = getRow(uuid)
|
|
||||||
val column = getColumn(key)
|
|
||||||
val raw = row[column]
|
|
||||||
key.type.fromConstrained(raw)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ensureKeyRegistration(key) // DON'T DELETE THIS LINE! I know it's covered in getColumn, but I need to do it here as well.
|
|
||||||
|
|
||||||
doRead.call()
|
|
||||||
|
|
||||||
return if (Eco.get().ecoPlugin.configYml.getBool("mysql.async-reads")) {
|
|
||||||
executor.submit(doRead).get()
|
|
||||||
} else {
|
|
||||||
doRead.call()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> registerColumn(key: PersistentDataKey<T>) {
|
|
||||||
try {
|
|
||||||
transaction(database) {
|
|
||||||
try {
|
|
||||||
table.apply {
|
|
||||||
if (table.columns.any { it.name == key.key.toString() }) {
|
|
||||||
return@apply
|
|
||||||
}
|
|
||||||
|
|
||||||
when (key.type) {
|
|
||||||
PersistentDataKeyType.INT -> registerColumn<Int>(key.key.toString(), IntegerColumnType())
|
|
||||||
.default(key.defaultValue as Int)
|
|
||||||
|
|
||||||
PersistentDataKeyType.DOUBLE -> registerColumn<Double>(
|
|
||||||
key.key.toString(),
|
|
||||||
DoubleColumnType()
|
|
||||||
).default(key.defaultValue as Double)
|
|
||||||
|
|
||||||
PersistentDataKeyType.BOOLEAN -> registerColumn<Boolean>(
|
|
||||||
key.key.toString(),
|
|
||||||
BooleanColumnType()
|
|
||||||
).default(key.defaultValue as Boolean)
|
|
||||||
|
|
||||||
PersistentDataKeyType.STRING -> registerColumn<String>(
|
|
||||||
key.key.toString(),
|
|
||||||
VarCharColumnType(512)
|
|
||||||
).default(key.defaultValue as String)
|
|
||||||
|
|
||||||
PersistentDataKeyType.STRING_LIST -> registerColumn<String>(
|
|
||||||
key.key.toString(),
|
|
||||||
VarCharColumnType(8192)
|
|
||||||
).default(PersistentDataKeyType.STRING_LIST.constrainSQLTypes(key.defaultValue as List<String>) as String)
|
|
||||||
|
|
||||||
PersistentDataKeyType.CONFIG -> throw IllegalArgumentException(
|
|
||||||
"Config Persistent Data Keys are not supported by the legacy MySQL handler!"
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> throw NullPointerException("Null value found!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.info("MySQL Error 1!")
|
|
||||||
e.printStackTrace()
|
|
||||||
// What's that? Two enormous exception catches? That's right! This code sucks.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
plugin.logger.info("MySQL Error 2!")
|
|
||||||
e.printStackTrace()
|
|
||||||
// It might fail. Who cares? This is legacy.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getColumn(key: PersistentDataKey<*>): Column<*> {
|
|
||||||
ensureKeyRegistration(key)
|
|
||||||
|
|
||||||
val name = key.key.toString()
|
|
||||||
|
|
||||||
return table.columns.first { it.name == name }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getRow(uuid: UUID): ResultRow {
|
|
||||||
fun select(uuid: UUID): ResultRow? {
|
|
||||||
return transaction(database) {
|
|
||||||
table.select { table.id eq uuid }.limit(1).singleOrNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rows.get(uuid) {
|
|
||||||
val row = select(uuid)
|
|
||||||
|
|
||||||
return@get if (row != null) {
|
|
||||||
row
|
|
||||||
} else {
|
|
||||||
transaction(database) {
|
|
||||||
table.insert { it[id] = uuid }
|
|
||||||
}
|
|
||||||
select(uuid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> PersistentDataKeyType<T>.constrainSQLTypes(value: Any): Any {
|
|
||||||
return if (this == PersistentDataKeyType.STRING_LIST) {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
value as List<String>
|
|
||||||
value.joinToString(separator = ";")
|
|
||||||
} else {
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> PersistentDataKeyType<T>.fromConstrained(constrained: Any?): T? {
|
|
||||||
if (constrained == null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return if (this == PersistentDataKeyType.STRING_LIST) {
|
|
||||||
constrained as String
|
|
||||||
constrained.split(";").toList()
|
|
||||||
} else {
|
|
||||||
constrained
|
|
||||||
} as T
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.willfp.eco.internal.spigot.data.storage
|
package com.willfp.eco.internal.spigot.data.storage
|
||||||
|
|
||||||
import com.willfp.eco.core.data.Profile
|
|
||||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||||
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
||||||
import com.willfp.eco.internal.spigot.data.ProfileHandler
|
import com.willfp.eco.internal.spigot.data.ProfileHandler
|
||||||
@@ -51,18 +50,16 @@ class MongoDataHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
override fun saveKeysFor(uuid: UUID, keys: Map<PersistentDataKey<*>, Any>) {
|
||||||
val profile = handler.loadGenericProfile(uuid)
|
|
||||||
|
|
||||||
scope.launch {
|
scope.launch {
|
||||||
for (key in keys) {
|
for ((key, value) in keys) {
|
||||||
saveKey(profile, uuid, key)
|
saveKey(uuid, key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun <T : Any> saveKey(profile: Profile, uuid: UUID, key: PersistentDataKey<T>) {
|
private suspend fun <T : Any> saveKey(uuid: UUID, key: PersistentDataKey<T>, value: Any) {
|
||||||
val data = profile.read(key)
|
val data = value as T
|
||||||
doWrite(uuid, key, data)
|
doWrite(uuid, key, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +97,18 @@ class MongoDataHandler(
|
|||||||
profile
|
profile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return other is MongoDataHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return type.hashCode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class UUIDProfile(
|
private data class UUIDProfile(
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.jetbrains.exposed.sql.insert
|
|||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@@ -34,7 +35,7 @@ Whatever. At least it works.
|
|||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
class MySQLDataHandler(
|
class MySQLDataHandler(
|
||||||
private val plugin: EcoSpigotPlugin,
|
plugin: EcoSpigotPlugin,
|
||||||
private val handler: ProfileHandler
|
private val handler: ProfileHandler
|
||||||
) : DataHandler(HandlerType.MYSQL) {
|
) : DataHandler(HandlerType.MYSQL) {
|
||||||
private val database: Database
|
private val database: Database
|
||||||
@@ -84,6 +85,9 @@ class MySQLDataHandler(
|
|||||||
PersistentDataKeyType.BOOLEAN -> data.getBoolOrNull(key.key.toString())
|
PersistentDataKeyType.BOOLEAN -> data.getBoolOrNull(key.key.toString())
|
||||||
PersistentDataKeyType.STRING_LIST -> data.getStringsOrNull(key.key.toString())
|
PersistentDataKeyType.STRING_LIST -> data.getStringsOrNull(key.key.toString())
|
||||||
PersistentDataKeyType.CONFIG -> data.getSubsectionOrNull(key.key.toString())
|
PersistentDataKeyType.CONFIG -> data.getSubsectionOrNull(key.key.toString())
|
||||||
|
PersistentDataKeyType.BIG_DECIMAL -> if (data.has(key.key.toString()))
|
||||||
|
BigDecimal(data.getString(key.key.toString())) else null
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,16 +101,15 @@ class MySQLDataHandler(
|
|||||||
setData(uuid, data)
|
setData(uuid, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
override fun saveKeysFor(uuid: UUID, keys: Map<PersistentDataKey<*>, Any>) {
|
||||||
val profile = handler.loadGenericProfile(uuid)
|
|
||||||
|
|
||||||
executor.submit {
|
executor.submit {
|
||||||
val data = getData(uuid)
|
val data = getData(uuid)
|
||||||
for (key in keys) {
|
|
||||||
data.set(key.key.toString(), profile.read(key))
|
for ((key, value) in keys) {
|
||||||
|
data.set(key.key.toString(), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
setData(uuid, data)
|
doSetData(uuid, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,10 +139,14 @@ class MySQLDataHandler(
|
|||||||
|
|
||||||
private fun setData(uuid: UUID, config: Config) {
|
private fun setData(uuid: UUID, config: Config) {
|
||||||
executor.submit {
|
executor.submit {
|
||||||
transaction(database) {
|
doSetData(uuid, config)
|
||||||
table.update({ table.id eq uuid }) {
|
}
|
||||||
it[dataColumn] = config.toPlaintext()
|
}
|
||||||
}
|
|
||||||
|
private fun doSetData(uuid: UUID, config: Config) {
|
||||||
|
transaction(database) {
|
||||||
|
table.update({ table.id eq uuid }) {
|
||||||
|
it[dataColumn] = config.toPlaintext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,8 +157,15 @@ class MySQLDataHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun save() {
|
override fun equals(other: Any?): Boolean {
|
||||||
plugin.dataYml.set("new-mysql", true)
|
if (this === other) {
|
||||||
plugin.dataYml.save()
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return other is MySQLDataHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return type.hashCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user