Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eddf240f0c | ||
|
|
4f406353ba | ||
|
|
095494dd2e | ||
|
|
fd92645500 | ||
|
|
1a6ac29083 | ||
|
|
7edc00d459 | ||
|
|
a51bad058f | ||
|
|
89ebb8ba59 | ||
|
|
f0ae8f4f84 | ||
|
|
7d6cf78442 | ||
|
|
780d8f3b86 | ||
|
|
146a0130f9 | ||
|
|
df8c3411cb | ||
|
|
4fc3c22a7d | ||
|
|
cfc4808bb8 | ||
|
|
4ac6325a41 | ||
|
|
4aed33751d | ||
|
|
3fe1c2c69f | ||
|
|
5feaa84b2c | ||
|
|
d8793bc2bb | ||
|
|
15c512f3ca | ||
|
|
15ff2fb1d6 | ||
|
|
862b588c8d | ||
|
|
3c2a99b5f4 | ||
|
|
2d23c05c47 | ||
|
|
8fc55d3393 | ||
|
|
5900a756e4 | ||
|
|
c18b85f223 | ||
|
|
85116108c2 | ||
|
|
044f141bd0 | ||
|
|
9ca7f99fdb | ||
|
|
7aa7770a3e | ||
|
|
10202917fa | ||
|
|
43df79e3b1 | ||
|
|
5ef244f0bc | ||
|
|
861f076c11 | ||
|
|
7bed43059f | ||
|
|
37e271c96c | ||
|
|
3dad48e24d | ||
|
|
ae77e4810b | ||
|
|
3d50e37c37 | ||
|
|
421fd3bd04 | ||
|
|
5ecae0a366 | ||
|
|
5de4914fd7 |
@@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -126,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.
|
||||||
@@ -164,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>
|
||||||
@@ -425,7 +430,18 @@ 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();
|
||||||
@@ -601,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();
|
||||||
}
|
}
|
||||||
@@ -722,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>
|
||||||
@@ -1150,6 +1191,16 @@ 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() {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,10 +3,12 @@ package com.willfp.eco.core.placeholder.context;
|
|||||||
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 org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,4 +69,24 @@ public class MergedInjectableContext implements PlaceholderInjectable {
|
|||||||
|
|
||||||
return injections;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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("Crafting recipe " + plugin.getID() + ":" + key + " consists only");
|
plugin.getLogger().warning("Crafting recipe " + plugin.getID() + ":" + key + " consists only");
|
||||||
Bukkit.getLogger().warning("of air or invalid items! It will not be registered.");
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ public final class NumberUtils {
|
|||||||
* @deprecated Use {@link #evaluateExpression(String, PlaceholderContext)} instead.
|
* @deprecated Use {@link #evaluateExpression(String, PlaceholderContext)} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated(since = "6.56.0", forRemoval = true)
|
@Deprecated(since = "6.56.0", forRemoval = true)
|
||||||
@SuppressWarnings("removal")
|
@SuppressWarnings({"removal", "DeprecatedIsStillUsed"})
|
||||||
public static double evaluateExpression(@NotNull final String expression,
|
public static double evaluateExpression(@NotNull final String expression,
|
||||||
@NotNull final com.willfp.eco.core.math.MathContext context) {
|
@NotNull final com.willfp.eco.core.math.MathContext context) {
|
||||||
return evaluateExpression(expression, context.toPlaceholderContext());
|
return evaluateExpression(expression, context.toPlaceholderContext());
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ 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 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;
|
||||||
@@ -784,6 +786,127 @@ public final class StringUtils {
|
|||||||
return result.toString();
|
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()
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,32 @@
|
|||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -69,3 +69,15 @@ fun Any?.toNiceString(): String =
|
|||||||
/** @see StringUtils.replaceQuickly */
|
/** @see StringUtils.replaceQuickly */
|
||||||
fun String.replaceQuickly(target: String, replacement: String): String =
|
fun String.replaceQuickly(target: String, replacement: String): String =
|
||||||
StringUtils.replaceQuickly(this, target, replacement)
|
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(
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
|||||||
import com.willfp.eco.internal.fast.listView
|
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.Objects
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@@ -235,22 +234,26 @@ open class EcoConfig(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configType != other.configType) {
|
// Hey! Don't care. This works.
|
||||||
return false
|
return this.hashCode() == other.hashCode()
|
||||||
}
|
|
||||||
|
|
||||||
if (values != other.values) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (injections != other.injections) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return Objects.hash(values, configType, injections)
|
/*
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class EcoExtensionLoader(
|
|||||||
val pluginVersion = Version(extensionYml.getStringOrNull("plugin-version") ?: "0.0.0")
|
val pluginVersion = Version(extensionYml.getStringOrNull("plugin-version") ?: "0.0.0")
|
||||||
val pluginName = extensionYml.getStringOrNull("plugin")
|
val pluginName = extensionYml.getStringOrNull("plugin")
|
||||||
|
|
||||||
if (pluginName != null && pluginName.equals(this.plugin.description.name, ignoreCase = true)) {
|
if (pluginName != null && !pluginName.equals(this.plugin.description.name, ignoreCase = true)) {
|
||||||
throw ExtensionLoadException("${extensionJar.name} is only compatible with $pluginName!")
|
throw ExtensionLoadException("${extensionJar.name} is only compatible with $pluginName!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ 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.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
|
||||||
@@ -125,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)
|
||||||
}
|
}
|
||||||
@@ -184,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,
|
||||||
@@ -258,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> =
|
||||||
@@ -281,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)
|
||||||
|
|
||||||
|
|||||||
@@ -219,8 +219,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
|
||||||
@@ -251,14 +249,15 @@ 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() },
|
{ getProxy(PacketHandlerProxy::class.java).clearDisplayFrames() },
|
||||||
this.configYml.getInt("display-frame-ttl").toLong(),
|
this.configYml.getInt("display-frame-ttl").toLong(),
|
||||||
@@ -383,7 +382,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,5 +1,6 @@
|
|||||||
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
|
||||||
@@ -11,7 +12,8 @@ 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
|
||||||
@@ -25,7 +27,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +56,9 @@ abstract class EcoProfile(
|
|||||||
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}"
|
||||||
}
|
}
|
||||||
@@ -58,9 +66,13 @@ class EcoPlayerProfile(
|
|||||||
|
|
||||||
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 toString(): String {
|
override fun toString(): String {
|
||||||
return "EcoServerProfile"
|
return "EcoServerProfile"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val PersistentDataKey<*>.isLocal: Boolean
|
||||||
|
get() = EcoPlugin.getPlugin(this.key.namespace)?.isUsingLocalStorage == true
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.willfp.eco.core.config.interfaces.Config
|
|||||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
import com.willfp.eco.core.data.keys.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
|
||||||
@@ -24,21 +23,12 @@ class ProfileHandler(
|
|||||||
) {
|
) {
|
||||||
private val loaded = mutableMapOf<UUID, EcoProfile>()
|
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 {
|
|
||||||
if (handler.type == HandlerType.LEGACY_MYSQL) {
|
|
||||||
plugin.logger.warning("You're using the legacy MySQL handler!")
|
|
||||||
plugin.logger.warning("Some features will not work and you may get unfixable errors.")
|
|
||||||
plugin.logger.warning("Support cannot be given to data issues related to legacy MySQL.")
|
|
||||||
plugin.logger.warning("Change your data handler to mysql, mongo, or yaml to fix this!")
|
|
||||||
plugin.logger.warning("This can be done in /plugins/eco/config.yml")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun accessLoadedProfile(uuid: UUID): EcoProfile? =
|
fun accessLoadedProfile(uuid: UUID): EcoProfile? =
|
||||||
@@ -53,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
|
||||||
@@ -68,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) {
|
||||||
@@ -77,6 +79,10 @@ class ProfileHandler(
|
|||||||
|
|
||||||
fun save() {
|
fun save() {
|
||||||
handler.save()
|
handler.save()
|
||||||
|
|
||||||
|
if (localHandler != handler) {
|
||||||
|
localHandler.save()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun migrateIfNeeded() {
|
fun migrateIfNeeded() {
|
||||||
@@ -90,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
|
||||||
@@ -104,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.")
|
||||||
@@ -164,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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import com.willfp.eco.internal.spigot.data.EcoProfile
|
|||||||
import com.willfp.eco.internal.spigot.data.ProfileHandler
|
import com.willfp.eco.internal.spigot.data.ProfileHandler
|
||||||
|
|
||||||
class ProfileSaver(
|
class ProfileSaver(
|
||||||
plugin: EcoPlugin,
|
private val plugin: EcoPlugin,
|
||||||
handler: ProfileHandler
|
private val handler: ProfileHandler
|
||||||
) {
|
) {
|
||||||
init {
|
fun startTicking() {
|
||||||
val interval = plugin.configYml.getInt("save-interval").toLong()
|
val interval = plugin.configYml.getInt("save-interval").toLong()
|
||||||
|
|
||||||
plugin.scheduler.runTimer(20, interval) {
|
plugin.scheduler.runTimer(20, interval) {
|
||||||
@@ -18,7 +18,12 @@ class ProfileSaver(
|
|||||||
val uuid = iterator.next()
|
val uuid = iterator.next()
|
||||||
iterator.remove()
|
iterator.remove()
|
||||||
|
|
||||||
val profile = handler.accessLoadedProfile(uuid) ?: continue
|
val profile = handler.accessLoadedProfile(uuid)
|
||||||
|
|
||||||
|
if (profile == null) {
|
||||||
|
iterator.remove()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
handler.saveKeysFor(uuid, profile.data.keys)
|
handler.saveKeysFor(uuid, profile.data.keys)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.willfp.eco.core.data.keys.PersistentDataKeyType
|
|||||||
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
|
||||||
import org.bukkit.NamespacedKey
|
import org.bukkit.NamespacedKey
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@@ -27,6 +28,9 @@ class YamlDataHandler(
|
|||||||
PersistentDataKeyType.BOOLEAN -> dataYml.getBoolOrNull("player.$uuid.${key.key}") as T?
|
PersistentDataKeyType.BOOLEAN -> dataYml.getBoolOrNull("player.$uuid.${key.key}") as T?
|
||||||
PersistentDataKeyType.STRING_LIST -> dataYml.getStringsOrNull("player.$uuid.${key.key}") as T?
|
PersistentDataKeyType.STRING_LIST -> dataYml.getStringsOrNull("player.$uuid.${key.key}") as T?
|
||||||
PersistentDataKeyType.CONFIG -> dataYml.getSubsectionOrNull("player.$uuid.${key.key}") as T?
|
PersistentDataKeyType.CONFIG -> dataYml.getSubsectionOrNull("player.$uuid.${key.key}") as T?
|
||||||
|
PersistentDataKeyType.BIG_DECIMAL -> (if (dataYml.has(key.key.toString()))
|
||||||
|
BigDecimal(dataYml.getString(key.key.toString())) else null) as T?
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,15 +41,25 @@ class YamlDataHandler(
|
|||||||
doWrite(uuid, key.key, value)
|
doWrite(uuid, key.key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
override fun saveKeysFor(uuid: UUID, keys: Map<PersistentDataKey<*>, Any>) {
|
||||||
val profile = handler.loadGenericProfile(uuid)
|
for ((key, value) in keys) {
|
||||||
|
doWrite(uuid, key.key, value)
|
||||||
for (key in keys) {
|
|
||||||
doWrite(uuid, key.key, profile.read(key))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doWrite(uuid: UUID, key: NamespacedKey, value: Any) {
|
private fun doWrite(uuid: UUID, key: NamespacedKey, value: Any) {
|
||||||
dataYml.set("player.$uuid.$key", value)
|
dataYml.set("player.$uuid.$key", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return other is YamlDataHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return type.hashCode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
|
|||||||
|
|
||||||
if (delegate is EcoSlot) {
|
if (delegate is EcoSlot) {
|
||||||
delegate.handleInventoryClick(event, menu)
|
delegate.handleInventoryClick(event, menu)
|
||||||
|
|
||||||
|
if (delegate.shouldRenderOnClick()) {
|
||||||
|
player.renderActiveMenu()
|
||||||
|
}
|
||||||
} else if (delegate === this) {
|
} else if (delegate === this) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -51,14 +55,6 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(
|
|
||||||
priority = EventPriority.HIGHEST
|
|
||||||
)
|
|
||||||
fun handleRender(event: InventoryClickEvent) {
|
|
||||||
val player = event.whoClicked as? Player ?: return
|
|
||||||
player.renderActiveMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(
|
@EventHandler(
|
||||||
priority = EventPriority.HIGH
|
priority = EventPriority.HIGH
|
||||||
)
|
)
|
||||||
@@ -94,6 +90,8 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
|
|||||||
if (slot.isCaptive(player, menu)) {
|
if (slot.isCaptive(player, menu)) {
|
||||||
if (!slot.isAllowedCaptive(player, menu, event.oldCursor)) {
|
if (!slot.isAllowedCaptive(player, menu, event.oldCursor)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
} else {
|
||||||
|
player.renderActiveMenu()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
@@ -126,6 +124,8 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
|
|||||||
if (slot.isCaptive(player, menu)) {
|
if (slot.isCaptive(player, menu)) {
|
||||||
if (!slot.isAllowedCaptive(player, menu, event.currentItem)) {
|
if (!slot.isAllowedCaptive(player, menu, event.currentItem)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
|
} else {
|
||||||
|
player.renderActiveMenu()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
@@ -141,18 +141,6 @@ class GUIListener(private val plugin: EcoPlugin) : Listener {
|
|||||||
plugin.scheduler.run { MenuHandler.unregisterInventory(event.inventory) }
|
plugin.scheduler.run { MenuHandler.unregisterInventory(event.inventory) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun forceRender(event: InventoryClickEvent) {
|
|
||||||
val player = event.whoClicked as? Player ?: return
|
|
||||||
player.renderActiveMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun forceRender(event: InventoryDragEvent) {
|
|
||||||
val player = event.whoClicked as? Player ?: return
|
|
||||||
player.renderActiveMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(
|
@EventHandler(
|
||||||
priority = EventPriority.HIGHEST
|
priority = EventPriority.HIGHEST
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,23 +4,21 @@ import com.github.benmanes.caffeine.cache.Cache
|
|||||||
import com.github.benmanes.caffeine.cache.Caffeine
|
import com.github.benmanes.caffeine.cache.Caffeine
|
||||||
import com.willfp.eco.core.EcoPlugin
|
import com.willfp.eco.core.EcoPlugin
|
||||||
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
import com.willfp.eco.core.placeholder.context.PlaceholderContext
|
||||||
import java.util.Objects
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class DelegatedExpressionHandler(
|
class DelegatedExpressionHandler(
|
||||||
plugin: EcoPlugin,
|
plugin: EcoPlugin,
|
||||||
private val handler: ExpressionHandler
|
private val handler: ExpressionHandler
|
||||||
): ExpressionHandler {
|
) : ExpressionHandler {
|
||||||
private val evaluationCache: Cache<Int, Double> = Caffeine.newBuilder()
|
private val evaluationCache: Cache<Int, Double> = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(plugin.configYml.getInt("math-cache-ttl").toLong(), TimeUnit.MILLISECONDS)
|
.expireAfterWrite(plugin.configYml.getInt("math-cache-ttl").toLong(), TimeUnit.MILLISECONDS)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
override fun evaluate(expression: String, context: PlaceholderContext): Double {
|
override fun evaluate(expression: String, context: PlaceholderContext): Double {
|
||||||
val hash = Objects.hash(
|
// Peak performance (totally not having fun with bitwise operators)
|
||||||
expression,
|
val hash = (((expression.hashCode() shl 5) - expression.hashCode()) xor
|
||||||
context.player?.uniqueId,
|
(context.player?.uniqueId?.hashCode() ?: 0)
|
||||||
context.injectableContext
|
) xor context.injectableContext.hashCode()
|
||||||
)
|
|
||||||
|
|
||||||
return evaluationCache.get(hash) {
|
return evaluationCache.get(hash) {
|
||||||
handler.evaluate(expression, context)
|
handler.evaluate(expression, context)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version = 6.57.0
|
version = 6.60.2
|
||||||
plugin-name = eco
|
plugin-name = eco
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
Reference in New Issue
Block a user