Compare commits

..

16 Commits

Author SHA1 Message Date
Auxilor
732aaa3bf1 Fixed NamespacedKeyUtils.fromString 2022-01-27 13:23:25 +00:00
Auxilor
a38387be33 Fixed more stupidity 2022-01-27 13:16:42 +00:00
Auxilor
582f9b08f3 Fixed stupidity 2022-01-27 13:15:19 +00:00
Auxilor
638367cbb2 Switched objenesis instantiator 2022-01-27 13:08:59 +00:00
Auxilor
ec35e7d779 Fixed lateinit issues 2022-01-27 13:04:33 +00:00
Auxilor
1cc2a585d6 NamespacedKey changes 2022-01-27 12:51:22 +00:00
Auxilor
aa553b96d6 Updated to 6.21.0 2022-01-27 12:41:53 +00:00
Auxilor
feb7ecee48 Added fast NamespacedKey creation 2022-01-27 12:41:18 +00:00
Auxilor
c0be6a12ff Changed behaviour to not be the same as enum behaviour 2022-01-26 12:42:05 +00:00
Auxilor
1dc6b651a0 Switched PersistentDataKeyType to not be an enum 2022-01-26 12:40:15 +00:00
Auxilor
3c26c02642 Added issue template 2022-01-26 11:19:02 +00:00
Auxilor
343508f099 Updated to 6.20.4 2022-01-20 09:44:08 +00:00
Auxilor
76dc4948bc Fixed playerless placeholders 2022-01-20 09:43:53 +00:00
Auxilor
8fa209a981 Switched from shallow to deep packet cloning for async 2022-01-18 09:19:14 +00:00
Auxilor
b3a0634ad0 Updated to 6.20.3 2022-01-18 09:18:36 +00:00
Auxilor
97d7acc0a9 Tweaked async display 2022-01-18 09:18:25 +00:00
21 changed files with 279 additions and 40 deletions

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Auxilor Community Discord
url: https://discord.gg/ZcwpSsE/
about: Join the Auxilor discord to get help from support staff and the general community!
- name: The most common issues people have
url: https://github.com/Auxilor/eco/issues/78
about: Check the list of known common issues to see if your issue has already been solved

31
.github/ISSUE_TEMPLATE/report-a-bug.md vendored Normal file
View File

@@ -0,0 +1,31 @@
---
name: Report a Bug
about: Report an issue with the plugin
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Server Information (please complete the following information):**
- Version: (output of `/ver` command)
- Version of plugin and eco (`/ver eco`, `/ver <plugin>`)
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Request a Feature
about: Suggest an idea for this plugin
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -19,6 +19,7 @@ import com.willfp.eco.core.requirement.RequirementFactory;
import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
@@ -243,4 +244,19 @@ public interface Handler {
*/
@NotNull
Entity createDummyEntity(@NotNull Location location);
/**
* Create a {@link NamespacedKey} quickly
* <p>
* Bypasses the constructor, allowing for the creation of invalid keys,
* therefore this is considered unsafe and should only be called after
* the key has been confirmed to be valid.
*
* @param namespace The namespace.
* @param key The key.
* @return The key.
*/
@NotNull
NamespacedKey createNamespacedKey(@NotNull String namespace,
@NotNull String key);
}

View File

@@ -25,7 +25,7 @@ public class PersistentDataKey<T> {
/**
* The persistent data key type.
*/
private final PersistentDataKeyType type;
private final PersistentDataKeyType<T> type;
/**
* Create a new Persistent Data Key.
@@ -35,7 +35,7 @@ public class PersistentDataKey<T> {
* @param defaultValue The default value.
*/
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType type,
@NotNull final PersistentDataKeyType<T> type,
@NotNull final T defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
@@ -76,7 +76,7 @@ public class PersistentDataKey<T> {
*
* @return The key type.
*/
public PersistentDataKeyType getType() {
public PersistentDataKeyType<T> getType() {
return this.type;
}

View File

@@ -1,26 +1,108 @@
package com.willfp.eco.core.data.keys;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* All storable data key types.
*
* @param <T> The type.
*/
public enum PersistentDataKeyType {
public final class PersistentDataKeyType<T> {
/**
* The registered key types.
*/
private static final List<PersistentDataKeyType<?>> VALUES = new ArrayList<>();
/**
* String.
*/
STRING,
public static final PersistentDataKeyType<String> STRING = new PersistentDataKeyType<>(String.class, "STRING");
/**
* Boolean.
*/
BOOLEAN,
public static final PersistentDataKeyType<Boolean> BOOLEAN = new PersistentDataKeyType<>(Boolean.class, "BOOLEAN");
/**
* Integer.
* Int.
*/
INT,
public static final PersistentDataKeyType<Integer> INT = new PersistentDataKeyType<>(Integer.class, "INT");
/**
* Double.
*/
DOUBLE
public static final PersistentDataKeyType<Double> DOUBLE = new PersistentDataKeyType<>(Double.class, "DOUBLE");
/**
* The class of the type.
*/
private final Class<T> typeClass;
/**
* The name of the key type.
*/
private final String name;
/**
* Get the class of the type.
*
* @return The class.
*/
public Class<T> getTypeClass() {
return typeClass;
}
/**
* Get the name of the key type.
*
* @return The name.
*/
public String name() {
return name;
}
/**
* Create new PersistentDataKeyType.
*
* @param typeClass The type class.
* @param name The name.
*/
private PersistentDataKeyType(@NotNull final Class<T> typeClass,
@NotNull final String name) {
VALUES.add(this);
this.typeClass = typeClass;
this.name = name;
}
/**
* Get all registered {@link PersistentDataKeyType}s.
*
* @return The registered types.
*/
@NotNull
public static PersistentDataKeyType<?>[] values() {
return VALUES.toArray(new PersistentDataKeyType[0]);
}
/**
* Get a key type from a name.
*
* @param name The name.
* @return The type, or null if not found.
*/
@Nullable
public static PersistentDataKeyType<?> valueOf(@NotNull final String name) {
for (PersistentDataKeyType<?> type : VALUES) {
if (type.name.equalsIgnoreCase(name)) {
return type;
}
}
return null;
}
}

View File

@@ -75,7 +75,7 @@ public final class PlaceholderManager {
public static String getResult(@Nullable final Player player,
@NotNull final String identifier,
@Nullable final EcoPlugin plugin) {
EcoPlugin owner = player == null ? Eco.getHandler().getEcoPlugin() : plugin;
EcoPlugin owner = plugin == null ? Eco.getHandler().getEcoPlugin() : plugin;
PlaceholderEntry entry = REGISTERED_PLACEHOLDERS.getOrDefault(owner, new HashMap<>()).get(identifier.toLowerCase());
if (entry == null && plugin != null) {

View File

@@ -6,6 +6,7 @@ import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -58,7 +59,10 @@ public final class Recipes {
}
if (key.getKey().contains("_displayed")) {
NamespacedKey otherKey = new NamespacedKey(key.getNamespace(), key.getKey().replace("_displayed", ""));
NamespacedKey otherKey = NamespacedKeyUtils.create(
key.getNamespace(),
key.getKey().replace("_displayed", "")
);
return RECIPES.get(otherKey);
}

View File

@@ -1,10 +1,9 @@
package com.willfp.eco.util;
import com.willfp.eco.core.Eco;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import java.util.Objects;
/**
* Utilities / API methods for {@link NamespacedKey}s.
*/
@@ -17,7 +16,7 @@ public final class NamespacedKeyUtils {
*/
@NotNull
public static NamespacedKey createEcoKey(@NotNull final String string) {
return Objects.requireNonNull(NamespacedKey.fromString("eco:" + string));
return NamespacedKeyUtils.create("eco", string);
}
/**
@@ -30,7 +29,28 @@ public final class NamespacedKeyUtils {
@NotNull
public static NamespacedKey create(@NotNull final String namespace,
@NotNull final String key) {
return Objects.requireNonNull(NamespacedKey.fromString(namespace + ":" + key));
return Eco.getHandler().createNamespacedKey(
namespace,
key
);
}
/**
* Create a NamespacedKey from a string.
* <p>
* Preferred over {@link NamespacedKey#fromString(String)} for performance reasons.
*
* @param string The string.
* @return The key.
*/
@NotNull
public static NamespacedKey fromString(@NotNull final String string) {
int index = string.indexOf(":");
return NamespacedKeyUtils.create(
string.substring(0, index),
string.substring(index + 1)
);
}
private NamespacedKeyUtils() {

View File

@@ -8,4 +8,5 @@ dependencies {
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
compileOnly 'com.google.guava:guava:31.0.1-jre'
compileOnly 'org.objenesis:objenesis:3.2'
}

View File

@@ -2,10 +2,11 @@ package com.willfp.eco.internal.factory
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.factory.NamespacedKeyFactory
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.NamespacedKey
class EcoNamespacedKeyFactory(private val plugin: EcoPlugin) : NamespacedKeyFactory {
override fun create(key: String): NamespacedKey {
return NamespacedKey(plugin, key)
return NamespacedKeyUtils.create(plugin.name, key)
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.internal.fast
import org.bukkit.NamespacedKey
import org.objenesis.ObjenesisStd
interface InternalNamespacedKeyFactory {
fun create(namespace: String, key: String): NamespacedKey
}
class FastInternalNamespacedKeyFactory : InternalNamespacedKeyFactory {
private val creator = ObjenesisStd().getInstantiatorOf(NamespacedKey::class.java)
private val namespaceField = NamespacedKey::class.java.getDeclaredField("namespace")
.apply { isAccessible = true }
private val keyField = NamespacedKey::class.java.getDeclaredField("key")
.apply { isAccessible = true }
override fun create(namespace: String, key: String): NamespacedKey {
val namespacedKey = creator.newInstance()
keyField.set(namespacedKey, key.lowercase())
namespaceField.set(namespacedKey, namespace.lowercase())
return namespacedKey
}
}
class SafeInternalNamespacedKeyFactory : InternalNamespacedKeyFactory {
override fun create(namespace: String, key: String): NamespacedKey {
@Suppress("DEPRECATION")
return NamespacedKey(namespace, key)
}
}

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.internal.items
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.items.args.LookupArgParser
import org.bukkit.NamespacedKey
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.EnchantmentStorageMeta
@@ -20,7 +20,7 @@ class ArgParserEnchantment : LookupArgParser {
continue
}
val enchant = Enchantment.getByKey(NamespacedKey.minecraft(argSplit[0].lowercase()))
val enchant = Enchantment.getByKey(NamespacedKeyUtils.create("minecraft", argSplit[0]))
val level = argSplit[1].toIntOrNull()
if (enchant != null && level != null) {

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.spigot.proxy.v1_16_R3.fast
import com.willfp.eco.internal.fast.EcoFastItemStack
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.StringUtils
import net.minecraft.server.v1_16_R3.Item
import net.minecraft.server.v1_16_R3.ItemEnchantedBook
@@ -11,7 +12,6 @@ import net.minecraft.server.v1_16_R3.NBTTagList
import net.minecraft.server.v1_16_R3.NBTTagString
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_16_R3.util.CraftNamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import kotlin.experimental.and
@@ -29,7 +29,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
val compound = base as NBTTagCompound
val key = compound.getString("id")
val level: Int = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
val found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key))
val found = Enchantment.getByKey(NamespacedKeyUtils.fromString(key))
if (found != null) {
foundEnchantments[found] = level
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1.fast
import com.willfp.eco.internal.fast.EcoFastItemStack
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.StringUtils
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
@@ -11,7 +12,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import kotlin.experimental.and
@@ -31,7 +31,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
val compound = base as CompoundTag
val key = compound.getString("id")
val level = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
val found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key))
val found = Enchantment.getByKey(NamespacedKeyUtils.fromString(key))
if (found != null) {
foundEnchantments[found] = level
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1.fast
import com.willfp.eco.internal.fast.EcoFastItemStack
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.StringUtils
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
@@ -11,7 +12,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers
import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemFlag
import kotlin.experimental.and
@@ -32,7 +32,7 @@ class NMSFastItemStack(itemStack: org.bukkit.inventory.ItemStack) : EcoFastItemS
val compound = base as CompoundTag
val key = compound.getString("id")
val level = ('\uffff'.code.toShort() and compound.getShort("lvl")).toInt()
val found = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(key))
val found = Enchantment.getByKey(NamespacedKeyUtils.fromString(key))
if (found != null) {
foundEnchantments[found] = level
}

View File

@@ -14,6 +14,9 @@ import com.willfp.eco.internal.extensions.EcoExtensionLoader
import com.willfp.eco.internal.factory.EcoMetadataValueFactory
import com.willfp.eco.internal.factory.EcoNamespacedKeyFactory
import com.willfp.eco.internal.factory.EcoRunnableFactory
import com.willfp.eco.internal.fast.FastInternalNamespacedKeyFactory
import com.willfp.eco.internal.fast.InternalNamespacedKeyFactory
import com.willfp.eco.internal.fast.SafeInternalNamespacedKeyFactory
import com.willfp.eco.internal.gui.EcoGUIFactory
import com.willfp.eco.internal.integrations.PlaceholderIntegrationPAPI
import com.willfp.eco.internal.logging.EcoLogger
@@ -29,6 +32,7 @@ import com.willfp.eco.internal.spigot.proxy.DummyEntityProxy
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import net.kyori.adventure.platform.bukkit.BukkitAudiences
import org.bukkit.Location
import org.bukkit.NamespacedKey
import org.bukkit.entity.Entity
import org.bukkit.inventory.ItemStack
import java.util.logging.Logger
@@ -43,6 +47,9 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
if (this.configYml.getBool("mysql.enabled"))
MySQLDataHandler(this) else YamlDataHandler(this)
)
private val keyFactory: InternalNamespacedKeyFactory? =
if (this.configYml.getBool("use-safer-namespacedkey-creation"))
SafeInternalNamespacedKeyFactory() else FastInternalNamespacedKeyFactory()
override fun createScheduler(plugin: EcoPlugin): EcoScheduler {
return EcoScheduler(plugin)
@@ -147,4 +154,9 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
override fun createDummyEntity(location: Location): Entity {
return getProxy(DummyEntityProxy::class.java).createDummyEntity(location)
}
override fun createNamespacedKey(namespace: String, key: String): NamespacedKey {
@Suppress("DEPRECATION")
return keyFactory?.create(namespace, key) ?: NamespacedKey(namespace, key)
}
}

View File

@@ -6,6 +6,7 @@ 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.fast.FastItemStack
@@ -47,17 +48,10 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
handleRateLimit(player)
if (usingAsync(player)) {
val newPacket = packet.deepClone()
executor.execute {
runCatching {
modifyAndSend(packet.shallowClone(), itemStacks, windowId, player)
}.onFailure {
if (this.getPlugin().configYml.getBool("async-display.log-errors")) {
this.getPlugin().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)"
)
}
}
runCatchingWithLogs { modifyAndSend(newPacket, itemStacks, windowId, player) }
}
} else {
modifyPacket(packet, itemStacks, windowId, player)
@@ -82,7 +76,7 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
modifyPacket(packet, itemStacks, windowId, player)
ignorePacketList.add(player.name)
this.getPlugin().scheduler.run {
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet)
runCatchingWithLogs { ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet) }
}
}
@@ -169,4 +163,15 @@ 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)"
)
}
}
}

View File

@@ -46,6 +46,13 @@ display-frame-ttl: 17
# memory use.
item-cache-ttl: 6000
# The default bukkit NamespacedKey creation can cause decent amounts of lag under
# load due to the use of regex validation in the constructor. eco has its own system
# to create NamespacedKeys, however it can be unsafe as it skips most validation checks.
# If you encounter any bugs with this, then enable this option - however it will come
# at a performance penalty.
use-safer-namespacedkey-creation: 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
@@ -69,14 +76,14 @@ async-display:
# If emergency async should be used.
enabled: true
# Below this TPS value, emergency async display will be used.
cutoff: 18
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: true
enabled: false
# The amount of window items packets per timeframe needed to enable async display
# for a specified player.
cutoff: 4

View File

@@ -56,4 +56,5 @@ libraries:
- 'mysql:mysql-connector-java:8.0.25'
- 'com.google.guava:guava:31.0.1-jre'
- 'com.zaxxer:HikariCP:5.0.0'
- 'org.apache.commons:commons-lang3:3.0'
- 'org.apache.commons:commons-lang3:3.0'
- 'org.objenesis:objenesis:3.2'

View File

@@ -1,3 +1,3 @@
version = 6.20.2
version = 6.21.0
plugin-name = eco
kotlin.code.style = official