Compare commits

..

18 Commits
6.6.1 ... 6.7.0

Author SHA1 Message Date
Auxilor
61ace5c8e5 Updated to 6.7.0 2021-09-03 12:50:23 +01:00
Auxilor
94b73ef35c Improved Arg Parser javadoc 2021-09-03 12:49:59 +01:00
Auxilor
5cfc2068e7 Added arg parser lookup system 2021-09-03 12:47:23 +01:00
Auxilor
0ce7d1dd6c Added texture:<base64> to Items.lookup 2021-09-03 12:28:03 +01:00
Auxilor
19eefaf879 Improved Items.lookup javadoc 2021-09-03 11:54:48 +01:00
Auxilor
1ebf7fb875 Added Head Database integration 2021-09-03 11:45:34 +01:00
Auxilor
e8afd15d80 Updated to 6.6.4 2021-09-02 18:55:49 +01:00
Auxilor
d024c9238e Switched TestableStack display to only show recipe lore in recipes 2021-09-02 18:55:37 +01:00
Auxilor
1356bd1f26 ItemsAdder fix 2021-09-02 18:50:01 +01:00
Auxilor
407ccca5e0 TestableStack changes don't stop ever 2021-09-02 11:49:48 +01:00
Auxilor
82de602d47 Hopefully fixed crafting exploit 2021-09-02 10:53:14 +01:00
Auxilor
b0873112af Added ItemsAdder and Oraxen to plugin.yml 2021-09-02 10:50:40 +01:00
Auxilor
3a0b81b7de Updated to 6.6.3 2021-09-02 10:50:12 +01:00
Auxilor
5142b9ce92 More Items#lookup improvements 2021-09-02 10:46:25 +01:00
Auxilor
9403a1cbcb Marked item:amount system as legacy and replaced it with item amount 2021-09-02 10:42:29 +01:00
Auxilor
e4ebea354d Added ItemsAdder support 2021-09-02 10:35:03 +01:00
Auxilor
d32b31f1e5 Updated to 6.6.2 2021-09-01 15:35:57 +01:00
Auxilor
384657f1dc Fixed menu inventory registration memory leak 2021-09-01 15:35:33 +01:00
21 changed files with 500 additions and 130 deletions

View File

@@ -51,6 +51,9 @@ allprojects {
// CombatLogX // CombatLogX
maven { url 'https://nexus.sirblobman.xyz/repository/public/' } maven { url 'https://nexus.sirblobman.xyz/repository/public/' }
// Head Database
maven { url 'https://mvn.intellectualsites.com/content/groups/public/' }
} }
dependencies { dependencies {

View File

@@ -1,9 +1,11 @@
package com.willfp.eco.core.integrations.customitems; package com.willfp.eco.core.integrations.customitems;
import com.willfp.eco.core.integrations.Integration;
/** /**
* Wrapper class for custom item integrations. * Wrapper class for custom item integrations.
*/ */
public interface CustomItemsWrapper { public interface CustomItemsWrapper extends Integration {
/** /**
* Register all the custom items for a specific plugin into eco. * Register all the custom items for a specific plugin into eco.
* *

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.items; package com.willfp.eco.core.items;
import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem; import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem; import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem; import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
@@ -8,18 +9,19 @@ import com.willfp.eco.util.NamespacedKeyUtils;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
/** /**
* Class to manage all custom and vanilla items. * Class to manage all custom and vanilla items.
@@ -29,19 +31,33 @@ public final class Items {
/** /**
* All recipe parts. * All recipe parts.
*/ */
private static final Map<NamespacedKey, CustomItem> REGISTRY = new HashMap<>(); private static final Map<NamespacedKey, CustomItem> REGISTRY = new ConcurrentHashMap<>();
/** /**
* Register a new recipe part. * All recipe parts.
*/
private static final List<LookupArgParser> ARG_PARSERS = new ArrayList<>();
/**
* Register a new custom item.
* *
* @param key The key of the recipe part. * @param key The key of the item.
* @param part The recipe part. * @param part The item.
*/ */
public void registerCustomItem(@NotNull final NamespacedKey key, public void registerCustomItem(@NotNull final NamespacedKey key,
@NotNull final CustomItem part) { @NotNull final CustomItem part) {
REGISTRY.put(key, part); REGISTRY.put(key, part);
} }
/**
* Register a new arg parser.
*
* @param parser The parser.
*/
public void registerArgParser(@NotNull final LookupArgParser parser) {
ARG_PARSERS.add(parser);
}
/** /**
* Remove an item. * Remove an item.
* *
@@ -52,12 +68,27 @@ public final class Items {
} }
/** /**
* Lookup item from string. * This is the backbone of the entire eco item system.
* <p> * <p>
* Used for recipes. * You can lookup a TestableItem for any material, custom item,
* or item in general, and it will return it with any modifiers
* passed as parameters. This includes stack size (item amount)
* and enchantments that should be present on the item.
* <p>
* If you want to get an ItemStack instance from this, then just call
* {@link TestableItem#getItem()}.
* <p>
* The advantages of the testable item system are that there is the inbuilt
* {@link TestableItem#matches(ItemStack)} - this allows to check if any item
* is that testable item; which may sound negligible but actually it allows for
* much more power an flexibility. For example, you can have an item with an
* extra metadata tag, extra lore lines, different display name - and it
* will still work as long as the test passes. This is very important
* for custom crafting recipes where other plugins may add metadata
* values or the play may rename the item.
* *
* @param key The string to test. * @param key The lookup string.
* @return The found testable item, or an empty item if not found. * @return The testable item, or an {@link EmptyTestableItem}.
*/ */
public TestableItem lookup(@NotNull final String key) { public TestableItem lookup(@NotNull final String key) {
if (key.contains("?")) { if (key.contains("?")) {
@@ -79,6 +110,8 @@ public final class Items {
TestableItem item = null; TestableItem item = null;
int stackAmount = 1;
String[] split = args[0].toLowerCase().split(":"); String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) { if (split.length == 1) {
@@ -92,84 +125,70 @@ public final class Items {
if (split.length == 2) { if (split.length == 2) {
CustomItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1])); CustomItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1]));
/*
Legacy id:amount format
This has been superseded by id amount
*/
if (part == null) { if (part == null) {
Material material = Material.getMaterial(split[0].toUpperCase()); Material material = Material.getMaterial(split[0].toUpperCase());
if (material == null || material == Material.AIR) { if (material == null || material == Material.AIR) {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
item = new TestableStack(new MaterialTestableItem(material), Integer.parseInt(split[1])); item = new MaterialTestableItem(material);
stackAmount = Integer.parseInt(split[1]);
} else { } else {
item = part; item = part;
} }
} }
/*
Legacy namespace:id:amount format
This has been superseded by namespace:id amount
*/
if (split.length == 3) { if (split.length == 3) {
CustomItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1])); CustomItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1]));
item = part == null ? new EmptyTestableItem() : new TestableStack(part, Integer.parseInt(split[2])); if (part == null) {
return new EmptyTestableItem();
}
item = part;
stackAmount = Integer.parseInt(split[2]);
} }
if (item == null || item instanceof EmptyTestableItem) { boolean usingNewStackFormat = false;
if (args.length >= 2) {
try {
stackAmount = Integer.parseInt(args[1]);
usingNewStackFormat = true;
} catch (NumberFormatException ignored) {
}
}
if (item == null) {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
String[] enchantArgs = Arrays.copyOfRange(args, 1, args.length);
Map<Enchantment, Integer> requiredEnchantments = new HashMap<>();
for (String enchantArg : enchantArgs) {
String[] enchantArgSplit = enchantArg.split(":");
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(enchantArgSplit[0].toLowerCase()));
int level = Integer.parseInt(enchantArgSplit[1]);
requiredEnchantments.put(enchantment, level);
}
if (requiredEnchantments.isEmpty()) {
return item;
}
ItemStack example = item.getItem(); ItemStack example = item.getItem();
if (example.getItemMeta() instanceof EnchantmentStorageMeta storageMeta) {
requiredEnchantments.forEach((enchantment, integer) -> storageMeta.addStoredEnchant(enchantment, integer, true));
example.setItemMeta(storageMeta);
} else {
ItemMeta meta = example.getItemMeta(); ItemMeta meta = example.getItemMeta();
assert meta != null; assert meta != null;
requiredEnchantments.forEach((enchantment, integer) -> meta.addEnchant(enchantment, integer, true));
String[] modifierArgs = Arrays.copyOfRange(args, usingNewStackFormat ? 2 : 1, args.length);
List<Predicate<ItemStack>> predicates = new ArrayList<>();
for (LookupArgParser argParser : ARG_PARSERS) {
predicates.add(argParser.parseArguments(modifierArgs, meta));
}
example.setItemMeta(meta); example.setItemMeta(meta);
} if (!predicates.isEmpty()) {
item = new ModifiedTestableItem(
return new ModifiedTestableItem(
item, item,
itemStack -> { test -> {
if (!itemStack.hasItemMeta()) { for (Predicate<ItemStack> predicate : predicates) {
if (!predicate.test(test)) {
return false; return false;
} }
ItemMeta meta = itemStack.getItemMeta();
assert meta != null;
if (meta instanceof EnchantmentStorageMeta storageMeta) {
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
if (!storageMeta.hasStoredEnchant(entry.getKey())) {
return false;
}
if (storageMeta.getStoredEnchantLevel(entry.getKey()) < entry.getValue()) {
return false;
}
}
} else {
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
if (!meta.hasEnchant(entry.getKey())) {
return false;
}
if (meta.getEnchantLevel(entry.getKey()) < entry.getValue()) {
return false;
}
}
} }
return true; return true;
@@ -178,6 +197,13 @@ public final class Items {
); );
} }
if (stackAmount == 1) {
return item;
} else {
return new TestableStack(item, stackAmount);
}
}
/** /**
* Get if itemStack is a custom item. * Get if itemStack is a custom item.
* *

View File

@@ -0,0 +1,75 @@
package com.willfp.eco.core.items.args;
import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
public class EnchantmentArgParser implements LookupArgParser {
@Override
public Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
Map<Enchantment, Integer> requiredEnchantments = new HashMap<>();
for (String enchantArg : args) {
String[] enchantArgSplit = enchantArg.split(":");
Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(enchantArgSplit[0].toLowerCase()));
if (enchantment == null) {
continue;
}
if (enchantArgSplit.length < 2) {
continue;
}
int level = Integer.parseInt(enchantArgSplit[1]);
requiredEnchantments.put(enchantment, level);
}
if (meta instanceof EnchantmentStorageMeta storageMeta) {
requiredEnchantments.forEach((enchantment, integer) -> storageMeta.addStoredEnchant(enchantment, integer, true));
} else {
requiredEnchantments.forEach((enchantment, integer) -> meta.addEnchant(enchantment, integer, true));
}
return test -> {
if (!test.hasItemMeta()) {
return false;
}
ItemMeta testMeta = test.getItemMeta();
assert testMeta != null;
if (testMeta instanceof EnchantmentStorageMeta storageMeta) {
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
if (!storageMeta.hasStoredEnchant(entry.getKey())) {
return false;
}
if (storageMeta.getStoredEnchantLevel(entry.getKey()) < entry.getValue()) {
return false;
}
}
} else {
for (Map.Entry<Enchantment, Integer> entry : requiredEnchantments.entrySet()) {
if (!testMeta.hasEnchant(entry.getKey())) {
return false;
}
if (testMeta.getEnchantLevel(entry.getKey()) < entry.getValue()) {
return false;
}
}
}
return true;
};
}
}

View File

@@ -0,0 +1,23 @@
package com.willfp.eco.core.items.args;
import com.willfp.eco.core.items.TestableItem;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.function.Predicate;
public interface LookupArgParser {
/**
* Parse the arguments.
* <p>
* An argument parser should generate the predicate as well
* as modify the ItemMeta for {@link TestableItem#getItem()}
*
* @param args The arguments.
* @param meta The ItemMeta to modify.
* @return The predicate test to apply to the modified item.
*/
Predicate<ItemStack> parseArguments(@NotNull String[] args,
@NotNull ItemMeta meta);
}

View File

@@ -0,0 +1,51 @@
package com.willfp.eco.core.items.args;
import com.willfp.eco.util.SkullUtils;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.jetbrains.annotations.NotNull;
import java.util.function.Predicate;
public class TextureArgParser implements LookupArgParser {
@Override
public Predicate<ItemStack> parseArguments(@NotNull final String[] args,
@NotNull final ItemMeta meta) {
String skullTexture = null;
for (String arg : args) {
String[] argSplit = arg.split(":");
if (!argSplit[0].equalsIgnoreCase("texture")) {
continue;
}
if (argSplit.length < 2) {
continue;
}
skullTexture = argSplit[1];
}
if (meta instanceof SkullMeta skullMeta && skullTexture != null) {
SkullUtils.setSkullTexture(skullMeta, skullTexture);
}
String finalSkullTexture = skullTexture;
return test -> {
if (!test.hasItemMeta()) {
return false;
}
ItemMeta testMeta = test.getItemMeta();
assert testMeta != null;
if (testMeta instanceof SkullMeta skullMeta && finalSkullTexture != null) {
return finalSkullTexture.equalsIgnoreCase(SkullUtils.getSkullTexture(skullMeta));
}
return true;
};
}
}

View File

@@ -1,17 +1,12 @@
package com.willfp.eco.core.recipe.parts; package com.willfp.eco.core.recipe.parts;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.items.TestableItem; import com.willfp.eco.core.items.TestableItem;
import lombok.Getter; import lombok.Getter;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/** /**
* Stacks of items. * Stacks of items.
*/ */
@@ -56,19 +51,7 @@ public class TestableStack implements TestableItem {
@Override @Override
public ItemStack getItem() { public ItemStack getItem() {
ItemStack temp = handle.getItem().clone(); ItemStack temp = handle.getItem().clone();
ItemMeta meta = temp.getItemMeta();
assert meta != null;
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
assert lore != null;
lore.add("");
String add = Eco.getHandler().getEcoPlugin().getLangYml().getString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(amount));
lore.add(add);
meta.setLore(lore);
temp.setItemMeta(meta);
temp.setAmount(amount); temp.setAmount(amount);
return temp; return temp;
} }
} }

View File

@@ -1,16 +1,19 @@
package com.willfp.eco.core.recipe.recipes; package com.willfp.eco.core.recipe.recipes;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent; import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.items.TestableItem; import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.recipe.Recipes; import com.willfp.eco.core.recipe.Recipes;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem; import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
import com.willfp.eco.core.recipe.parts.TestableStack;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.RecipeChoice; import org.bukkit.inventory.RecipeChoice;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
@@ -87,7 +90,23 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
displayedRecipe.shape("012", "345", "678"); displayedRecipe.shape("012", "345", "678");
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
char character = String.valueOf(i).toCharArray()[0]; char character = String.valueOf(i).toCharArray()[0];
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(parts.get(i).getItem())); ItemStack item = parts.get(i).getItem();
if (parts.get(i) instanceof TestableStack) {
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().getString("multiple-in-craft");
add = add.replace("%amount%", String.valueOf(item.getAmount()));
lore.add(add);
meta.setLore(lore);
item.setItemMeta(meta);
}
displayedRecipe.setIngredient(character, new RecipeChoice.ExactChoice(item));
} }
Bukkit.getServer().addRecipe(shapedRecipe); Bukkit.getServer().addRecipe(shapedRecipe);

View File

@@ -7,6 +7,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Function;
/** /**
* Utilities / API methods for player heads. * Utilities / API methods for player heads.
@@ -23,6 +24,11 @@ public class SkullUtils {
*/ */
private BiConsumer<SkullMeta, String> metaSetConsumer = null; private BiConsumer<SkullMeta, String> metaSetConsumer = null;
/**
* The meta get function.
*/
private Function<SkullMeta, String> metaGetConsumer = null;
/** /**
* Set the texture of a skull from base64. * Set the texture of a skull from base64.
* *
@@ -37,16 +43,32 @@ public class SkullUtils {
metaSetConsumer.accept(meta, base64); metaSetConsumer.accept(meta, base64);
} }
/**
* Get the texture of a skull - in base64.
*
* @param meta The meta to modify.
* @return The texture.
*/
public String getSkullTexture(@NotNull final SkullMeta meta) {
Validate.isTrue(initialized, "Must be initialized!");
Validate.notNull(metaGetConsumer, "Must be initialized!");
return metaGetConsumer.apply(meta);
}
/** /**
* Initialize the skull texture function. * Initialize the skull texture function.
* *
* @param function The function. * @param function The function.
* @param function2 Get function.
*/ */
@ApiStatus.Internal @ApiStatus.Internal
public void initialize(@NotNull final BiConsumer<SkullMeta, String> function) { public void initialize(@NotNull final BiConsumer<SkullMeta, String> function,
@NotNull final Function<SkullMeta, String> function2) {
Validate.isTrue(!initialized, "Already initialized!"); Validate.isTrue(!initialized, "Already initialized!");
metaSetConsumer = function; metaSetConsumer = function;
metaGetConsumer = function2;
initialized = true; initialized = true;
} }
} }

View File

@@ -63,6 +63,7 @@ class EcoMenu(
fun handleClose(event: InventoryCloseEvent) { fun handleClose(event: InventoryCloseEvent) {
onClose.handle(event, this) onClose.handle(event, this)
MenuHandler.unregisterMenu(event.inventory)
} }
override fun getRows(): Int { override fun getRows(): Int {

View File

@@ -1,19 +1,21 @@
package com.willfp.eco.proxy.v1_16_R3 package com.willfp.eco.proxy.v1_16_R3
import com.mojang.authlib.GameProfile import com.mojang.authlib.GameProfile
import com.mojang.authlib.properties.Property import com.mojang.authlib.properties.Property
import org.bukkit.inventory.meta.SkullMeta
import com.willfp.eco.proxy.SkullProxy import com.willfp.eco.proxy.SkullProxy
import org.bukkit.inventory.meta.SkullMeta
import java.lang.reflect.Field
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util.* import java.util.*
class Skull : SkullProxy { class Skull : SkullProxy {
private lateinit var setProfile: Method private lateinit var setProfile: Method
private lateinit var profile: Field
override fun setSkullTexture( override fun setSkullTexture(
meta: SkullMeta, meta: SkullMeta,
base64: String base64: String
) { ) {
try {
if (!this::setProfile.isInitialized) { if (!this::setProfile.isInitialized) {
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
setProfile.isAccessible = true setProfile.isAccessible = true
@@ -25,8 +27,17 @@ class Skull : SkullProxy {
val profile = GameProfile(uuid, "eco") val profile = GameProfile(uuid, "eco")
profile.properties.put("textures", Property("textures", base64)) profile.properties.put("textures", Property("textures", base64))
setProfile.invoke(meta, profile) setProfile.invoke(meta, profile)
} catch (e: ReflectiveOperationException) {
e.printStackTrace()
} }
override fun getSkullTexture(
meta: SkullMeta
): String? {
if (!this::profile.isInitialized) {
profile = meta.javaClass.getDeclaredField("profile")
profile.isAccessible = true
}
val profile = profile[meta] as GameProfile?
val property = profile?.properties?.get("textures") as Property?
return property?.value
} }
} }

View File

@@ -4,17 +4,18 @@ import com.mojang.authlib.GameProfile
import com.mojang.authlib.properties.Property import com.mojang.authlib.properties.Property
import com.willfp.eco.proxy.SkullProxy import com.willfp.eco.proxy.SkullProxy
import org.bukkit.inventory.meta.SkullMeta import org.bukkit.inventory.meta.SkullMeta
import java.lang.reflect.Field
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util.* import java.util.*
class Skull : SkullProxy { class Skull : SkullProxy {
private lateinit var setProfile: Method private lateinit var setProfile: Method
private lateinit var profile: Field
override fun setSkullTexture( override fun setSkullTexture(
meta: SkullMeta, meta: SkullMeta,
base64: String base64: String
) { ) {
try {
if (!this::setProfile.isInitialized) { if (!this::setProfile.isInitialized) {
setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java) setProfile = meta.javaClass.getDeclaredMethod("setProfile", GameProfile::class.java)
setProfile.isAccessible = true setProfile.isAccessible = true
@@ -26,8 +27,17 @@ class Skull : SkullProxy {
val profile = GameProfile(uuid, "eco") val profile = GameProfile(uuid, "eco")
profile.properties.put("textures", Property("textures", base64)) profile.properties.put("textures", Property("textures", base64))
setProfile.invoke(meta, profile) setProfile.invoke(meta, profile)
} catch (e: ReflectiveOperationException) {
e.printStackTrace()
} }
override fun getSkullTexture(
meta: SkullMeta
): String? {
if (!this::profile.isInitialized) {
profile = meta.javaClass.getDeclaredField("profile")
profile.isAccessible = true
}
val profile = profile[meta] as GameProfile?
val property = profile?.properties?.get("textures") as Property?
return property?.value
} }
} }

View File

@@ -21,8 +21,8 @@ dependencies {
compileOnly 'me.clip:placeholderapi:2.10.9' compileOnly 'me.clip:placeholderapi:2.10.9'
compileOnly 'com.willfp:Oraxen:e1f4003d8d' compileOnly 'com.willfp:Oraxen:e1f4003d8d'
compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0' compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0'
compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7'
compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.3.8' compileOnly 'me.arcaniax:HeadDatabase-API:1.2.0'
// CombatLogX V10 + NewbieHelper Expansion // CombatLogX V10 + NewbieHelper Expansion
compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT' compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT'

View File

@@ -98,16 +98,65 @@ public class ShapedRecipeListener extends PluginDependent<EcoPlugin> implements
return; return;
} }
this.getPlugin().getScheduler().runLater(() -> { boolean isStackedRecipe = false;
int upperBound = 64;
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
ItemStack inMatrix = event.getInventory().getMatrix()[i]; ItemStack inMatrix = event.getInventory().getMatrix()[i];
TestableItem inRecipe = matched.getParts().get(i); TestableItem inRecipe = matched.getParts().get(i);
if (inRecipe instanceof TestableStack testableStack) { if (inRecipe instanceof TestableStack testableStack) {
int max = Math.floorDiv(inMatrix.getAmount(), testableStack.getAmount());
if (max < upperBound) {
upperBound = max;
}
isStackedRecipe = true;
} else if (inMatrix != null) {
int max = inMatrix.getAmount();
if (max < upperBound) {
upperBound = max;
}
}
}
if (!isStackedRecipe) {
return;
}
int toGivePerRecipe = event.getRecipe().getResult().getAmount();
int maxStackSize = event.getRecipe().getResult().getMaxStackSize();
while (toGivePerRecipe * upperBound > maxStackSize) {
upperBound--;
}
for (int i = 0; i < 9; i++) {
ItemStack inMatrix = event.getInventory().getMatrix()[i];
TestableItem inRecipe = matched.getParts().get(i);
if (inRecipe instanceof TestableStack testableStack) {
if (event.isShiftClick()) {
int amount = inMatrix.getAmount() + 1;
for (int j = 0; j < upperBound; j++) {
amount -= testableStack.getAmount();
}
inMatrix.setAmount(amount);
} else {
inMatrix.setAmount(inMatrix.getAmount() - (testableStack.getAmount() - 1)); inMatrix.setAmount(inMatrix.getAmount() - (testableStack.getAmount() - 1));
} }
} }
}, 1); }
int finalUpperBound = upperBound;
if (event.isShiftClick()) {
ItemStack result = event.getInventory().getResult();
if (result == null) {
return;
}
result.setAmount(result.getAmount() * finalUpperBound);
event.getInventory().setResult(result);
}
} }
@EventHandler @EventHandler

View File

@@ -9,6 +9,9 @@ import com.willfp.eco.core.integrations.antigrief.AntigriefManager
import com.willfp.eco.core.integrations.customitems.CustomItemsManager import com.willfp.eco.core.integrations.customitems.CustomItemsManager
import com.willfp.eco.core.integrations.mcmmo.McmmoManager import com.willfp.eco.core.integrations.mcmmo.McmmoManager
import com.willfp.eco.core.integrations.shop.ShopManager import com.willfp.eco.core.integrations.shop.ShopManager
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.args.EnchantmentArgParser
import com.willfp.eco.core.items.args.TextureArgParser
import com.willfp.eco.internal.drops.DropManager import com.willfp.eco.internal.drops.DropManager
import com.willfp.eco.proxy.BlockBreakProxy import com.willfp.eco.proxy.BlockBreakProxy
import com.willfp.eco.proxy.FastItemStackFactoryProxy import com.willfp.eco.proxy.FastItemStackFactoryProxy
@@ -20,6 +23,8 @@ import com.willfp.eco.spigot.eventlisteners.*
import com.willfp.eco.spigot.gui.GUIListener import com.willfp.eco.spigot.gui.GUIListener
import com.willfp.eco.spigot.integrations.anticheat.* import com.willfp.eco.spigot.integrations.anticheat.*
import com.willfp.eco.spigot.integrations.antigrief.* import com.willfp.eco.spigot.integrations.antigrief.*
import com.willfp.eco.spigot.integrations.customitems.CustomItemsHeadDatabase
import com.willfp.eco.spigot.integrations.customitems.CustomItemsItemsAdder
import com.willfp.eco.spigot.integrations.customitems.CustomItemsOraxen import com.willfp.eco.spigot.integrations.customitems.CustomItemsOraxen
import com.willfp.eco.spigot.integrations.mcmmo.McmmoIntegrationImpl import com.willfp.eco.spigot.integrations.mcmmo.McmmoIntegrationImpl
import com.willfp.eco.spigot.integrations.shop.ShopShopGuiPlus import com.willfp.eco.spigot.integrations.shop.ShopShopGuiPlus
@@ -43,8 +48,14 @@ abstract class EcoSpigotPlugin : EcoPlugin(
init { init {
Display.setFinalizeKey(namespacedKeyFactory.create("finalized")) Display.setFinalizeKey(namespacedKeyFactory.create("finalized"))
Items.registerArgParser(EnchantmentArgParser())
Items.registerArgParser(TextureArgParser())
val skullProxy = getProxy(SkullProxy::class.java) val skullProxy = getProxy(SkullProxy::class.java)
SkullUtils.initialize { meta: SkullMeta, base64: String -> skullProxy.setSkullTexture(meta, base64) } SkullUtils.initialize(
{ meta: SkullMeta, base64: String -> skullProxy.setSkullTexture(meta, base64) },
{ meta: SkullMeta -> skullProxy.getSkullTexture(meta) }
)
val blockBreakProxy = getProxy(BlockBreakProxy::class.java) val blockBreakProxy = getProxy(BlockBreakProxy::class.java)
BlockUtils.initialize { player: Player, block: Block -> blockBreakProxy.breakBlock(player, block) } BlockUtils.initialize { player: Player, block: Block -> blockBreakProxy.breakBlock(player, block) }
@@ -111,6 +122,8 @@ abstract class EcoSpigotPlugin : EcoPlugin(
// Custom Items // Custom Items
IntegrationLoader("Oraxen") { CustomItemsManager.register(CustomItemsOraxen()) }, IntegrationLoader("Oraxen") { CustomItemsManager.register(CustomItemsOraxen()) },
IntegrationLoader("ItemsAdder") { CustomItemsManager.register(CustomItemsItemsAdder(this)) },
IntegrationLoader("HeadDatabase") { CustomItemsManager.register(CustomItemsHeadDatabase()) },
// Shop // Shop
IntegrationLoader("ShopGuiPlus") { ShopManager.register(ShopShopGuiPlus()) }, IntegrationLoader("ShopGuiPlus") { ShopManager.register(ShopShopGuiPlus()) },

View File

@@ -0,0 +1,34 @@
package com.willfp.eco.spigot.integrations.customitems
import com.willfp.eco.core.integrations.customitems.CustomItemsWrapper
import com.willfp.eco.core.items.CustomItem
import com.willfp.eco.util.NamespacedKeyUtils
import me.arcaniax.hdb.api.HeadDatabaseAPI
import me.arcaniax.hdb.enums.CategoryEnum
import java.util.function.Predicate
class CustomItemsHeadDatabase : CustomItemsWrapper {
private val api = HeadDatabaseAPI()
override fun registerAllItems() {
for (categoryEnum in CategoryEnum.values()) {
for (head in api.getHeads(categoryEnum)) {
val stack = head.head
val id = head.id
val key = NamespacedKeyUtils.create("headdb", id.lowercase());
CustomItem(
key,
Predicate { test ->
val headId = api.getItemID(test) ?: return@Predicate false
headId.equals(id, ignoreCase = true)
},
stack
).register()
}
}
}
override fun getPluginName(): String {
return "HeadDatabase"
}
}

View File

@@ -0,0 +1,36 @@
package com.willfp.eco.spigot.integrations.customitems
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.integrations.customitems.CustomItemsWrapper
import com.willfp.eco.core.items.CustomItem
import com.willfp.eco.util.NamespacedKeyUtils
import dev.lone.itemsadder.api.CustomStack
import dev.lone.itemsadder.api.ItemsAdder
import org.bukkit.inventory.ItemStack
import java.util.function.Predicate
class CustomItemsItemsAdder(
private val plugin: EcoPlugin
) : CustomItemsWrapper {
override fun registerAllItems() {
plugin.scheduler.runLater({
for (item in ItemsAdder.getAllItems()) {
val stack = item.itemStack
val id = item.id
val key = NamespacedKeyUtils.create("itemsadder", id.lowercase())
CustomItem(
key,
Predicate { test: ItemStack ->
val customStack = CustomStack.byItemStack(test) ?: return@Predicate false
customStack.id.equals(id, ignoreCase = true)
},
stack
).register()
}
}, 2)
}
override fun getPluginName(): String {
return "ItemsAdder"
}
}

View File

@@ -23,4 +23,8 @@ class CustomItemsOraxen : CustomItemsWrapper {
).register() ).register()
} }
} }
override fun getPluginName(): String {
return "Oraxen"
}
} }

View File

@@ -4,6 +4,7 @@ main: com.willfp.eco.spigot.EcoHandler
api-version: 1.16 api-version: 1.16
authors: [Auxilor] authors: [Auxilor]
website: willfp.com website: willfp.com
load: STARTUP
depend: depend:
- ProtocolLib - ProtocolLib
softdepend: softdepend:
@@ -21,6 +22,9 @@ softdepend:
- mcMMO - mcMMO
- CombatLogX - CombatLogX
- ShopGuiPlus - ShopGuiPlus
- ItemsAdder
- Oraxen
- HeadDatabase
libraries: libraries:
- org.reflections:reflections:0.9.12 - org.reflections:reflections:0.9.12
- org.apache.maven:maven-artifact:3.0.3 - org.apache.maven:maven-artifact:3.0.3

View File

@@ -8,4 +8,8 @@ interface SkullProxy : AbstractProxy {
meta: SkullMeta, meta: SkullMeta,
base64: String base64: String
) )
fun getSkullTexture(
meta: SkullMeta
): String?
} }

View File

@@ -1,2 +1,2 @@
version = 6.6.1 version = 6.7.0
plugin-name = eco plugin-name = eco