Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60f552ce65 | ||
|
|
9fe8d4ad15 | ||
|
|
b835988eec | ||
|
|
22366835de | ||
|
|
cdd1baec6c | ||
|
|
1ea0da365a | ||
|
|
852d40372d | ||
|
|
999c831dd7 | ||
|
|
80fa5d346a | ||
|
|
336cdc3716 | ||
|
|
a49a9e92b4 | ||
|
|
1c6e64832e | ||
|
|
44a141cddc | ||
|
|
ea4956870e | ||
|
|
9207d1782b | ||
|
|
9debcb7089 | ||
|
|
ef53ee2ed3 | ||
|
|
4c90360038 | ||
|
|
d4b5102913 | ||
|
|
f4553c544a | ||
|
|
5ad1db72fc | ||
|
|
c761df9ee6 | ||
|
|
b6d79da4e1 | ||
|
|
42f41618ca | ||
|
|
de878fd423 | ||
|
|
7782657d57 | ||
|
|
7778425936 | ||
|
|
6446cef255 | ||
|
|
8dacecbcba | ||
|
|
5f8ec4f94a | ||
|
|
d7847e9efc | ||
|
|
930ecd4896 | ||
|
|
af8d6a4167 | ||
|
|
361f0a0103 | ||
|
|
eb545a7d9e | ||
|
|
d3c64deef4 | ||
|
|
31db9dcb95 | ||
|
|
4938ad84bc | ||
|
|
06b2301da1 | ||
|
|
c307878c09 | ||
|
|
3b10ff01ec | ||
|
|
e042754f5d | ||
|
|
c2b8a80560 | ||
|
|
07c0e72564 | ||
|
|
de9b961d83 | ||
|
|
83958c719c | ||
|
|
9c3dfaeb01 | ||
|
|
7e61340285 | ||
|
|
78b76cb453 | ||
|
|
bb1da29704 | ||
|
|
cf152215d3 | ||
|
|
e6a59fbc91 | ||
|
|
b787f8b76a | ||
|
|
ccc83da5b0 | ||
|
|
f11068f2f1 | ||
|
|
a5cc1a5d32 | ||
|
|
7440749ba5 | ||
|
|
75010d25fa | ||
|
|
bb95376b93 | ||
|
|
ab6d4c7aa2 | ||
|
|
9ab8827e55 | ||
|
|
991290095b | ||
|
|
8735478fc3 | ||
|
|
6e44f09621 | ||
|
|
060106881e | ||
|
|
96cc9706b3 | ||
|
|
3d87b1eb73 | ||
|
|
4c4247b4ec | ||
|
|
b94dc4ac3a | ||
|
|
06bcb10958 | ||
|
|
295095e9ce | ||
|
|
ba9c5865e3 | ||
|
|
d24be4121f | ||
|
|
bcc5e4ef08 | ||
|
|
bf8609666a | ||
|
|
1a02335825 | ||
|
|
f5ef98ec5c | ||
|
|
45135e2b55 | ||
|
|
758b42ff8e | ||
|
|
4a134402da | ||
|
|
e6ad4c9268 | ||
|
|
809dcbae85 | ||
|
|
d7fce6834c | ||
|
|
ac807a991b | ||
|
|
bd5555ff01 | ||
|
|
5f80b6052d |
@@ -18,7 +18,7 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
implementation(project(":eco-api"))
|
||||
implementation(project(":eco-core:core-plugin"))
|
||||
implementation(project(path = ":eco-core:core-plugin", configuration = "shadow"))
|
||||
implementation(project(":eco-core:core-proxy"))
|
||||
implementation(project(":eco-core:core-backend"))
|
||||
implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf"))
|
||||
@@ -44,11 +44,8 @@ allprojects {
|
||||
// SuperiorSkyblock2
|
||||
maven("https://repo.bg-software.com/repository/api/")
|
||||
|
||||
// NMS (for jitpack compilation)
|
||||
maven("https://repo.codemc.org/repository/nms/")
|
||||
|
||||
// mcMMO, BentoBox
|
||||
maven("https://repo.codemc.org/repository/maven-public/")
|
||||
maven("https://repo.codemc.io/repository/maven-public/")
|
||||
|
||||
// Spigot API, Bungee API
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
||||
@@ -84,6 +81,7 @@ allprojects {
|
||||
dependencies {
|
||||
// Kotlin
|
||||
implementation(kotlin("stdlib", version = "1.6.21"))
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1")
|
||||
|
||||
// Included in spigot jar, no need to move to implementation
|
||||
compileOnly("org.jetbrains:annotations:23.0.0")
|
||||
@@ -101,7 +99,7 @@ allprojects {
|
||||
implementation("net.kyori:adventure-text-serializer-legacy:4.10.1")
|
||||
|
||||
// Other
|
||||
implementation("com.github.ben-manes.caffeine:caffeine:3.0.6")
|
||||
implementation("com.github.ben-manes.caffeine:caffeine:3.1.0")
|
||||
implementation("org.apache.maven:maven-artifact:3.8.5")
|
||||
}
|
||||
|
||||
@@ -154,6 +152,13 @@ allprojects {
|
||||
relocate("google.protobuf", "com.willfp.eco.libs.protobuf") // Still don't know
|
||||
relocate("com.zaxxer.hikari", "com.willfp.eco.libs.hikari")
|
||||
//relocate("com.mysql", "com.willfp.eco.libs.mysql")
|
||||
relocate("de.undercouch.bson4jackson", "com.willfp.eco.libs.bson4jackson")
|
||||
relocate("com.fasterxml.jackson", "com.willfp.eco.libs.jackson")
|
||||
relocate("com.mongodb", "com.willfp.eco.libs.mongodb")
|
||||
relocate("org.bson", "com.willfp.eco.libs.bson")
|
||||
relocate("org.litote", "com.willfp.eco.libs.litote")
|
||||
relocate("org.reactivestreams", "com.willfp.eco.libs.reactivestreams")
|
||||
relocate("reactor.", "com.willfp.eco.libs.reactor.") // Dot in name to be safe
|
||||
|
||||
/*
|
||||
Kotlin and caffeine are not shaded so that they can be accessed directly by eco plugins.
|
||||
|
||||
@@ -376,12 +376,12 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike {
|
||||
PlaceholderManager.addIntegration(Eco.getHandler().createPAPIIntegration(this));
|
||||
}
|
||||
|
||||
this.loadIntegrationLoaders().forEach((integrationLoader -> {
|
||||
this.loadIntegrationLoaders().forEach(integrationLoader -> {
|
||||
if (enabledPlugins.contains(integrationLoader.getPluginName().toLowerCase())) {
|
||||
this.loadedIntegrations.add(integrationLoader.getPluginName());
|
||||
integrationLoader.load();
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
this.getLogger().info("Loaded integrations: " + String.join(", ", this.getLoadedIntegrations()));
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public class Prerequisite {
|
||||
* Requires the server to be running an implementation of paper.
|
||||
*/
|
||||
public static final Prerequisite HAS_PAPER = new Prerequisite(
|
||||
() -> ClassUtils.exists("com.destroystokyo.paper.event.player.PlayerElytraBoostEvent"),
|
||||
() -> ClassUtils.exists("com.destroystokyo.paper.event.block.BeaconEffectEvent"),
|
||||
"Requires server to be running paper (or a fork)"
|
||||
);
|
||||
|
||||
|
||||
@@ -167,7 +167,10 @@ abstract class HandledCommand implements CommandBase {
|
||||
|
||||
StringUtil.copyPartialMatches(
|
||||
args[0],
|
||||
this.getSubcommands().stream().map(CommandBase::getName).collect(Collectors.toList()),
|
||||
this.getSubcommands().stream()
|
||||
.filter(subCommand -> sender.hasPermission(subCommand.getPermission()))
|
||||
.map(CommandBase::getName)
|
||||
.collect(Collectors.toList()),
|
||||
completions
|
||||
);
|
||||
|
||||
@@ -182,6 +185,10 @@ abstract class HandledCommand implements CommandBase {
|
||||
HandledCommand command = null;
|
||||
|
||||
for (CommandBase subcommand : this.getSubcommands()) {
|
||||
if (!sender.hasPermission(subcommand.getPermission())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase(subcommand.getName())) {
|
||||
command = (HandledCommand) subcommand;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public interface ProfileHandler {
|
||||
* @param async If the saving should be done asynchronously.
|
||||
* @deprecated async is now handled automatically depending on implementation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Deprecated(forRemoval = true)
|
||||
default void saveAll(boolean async) {
|
||||
saveAll();
|
||||
}
|
||||
@@ -77,8 +77,13 @@ public interface ProfileHandler {
|
||||
* Save all player data.
|
||||
* <p>
|
||||
* Can run async if using MySQL.
|
||||
*
|
||||
* @deprecated Never used.
|
||||
*/
|
||||
void saveAll();
|
||||
@Deprecated(since = "6.36.0", forRemoval = true)
|
||||
default void saveAll() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit all changes to the file.
|
||||
|
||||
@@ -21,6 +21,15 @@ public interface KeyRegistry {
|
||||
*/
|
||||
void registerKey(@NotNull PersistentDataKey<?> key);
|
||||
|
||||
/**
|
||||
* Get a key's category.
|
||||
*
|
||||
* @param key The key.
|
||||
* @return The category.
|
||||
*/
|
||||
@Nullable
|
||||
KeyCategory getCategory(@NotNull PersistentDataKey<?> key);
|
||||
|
||||
/**
|
||||
* Get all registered keys.
|
||||
*
|
||||
|
||||
@@ -38,6 +38,11 @@ public final class PersistentDataKeyType<T> {
|
||||
*/
|
||||
public static final PersistentDataKeyType<Double> DOUBLE = new PersistentDataKeyType<>(Double.class, "DOUBLE");
|
||||
|
||||
/**
|
||||
* String List.
|
||||
*/
|
||||
public static final PersistentDataKeyType<List<String>> STRING_LIST = new PersistentDataKeyType<>(null, "STRING_LIST");
|
||||
|
||||
/**
|
||||
* The class of the type.
|
||||
*/
|
||||
@@ -52,7 +57,10 @@ public final class PersistentDataKeyType<T> {
|
||||
* Get the class of the type.
|
||||
*
|
||||
* @return The class.
|
||||
* @deprecated String list type will return null.
|
||||
*/
|
||||
@Deprecated(since = "6.36.0", forRemoval = true)
|
||||
@Nullable
|
||||
public Class<T> getTypeClass() {
|
||||
return typeClass;
|
||||
}
|
||||
@@ -72,7 +80,7 @@ public final class PersistentDataKeyType<T> {
|
||||
* @param typeClass The type class.
|
||||
* @param name The name.
|
||||
*/
|
||||
private PersistentDataKeyType(@NotNull final Class<T> typeClass,
|
||||
private PersistentDataKeyType(@Nullable final Class<T> typeClass,
|
||||
@NotNull final String name) {
|
||||
VALUES.add(this);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.bukkit.Material;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -17,6 +18,15 @@ import java.util.List;
|
||||
* @param items The items.
|
||||
*/
|
||||
public record MaskItems(@NotNull TestableItem... items) {
|
||||
/**
|
||||
* Create mask items from materials.
|
||||
*
|
||||
* @param materials The materials.
|
||||
*/
|
||||
public MaskItems(@NotNull final Material... materials) {
|
||||
this(Arrays.stream(materials).map(MaterialTestableItem::new).toList().toArray(new TestableItem[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create MaskItems from a list of item names.
|
||||
*
|
||||
|
||||
@@ -222,7 +222,10 @@ public final class Items {
|
||||
|
||||
if (part == null && PROVIDERS.containsKey(namespace)) {
|
||||
ItemProvider provider = PROVIDERS.get(namespace);
|
||||
item = provider.provideForKey(keyID);
|
||||
|
||||
String reformattedKey = keyID.replace("__", ":");
|
||||
|
||||
item = provider.provideForKey(reformattedKey);
|
||||
if (item instanceof EmptyTestableItem || item == null) {
|
||||
return new EmptyTestableItem();
|
||||
}
|
||||
|
||||
@@ -96,50 +96,53 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
|
||||
shapedRecipe.setIngredient(character, parts.get(i).getItem().getType());
|
||||
}
|
||||
|
||||
ShapedRecipe displayedRecipe = new ShapedRecipe(this.getDisplayedKey(), this.getOutput());
|
||||
displayedRecipe.shape("012", "345", "678");
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (parts.get(i) instanceof EmptyTestableItem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char character = String.valueOf(i).toCharArray()[0];
|
||||
|
||||
List<TestableItem> items = new ArrayList<>();
|
||||
if (parts.get(i) instanceof GroupedTestableItems group) {
|
||||
items.addAll(group.getChildren());
|
||||
} else {
|
||||
items.add(parts.get(i));
|
||||
}
|
||||
|
||||
List<ItemStack> displayedItems = new ArrayList<>();
|
||||
|
||||
for (TestableItem testableItem : items) {
|
||||
if (testableItem instanceof TestableStack) {
|
||||
ItemStack item = testableItem.getItem().clone();
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
|
||||
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
|
||||
assert lore != null;
|
||||
lore.add("");
|
||||
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
|
||||
add = add.replace("%amount%", String.valueOf(item.getAmount()));
|
||||
lore.add(add);
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
|
||||
displayedItems.add(item);
|
||||
} else {
|
||||
displayedItems.add(testableItem.getItem());
|
||||
if (Eco.getHandler().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
|
||||
ShapedRecipe displayedRecipe = new ShapedRecipe(this.getDisplayedKey(), this.getOutput());
|
||||
displayedRecipe.shape("012", "345", "678");
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (parts.get(i) instanceof EmptyTestableItem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char character = String.valueOf(i).toCharArray()[0];
|
||||
|
||||
List<TestableItem> items = new ArrayList<>();
|
||||
if (parts.get(i) instanceof GroupedTestableItems group) {
|
||||
items.addAll(group.getChildren());
|
||||
} else {
|
||||
items.add(parts.get(i));
|
||||
}
|
||||
|
||||
List<ItemStack> displayedItems = new ArrayList<>();
|
||||
|
||||
for (TestableItem testableItem : items) {
|
||||
if (testableItem instanceof TestableStack) {
|
||||
ItemStack item = testableItem.getItem().clone();
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
|
||||
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
|
||||
assert lore != null;
|
||||
lore.add("");
|
||||
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
|
||||
add = add.replace("%amount%", String.valueOf(item.getAmount()));
|
||||
lore.add(add);
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
|
||||
displayedItems.add(item);
|
||||
} else {
|
||||
displayedItems.add(testableItem.getItem());
|
||||
}
|
||||
}
|
||||
|
||||
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(displayedItems));
|
||||
}
|
||||
|
||||
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(displayedItems));
|
||||
Bukkit.getServer().addRecipe(displayedRecipe);
|
||||
}
|
||||
|
||||
Bukkit.getServer().addRecipe(shapedRecipe);
|
||||
Bukkit.getServer().addRecipe(displayedRecipe);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,43 +101,46 @@ public final class ShapelessCraftingRecipe extends PluginDependent<EcoPlugin> im
|
||||
shapelessRecipe.addIngredient(part.getItem().getType());
|
||||
}
|
||||
|
||||
ShapelessRecipe displayedRecipe = new ShapelessRecipe(this.getDisplayedKey(), this.getOutput());
|
||||
for (TestableItem part : parts) {
|
||||
List<TestableItem> items = new ArrayList<>();
|
||||
if (part instanceof GroupedTestableItems group) {
|
||||
items.addAll(group.getChildren());
|
||||
} else {
|
||||
items.add(part);
|
||||
}
|
||||
|
||||
List<ItemStack> displayedItems = new ArrayList<>();
|
||||
|
||||
for (TestableItem testableItem : items) {
|
||||
if (testableItem instanceof TestableStack) {
|
||||
ItemStack item = testableItem.getItem().clone();
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
|
||||
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
|
||||
assert lore != null;
|
||||
lore.add("");
|
||||
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
|
||||
add = add.replace("%amount%", String.valueOf(item.getAmount()));
|
||||
lore.add(add);
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
|
||||
displayedItems.add(item);
|
||||
if (Eco.getHandler().getEcoPlugin().getConfigYml().getBool("displayed-recipes")) {
|
||||
ShapelessRecipe displayedRecipe = new ShapelessRecipe(this.getDisplayedKey(), this.getOutput());
|
||||
for (TestableItem part : parts) {
|
||||
List<TestableItem> items = new ArrayList<>();
|
||||
if (part instanceof GroupedTestableItems group) {
|
||||
items.addAll(group.getChildren());
|
||||
} else {
|
||||
displayedItems.add(testableItem.getItem());
|
||||
items.add(part);
|
||||
}
|
||||
|
||||
List<ItemStack> displayedItems = new ArrayList<>();
|
||||
|
||||
for (TestableItem testableItem : items) {
|
||||
if (testableItem instanceof TestableStack) {
|
||||
ItemStack item = testableItem.getItem().clone();
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
assert meta != null;
|
||||
|
||||
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
|
||||
assert lore != null;
|
||||
lore.add("");
|
||||
String add = Eco.getHandler().getEcoPlugin().getLangYml().getFormattedString("multiple-in-craft");
|
||||
add = add.replace("%amount%", String.valueOf(item.getAmount()));
|
||||
lore.add(add);
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
|
||||
displayedItems.add(item);
|
||||
} else {
|
||||
displayedItems.add(testableItem.getItem());
|
||||
}
|
||||
}
|
||||
|
||||
displayedRecipe.addIngredient(new RecipeChoice.ExactChoice(displayedItems));
|
||||
}
|
||||
|
||||
displayedRecipe.addIngredient(new RecipeChoice.ExactChoice(displayedItems));
|
||||
Bukkit.getServer().addRecipe(displayedRecipe);
|
||||
}
|
||||
|
||||
Bukkit.getServer().addRecipe(shapelessRecipe);
|
||||
Bukkit.getServer().addRecipe(displayedRecipe);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,6 +43,7 @@ public final class StringUtils {
|
||||
.add(Pattern.compile("<G#([0-9A-Fa-f]{6})>(.*?)</G#([0-9A-Fa-f]{6})>", Pattern.CASE_INSENSITIVE))
|
||||
.add(Pattern.compile("<#:([0-9A-Fa-f]{6})>(.*?)</#:([0-9A-Fa-f]{6})>"))
|
||||
.add(Pattern.compile("\\{#:([0-9A-Fa-f]{6})}(.*?)\\{/#:([0-9A-Fa-f]{6})}"))
|
||||
.add(Pattern.compile("\\{#([0-9A-Fa-f]{6})>}(.*?)\\{#([0-9A-Fa-f]{6})<}"))
|
||||
.build();
|
||||
|
||||
/**
|
||||
|
||||
@@ -121,8 +121,8 @@ fun CommandBase.addSubcommand(
|
||||
}
|
||||
|
||||
/**
|
||||
* Kotlin builder for commands.
|
||||
* Inherits plugin, permission, players only.
|
||||
* Kotlin builder for commands. Inherits plugin, permission, players
|
||||
* only.
|
||||
*
|
||||
* @param name The command name.
|
||||
* @param init The builder.
|
||||
|
||||
@@ -4,9 +4,7 @@ package com.willfp.eco.core.config
|
||||
|
||||
import com.willfp.eco.core.config.interfaces.Config
|
||||
|
||||
/**
|
||||
* Helper class to create configs with a kotlin DSL.
|
||||
*/
|
||||
/** Helper class to create configs with a kotlin DSL. */
|
||||
class DSLConfig internal constructor(type: ConfigType) : TransientConfig(emptyMap(), type) {
|
||||
/**
|
||||
* Map a key to a value.
|
||||
|
||||
@@ -5,47 +5,33 @@ package com.willfp.eco.core.data
|
||||
import org.bukkit.persistence.PersistentDataContainer
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
|
||||
/**
|
||||
* @see ExtendedPersistentDataContainer.set
|
||||
*/
|
||||
/** @see ExtendedPersistentDataContainer.set */
|
||||
fun <T : Any, Z : Any> PersistentDataContainer.set(key: String, dataType: PersistentDataType<T, Z>, value: Z) =
|
||||
ExtendedPersistentDataContainer.extend(this).set(key, dataType, value)
|
||||
|
||||
/**
|
||||
* @see ExtendedPersistentDataContainer.has
|
||||
*/
|
||||
/** @see ExtendedPersistentDataContainer.has */
|
||||
fun <T : Any, Z : Any> PersistentDataContainer.has(key: String, dataType: PersistentDataType<T, Z>): Boolean =
|
||||
ExtendedPersistentDataContainer.extend(this).has(key, dataType)
|
||||
|
||||
/**
|
||||
* @see ExtendedPersistentDataContainer.get
|
||||
*/
|
||||
/** @see ExtendedPersistentDataContainer.get */
|
||||
fun <T : Any, Z : Any> PersistentDataContainer.get(key: String, dataType: PersistentDataType<T, Z>): Z? =
|
||||
ExtendedPersistentDataContainer.extend(this).get(key, dataType)
|
||||
|
||||
/**
|
||||
* @see ExtendedPersistentDataContainer.getOrDefault
|
||||
*/
|
||||
/** @see ExtendedPersistentDataContainer.getOrDefault */
|
||||
fun <T : Any, Z : Any> PersistentDataContainer.getOrDefault(
|
||||
key: String,
|
||||
dataType: PersistentDataType<T, Z>,
|
||||
defaultValue: Z
|
||||
): Z = ExtendedPersistentDataContainer.extend(this).getOrDefault(key, dataType, defaultValue)
|
||||
|
||||
/**
|
||||
* @see ExtendedPersistentDataContainer.getAllKeys
|
||||
*/
|
||||
/** @see ExtendedPersistentDataContainer.getAllKeys */
|
||||
fun PersistentDataContainer.getAllKeys(): Set<String> =
|
||||
ExtendedPersistentDataContainer.extend(this).allKeys
|
||||
|
||||
/**
|
||||
* @see ExtendedPersistentDataContainer.remove
|
||||
*/
|
||||
/** @see ExtendedPersistentDataContainer.remove */
|
||||
fun PersistentDataContainer.remove(key: String) =
|
||||
ExtendedPersistentDataContainer.extend(this).remove(key)
|
||||
|
||||
/**
|
||||
* Create a new PDC without the need for an adapter context.
|
||||
*/
|
||||
/** Create a new PDC without the need for an adapter context. */
|
||||
fun newPersistentDataContainer() =
|
||||
ExtendedPersistentDataContainer.create().base
|
||||
|
||||
@@ -5,14 +5,10 @@ package com.willfp.eco.core.data
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.Server
|
||||
|
||||
/**
|
||||
* @see PlayerProfile.load
|
||||
*/
|
||||
/** @see PlayerProfile.load */
|
||||
val OfflinePlayer.profile: PlayerProfile
|
||||
get() = PlayerProfile.load(this)
|
||||
|
||||
/**
|
||||
* @see ServerProfile.load
|
||||
*/
|
||||
/** @see ServerProfile.load */
|
||||
val Server.profile: ServerProfile
|
||||
get() = ServerProfile.load()
|
||||
|
||||
@@ -5,8 +5,6 @@ package com.willfp.eco.core.entities
|
||||
import com.willfp.eco.core.entities.ai.EntityController
|
||||
import org.bukkit.entity.Mob
|
||||
|
||||
/**
|
||||
* @see EntityController.getFor
|
||||
*/
|
||||
/** @see EntityController.getFor */
|
||||
val <T : Mob> T.controller: EntityController<T>
|
||||
get() = EntityController.getFor(this)
|
||||
|
||||
@@ -4,8 +4,6 @@ package com.willfp.eco.core.fast
|
||||
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
/**
|
||||
* @see FastItemStack.wrap
|
||||
*/
|
||||
/** @see FastItemStack.wrap */
|
||||
fun ItemStack.fast(): FastItemStack =
|
||||
FastItemStack.wrap(this)
|
||||
|
||||
@@ -6,38 +6,29 @@ import com.willfp.eco.core.gui.menu.Menu
|
||||
import com.willfp.eco.core.gui.menu.MenuBuilder
|
||||
import com.willfp.eco.core.gui.slot.Slot
|
||||
import com.willfp.eco.core.gui.slot.SlotBuilder
|
||||
import com.willfp.eco.core.items.TestableItem
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.inventory.InventoryClickEvent
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
/**
|
||||
* @see SlotBuilder.onLeftClick
|
||||
*/
|
||||
/** @see SlotBuilder.onLeftClick */
|
||||
fun SlotBuilder.onLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
|
||||
this.onLeftClick { a, b, c -> action(a, b, c) }
|
||||
|
||||
/**
|
||||
* @see SlotBuilder.onRightClick
|
||||
*/
|
||||
/** @see SlotBuilder.onRightClick */
|
||||
fun SlotBuilder.onRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
|
||||
this.onRightClick { a, b, c -> action(a, b, c) }
|
||||
|
||||
/**
|
||||
* @see SlotBuilder.onShiftLeftClick
|
||||
*/
|
||||
/** @see SlotBuilder.onShiftLeftClick */
|
||||
fun SlotBuilder.onShiftLeftClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
|
||||
this.onShiftLeftClick { a, b, c -> action(a, b, c) }
|
||||
|
||||
/**
|
||||
* @see SlotBuilder.onShiftRightClick
|
||||
*/
|
||||
/** @see SlotBuilder.onShiftRightClick */
|
||||
fun SlotBuilder.onShiftRightClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
|
||||
this.onShiftRightClick { a, b, c -> action(a, b, c) }
|
||||
|
||||
/**
|
||||
* @see SlotBuilder.onShiftRightClick
|
||||
*/
|
||||
/** @see SlotBuilder.onShiftRightClick */
|
||||
fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit): SlotBuilder =
|
||||
this.onMiddleClick { a, b, c -> action(a, b, c) }
|
||||
|
||||
@@ -50,15 +41,32 @@ fun SlotBuilder.onMiddleClick(action: (InventoryClickEvent, Slot, Menu) -> Unit)
|
||||
fun SlotBuilder.setModifier(action: (Player, Menu, ItemStack) -> Unit): SlotBuilder =
|
||||
this.setUpdater { a, b, c -> c.apply { action(a, b, c) } }
|
||||
|
||||
/**
|
||||
* @see SlotBuilder.setUpdater
|
||||
*/
|
||||
/** @see SlotBuilder.setUpdater */
|
||||
fun SlotBuilder.setUpdater(action: (Player, Menu, ItemStack) -> ItemStack): SlotBuilder =
|
||||
this.setUpdater { a, b, c -> action(a, b, c) }
|
||||
|
||||
/**
|
||||
* Kotlin builder for slots.
|
||||
*/
|
||||
/** Kotlin builder for slots. */
|
||||
fun captiveSlot(): Slot = Slot.builder().setCaptive().build()
|
||||
|
||||
/** Kotlin builder for slots. */
|
||||
fun captiveSlot(
|
||||
init: SlotBuilder.() -> Unit
|
||||
): Slot {
|
||||
val builder = Slot.builder().setCaptive()
|
||||
init(builder)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
/** Kotlin builder for slots. */
|
||||
fun slot(
|
||||
init: SlotBuilder.() -> Unit
|
||||
): Slot {
|
||||
val builder = Slot.builder()
|
||||
init(builder)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
/** Kotlin builder for slots. */
|
||||
fun slot(
|
||||
item: ItemStack,
|
||||
init: SlotBuilder.() -> Unit
|
||||
@@ -68,9 +76,17 @@ fun slot(
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Kotlin builder for slots.
|
||||
*/
|
||||
/** Kotlin builder for slots. */
|
||||
fun slot(
|
||||
item: ItemStack
|
||||
): Slot = Slot.builder(item).build()
|
||||
|
||||
/** Kotlin builder for slots. */
|
||||
fun slot(
|
||||
item: TestableItem
|
||||
): Slot = Slot.builder(item.item).build()
|
||||
|
||||
/** Kotlin builder for slots. */
|
||||
fun slot(
|
||||
provider: (Player, Menu) -> ItemStack,
|
||||
init: SlotBuilder.() -> Unit
|
||||
@@ -80,27 +96,24 @@ fun slot(
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* @see MenuBuilder.onClose
|
||||
*/
|
||||
/** Kotlin builder for slots. */
|
||||
fun slot(
|
||||
provider: (Player, Menu) -> ItemStack
|
||||
): Slot = Slot.builder { a, b -> provider(a, b) }.build()
|
||||
|
||||
/** @see MenuBuilder.onClose */
|
||||
fun MenuBuilder.onClose(action: (InventoryCloseEvent, Menu) -> Unit): MenuBuilder =
|
||||
this.onClose { a, b -> action(a, b) }
|
||||
|
||||
/**
|
||||
* @see MenuBuilder.modify
|
||||
*/
|
||||
/** @see MenuBuilder.modify */
|
||||
fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder =
|
||||
this.modfiy { modifier(it) }
|
||||
|
||||
/**
|
||||
* @see MenuBuilder.onRender
|
||||
*/
|
||||
/** @see MenuBuilder.onRender */
|
||||
fun MenuBuilder.onRender(action: (Player, Menu) -> Unit): MenuBuilder =
|
||||
this.onRender { a, b -> action(a, b) }
|
||||
|
||||
/**
|
||||
* Kotlin builder for menus.
|
||||
*/
|
||||
/** Kotlin builder for menus. */
|
||||
fun menu(
|
||||
rows: Int,
|
||||
init: MenuBuilder.() -> Unit
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
@file:JvmName("EconomyExtensions")
|
||||
|
||||
package com.willfp.eco.core.integrations.economy
|
||||
|
||||
import org.bukkit.OfflinePlayer
|
||||
|
||||
/** @see EconomyManager */
|
||||
var OfflinePlayer.balance: Double
|
||||
get() = EconomyManager.getBalance(this)
|
||||
set(value) {
|
||||
if (value <= 0) {
|
||||
EconomyManager.removeMoney(this, this.balance)
|
||||
return
|
||||
}
|
||||
|
||||
val diff = this.balance - value
|
||||
|
||||
if (diff > 0) {
|
||||
EconomyManager.removeMoney(this, diff)
|
||||
} else if (diff < 0) {
|
||||
EconomyManager.giveMoney(this, -diff)
|
||||
}
|
||||
}
|
||||
@@ -6,21 +6,15 @@ import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.ItemMeta
|
||||
import org.bukkit.persistence.PersistentDataContainer
|
||||
|
||||
/**
|
||||
* @see Items.toLookupString
|
||||
*/
|
||||
/** @see Items.toLookupString */
|
||||
fun ItemStack?.toLookupString(): String =
|
||||
Items.toLookupString(this)
|
||||
|
||||
/**
|
||||
* @see Items.mergeFrom
|
||||
*/
|
||||
/** @see Items.mergeFrom */
|
||||
fun ItemStack.mergeFrom(other: ItemStack): ItemStack =
|
||||
Items.mergeFrom(other, this)
|
||||
|
||||
/**
|
||||
* @see Items.mergeFrom
|
||||
*/
|
||||
/** @see Items.mergeFrom */
|
||||
fun ItemMeta.mergeFrom(other: ItemMeta): ItemMeta =
|
||||
Items.mergeFrom(other, this)
|
||||
|
||||
@@ -34,8 +28,6 @@ var ItemStack.baseNBT: PersistentDataContainer
|
||||
Items.setBaseNBT(this, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Items.setBaseNBT
|
||||
*/
|
||||
/** @see Items.setBaseNBT */
|
||||
fun ItemStack.clearNBT() =
|
||||
Items.setBaseNBT(this, null)
|
||||
|
||||
@@ -5,8 +5,6 @@ package com.willfp.eco.util
|
||||
import org.bukkit.entity.Arrow
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
/**
|
||||
* @see ArrowUtils.getBow
|
||||
*/
|
||||
/** @see ArrowUtils.getBow */
|
||||
val Arrow.bow: ItemStack?
|
||||
get() = ArrowUtils.getBow(this)
|
||||
|
||||
@@ -4,8 +4,6 @@ package com.willfp.eco.util
|
||||
|
||||
import org.bukkit.block.Block
|
||||
|
||||
/**
|
||||
* @see ArrowUtils.getBow
|
||||
*/
|
||||
/** @see ArrowUtils.getBow */
|
||||
val Block.isPlayerPlaced: Boolean
|
||||
get() = BlockUtils.isPlayerPlaced(this)
|
||||
|
||||
@@ -5,14 +5,10 @@ package com.willfp.eco.util
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
/**
|
||||
* @see DurabilityUtils.damageItem
|
||||
*/
|
||||
/** @see DurabilityUtils.damageItem */
|
||||
fun ItemStack.damage(damage: Int) =
|
||||
DurabilityUtils.damageItem(this, damage)
|
||||
|
||||
/**
|
||||
* @see DurabilityUtils.damageItem
|
||||
*/
|
||||
/** @see DurabilityUtils.damageItem */
|
||||
fun ItemStack.damage(damage: Int, player: Player) =
|
||||
DurabilityUtils.damageItem(player, this, damage)
|
||||
|
||||
@@ -2,20 +2,18 @@
|
||||
|
||||
package com.willfp.eco.util
|
||||
|
||||
/**
|
||||
* @see ListUtils.listToFrequencyMap
|
||||
*/
|
||||
/** @see ListUtils.listToFrequencyMap */
|
||||
fun <T> List<T>.toFrequencyMap(): Map<T, Int> =
|
||||
ListUtils.listToFrequencyMap(this)
|
||||
|
||||
/**
|
||||
* @see ListUtils.containsIgnoreCase
|
||||
*/
|
||||
/** @see ListUtils.containsIgnoreCase */
|
||||
fun Iterable<String>.containsIgnoreCase(element: String): Boolean =
|
||||
ListUtils.containsIgnoreCase(this, element)
|
||||
|
||||
/**
|
||||
* @see ListUtils.create2DList
|
||||
*/
|
||||
/** @see ListUtils.create2DList */
|
||||
fun <T> create2DList(rows: Int, columns: Int): MutableList<MutableList<T>> =
|
||||
ListUtils.create2DList(rows, columns)
|
||||
|
||||
/** @see ListUtils.toSingletonList */
|
||||
fun <T> T.toSingletonList(): List<T> =
|
||||
ListUtils.toSingletonList(this)
|
||||
|
||||
@@ -4,26 +4,18 @@ package com.willfp.eco.util
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
|
||||
/**
|
||||
* @see NamespacedKeyUtils.fromString
|
||||
*/
|
||||
/** @see NamespacedKeyUtils.fromString */
|
||||
fun namespacedKeyOf(string: String) =
|
||||
NamespacedKeyUtils.fromString(string)
|
||||
|
||||
/**
|
||||
* @see NamespacedKeyUtils.fromString
|
||||
*/
|
||||
/** @see NamespacedKeyUtils.fromString */
|
||||
fun safeNamespacedKeyOf(string: String) =
|
||||
NamespacedKeyUtils.fromStringOrNull(string)
|
||||
|
||||
/**
|
||||
* @see NamespacedKeyUtils.create
|
||||
*/
|
||||
/** @see NamespacedKeyUtils.create */
|
||||
fun namespacedKeyOf(namespace: String, key: String) =
|
||||
NamespacedKeyUtils.create(namespace, key)
|
||||
|
||||
/**
|
||||
* @see EcoPlugin.namespacedKeyFactory
|
||||
*/
|
||||
/** @see EcoPlugin.namespacedKeyFactory */
|
||||
fun namespacedKeyOf(plugin: EcoPlugin, key: String) =
|
||||
plugin.namespacedKeyFactory.create(key)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
package com.willfp.eco.util
|
||||
|
||||
/**
|
||||
* @see NumberUtils.toNumeral
|
||||
*/
|
||||
/** @see NumberUtils.toNumeral */
|
||||
fun Number.toNumeral(): String =
|
||||
NumberUtils.toNumeral(this.toInt())
|
||||
|
||||
@@ -8,32 +8,22 @@ import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Entity
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
/**
|
||||
* @see PlayerUtils.getSavedDisplayName
|
||||
*/
|
||||
/** @see PlayerUtils.getSavedDisplayName */
|
||||
val OfflinePlayer.savedDisplayName: String
|
||||
get() = PlayerUtils.getSavedDisplayName(this)
|
||||
|
||||
/**
|
||||
* @see PlayerUtils.getAudience
|
||||
*/
|
||||
/** @see PlayerUtils.getAudience */
|
||||
fun Player.asAudience(): Audience =
|
||||
PlayerUtils.getAudience(this)
|
||||
|
||||
/**
|
||||
* @see PlayerUtils.getAudience
|
||||
*/
|
||||
/** @see PlayerUtils.getAudience */
|
||||
fun CommandSender.asAudience(): Audience =
|
||||
PlayerUtils.getAudience(this)
|
||||
|
||||
/**
|
||||
* @see PlayerUtils.runExempted
|
||||
*/
|
||||
/** @see PlayerUtils.runExempted */
|
||||
fun Player.runExempted(action: () -> Unit) =
|
||||
PlayerUtils.runExempted(this, action)
|
||||
|
||||
/**
|
||||
* @see PlayerUtils.tryAsPlayer
|
||||
*/
|
||||
/** @see PlayerUtils.tryAsPlayer */
|
||||
fun Entity?.tryAsPlayer(): Player? =
|
||||
PlayerUtils.tryAsPlayer(this)
|
||||
|
||||
@@ -4,8 +4,6 @@ package com.willfp.eco.util
|
||||
|
||||
import org.bukkit.potion.PotionData
|
||||
|
||||
/**
|
||||
* @see PotionData.duration
|
||||
*/
|
||||
/** @see PotionData.duration */
|
||||
val PotionData.duration: Int
|
||||
get() = PotionUtils.getDuration(this)
|
||||
|
||||
@@ -4,8 +4,6 @@ package com.willfp.eco.util
|
||||
|
||||
import org.bukkit.Server
|
||||
|
||||
/**
|
||||
* @see ServerUtils.getTps
|
||||
*/
|
||||
/** @see ServerUtils.getTps */
|
||||
val Server.tps: Double
|
||||
get() = ServerUtils.getTps()
|
||||
|
||||
@@ -5,33 +5,23 @@ package com.willfp.eco.util
|
||||
import net.kyori.adventure.text.Component
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
/**
|
||||
* @see StringUtils.toComponent
|
||||
*/
|
||||
/** @see StringUtils.toComponent */
|
||||
fun String.toComponent(): Component =
|
||||
StringUtils.toComponent(this)
|
||||
|
||||
/**
|
||||
* @see StringUtils.jsonToComponent
|
||||
*/
|
||||
/** @see StringUtils.jsonToComponent */
|
||||
fun String.jsonToComponent(): Component =
|
||||
StringUtils.jsonToComponent(this)
|
||||
|
||||
/**
|
||||
* @see StringUtils.toLegacy
|
||||
*/
|
||||
/** @see StringUtils.toLegacy */
|
||||
fun Component.toLegacy(): String =
|
||||
StringUtils.toLegacy(this)
|
||||
|
||||
/**
|
||||
* @see StringUtils.componentToJson
|
||||
*/
|
||||
/** @see StringUtils.componentToJson */
|
||||
fun Component.toJSON(): String =
|
||||
StringUtils.componentToJson(this)
|
||||
|
||||
/**
|
||||
* @see StringUtils.format
|
||||
*/
|
||||
/** @see StringUtils.format */
|
||||
fun String.formatEco(
|
||||
player: Player? = null,
|
||||
formatPlaceholders: Boolean = false
|
||||
@@ -41,9 +31,7 @@ fun String.formatEco(
|
||||
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
|
||||
)
|
||||
|
||||
/**
|
||||
* @see StringUtils.formatList
|
||||
*/
|
||||
/** @see StringUtils.formatList */
|
||||
fun List<String>.formatEco(
|
||||
player: Player? = null,
|
||||
formatPlaceholders: Boolean = false
|
||||
@@ -53,14 +41,10 @@ fun List<String>.formatEco(
|
||||
if (formatPlaceholders) StringUtils.FormatOption.WITH_PLACEHOLDERS else StringUtils.FormatOption.WITHOUT_PLACEHOLDERS
|
||||
)
|
||||
|
||||
/**
|
||||
* @see StringUtils.splitAround
|
||||
*/
|
||||
/** @see StringUtils.splitAround */
|
||||
fun String.splitAround(separator: String): Array<String> =
|
||||
StringUtils.splitAround(this, separator)
|
||||
|
||||
/**
|
||||
* @see StringUtils.toNiceString
|
||||
*/
|
||||
/** @see StringUtils.toNiceString */
|
||||
fun Any?.toNiceString(): String =
|
||||
StringUtils.toNiceString(this)
|
||||
|
||||
@@ -4,14 +4,10 @@ package com.willfp.eco.util
|
||||
|
||||
import org.bukkit.util.Vector
|
||||
|
||||
/**
|
||||
* @see VectorUtils.isFinite
|
||||
*/
|
||||
/** @see VectorUtils.isFinite */
|
||||
val Vector.isFinite: Boolean
|
||||
get() = VectorUtils.isFinite(this)
|
||||
|
||||
/**
|
||||
* @see VectorUtils.simplifyVector
|
||||
*/
|
||||
/** @see VectorUtils.simplifyVector */
|
||||
fun Vector.simplify(): Vector =
|
||||
VectorUtils.simplifyVector(this)
|
||||
|
||||
@@ -16,7 +16,7 @@ fun ConfigType.toMap(input: String?): Map<String, Any?> =
|
||||
fun ConfigType.toString(map: Map<String, Any?>): String =
|
||||
this.handler.toString(map)
|
||||
|
||||
fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
|
||||
internal fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
|
||||
is Map<*, *> -> EcoConfigSection(type, this.normalizeToConfig(type))
|
||||
is Iterable<*> -> {
|
||||
if (this.firstOrNull() == null) {
|
||||
@@ -31,7 +31,7 @@ fun Any?.constrainConfigTypes(type: ConfigType): Any? = when (this) {
|
||||
else -> this
|
||||
}
|
||||
|
||||
fun Map<*, *>.normalizeToConfig(type: ConfigType): Map<String, Any?> {
|
||||
internal fun Map<*, *>.normalizeToConfig(type: ConfigType): Map<String, Any?> {
|
||||
val building = mutableMapOf<String, Any?>()
|
||||
|
||||
for ((unprocessedKey, value) in this.entries) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.willfp.eco.internal.config
|
||||
import com.willfp.eco.core.config.ConfigType
|
||||
import com.willfp.eco.core.config.interfaces.Config
|
||||
import com.willfp.eco.core.placeholder.InjectablePlaceholder
|
||||
import com.willfp.eco.core.placeholder.StaticPlaceholder
|
||||
import com.willfp.eco.util.StringUtils
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -103,11 +104,13 @@ open class EcoConfig(
|
||||
}
|
||||
|
||||
override fun getSubsectionOrNull(path: String): Config? {
|
||||
return get(path) as? Config
|
||||
return (get(path) as? Config)?.apply { this.addInjectablePlaceholder(injections) }
|
||||
}
|
||||
|
||||
override fun getSubsectionsOrNull(path: String): List<Config>? {
|
||||
return (get(path) as? Iterable<Config>)?.toList()
|
||||
return (get(path) as? Iterable<Config>)
|
||||
?.map { it.apply { this.addInjectablePlaceholder(injections) } }
|
||||
?.toList()
|
||||
}
|
||||
|
||||
override fun getType(): ConfigType {
|
||||
@@ -135,7 +138,14 @@ open class EcoConfig(
|
||||
format: Boolean,
|
||||
option: StringUtils.FormatOption
|
||||
): String? {
|
||||
val string = get(path)?.toString() ?: return null
|
||||
var string = get(path)?.toString() ?: return null
|
||||
if (format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
|
||||
for (injection in placeholderInjections) {
|
||||
if (injection is StaticPlaceholder) {
|
||||
string = string.replace("%${injection.identifier}%", injection.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (format) StringUtils.format(string, option) else string
|
||||
}
|
||||
|
||||
@@ -144,7 +154,18 @@ open class EcoConfig(
|
||||
format: Boolean,
|
||||
option: StringUtils.FormatOption
|
||||
): List<String>? {
|
||||
val strings = (get(path) as? Iterable<*>)?.map { it.toString() } ?: return null
|
||||
val strings = (get(path) as? Iterable<*>)?.map { it.toString() }?.toMutableList() ?: return null
|
||||
if (placeholderInjections.isNotEmpty() && format && option == StringUtils.FormatOption.WITH_PLACEHOLDERS) {
|
||||
strings.replaceAll {
|
||||
var string = it
|
||||
for (injection in placeholderInjections) {
|
||||
if (injection is StaticPlaceholder) {
|
||||
string = string.replace("%${injection.identifier}%", injection.value)
|
||||
}
|
||||
}
|
||||
string
|
||||
}
|
||||
}
|
||||
return if (format) StringUtils.formatList(strings, option) else strings
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "1.3.5"
|
||||
id("io.papermc.paperweight.userdev") version "1.3.6"
|
||||
}
|
||||
|
||||
group = "com.willfp"
|
||||
|
||||
@@ -26,6 +26,8 @@ import org.bukkit.inventory.ItemFlag
|
||||
import org.bukkit.persistence.PersistentDataContainer
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
import kotlin.experimental.and
|
||||
import kotlin.experimental.inv
|
||||
import kotlin.experimental.or
|
||||
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
class EcoFastItemStack(
|
||||
@@ -149,35 +151,29 @@ class EcoFastItemStack(
|
||||
override fun getDisplayName(): String = displayNameComponent.toLegacy()
|
||||
|
||||
override fun addItemFlags(vararg hideFlags: ItemFlag) {
|
||||
for (flag in hideFlags) {
|
||||
this.flagBits = this.flagBits or getBitModifier(flag)
|
||||
for (f in hideFlags) {
|
||||
this.flagBits = this.flagBits or getBitModifier(f)
|
||||
}
|
||||
|
||||
apply()
|
||||
}
|
||||
|
||||
override fun removeItemFlags(vararg hideFlags: ItemFlag) {
|
||||
for (flag in hideFlags) {
|
||||
this.flagBits = this.flagBits and getBitModifier(flag)
|
||||
for (f in hideFlags) {
|
||||
this.flagBits = this.flagBits and getBitModifier(f).inv()
|
||||
}
|
||||
|
||||
apply()
|
||||
}
|
||||
|
||||
override fun getItemFlags(): MutableSet<ItemFlag> {
|
||||
val flags = mutableSetOf<ItemFlag>()
|
||||
|
||||
var flagArr: Array<ItemFlag>
|
||||
val size = ItemFlag.values().also { flagArr = it }.size
|
||||
|
||||
for (i in 0 until size) {
|
||||
val flag = flagArr[i]
|
||||
if (this.hasItemFlag(flag)) {
|
||||
flags.add(flag)
|
||||
override fun getItemFlags(): Set<ItemFlag> {
|
||||
val currentFlags = mutableSetOf<ItemFlag>()
|
||||
for (f in ItemFlag.values()) {
|
||||
if (hasItemFlag(f)) {
|
||||
currentFlags.add(f)
|
||||
}
|
||||
}
|
||||
|
||||
return flags
|
||||
return currentFlags
|
||||
}
|
||||
|
||||
override fun hasItemFlag(flag: ItemFlag): Boolean {
|
||||
@@ -194,15 +190,15 @@ class EcoFastItemStack(
|
||||
}
|
||||
|
||||
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
private var flagBits: Int
|
||||
private var flagBits: Byte
|
||||
get() =
|
||||
if (handle.hasTag() && handle.getTag()!!.contains(
|
||||
"HideFlags",
|
||||
99
|
||||
)
|
||||
) handle.getTag()!!.getInt("HideFlags") else 0
|
||||
) handle.getTag()!!.getInt("HideFlags").toByte() else 0
|
||||
set(value) =
|
||||
handle.getOrCreateTag().putInt("HideFlags", value)
|
||||
handle.getOrCreateTag().putInt("HideFlags", value.toInt())
|
||||
|
||||
override fun getRepairCost(): Int {
|
||||
return handle.getBaseRepairCost()
|
||||
@@ -268,8 +264,8 @@ class EcoFastItemStack(
|
||||
bukkit.mergeIfNeeded(handle)
|
||||
}
|
||||
|
||||
private fun getBitModifier(hideFlag: ItemFlag): Int {
|
||||
return 1 shl hideFlag.ordinal
|
||||
private fun getBitModifier(hideFlag: ItemFlag): Byte {
|
||||
return (1 shl hideFlag.ordinal).toByte()
|
||||
}
|
||||
|
||||
override fun unwrap(): org.bukkit.inventory.ItemStack {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "1.3.5"
|
||||
id("io.papermc.paperweight.userdev") version "1.3.6"
|
||||
}
|
||||
|
||||
group = "com.willfp"
|
||||
|
||||
@@ -20,6 +20,10 @@ class Skull : SkullProxy {
|
||||
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
|
||||
setProfile.isAccessible = true
|
||||
}
|
||||
if (base64.length < 20) {
|
||||
return
|
||||
}
|
||||
|
||||
val uuid = UUID(
|
||||
base64.substring(base64.length - 20).hashCode().toLong(),
|
||||
base64.substring(base64.length - 10).hashCode().toLong()
|
||||
@@ -39,6 +43,6 @@ class Skull : SkullProxy {
|
||||
val profile = profile[meta] as GameProfile? ?: return null
|
||||
val properties = profile.properties ?: return null
|
||||
val prop = properties["textures"] ?: return null
|
||||
return prop.toMutableList().firstOrNull()?.value
|
||||
return prop.toMutableList().firstOrNull()?.name
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,10 @@ package com.willfp.eco.internal.spigot.proxy.v1_17_R1
|
||||
|
||||
import com.willfp.eco.core.display.Display
|
||||
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.trading.MerchantOffer
|
||||
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
|
||||
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftMerchantRecipe
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.MerchantRecipe
|
||||
@@ -15,20 +18,17 @@ class VillagerTrade : VillagerTradeProxy {
|
||||
recipe: MerchantRecipe,
|
||||
player: Player
|
||||
): MerchantRecipe {
|
||||
val oldRecipe = recipe as CraftMerchantRecipe
|
||||
val newRecipe = CraftMerchantRecipe(
|
||||
Display.display(recipe.getResult().clone(), player),
|
||||
recipe.getUses(),
|
||||
recipe.getMaxUses(),
|
||||
recipe.hasExperienceReward(),
|
||||
recipe.getVillagerExperience(),
|
||||
recipe.getPriceMultiplier()
|
||||
)
|
||||
for (ingredient in recipe.getIngredients()) {
|
||||
newRecipe.addIngredient(Display.display(ingredient.clone(), player))
|
||||
recipe as CraftMerchantRecipe
|
||||
|
||||
val nbt = getHandle(recipe).createTag()
|
||||
for (tag in arrayOf("buy", "buyB", "sell")) {
|
||||
val nms = ItemStack.of(nbt.getCompound(tag))
|
||||
val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
|
||||
val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
|
||||
nbt.put(tag, itemNBT)
|
||||
}
|
||||
getHandle(newRecipe).specialPriceDiff = getHandle(oldRecipe).specialPriceDiff
|
||||
return newRecipe
|
||||
|
||||
return CraftMerchantRecipe(MerchantOffer(nbt))
|
||||
}
|
||||
|
||||
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "1.3.5"
|
||||
id("io.papermc.paperweight.userdev") version "1.3.6"
|
||||
}
|
||||
|
||||
group = "com.willfp"
|
||||
|
||||
@@ -20,6 +20,10 @@ class Skull : SkullProxy {
|
||||
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
|
||||
setProfile.isAccessible = true
|
||||
}
|
||||
if (base64.length < 20) {
|
||||
return
|
||||
}
|
||||
|
||||
val uuid = UUID(
|
||||
base64.substring(base64.length - 20).hashCode().toLong(),
|
||||
base64.substring(base64.length - 10).hashCode().toLong()
|
||||
@@ -39,6 +43,6 @@ class Skull : SkullProxy {
|
||||
val profile = profile[meta] as GameProfile? ?: return null
|
||||
val properties = profile.properties ?: return null
|
||||
val prop = properties["textures"] ?: return null
|
||||
return prop.toMutableList().firstOrNull()?.value
|
||||
return prop.toMutableList().firstOrNull()?.name
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,10 @@ package com.willfp.eco.internal.spigot.proxy.v1_18_R1
|
||||
|
||||
import com.willfp.eco.core.display.Display
|
||||
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.trading.MerchantOffer
|
||||
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
|
||||
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMerchantRecipe
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.MerchantRecipe
|
||||
@@ -15,20 +18,17 @@ class VillagerTrade : VillagerTradeProxy {
|
||||
recipe: MerchantRecipe,
|
||||
player: Player
|
||||
): MerchantRecipe {
|
||||
val oldRecipe = recipe as CraftMerchantRecipe
|
||||
val newRecipe = CraftMerchantRecipe(
|
||||
Display.display(recipe.getResult().clone(), player),
|
||||
recipe.getUses(),
|
||||
recipe.getMaxUses(),
|
||||
recipe.hasExperienceReward(),
|
||||
recipe.getVillagerExperience(),
|
||||
recipe.getPriceMultiplier()
|
||||
)
|
||||
for (ingredient in recipe.getIngredients()) {
|
||||
newRecipe.addIngredient(Display.display(ingredient.clone(), player))
|
||||
recipe as CraftMerchantRecipe
|
||||
|
||||
val nbt = getHandle(recipe).createTag()
|
||||
for (tag in arrayOf("buy", "buyB", "sell")) {
|
||||
val nms = ItemStack.of(nbt.getCompound(tag))
|
||||
val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
|
||||
val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
|
||||
nbt.put(tag, itemNBT)
|
||||
}
|
||||
getHandle(newRecipe).setSpecialPriceDiff(getHandle(oldRecipe).getSpecialPriceDiff())
|
||||
return newRecipe
|
||||
|
||||
return CraftMerchantRecipe(MerchantOffer(nbt))
|
||||
}
|
||||
|
||||
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id("io.papermc.paperweight.userdev") version "1.3.5"
|
||||
id("io.papermc.paperweight.userdev") version "1.3.6"
|
||||
}
|
||||
|
||||
group = "com.willfp"
|
||||
|
||||
@@ -20,6 +20,10 @@ class Skull : SkullProxy {
|
||||
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
|
||||
setProfile.isAccessible = true
|
||||
}
|
||||
if (base64.length < 20) {
|
||||
return
|
||||
}
|
||||
|
||||
val uuid = UUID(
|
||||
base64.substring(base64.length - 20).hashCode().toLong(),
|
||||
base64.substring(base64.length - 10).hashCode().toLong()
|
||||
@@ -39,6 +43,6 @@ class Skull : SkullProxy {
|
||||
val profile = profile[meta] as GameProfile? ?: return null
|
||||
val properties = profile.properties ?: return null
|
||||
val prop = properties["textures"] ?: return null
|
||||
return prop.toMutableList().firstOrNull()?.value
|
||||
return prop.toMutableList().firstOrNull()?.name
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,10 @@ package com.willfp.eco.internal.spigot.proxy.v1_18_R2
|
||||
|
||||
import com.willfp.eco.core.display.Display
|
||||
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.trading.MerchantOffer
|
||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack
|
||||
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftMerchantRecipe
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.MerchantRecipe
|
||||
@@ -15,20 +18,17 @@ class VillagerTrade : VillagerTradeProxy {
|
||||
recipe: MerchantRecipe,
|
||||
player: Player
|
||||
): MerchantRecipe {
|
||||
val oldRecipe = recipe as CraftMerchantRecipe
|
||||
val newRecipe = CraftMerchantRecipe(
|
||||
Display.display(recipe.getResult().clone(), player),
|
||||
recipe.getUses(),
|
||||
recipe.getMaxUses(),
|
||||
recipe.hasExperienceReward(),
|
||||
recipe.getVillagerExperience(),
|
||||
recipe.getPriceMultiplier()
|
||||
)
|
||||
for (ingredient in recipe.getIngredients()) {
|
||||
newRecipe.addIngredient(Display.display(ingredient.clone(), player))
|
||||
recipe as CraftMerchantRecipe
|
||||
|
||||
val nbt = getHandle(recipe).createTag()
|
||||
for (tag in arrayOf("buy", "buyB", "sell")) {
|
||||
val nms = ItemStack.of(nbt.getCompound(tag))
|
||||
val displayed = Display.display(CraftItemStack.asBukkitCopy(nms), player)
|
||||
val itemNBT = CraftItemStack.asNMSCopy(displayed).save(CompoundTag())
|
||||
nbt.put(tag, itemNBT)
|
||||
}
|
||||
getHandle(newRecipe).setSpecialPriceDiff(getHandle(oldRecipe).getSpecialPriceDiff())
|
||||
return newRecipe
|
||||
|
||||
return CraftMerchantRecipe(MerchantOffer(nbt))
|
||||
}
|
||||
|
||||
private fun getHandle(recipe: CraftMerchantRecipe): MerchantOffer {
|
||||
|
||||
@@ -14,10 +14,12 @@ dependencies {
|
||||
implementation 'com.zaxxer:HikariCP:5.0.0'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.1.0'
|
||||
implementation 'org.javassist:javassist:3.28.0-GA'
|
||||
implementation 'org.mongodb:mongodb-driver-sync:4.6.0'
|
||||
implementation 'org.litote.kmongo:kmongo-coroutine:4.6.0'
|
||||
|
||||
// Included in spigot jar
|
||||
compileOnly 'com.google.code.gson:gson:2.8.8'
|
||||
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
||||
compileOnly 'io.papermc.paper:paper-api:1.17.1-R0.1-SNAPSHOT'
|
||||
|
||||
// Plugin dependencies
|
||||
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT'
|
||||
@@ -63,6 +65,13 @@ dependencies {
|
||||
compileOnly fileTree(dir: '../../lib', include: ['*.jar'])
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
minimize {
|
||||
exclude(dependency('org.litote.kmongo:kmongo-coroutine:.*'))
|
||||
exclude(dependency('org.jetbrains.exposed:.*:.*'))
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**"]) {
|
||||
expand projectVersion: project.version
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.mongodb.diagnostics.logging
|
||||
|
||||
/*
|
||||
This is a terrible fix for mongo logging.
|
||||
|
||||
I've tried every 'solution' on the internet - setting the level with java native logging,
|
||||
with Log4j / Slf4j, reflectively changing the logger delegate in the Log4J impl, every
|
||||
single method under the sun - but I just couldn't get any of them to work.
|
||||
|
||||
So, I've 'fixed' the problem at the source - the class in the jar now always returns a useless
|
||||
logger that can't do anything. At least there's no console spam anymore.
|
||||
*/
|
||||
|
||||
@Suppress("UNUSED")
|
||||
object Loggers {
|
||||
private const val PREFIX = "org.mongodb.driver"
|
||||
|
||||
@JvmStatic
|
||||
fun getLogger(suffix: String): Logger = NoOpLogger("$PREFIX.$suffix")
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.willfp.eco.internal.spigot
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.util.containsIgnoreCase
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.plugin.Plugin
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
object ConflictFinder {
|
||||
fun searchForConflicts(eco: EcoPlugin): List<Conflict> {
|
||||
val conflicts = mutableListOf<Conflict>()
|
||||
|
||||
for (plugin in Bukkit.getPluginManager().plugins) {
|
||||
if (eco.configYml.getStrings("conflicts.whitelist").containsIgnoreCase(plugin.name)) {
|
||||
continue
|
||||
}
|
||||
|
||||
val conflict = plugin.getConflict()
|
||||
|
||||
if (conflict != null) {
|
||||
conflicts.add(conflict)
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts
|
||||
}
|
||||
}
|
||||
|
||||
data class Conflict(
|
||||
val plugin: Plugin,
|
||||
val conflictType: ConflictType
|
||||
) {
|
||||
val conflictMessage: String
|
||||
get() = "${plugin.name} will likely conflict with eco! Reason: ${conflictType.friendlyMessage}"
|
||||
}
|
||||
|
||||
enum class ConflictType(
|
||||
val friendlyMessage: String
|
||||
) {
|
||||
LIB_LOADER("Kotlin found in libraries (lib-loader)"),
|
||||
KOTLIN_SHADE("Kotlin shaded into jar");
|
||||
}
|
||||
|
||||
private fun Plugin.getConflict(): Conflict? {
|
||||
if (this.description.libraries.any { it.contains("kotlin-stdlib") }) {
|
||||
return Conflict(this, ConflictType.LIB_LOADER)
|
||||
}
|
||||
|
||||
val zip = ZipFile(File(this::class.java.protectionDomain.codeSource.location.toURI()))
|
||||
|
||||
for (entry in zip.entries()) {
|
||||
if (entry.name.startsWith("kotlin/") || entry.name.startsWith("kotlinx/")) {
|
||||
return Conflict(this, ConflictType.KOTLIN_SHADE)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import com.willfp.eco.internal.scheduling.EcoScheduler
|
||||
import com.willfp.eco.internal.spigot.data.DataYml
|
||||
import com.willfp.eco.internal.spigot.data.EcoKeyRegistry
|
||||
import com.willfp.eco.internal.spigot.data.EcoProfileHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.HandlerType
|
||||
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
|
||||
import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy
|
||||
import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy
|
||||
@@ -57,7 +58,17 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
|
||||
|
||||
private var adventure: BukkitAudiences? = null
|
||||
private val keyRegistry = EcoKeyRegistry()
|
||||
private val playerProfileHandler = EcoProfileHandler(this.configYml.getBool("mysql.enabled"), this)
|
||||
private val playerProfileHandler = EcoProfileHandler(
|
||||
if (this.configYml.getBool("mysql.enabled")) {
|
||||
this.configYml.set("mysql.enabled", false)
|
||||
this.configYml.set("data-handler", "mysql")
|
||||
HandlerType.MYSQL
|
||||
} else {
|
||||
HandlerType.valueOf(
|
||||
this.configYml.getString("data-handler").uppercase()
|
||||
)
|
||||
}, this
|
||||
)
|
||||
|
||||
@Suppress("RedundantNullableReturnType")
|
||||
private val keyFactory: InternalNamespacedKeyFactory? =
|
||||
|
||||
@@ -63,7 +63,8 @@ import com.willfp.eco.internal.spigot.display.PacketWindowItems
|
||||
import com.willfp.eco.internal.spigot.display.frame.clearFrames
|
||||
import com.willfp.eco.internal.spigot.drops.CollatedRunnable
|
||||
import com.willfp.eco.internal.spigot.eventlisteners.EntityDeathByEntityListeners
|
||||
import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListeners
|
||||
import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListenersPaper
|
||||
import com.willfp.eco.internal.spigot.eventlisteners.NaturalExpGainListenersSpigot
|
||||
import com.willfp.eco.internal.spigot.eventlisteners.PlayerJumpListenersPaper
|
||||
import com.willfp.eco.internal.spigot.eventlisteners.PlayerJumpListenersSpigot
|
||||
import com.willfp.eco.internal.spigot.eventlisteners.armor.ArmorChangeEventListeners
|
||||
@@ -191,7 +192,27 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
}
|
||||
|
||||
override fun handleEnable() {
|
||||
this.logger.info("Scanning for conflicts...")
|
||||
val conflicts = ConflictFinder.searchForConflicts(this)
|
||||
for (conflict in conflicts) {
|
||||
this.logger.warning(conflict.conflictMessage)
|
||||
}
|
||||
if (conflicts.isNotEmpty()) {
|
||||
this.logger.warning(
|
||||
"You can fix the conflicts by either removing the conflicting plugins, " +
|
||||
"or by asking on the support discord to have them patched!"
|
||||
)
|
||||
this.logger.warning(
|
||||
"Only remove potentially conflicting plugins if you see " +
|
||||
"Loader Constraint Violation / LinkageError anywhere"
|
||||
)
|
||||
} else {
|
||||
this.logger.info("No conflicts found!")
|
||||
}
|
||||
|
||||
|
||||
CollatedRunnable(this)
|
||||
CustomItemsManager.registerProviders() // Do it again here
|
||||
|
||||
// Register events for ShopSellEvent
|
||||
ShopManager.registerEvents(this)
|
||||
@@ -218,7 +239,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
override fun handleReload() {
|
||||
CollatedRunnable(this)
|
||||
DropManager.update(this)
|
||||
ProfileSaver(this)
|
||||
ProfileSaver(this, Eco.getHandler().profileHandler)
|
||||
this.scheduler.runTimer(
|
||||
{ clearFrames() },
|
||||
this.configYml.getInt("display-frame-ttl").toLong(),
|
||||
@@ -329,7 +350,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
|
||||
override fun loadListeners(): List<Listener> {
|
||||
val listeners = mutableListOf(
|
||||
NaturalExpGainListeners(),
|
||||
ArmorListener(),
|
||||
EntityDeathByEntityListeners(this),
|
||||
CraftingRecipeListener(),
|
||||
@@ -343,8 +363,10 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
|
||||
|
||||
if (Prerequisite.HAS_PAPER.isMet) {
|
||||
listeners.add(PlayerJumpListenersPaper())
|
||||
listeners.add(NaturalExpGainListenersPaper())
|
||||
} else {
|
||||
listeners.add(PlayerJumpListenersSpigot())
|
||||
listeners.add(NaturalExpGainListenersSpigot())
|
||||
}
|
||||
|
||||
return listeners
|
||||
|
||||
@@ -24,6 +24,10 @@ class EcoKeyRegistry : KeyRegistry {
|
||||
return registry.values.toMutableSet()
|
||||
}
|
||||
|
||||
override fun getCategory(key: PersistentDataKey<*>): KeyRegistry.KeyCategory? {
|
||||
return categories[key.key]
|
||||
}
|
||||
|
||||
private fun <T> validateKey(key: PersistentDataKey<T>) {
|
||||
when (key.type) {
|
||||
PersistentDataKeyType.INT -> if (key.defaultValue !is Int) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.willfp.eco.internal.spigot.data
|
||||
|
||||
import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.data.PlayerProfile
|
||||
import com.willfp.eco.core.data.Profile
|
||||
import com.willfp.eco.core.data.ProfileHandler
|
||||
@@ -7,19 +8,26 @@ import com.willfp.eco.core.data.ServerProfile
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||
import com.willfp.eco.internal.spigot.EcoSpigotPlugin
|
||||
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.MongoDataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
|
||||
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
|
||||
import org.bukkit.Bukkit
|
||||
import java.util.UUID
|
||||
|
||||
val serverProfileUUID = UUID(0, 0)
|
||||
|
||||
class EcoProfileHandler(
|
||||
useSql: Boolean,
|
||||
plugin: EcoSpigotPlugin
|
||||
private val type: HandlerType,
|
||||
private val plugin: EcoSpigotPlugin
|
||||
) : ProfileHandler {
|
||||
private val loaded = mutableMapOf<UUID, Profile>()
|
||||
val handler: DataHandler = if (useSql) MySQLDataHandler(plugin, this) else
|
||||
YamlDataHandler(plugin, this)
|
||||
|
||||
val handler: DataHandler = when (type) {
|
||||
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
||||
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
||||
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
||||
}
|
||||
|
||||
fun loadGenericProfile(uuid: UUID): Profile {
|
||||
val found = loaded[uuid]
|
||||
@@ -45,26 +53,87 @@ class EcoProfileHandler(
|
||||
}
|
||||
|
||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
val profile = loadGenericProfile(uuid)
|
||||
|
||||
for (key in keys) {
|
||||
handler.write(uuid, key.key, profile.read(key))
|
||||
}
|
||||
handler.saveKeysFor(uuid, keys)
|
||||
}
|
||||
|
||||
override fun unloadPlayer(uuid: UUID) {
|
||||
loaded.remove(uuid)
|
||||
}
|
||||
|
||||
override fun saveAll() {
|
||||
handler.saveAll(loaded.keys.toList())
|
||||
}
|
||||
|
||||
override fun save() {
|
||||
handler.save()
|
||||
}
|
||||
|
||||
fun initialize() {
|
||||
handler.initialize()
|
||||
private fun migrateIfNeeded() {
|
||||
if (!plugin.configYml.getBool("perform-data-migration")) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!plugin.dataYml.has("previous-handler")) {
|
||||
plugin.dataYml.set("previous-handler", type.name)
|
||||
plugin.dataYml.save()
|
||||
}
|
||||
|
||||
val previousHandlerType = HandlerType.valueOf(plugin.dataYml.getString("previous-handler"))
|
||||
|
||||
if (previousHandlerType == type) {
|
||||
return
|
||||
}
|
||||
|
||||
val previousHandler = when (previousHandlerType) {
|
||||
HandlerType.YAML -> YamlDataHandler(plugin, this)
|
||||
HandlerType.MYSQL -> MySQLDataHandler(plugin, this)
|
||||
HandlerType.MONGO -> MongoDataHandler(plugin, this)
|
||||
}
|
||||
|
||||
plugin.logger.info("eco has detected a change in data handler!")
|
||||
plugin.logger.info("Migrating server data from ${previousHandlerType.name} to ${type.name}")
|
||||
plugin.logger.info("This will take a while!")
|
||||
|
||||
val players = Bukkit.getOfflinePlayers().map { it.uniqueId }
|
||||
|
||||
plugin.logger.info("Found data for ${players.size} players!")
|
||||
|
||||
/*
|
||||
Declared here as its own function to be able to use T.
|
||||
*/
|
||||
fun <T : Any> migrateKey(uuid: UUID, key: PersistentDataKey<T>, from: DataHandler, to: DataHandler) {
|
||||
val category = Eco.getHandler().keyRegistry.getCategory(key)
|
||||
if (category != null) {
|
||||
from.categorize(key, category)
|
||||
}
|
||||
val previous: T? = from.read(uuid, key)
|
||||
if (previous != null) {
|
||||
to.write(uuid, key, previous)
|
||||
}
|
||||
}
|
||||
|
||||
var i = 1
|
||||
for (uuid in players) {
|
||||
plugin.logger.info("Migrating data for $uuid... ($i / ${players.size})")
|
||||
|
||||
for (key in PersistentDataKey.values()) {
|
||||
migrateKey(uuid, key, previousHandler, handler)
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
plugin.logger.info("Updating previous handler...")
|
||||
plugin.dataYml.set("previous-handler", type.name)
|
||||
plugin.dataYml.save()
|
||||
plugin.logger.info("Done!")
|
||||
}
|
||||
}
|
||||
|
||||
fun initialize() {
|
||||
plugin.dataYml.getStrings("categorized-keys.player")
|
||||
.mapNotNull { KeyHelpers.deserializeFromString(it) }
|
||||
|
||||
plugin.dataYml.getStrings("categorized-keys.server")
|
||||
.mapNotNull { KeyHelpers.deserializeFromString(it, server = true) }
|
||||
|
||||
handler.initialize()
|
||||
|
||||
migrateIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.willfp.eco.util.NamespacedKeyUtils
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
object KeyHelpers {
|
||||
fun deserializeFromString(serialized: String): PersistentDataKey<*>? {
|
||||
fun deserializeFromString(serialized: String, server: Boolean = false): PersistentDataKey<*>? {
|
||||
val split = serialized.split(";").toTypedArray()
|
||||
|
||||
if (split.size < 2) {
|
||||
@@ -15,7 +15,7 @@ object KeyHelpers {
|
||||
|
||||
val key = NamespacedKeyUtils.fromStringOrNull(split[0]) ?: return null
|
||||
val type = PersistentDataKeyType.valueOf(split[1]) ?: return null
|
||||
return when (type) {
|
||||
val persistentKey = when (type) {
|
||||
PersistentDataKeyType.STRING -> PersistentDataKey(
|
||||
key,
|
||||
type as PersistentDataKeyType<String>,
|
||||
@@ -38,6 +38,16 @@ object KeyHelpers {
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (persistentKey != null) {
|
||||
if (server) {
|
||||
persistentKey.server()
|
||||
} else {
|
||||
persistentKey.player()
|
||||
}
|
||||
}
|
||||
|
||||
return persistentKey
|
||||
}
|
||||
|
||||
fun serializeToString(key: PersistentDataKey<*>): String {
|
||||
|
||||
@@ -2,26 +2,37 @@ package com.willfp.eco.internal.spigot.data.storage
|
||||
|
||||
import com.willfp.eco.core.data.keys.KeyRegistry
|
||||
import com.willfp.eco.core.data.keys.PersistentDataKey
|
||||
import org.bukkit.NamespacedKey
|
||||
import java.util.UUID
|
||||
|
||||
interface DataHandler {
|
||||
fun save()
|
||||
fun saveAll(uuids: Iterable<UUID>)
|
||||
abstract class DataHandler(
|
||||
val type: HandlerType
|
||||
) {
|
||||
/**
|
||||
* Read value from a key.
|
||||
*/
|
||||
abstract fun <T : Any> read(uuid: UUID, key: PersistentDataKey<T>): T?
|
||||
|
||||
fun categorize(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) {
|
||||
/**
|
||||
* Write value to a key.
|
||||
*/
|
||||
abstract fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: T)
|
||||
|
||||
/**
|
||||
* Save a set of keys for a given UUID.
|
||||
*/
|
||||
abstract fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>)
|
||||
|
||||
// Everything below this are methods that are only needed for certain implementations.
|
||||
|
||||
open fun save() {
|
||||
|
||||
}
|
||||
|
||||
fun initialize() {
|
||||
open fun categorize(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) {
|
||||
|
||||
}
|
||||
|
||||
fun savePlayer(uuid: UUID) {
|
||||
saveKeysFor(uuid, PersistentDataKey.values())
|
||||
}
|
||||
open fun initialize() {
|
||||
|
||||
fun <T> write(uuid: UUID, key: NamespacedKey, value: T)
|
||||
fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>)
|
||||
fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.willfp.eco.internal.spigot.data.storage
|
||||
|
||||
enum class HandlerType {
|
||||
YAML,
|
||||
MYSQL,
|
||||
MONGO
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
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.internal.spigot.EcoSpigotPlugin
|
||||
import com.willfp.eco.internal.spigot.data.EcoProfileHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.bson.codecs.pojo.annotations.BsonId
|
||||
import org.litote.kmongo.coroutine.CoroutineClient
|
||||
import org.litote.kmongo.coroutine.CoroutineCollection
|
||||
import org.litote.kmongo.coroutine.coroutine
|
||||
import org.litote.kmongo.eq
|
||||
import org.litote.kmongo.reactivestreams.KMongo
|
||||
import org.litote.kmongo.setValue
|
||||
import java.util.UUID
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class MongoDataHandler(
|
||||
plugin: EcoSpigotPlugin,
|
||||
private val handler: EcoProfileHandler
|
||||
) : DataHandler(HandlerType.MONGO) {
|
||||
private val client: CoroutineClient
|
||||
private val collection: CoroutineCollection<UUIDProfile>
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
init {
|
||||
System.setProperty(
|
||||
"org.litote.mongo.mapping.service",
|
||||
"org.litote.kmongo.jackson.JacksonClassMappingTypeService"
|
||||
)
|
||||
|
||||
val url = plugin.configYml.getString("mongodb.url")
|
||||
|
||||
client = KMongo.createClient(url).coroutine
|
||||
collection = client.getDatabase("eco").getCollection()
|
||||
}
|
||||
|
||||
override fun <T : Any> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
return runBlocking {
|
||||
doRead(uuid, key)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: T) {
|
||||
scope.launch {
|
||||
doWrite(uuid, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
val profile = handler.loadGenericProfile(uuid)
|
||||
|
||||
scope.launch {
|
||||
for (key in keys) {
|
||||
saveKey(profile, uuid, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun <T : Any> saveKey(profile: Profile, uuid: UUID, key: PersistentDataKey<T>) {
|
||||
val data = profile.read(key)
|
||||
doWrite(uuid, key, data)
|
||||
}
|
||||
|
||||
private suspend fun <T> doWrite(uuid: UUID, key: PersistentDataKey<T>, value: T) {
|
||||
val profile = getOrCreateDocument(uuid)
|
||||
|
||||
val newData = profile.data.apply {
|
||||
if (value == null) {
|
||||
this.remove(key.key.toString())
|
||||
} else {
|
||||
this[key.key.toString()] = value
|
||||
}
|
||||
}
|
||||
|
||||
collection.updateOne(UUIDProfile::uuid eq uuid.toString(), setValue(UUIDProfile::data, newData))
|
||||
}
|
||||
|
||||
private suspend fun <T> doRead(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
val profile = collection.findOne(UUIDProfile::uuid eq uuid.toString()) ?: return key.defaultValue
|
||||
return profile.data[key.key.toString()] as? T?
|
||||
}
|
||||
|
||||
private suspend fun getOrCreateDocument(uuid: UUID): UUIDProfile {
|
||||
val profile = collection.findOne(UUIDProfile::uuid eq uuid.toString())
|
||||
return if (profile == null) {
|
||||
collection.insertOne(
|
||||
UUIDProfile(
|
||||
uuid.toString(),
|
||||
mutableMapOf()
|
||||
)
|
||||
)
|
||||
|
||||
getOrCreateDocument(uuid)
|
||||
} else {
|
||||
profile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class UUIDProfile(
|
||||
// Storing UUID as strings for serialization
|
||||
@BsonId
|
||||
val uuid: String,
|
||||
// Storing NamespacedKeys as strings for serialization
|
||||
val data: MutableMap<String, Any>
|
||||
)
|
||||
@@ -13,8 +13,6 @@ import com.willfp.eco.internal.spigot.data.KeyHelpers
|
||||
import com.willfp.eco.internal.spigot.data.serverProfileUUID
|
||||
import com.zaxxer.hikari.HikariConfig
|
||||
import com.zaxxer.hikari.HikariDataSource
|
||||
import org.apache.logging.log4j.Level
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.jetbrains.exposed.dao.id.UUIDTable
|
||||
import org.jetbrains.exposed.sql.BooleanColumnType
|
||||
import org.jetbrains.exposed.sql.Column
|
||||
@@ -24,27 +22,43 @@ 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.exposedLogger
|
||||
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.ConcurrentHashMap
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.Future
|
||||
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 MySQLDataHandler(
|
||||
private val plugin: EcoSpigotPlugin,
|
||||
handler: EcoProfileHandler
|
||||
) : DataHandler {
|
||||
) : DataHandler(HandlerType.MYSQL) {
|
||||
private val playerHandler: ImplementedMySQLHandler
|
||||
private val serverHandler: ImplementedMySQLHandler
|
||||
|
||||
init {
|
||||
plugin.logger.warning("You're using the MySQL Data Handler")
|
||||
plugin.logger.warning("It's recommended to switch to MongoDB (mongo)!")
|
||||
|
||||
val config = HikariConfig()
|
||||
config.driverClassName = "com.mysql.cj.jdbc.Driver"
|
||||
@@ -58,40 +72,26 @@ class MySQLDataHandler(
|
||||
|
||||
Database.connect(HikariDataSource(config))
|
||||
|
||||
// Get Exposed to shut the hell up
|
||||
runCatching {
|
||||
exposedLogger::class.java.getDeclaredField("logger").apply { isAccessible = true }
|
||||
.apply {
|
||||
get(exposedLogger).apply {
|
||||
this.javaClass.getDeclaredMethod("setLevel", Level::class.java)
|
||||
.invoke(this, Level.OFF)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playerHandler = ImplementedMySQLHandler(
|
||||
handler,
|
||||
UUIDTable("eco_players"),
|
||||
plugin,
|
||||
plugin.dataYml.getStrings("categorized-keys.player")
|
||||
.mapNotNull { KeyHelpers.deserializeFromString(it) }
|
||||
plugin
|
||||
)
|
||||
|
||||
serverHandler = ImplementedMySQLHandler(
|
||||
handler,
|
||||
UUIDTable("eco_server"),
|
||||
plugin,
|
||||
plugin.dataYml.getStrings("categorized-keys.server")
|
||||
.mapNotNull { KeyHelpers.deserializeFromString(it) }
|
||||
plugin
|
||||
)
|
||||
}
|
||||
|
||||
override fun saveAll(uuids: Iterable<UUID>) {
|
||||
serverHandler.saveAll(uuids.filter { it == serverProfileUUID })
|
||||
playerHandler.saveAll(uuids.filter { it != serverProfileUUID })
|
||||
override fun <T : Any> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
return applyFor(uuid) {
|
||||
it.read(uuid, key)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> write(uuid: UUID, key: NamespacedKey, value: T) {
|
||||
override fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: T) {
|
||||
applyFor(uuid) {
|
||||
it.write(uuid, key, value)
|
||||
}
|
||||
@@ -103,12 +103,6 @@ class MySQLDataHandler(
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
return applyFor(uuid) {
|
||||
it.read(uuid, key.key)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <R> applyFor(uuid: UUID, function: (ImplementedMySQLHandler) -> R): R {
|
||||
return if (uuid == serverProfileUUID) {
|
||||
function(serverHandler)
|
||||
@@ -119,21 +113,21 @@ class MySQLDataHandler(
|
||||
|
||||
override fun categorize(key: PersistentDataKey<*>, category: KeyRegistry.KeyCategory) {
|
||||
if (category == KeyRegistry.KeyCategory.SERVER) {
|
||||
serverHandler.ensureKeyRegistration(key.key)
|
||||
serverHandler.ensureKeyRegistration(key)
|
||||
} else {
|
||||
playerHandler.ensureKeyRegistration(key.key)
|
||||
playerHandler.ensureKeyRegistration(key)
|
||||
}
|
||||
}
|
||||
|
||||
override fun save() {
|
||||
plugin.dataYml.set(
|
||||
"categorized-keys.player",
|
||||
playerHandler.registeredKeys.values
|
||||
playerHandler.registeredKeys
|
||||
.map { KeyHelpers.serializeToString(it) }
|
||||
)
|
||||
plugin.dataYml.set(
|
||||
"categorized-keys.server",
|
||||
serverHandler.registeredKeys.values
|
||||
serverHandler.registeredKeys
|
||||
.map { KeyHelpers.serializeToString(it) }
|
||||
)
|
||||
plugin.dataYml.save()
|
||||
@@ -149,21 +143,15 @@ class MySQLDataHandler(
|
||||
private class ImplementedMySQLHandler(
|
||||
private val handler: EcoProfileHandler,
|
||||
private val table: UUIDTable,
|
||||
plugin: EcoPlugin,
|
||||
private val knownKeys: Collection<PersistentDataKey<*>>
|
||||
plugin: EcoPlugin
|
||||
) {
|
||||
private val columns = Caffeine.newBuilder()
|
||||
.expireAfterWrite(3, TimeUnit.SECONDS)
|
||||
.build<String, Column<*>>()
|
||||
|
||||
private val rows = Caffeine.newBuilder()
|
||||
.expireAfterWrite(3, TimeUnit.SECONDS)
|
||||
.build<UUID, ResultRow>()
|
||||
|
||||
private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-mysql-thread-%d").build()
|
||||
private val executor = Executors.newFixedThreadPool(plugin.configYml.getInt("mysql.threads"), threadFactory)
|
||||
val registeredKeys = ConcurrentHashMap<NamespacedKey, PersistentDataKey<*>>()
|
||||
private val currentlyProcessingRegistration = ConcurrentHashMap<NamespacedKey, Future<*>>()
|
||||
val registeredKeys = mutableSetOf<PersistentDataKey<*>>()
|
||||
|
||||
init {
|
||||
transaction {
|
||||
@@ -173,58 +161,32 @@ private class ImplementedMySQLHandler(
|
||||
|
||||
fun initialize() {
|
||||
transaction {
|
||||
for (key in knownKeys) {
|
||||
registerColumn(key, table)
|
||||
}
|
||||
|
||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
||||
for (key in knownKeys) {
|
||||
registeredKeys[key.key] = key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ensureKeyRegistration(key: NamespacedKey) {
|
||||
if (registeredKeys.contains(key)) {
|
||||
fun ensureKeyRegistration(key: PersistentDataKey<*>) {
|
||||
if (table.columns.any { it.name == key.key.toString() }) {
|
||||
registeredKeys.add(key)
|
||||
return
|
||||
}
|
||||
|
||||
val persistentKey = Eco.getHandler().keyRegistry.getKeyFrom(key) ?: return
|
||||
|
||||
if (table.columns.any { it.name == key.toString() }) {
|
||||
registeredKeys[key] = persistentKey
|
||||
return
|
||||
}
|
||||
|
||||
val future = currentlyProcessingRegistration[key]
|
||||
|
||||
if (future != null) {
|
||||
future.get()
|
||||
return
|
||||
}
|
||||
|
||||
currentlyProcessingRegistration[key] = executor.submit {
|
||||
transaction {
|
||||
registerColumn(persistentKey, table)
|
||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
||||
}
|
||||
registeredKeys[key] = persistentKey
|
||||
currentlyProcessingRegistration.remove(key)
|
||||
}
|
||||
registerColumn(key)
|
||||
registeredKeys.add(key)
|
||||
}
|
||||
|
||||
fun <T> write(uuid: UUID, key: NamespacedKey, value: T) {
|
||||
getOrCreateRow(uuid)
|
||||
doWrite(uuid, key, value)
|
||||
fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: Any) {
|
||||
getRow(uuid)
|
||||
doWrite(uuid, key, key.type.constrainSQLTypes(value))
|
||||
}
|
||||
|
||||
private fun <T> doWrite(uuid: UUID, key: NamespacedKey, value: T) {
|
||||
val column: Column<T> = getColumn(key) as Column<T>
|
||||
private fun doWrite(uuid: UUID, key: PersistentDataKey<*>, constrainedValue: Any) {
|
||||
val column: Column<Any> = getColumn(key) as Column<Any>
|
||||
|
||||
executor.submit {
|
||||
transaction {
|
||||
table.update({ table.id eq uuid }) {
|
||||
it[column] = value
|
||||
it[column] = constrainedValue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,35 +196,28 @@ private class ImplementedMySQLHandler(
|
||||
saveRow(uuid, keys)
|
||||
}
|
||||
|
||||
fun saveAll(uuids: Iterable<UUID>) {
|
||||
for (uuid in uuids) {
|
||||
saveRow(uuid, PersistentDataKey.values())
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveRow(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
val profile = handler.loadGenericProfile(uuid)
|
||||
|
||||
executor.submit {
|
||||
transaction {
|
||||
getOrCreateRow(uuid)
|
||||
getRow(uuid)
|
||||
|
||||
for (key in keys) {
|
||||
doWrite(uuid, key.key, profile.read(key))
|
||||
doWrite(uuid, key, key.type.constrainSQLTypes(profile.read(key)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> read(uuid: UUID, key: NamespacedKey): T? {
|
||||
fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
val doRead = Callable<T?> {
|
||||
var value: T? = null
|
||||
transaction {
|
||||
val row = getOrCreateRow(uuid)
|
||||
value = row[getColumn(key)] as T?
|
||||
val row = getRow(uuid)
|
||||
val column = getColumn(key)
|
||||
val raw = row[column]
|
||||
key.type.fromConstrained(raw)
|
||||
}
|
||||
|
||||
return@Callable value
|
||||
}
|
||||
|
||||
ensureKeyRegistration(key) // DON'T DELETE THIS LINE! I know it's covered in getColumn, but I need to do it here as well.
|
||||
@@ -274,38 +229,40 @@ private class ImplementedMySQLHandler(
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> registerColumn(key: PersistentDataKey<T>, table: UUIDTable) {
|
||||
table.apply {
|
||||
if (this.columns.stream().anyMatch { it.name == key.key.toString() }) {
|
||||
return@apply
|
||||
private fun <T> registerColumn(key: PersistentDataKey<T>) {
|
||||
transaction {
|
||||
table.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)
|
||||
|
||||
else -> throw NullPointerException("Null value found!")
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
else -> throw NullPointerException("Null value found!")
|
||||
}
|
||||
SchemaUtils.createMissingTablesAndColumns(table, withLogs = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getColumn(key: NamespacedKey): Column<*> {
|
||||
private fun getColumn(key: PersistentDataKey<*>): Column<*> {
|
||||
ensureKeyRegistration(key)
|
||||
|
||||
val name = key.toString()
|
||||
val name = key.key.toString()
|
||||
|
||||
return columns.get(name) {
|
||||
table.columns.first { it.name == name }
|
||||
}
|
||||
return table.columns.first { it.name == name }
|
||||
}
|
||||
|
||||
private fun getOrCreateRow(uuid: UUID): ResultRow {
|
||||
private fun getRow(uuid: UUID): ResultRow {
|
||||
fun select(uuid: UUID): ResultRow? {
|
||||
return transaction {
|
||||
table.select { table.id eq uuid }.limit(1).singleOrNull()
|
||||
@@ -326,3 +283,27 @@ private class ImplementedMySQLHandler(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,16 +1,19 @@
|
||||
package com.willfp.eco.internal.spigot.data.storage
|
||||
|
||||
import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.data.ProfileHandler
|
||||
import com.willfp.eco.internal.spigot.data.EcoProfile
|
||||
|
||||
class ProfileSaver(plugin: EcoPlugin) {
|
||||
class ProfileSaver(
|
||||
plugin: EcoPlugin,
|
||||
handler: ProfileHandler
|
||||
) {
|
||||
init {
|
||||
plugin.scheduler.runTimer({
|
||||
plugin.scheduler.runTimer(1, 1) {
|
||||
for ((uuid, set) in EcoProfile.CHANGE_MAP) {
|
||||
Eco.getHandler().profileHandler.saveKeysFor(uuid, set)
|
||||
handler.saveKeysFor(uuid, set)
|
||||
}
|
||||
EcoProfile.CHANGE_MAP.clear()
|
||||
}, 1, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,42 +11,40 @@ import java.util.UUID
|
||||
class YamlDataHandler(
|
||||
plugin: EcoSpigotPlugin,
|
||||
private val handler: EcoProfileHandler
|
||||
) : DataHandler {
|
||||
) : DataHandler(HandlerType.YAML) {
|
||||
private val dataYml = plugin.dataYml
|
||||
|
||||
override fun save() {
|
||||
dataYml.save()
|
||||
}
|
||||
|
||||
override fun saveAll(uuids: Iterable<UUID>) {
|
||||
for (uuid in uuids) {
|
||||
savePlayer(uuid)
|
||||
override fun <T : Any> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
// Separate `as T?` for each branch to prevent compiler warnings.
|
||||
val value = when (key.type) {
|
||||
PersistentDataKeyType.INT -> dataYml.getIntOrNull("player.$uuid.${key.key}") as T?
|
||||
PersistentDataKeyType.DOUBLE -> dataYml.getDoubleOrNull("player.$uuid.${key.key}") as T?
|
||||
PersistentDataKeyType.STRING -> dataYml.getStringOrNull("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?
|
||||
else -> null
|
||||
}
|
||||
|
||||
save()
|
||||
return value
|
||||
}
|
||||
|
||||
override fun <T : Any> write(uuid: UUID, key: PersistentDataKey<T>, value: T) {
|
||||
doWrite(uuid, key.key, value)
|
||||
}
|
||||
|
||||
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
|
||||
val profile = handler.loadGenericProfile(uuid)
|
||||
|
||||
for (key in keys) {
|
||||
write(uuid, key.key, profile.read(key))
|
||||
doWrite(uuid, key.key, profile.read(key))
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> write(uuid: UUID, key: NamespacedKey, value: T) {
|
||||
private fun doWrite(uuid: UUID, key: NamespacedKey, value: Any) {
|
||||
dataYml.set("player.$uuid.$key", value)
|
||||
}
|
||||
|
||||
override fun <T> read(uuid: UUID, key: PersistentDataKey<T>): T? {
|
||||
val value = when (key.type) {
|
||||
PersistentDataKeyType.INT -> dataYml.getIntOrNull("player.$uuid.${key.key}")
|
||||
PersistentDataKeyType.DOUBLE -> dataYml.getDoubleOrNull("player.$uuid.${key.key}")
|
||||
PersistentDataKeyType.STRING -> dataYml.getStringOrNull("player.$uuid.${key.key}")
|
||||
PersistentDataKeyType.BOOLEAN -> dataYml.getBoolOrNull("player.$uuid.${key.key}")
|
||||
else -> null
|
||||
} as? T?
|
||||
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ class PacketAutoRecipe(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packet
|
||||
player: Player,
|
||||
event: PacketEvent
|
||||
) {
|
||||
if (!this.getPlugin().configYml.getBool("displayed-recipes")) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!EcoPlugin.getPluginNames()
|
||||
.contains(packet.minecraftKeys.values[0].fullKey.split(":".toRegex()).toTypedArray()[0])
|
||||
) {
|
||||
@@ -28,4 +32,4 @@ class PacketAutoRecipe(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packet
|
||||
newAutoRecipe.minecraftKeys.write(0, packet.minecraftKeys.read(0))
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newAutoRecipe)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ import com.comphenix.protocol.events.PacketEvent
|
||||
import com.willfp.eco.core.AbstractPacketAdapter
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.internal.spigot.proxy.VillagerTradeProxy
|
||||
import com.willfp.eco.util.NamespacedKeyUtils
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemFlag
|
||||
import org.bukkit.inventory.MerchantRecipe
|
||||
|
||||
class PacketOpenWindowMerchant(plugin: EcoPlugin) :
|
||||
@@ -24,22 +22,6 @@ class PacketOpenWindowMerchant(plugin: EcoPlugin) :
|
||||
) {
|
||||
val recipes = mutableListOf<MerchantRecipe>()
|
||||
|
||||
|
||||
/*
|
||||
This awful, awful bit of code exists to fix a bug that existed in EcoEnchants
|
||||
for too many versions.
|
||||
*/
|
||||
if (getPlugin().configYml.getBool("villager-display-fix")) {
|
||||
for (recipe in packet.merchantRecipeLists.read(0)) {
|
||||
val result = recipe.result
|
||||
val meta = result.itemMeta
|
||||
if (meta != null) {
|
||||
meta.removeItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_POTION_EFFECTS)
|
||||
meta.persistentDataContainer.remove(NamespacedKeyUtils.create("ecoenchants", "ecoenchantlore-skip"))
|
||||
result.itemMeta = meta
|
||||
}
|
||||
}
|
||||
}
|
||||
for (recipe in packet.merchantRecipeLists.read(0)) {
|
||||
val newRecipe = getPlugin().getProxy(VillagerTradeProxy::class.java).displayTrade(
|
||||
recipe!!, player
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
package com.willfp.eco.internal.spigot.display
|
||||
|
||||
import com.comphenix.protocol.PacketType
|
||||
import com.comphenix.protocol.ProtocolLibrary
|
||||
import com.comphenix.protocol.events.PacketContainer
|
||||
import com.comphenix.protocol.events.PacketEvent
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||
import com.willfp.eco.core.AbstractPacketAdapter
|
||||
import com.willfp.eco.core.Eco
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.display.Display
|
||||
import com.willfp.eco.core.items.HashedItem
|
||||
import com.willfp.eco.internal.spigot.display.frame.DisplayFrame
|
||||
import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame
|
||||
import com.willfp.eco.util.ServerUtils
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.WINDOW_ITEMS, false) {
|
||||
private val ignorePacketList = ConcurrentHashMap.newKeySet<String>()
|
||||
private val playerRates = ConcurrentHashMap<String, Int>()
|
||||
private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-display-thread-%d").build()
|
||||
private val executor = Executors.newCachedThreadPool(threadFactory)
|
||||
private val scheduledExecutor = Executors.newSingleThreadScheduledExecutor(threadFactory)
|
||||
|
||||
override fun onSend(
|
||||
packet: PacketContainer,
|
||||
@@ -44,90 +34,9 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
|
||||
|
||||
val itemStacks = packet.itemListModifier.read(0) ?: return
|
||||
|
||||
handleRateLimit(player)
|
||||
|
||||
if (usingAsync(player)) {
|
||||
val newPacket = packet.deepClone()
|
||||
|
||||
executor.execute {
|
||||
runCatchingWithLogs { modifyAndSend(newPacket, itemStacks, windowId, player) }
|
||||
}
|
||||
} else {
|
||||
modifyPacket(packet, itemStacks, windowId, player)
|
||||
}
|
||||
}
|
||||
|
||||
private fun modifyPacket(
|
||||
packet: PacketContainer,
|
||||
itemStacks: MutableList<ItemStack>,
|
||||
windowId: Int,
|
||||
player: Player
|
||||
) {
|
||||
packet.itemListModifier.write(0, modifyWindowItems(itemStacks, windowId, player))
|
||||
}
|
||||
|
||||
private fun modifyAndSend(
|
||||
packet: PacketContainer,
|
||||
itemStacks: MutableList<ItemStack>,
|
||||
windowId: Int,
|
||||
player: Player
|
||||
) {
|
||||
modifyPacket(packet, itemStacks, windowId, player)
|
||||
ignorePacketList.add(player.name)
|
||||
this.getPlugin().scheduler.run {
|
||||
runCatchingWithLogs { ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRateLimit(player: Player) {
|
||||
fun modifyRateValueBy(player: Player, amount: Int) {
|
||||
val name = player.name
|
||||
val current = playerRates[name] ?: 0
|
||||
val new = current + amount
|
||||
if (new <= 0) {
|
||||
playerRates.remove(name)
|
||||
} else {
|
||||
playerRates[name] = new
|
||||
}
|
||||
}
|
||||
|
||||
modifyRateValueBy(player, 1)
|
||||
|
||||
scheduledExecutor.schedule(
|
||||
{ modifyRateValueBy(player, -1) },
|
||||
this.getPlugin().configYml.getInt("async-display.ratelimit.timeframe").toLong(),
|
||||
TimeUnit.SECONDS
|
||||
)
|
||||
}
|
||||
|
||||
private fun usingAsync(player: Player): Boolean {
|
||||
if (this.getPlugin().configYml.getStrings("async-display.disable-on-types")
|
||||
.map { it.lowercase() }.contains(player.openInventory.type.name.lowercase())
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (this.getPlugin().configYml.getBool("async-display.always-enabled")) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (
|
||||
this.getPlugin().configYml.getBool("async-display.emergency.enabled")
|
||||
&& ServerUtils.getTps() <= this.getPlugin().configYml.getDouble("async-display.emergency.cutoff")
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (
|
||||
this.getPlugin().configYml.getBool("async-display.ratelimit.enabled")
|
||||
&& (playerRates[player.name] ?: 0) >= this.getPlugin().configYml.getInt("async-display.ratelimit.cutoff")
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun modifyWindowItems(
|
||||
itemStacks: MutableList<ItemStack>,
|
||||
windowId: Int,
|
||||
@@ -162,14 +71,3 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
|
||||
return itemStacks
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> runCatchingWithLogs(toRun: () -> T): Result<T> {
|
||||
return runCatching { toRun() }.onFailure {
|
||||
if (Eco.getHandler().ecoPlugin.configYml.getBool("async-display.log-errors")) {
|
||||
Eco.getHandler().ecoPlugin.logger.warning(
|
||||
"Error happened in async processing! Disable async display (/plugins/eco/config.yml)" +
|
||||
"if this is a frequent issue. (Remember to disable ratelimit and emergency too)"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.willfp.eco.internal.spigot.eventlisteners
|
||||
|
||||
import com.willfp.eco.core.events.EntityDeathByEntityEvent
|
||||
import org.apache.commons.lang.Validate
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Entity
|
||||
import org.bukkit.entity.LivingEntity
|
||||
@@ -10,20 +9,12 @@ import org.bukkit.inventory.ItemStack
|
||||
|
||||
internal class EntityDeathByEntityBuilder {
|
||||
var victim: LivingEntity? = null
|
||||
|
||||
var damager: Entity? = null
|
||||
|
||||
var deathEvent: EntityDeathEvent? = null
|
||||
|
||||
var drops: List<ItemStack>? = null
|
||||
|
||||
var xp = 0
|
||||
fun push() {
|
||||
|
||||
Validate.notNull(victim)
|
||||
Validate.notNull(damager)
|
||||
Validate.notNull(drops)
|
||||
Validate.notNull(deathEvent)
|
||||
fun push() {
|
||||
val event = EntityDeathByEntityEvent(victim!!, damager!!, drops!!, xp, deathEvent!!)
|
||||
Bukkit.getPluginManager().callEvent(event)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import org.bukkit.event.entity.EntityDeathEvent
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class EntityDeathByEntityListeners(
|
||||
private val plugin: EcoPlugin
|
||||
@@ -35,25 +34,24 @@ class EntityDeathByEntityListeners(
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
fun onEntityDeath(event: EntityDeathEvent) {
|
||||
val victim = event.entity
|
||||
val drops = event.drops
|
||||
val xp = event.droppedExp
|
||||
|
||||
val atomicBuiltEvent = AtomicReference<EntityDeathByEntityBuilder>(null)
|
||||
var builtEvent: EntityDeathByEntityBuilder? = null
|
||||
|
||||
for (builder in events) {
|
||||
if (builder.victim == victim) {
|
||||
atomicBuiltEvent.set(builder)
|
||||
builtEvent = builder
|
||||
}
|
||||
}
|
||||
|
||||
if (atomicBuiltEvent.get() == null) {
|
||||
if (builtEvent == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val builtEvent = atomicBuiltEvent.get()
|
||||
events.remove(builtEvent)
|
||||
builtEvent.drops = drops
|
||||
builtEvent.xp = xp
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
package com.willfp.eco.internal.spigot.eventlisteners
|
||||
|
||||
import com.willfp.eco.core.events.NaturalExpGainEvent
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.ThrownExpBottle
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.ExpBottleEvent
|
||||
import org.bukkit.event.player.PlayerExpChangeEvent
|
||||
|
||||
class NaturalExpGainListeners : Listener {
|
||||
class NaturalExpGainListenersPaper : Listener {
|
||||
@EventHandler
|
||||
fun onEvent(event: PlayerExpChangeEvent) {
|
||||
val source = event.source
|
||||
|
||||
if (source is ThrownExpBottle) {
|
||||
return
|
||||
}
|
||||
|
||||
val ecoEvent = NaturalExpGainEvent(event)
|
||||
Bukkit.getPluginManager().callEvent(ecoEvent)
|
||||
}
|
||||
}
|
||||
|
||||
class NaturalExpGainListenersSpigot : Listener {
|
||||
private val events: MutableSet<NaturalExpGainBuilder> = HashSet()
|
||||
|
||||
@EventHandler
|
||||
|
||||
@@ -11,10 +11,7 @@ import com.willfp.eco.core.integrations.antigrief.AntigriefIntegration
|
||||
import org.apache.commons.lang.Validate
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.entity.Animals
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.entity.Monster
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.entity.*
|
||||
|
||||
class AntigriefWorldGuard : AntigriefIntegration {
|
||||
override fun canBreakBlock(
|
||||
@@ -85,6 +82,7 @@ class AntigriefWorldGuard : AntigriefIntegration {
|
||||
is Player -> Flags.PVP
|
||||
is Monster -> Flags.MOB_DAMAGE
|
||||
is Animals -> Flags.DAMAGE_ANIMALS
|
||||
is ArmorStand -> Flags.INTERACT
|
||||
else -> return true
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ class CustomItemsItemsAdder : CustomItemsIntegration {
|
||||
|
||||
private class ItemsAdderProvider : ItemProvider("itemsadder") {
|
||||
override fun provideForKey(key: String): TestableItem? {
|
||||
val item = CustomStack.getInstance("itemsadder:$key") ?: return null
|
||||
val internalId = if (key.contains(":")) key else "itemsadder:$key"
|
||||
|
||||
val item = CustomStack.getInstance(internalId) ?: return null
|
||||
val id = item.id
|
||||
val namespacedKey = NamespacedKeyUtils.create("itemsadder", key)
|
||||
val stack = item.itemStack
|
||||
@@ -34,6 +36,5 @@ class CustomItemsItemsAdder : CustomItemsIntegration {
|
||||
stack
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
#
|
||||
# eco
|
||||
# by Auxilor
|
||||
# Default config (With Comments) can be found here: https://github.com/Auxilor/eco/blob/master/eco-core/core-plugin/src/main/resources/config.yml
|
||||
#
|
||||
|
||||
# How player/server data is saved:
|
||||
# yaml - Stored in data.yml: Good option for single-node servers (i.e. no BungeeCord/Velocity)
|
||||
# mongo - (Recommended) If you're running on a network (Bungee/Velocity), you should use MongoDB if you can.
|
||||
# mysql - (Not Recommended) The basic choice for Bungee/Velocity networks, less flexible and worse performance than MongoDB. Only use it if you can't use MongoDB.
|
||||
data-handler: yaml
|
||||
|
||||
# If data should be migrated automatically when changing data handler.
|
||||
perform-data-migration: true
|
||||
|
||||
mongodb:
|
||||
# The full MongoDB connection URL.
|
||||
url: ""
|
||||
|
||||
mysql:
|
||||
enabled: false # Set to false, data.yml will be used instead.
|
||||
# How many threads to execute statements on. Higher numbers can be faster however
|
||||
# very high numbers can cause issues with OS configuration. If writes are taking
|
||||
# too long, increase this value.
|
||||
threads: 2
|
||||
# The maximum number of MySQL connections.
|
||||
connections: 10
|
||||
# If read operations should be ran in the thread pool. Runs on main thread by default.
|
||||
# If read operations should be run in the thread pool. Runs on main thread by default.
|
||||
async-reads: false
|
||||
host: localhost
|
||||
port: 3306
|
||||
@@ -19,8 +32,13 @@ mysql:
|
||||
user: username
|
||||
password: passy
|
||||
|
||||
# Options to fix villager bugs left behind from old (buggy) versions.
|
||||
villager-display-fix: false
|
||||
# Ignore this option, it does nothing.
|
||||
enabled: false # Ignore this - only for backwards compatibility
|
||||
|
||||
# Options to manage the conflict finder
|
||||
conflicts:
|
||||
whitelist: # Plugins that should never be marked as conflicts
|
||||
- eco
|
||||
|
||||
# DropQueue by default uses a faster collated queue system where all drops
|
||||
# that originate from the same player on the same tick are dropped together.
|
||||
@@ -52,42 +70,10 @@ use-safer-namespacedkey-creation: false
|
||||
# default to prevent users from reporting bugs. Enable if you're a developer.
|
||||
log-full-extension-errors: false
|
||||
|
||||
# Window items packets have the option to be run asynchronously. This may cause
|
||||
# some bugs and is considered experimental, however it has been tested without
|
||||
# any apparent issues. Enable this if performance is absolutely crucial or if you
|
||||
# are experiencing severe display lag.
|
||||
async-display:
|
||||
# If async display should always be used.
|
||||
always-enabled: false
|
||||
|
||||
# Log errors that occur in async processing.
|
||||
log-errors: true
|
||||
|
||||
# The inventory types that should never be processed asynchronously.
|
||||
# A list of IDs can be found here:
|
||||
# https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/inventory/InventoryType.html
|
||||
disable-on-types:
|
||||
- 'anvil'
|
||||
|
||||
# If the server is running under heavy load (below a certain TPS value), enable
|
||||
# async display automatically. This can prevent some server crashes under load.
|
||||
emergency:
|
||||
# If emergency async should be used.
|
||||
enabled: true
|
||||
# Below this TPS value, emergency async display will be used.
|
||||
cutoff: 17
|
||||
|
||||
# If players with a large amount of display packets should have their processing
|
||||
# done asynchronously. This will help if a player is trying to crash the server
|
||||
# by overloading the display system.
|
||||
ratelimit:
|
||||
# If rate limit async display should be used.
|
||||
enabled: false
|
||||
# The amount of window items packets per timeframe needed to enable async display
|
||||
# for a specified player.
|
||||
cutoff: 4
|
||||
# The length of the timeframe in seconds.
|
||||
# Cutoff 5, Timeframe 1 means that if there are more than 5 window items packets
|
||||
# being sent per second for a player, then that player should have their packets
|
||||
# handled asynchronously.
|
||||
timeframe: 1
|
||||
# To make the custom crafting system work better for players, players are also sent an
|
||||
# additional recipe containing the displayed items as ingredients. However, with a large
|
||||
# number of recipes, this can create PacketTooLargeExceptions. If you have this exception,
|
||||
# disable this option. Bear in mind that this means the auto-craft preview will fail to
|
||||
# render items nicely, which may degrade the user experience on your server. If you use
|
||||
# a custom crafting table, though, this won't affect anything, and you should disable the option.
|
||||
displayed-recipes: true
|
||||
@@ -1,3 +1,3 @@
|
||||
version = 6.35.2
|
||||
version = 6.36.0
|
||||
plugin-name = eco
|
||||
kotlin.code.style = official
|
||||
@@ -1,7 +1,7 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven("https://papermc.io/repo/repository/maven-public/")
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user