Compare commits

..

13 Commits

Author SHA1 Message Date
Auxilor
4a8935f06d Added custom blocks API with initial oraxen integration 2024-07-30 15:57:44 +01:00
Auxilor
c89edd05f5 Updated to 6.73.2 2024-07-29 18:46:53 +01:00
Auxilor
ce2a53e689 Fixed FancyHolograms integration 2024-07-29 18:46:47 +01:00
Auxilor
6658824f9a Updated to 6.73.1 2024-07-24 15:24:59 +01:00
Auxilor
956d4fa10c Enchantment arg parser is now case insensitive 2024-07-24 15:24:49 +01:00
Auxilor
6a7a825376 Added extra apis to VanillaItemTag 2024-07-21 12:57:55 +01:00
Auxilor
cd232e804c Improved enchantment arg parser 2024-07-21 11:38:35 +01:00
Auxilor
7cf2fa4b4b Improved consistency with custom model data arg parser 2024-07-21 11:22:40 +01:00
Auxilor
cbf88ce678 Improved item tags 2024-07-20 15:36:26 +01:00
Auxilor
79db5978bd Improved ItemTag 2024-07-20 15:16:47 +01:00
Auxilor
0f11f9846c CustomItemTag is now an abstract class 2024-07-20 15:09:26 +01:00
Auxilor
1f460d7a00 Updated to 6.73.0 2024-07-20 15:07:55 +01:00
Auxilor
2fb9525175 Added Item Tags 2024-07-20 15:07:55 +01:00
23 changed files with 942 additions and 34 deletions

View File

@@ -0,0 +1,149 @@
package com.willfp.eco.core.blocks;
import com.willfp.eco.core.blocks.impl.EmptyTestableBlock;
import com.willfp.eco.core.blocks.impl.MaterialTestableBlock;
import com.willfp.eco.core.blocks.impl.UnrestrictedMaterialTestableBlock;
import com.willfp.eco.core.blocks.provider.BlockProvider;
import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Class to manage all custom and vanilla blocks.
*/
public final class Blocks {
/**
* All entities.
*/
private static final Map<NamespacedKey, TestableBlock> REGISTRY = new ConcurrentHashMap<>();
/**
* All block providers.
*/
private static final Map<String, BlockProvider> PROVIDERS = new ConcurrentHashMap<>();
/**
* The lookup handler.
*/
private static final BlocksLookupHandler BLOCKS_LOOKUP_HANDLER = new BlocksLookupHandler(Blocks::doParse);
/**
* Register a new custom block.
*
* @param key The key of the block.
* @param block The block.
*/
public static void registerCustomBlock(@NotNull final NamespacedKey key,
@NotNull final TestableBlock block) {
REGISTRY.put(key, block);
}
/**
* Register a new block provider.
*
* @param provider The provider.
*/
public static void registerBlockProvider(@NotNull final BlockProvider provider) {
PROVIDERS.put(provider.getNamespace(), provider);
}
/**
* Remove a block.
*
* @param key The key of the block.
*/
public static void removeCustomBlock(@NotNull final NamespacedKey key) {
REGISTRY.remove(key);
}
/**
* This is the backbone of the eco block system.
* <p>
* You can look up a TestableBlock for any material or custom block,
* and it will return it.
* <p>
* If you want to get a Block instance from this, then just call
* {@link TestableBlock#place(Location)}.
*
* @param key The lookup string.
* @return The testable block, or an empty testable block if not found.
*/
@NotNull
public static TestableBlock lookup(@NotNull final String key) {
return BLOCKS_LOOKUP_HANDLER.parseKey(key);
}
@NotNull
private static TestableBlock doParse(@NotNull final String[] args) {
if (args.length == 0) {
return new EmptyTestableBlock();
}
String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) {
if (args[0].startsWith("*")) {
Material type = Material.getMaterial(args[0].substring(1));
return (type == null) ? new EmptyTestableBlock() : new UnrestrictedMaterialTestableBlock(type);
} else {
Material type = Material.getMaterial(args[0].toUpperCase());
return (type == null) ? new EmptyTestableBlock() : new MaterialTestableBlock(type);
}
}
NamespacedKey namespacedKey = NamespacedKeyUtils.create(split[0], split[1]);
TestableBlock block = REGISTRY.get(namespacedKey);
if (block != null) {
return block;
}
BlockProvider provider = PROVIDERS.get(split[0]);
if (provider == null) {
return new EmptyTestableBlock();
}
block = provider.provideForKey(split[1]);
if (block == null) {
return new EmptyTestableBlock();
}
registerCustomBlock(namespacedKey, block);
return block;
}
/**
* Get if block is a custom block.
*
* @param block The block to check.
* @return If is custom.
*/
public static boolean isCustomBlock(@NotNull final Block block) {
for (TestableBlock testable : REGISTRY.values()) {
if (testable.matches(block)) {
return true;
}
}
return false;
}
/**
* Get all registered custom blocks.
*
* @return A set of all blocks.
*/
public static Set<TestableBlock> getCustomBlocks() {
return new HashSet<>(REGISTRY.values());
}
private Blocks() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.core.blocks;
import com.willfp.eco.core.blocks.impl.EmptyTestableBlock;
import com.willfp.eco.core.blocks.impl.GroupedTestableBlocks;
import com.willfp.eco.core.lookup.LookupHandler;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.Function;
/**
* Handle block lookup strings.
*/
public class BlocksLookupHandler implements LookupHandler<TestableBlock> {
/**
* The parser.
*/
private final Function<String[], @NotNull TestableBlock> parser;
/**
* Create new lookup handler.
*
* @param parser The parser.
*/
public BlocksLookupHandler(@NotNull final Function<String[], @NotNull TestableBlock> parser) {
this.parser = parser;
}
@Override
public @NotNull TestableBlock parse(@NotNull final String[] args) {
return parser.apply(args);
}
@Override
public boolean validate(@NotNull final TestableBlock object) {
return !(object instanceof EmptyTestableBlock);
}
@Override
public @NotNull TestableBlock getFailsafe() {
return new EmptyTestableBlock();
}
@Override
public @NotNull TestableBlock join(@NotNull final Collection<TestableBlock> options) {
return new GroupedTestableBlocks(options);
}
}

View File

@@ -0,0 +1,84 @@
package com.willfp.eco.core.blocks;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* A custom block has 3 components.
*
* <ul>
* <li>The key to identify it</li>
* <li>The test to check if any block is this custom block</li>
* <li>The supplier to spawn the custom {@link Block}</li>
* </ul>
*/
public class CustomBlock implements TestableBlock {
/**
* The key.
*/
private final NamespacedKey key;
/**
* The test for block to pass.
*/
private final Predicate<@NotNull Block> test;
/**
* The provider to spawn the block.
*/
private final Function<Location, Block> provider;
/**
* Create a new custom block.
*
* @param key The block key.
* @param test The test.
* @param provider The provider to spawn the block.
*/
public CustomBlock(@NotNull final NamespacedKey key,
@NotNull final Predicate<@NotNull Block> test,
@NotNull final Function<Location, Block> provider) {
this.key = key;
this.test = test;
this.provider = provider;
}
@Override
public boolean matches(@Nullable final Block other) {
if (other == null) {
return false;
}
return test.test(other);
}
@Override
public @NotNull Block place(@NotNull final Location location) {
Validate.notNull(location.getWorld());
return provider.apply(location);
}
/**
* Register the block.
*/
public void register() {
Blocks.registerCustomBlock(this.getKey(), this);
}
/**
* Get the key.
*
* @return The key.
*/
public NamespacedKey getKey() {
return this.key;
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.core.blocks;
import com.willfp.eco.core.lookup.Testable;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A block with a test.
*/
public interface TestableBlock extends Testable<Block> {
/**
* If a Block matches the test.
*
* @param other The other block.
* @return If the block matches.
*/
@Override
boolean matches(@Nullable Block other);
/**
* Place the block.
*
* @param location The location.
* @return The block.
*/
@NotNull
Block place(@NotNull Location location);
}

View File

@@ -0,0 +1,29 @@
package com.willfp.eco.core.blocks.impl;
import com.willfp.eco.core.blocks.TestableBlock;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Empty block.
*/
public class EmptyTestableBlock implements TestableBlock {
/**
* Create a new empty testable block.
*/
public EmptyTestableBlock() {
}
@Override
public boolean matches(@Nullable final Block other) {
return false;
}
@Override
public @NotNull Block place(@NotNull final Location location) {
return location.getBlock();
}
}

View File

@@ -0,0 +1,60 @@
package com.willfp.eco.core.blocks.impl;
import com.willfp.eco.core.blocks.TestableBlock;
import com.willfp.eco.util.NumberUtils;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
/**
* A group of testable blocks.
*/
public class GroupedTestableBlocks implements TestableBlock {
/**
* The children.
*/
private final Collection<TestableBlock> children;
/**
* Create a new group of testable blocks.
*
* @param children The children.
*/
public GroupedTestableBlocks(@NotNull final Collection<TestableBlock> children) {
Validate.isTrue(!children.isEmpty(), "Group must have at least one child!");
this.children = children;
}
@Override
public boolean matches(@Nullable final Block other) {
for (TestableBlock child : children) {
if (child.matches(other)) {
return true;
}
}
return false;
}
@Override
public @NotNull Block place(@NotNull final Location location) {
return new ArrayList<>(children)
.get(NumberUtils.randInt(0, children.size() - 1))
.place(location);
}
/**
* Get the children.
*
* @return The children.
*/
public Collection<TestableBlock> getChildren() {
return new ArrayList<>(children);
}
}

View File

@@ -0,0 +1,59 @@
package com.willfp.eco.core.blocks.impl;
import com.willfp.eco.core.blocks.Blocks;
import com.willfp.eco.core.blocks.TestableBlock;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A testable block for vanilla materials.
*/
public class MaterialTestableBlock implements TestableBlock {
/**
* The block type.
*/
private final Material material;
/**
* Create a new unrestricted material testable block.
*
* @param material The material.
*/
public MaterialTestableBlock(@NotNull final Material material) {
this.material = material;
}
@Override
public boolean matches(@Nullable final Block block) {
boolean simpleMatches = block != null && block.getType() == material;
if (!simpleMatches) {
return false;
}
return !Blocks.isCustomBlock(block);
}
@Override
public @NotNull Block place(@NotNull Location location) {
Validate.notNull(location.getWorld());
Block block = location.getWorld().getBlockAt(location);
block.setType(material);
return block;
}
/**
* Get the material.
*
* @return The material.
*/
public Material getMaterial() {
return this.material;
}
}

View File

@@ -0,0 +1,52 @@
package com.willfp.eco.core.blocks.impl;
import com.willfp.eco.core.blocks.TestableBlock;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A testable block for materials regardless of data.
*/
public class UnrestrictedMaterialTestableBlock implements TestableBlock {
/**
* The block type.
*/
private final Material material;
/**
* Create a new unrestricted material testable block.
*
* @param material The material.
*/
public UnrestrictedMaterialTestableBlock(@NotNull final Material material) {
this.material = material;
}
@Override
public boolean matches(@Nullable final Block other) {
return other != null && other.getType() == material;
}
@Override
public @NotNull Block place(@NotNull Location location) {
Validate.notNull(location.getWorld());
Block block = location.getWorld().getBlockAt(location);
block.setType(material);
return block;
}
/**
* Get the material.
*
* @return The material.
*/
public Material getMaterial() {
return this.material;
}
}

View File

@@ -0,0 +1,49 @@
package com.willfp.eco.core.blocks.provider;
import com.willfp.eco.core.blocks.TestableBlock;
import com.willfp.eco.core.registry.Registry;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Block providers are call-site registrations for blocks. In other words,
* they only register their blocks when a request is made. This is marginally
* slower, however it is required for certain plugins, and fixes bugs related to
* loading orders.
*
* @see TestableBlock
*/
public abstract class BlockProvider {
/**
* The namespace.
*/
private final String namespace;
/**
* Create a new BlockProvider for a specific namespace.
*
* @param namespace The namespace.
*/
protected BlockProvider(@NotNull final String namespace) {
this.namespace = namespace;
}
/**
* Provide a TestableBlock for a given key.
*
* @param key The block ID.
* @return The TestableBlock, or null if not found.
*/
@Nullable
public abstract TestableBlock provideForKey(@NotNull String key);
/**
* Get the namespace.
*
* @return The namespace.
*/
public String getNamespace() {
return this.namespace;
}
}

View File

@@ -0,0 +1,24 @@
package com.willfp.eco.core.integrations.customblocks;
import com.willfp.eco.core.integrations.Integration;
/**
* Wrapper class for custom block integrations.
*/
public interface CustomBlocksIntegration extends Integration {
/**
* Register all the custom block for a specific plugin into eco.
*
* @see com.willfp.eco.core.blocks.Blocks
*/
default void registerAllBlocks() {
// Override when needed.
}
/**
* Register {@link com.willfp.eco.core.blocks.provider.BlockProvider}s.
*/
default void registerProvider() {
// Override when needed.
}
}

View File

@@ -0,0 +1,45 @@
package com.willfp.eco.core.integrations.customblocks;
import com.willfp.eco.core.integrations.IntegrationRegistry;
import org.jetbrains.annotations.NotNull;
/**
* Class to handle custom block integrations.
*/
public final class CustomBlocksManager {
/**
* A set of all registered integrations.
*/
private static final IntegrationRegistry<CustomBlocksIntegration> REGISTRY = new IntegrationRegistry<>();
/**
* Register a new integration.
*
* @param integration The integration to register.
*/
public static void register(@NotNull final CustomBlocksIntegration integration) {
REGISTRY.register(integration);
}
/**
* Register all the custom block for a specific plugin into eco.
*
* @see com.willfp.eco.core.blocks.Blocks
*/
public static void registerAllBlocks() {
REGISTRY.forEachSafely(CustomBlocksIntegration::registerAllBlocks);
}
/**
* Register all the custom blocks for a specific plugin into eco.
*
* @see com.willfp.eco.core.blocks.Blocks
*/
public static void registerProviders() {
REGISTRY.forEachSafely(CustomBlocksIntegration::registerProvider);
}
private CustomBlocksManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
}

View File

@@ -6,6 +6,7 @@ import com.willfp.eco.core.Eco;
import com.willfp.eco.core.fast.FastItemStack; import com.willfp.eco.core.fast.FastItemStack;
import com.willfp.eco.core.items.args.LookupArgParser; import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider; import com.willfp.eco.core.items.provider.ItemProvider;
import com.willfp.eco.core.items.tag.ItemTag;
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;
@@ -13,7 +14,6 @@ import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.core.recipe.parts.UnrestrictedMaterialTestableItem; import com.willfp.eco.core.recipe.parts.UnrestrictedMaterialTestableItem;
import com.willfp.eco.util.NamespacedKeyUtils; import com.willfp.eco.util.NamespacedKeyUtils;
import com.willfp.eco.util.NumberUtils; import com.willfp.eco.util.NumberUtils;
import kotlin.Suppress;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
@@ -93,6 +93,11 @@ public final class Items {
*/ */
private static final Map<String, Material> FRIENDLY_MATERIAL_NAMES = new HashMap<>(); private static final Map<String, Material> FRIENDLY_MATERIAL_NAMES = new HashMap<>();
/**
* All tags.
*/
private static final Map<String, ItemTag> TAGS = new HashMap<>();
/** /**
* Register a new custom item. * Register a new custom item.
* *
@@ -217,7 +222,20 @@ public final class Items {
String[] split = args[0].toLowerCase().split(":"); String[] split = args[0].toLowerCase().split(":");
if (split.length == 1) { String base = split[0];
boolean isTag = base.startsWith("#");
if (isTag) {
String tag = base.substring(1);
ItemTag itemTag = TAGS.get(tag);
if (itemTag == null) {
return new EmptyTestableItem();
}
item = itemTag.toTestableItem();
}
if (split.length == 1 && !isTag) {
String itemType = args[0]; String itemType = args[0];
boolean isWildcard = itemType.startsWith("*"); boolean isWildcard = itemType.startsWith("*");
if (isWildcard) { if (isWildcard) {
@@ -230,7 +248,7 @@ public final class Items {
item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material); item = isWildcard ? new UnrestrictedMaterialTestableItem(material) : new MaterialTestableItem(material);
} }
if (split.length == 2) { if (split.length == 2 && !isTag) {
String namespace = split[0]; String namespace = split[0];
String keyID = split[1]; String keyID = split[1];
NamespacedKey namespacedKey = NamespacedKeyUtils.create(namespace, keyID); NamespacedKey namespacedKey = NamespacedKeyUtils.create(namespace, keyID);
@@ -274,7 +292,7 @@ public final class Items {
Legacy namespace:id:amount format Legacy namespace:id:amount format
This has been superseded by namespace:id amount This has been superseded by namespace:id amount
*/ */
if (split.length == 3) { if (split.length == 3 && !isTag) {
TestableItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1])); TestableItem part = REGISTRY.get(NamespacedKeyUtils.create(split[0], split[1]));
if (part == null) { if (part == null) {
return new EmptyTestableItem(); return new EmptyTestableItem();
@@ -306,7 +324,8 @@ public final class Items {
List<Predicate<ItemStack>> predicates = new ArrayList<>(); List<Predicate<ItemStack>> predicates = new ArrayList<>();
for (LookupArgParser argParser : ARG_PARSERS) { for (
LookupArgParser argParser : ARG_PARSERS) {
Predicate<ItemStack> predicate = argParser.parseArguments(modifierArgs, meta); Predicate<ItemStack> predicate = argParser.parseArguments(modifierArgs, meta);
if (predicate != null) { if (predicate != null) {
predicates.add(argParser.parseArguments(modifierArgs, meta)); predicates.add(argParser.parseArguments(modifierArgs, meta));
@@ -611,6 +630,24 @@ public final class Items {
return false; return false;
} }
/**
* Register a new item tag.
*
* @param tag The tag.
*/
public static void registerTag(@NotNull final ItemTag tag) {
TAGS.put(tag.getIdentifier(), tag);
}
/**
* Get all tags.
*
* @return All tags.
*/
public static Collection<ItemTag> getTags() {
return TAGS.values();
}
private Items() { private Items() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -0,0 +1,29 @@
package com.willfp.eco.core.items.tag;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
/**
* A custom item tag.
*/
public abstract class CustomItemTag implements ItemTag {
/**
* The key.
*/
private final NamespacedKey key;
/**
* Create a new custom item tag.
*
* @param key The key.
*/
public CustomItemTag(@NotNull final NamespacedKey key) {
this.key = key;
}
@Override
@NotNull
public String getIdentifier() {
return key.toString();
}
}

View File

@@ -0,0 +1,66 @@
package com.willfp.eco.core.items.tag;
import com.willfp.eco.core.items.TestableItem;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A group of items that share a common trait.
*/
public interface ItemTag {
/**
* Get the identifier of the tag.
*
* @return The identifier.
*/
@NotNull
String getIdentifier();
/**
* Check if an item matches the tag.
*
* @param itemStack The item to check.
* @return If the item matches the tag.
*/
boolean matches(@NotNull ItemStack itemStack);
/**
* Get an example item.
*
* @return The example item.
*/
@Nullable
default ItemStack getExampleItem() {
return null;
}
/**
* Convert this tag to a testable item.
*
* @return The testable item.
*/
@NotNull
default TestableItem toTestableItem() {
return new TestableItem() {
@Override
public boolean matches(@Nullable final ItemStack itemStack) {
return itemStack != null && ItemTag.this.matches(itemStack);
}
@Override
public @NotNull ItemStack getItem() {
ItemStack example = ItemTag.this.getExampleItem();
return example == null ? new ItemStack(Material.STONE) : example;
}
@Override
public String toString() {
return "ItemTagTestableItem{" +
"tag=" + ItemTag.this.getIdentifier() +
'}';
}
};
}
}

View File

@@ -0,0 +1,58 @@
package com.willfp.eco.core.items.tag;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* A vanilla item tag.
*/
public final class VanillaItemTag implements ItemTag {
/**
* The identifier.
*/
private final String identifier;
/**
* The tag.
*/
private final Tag<Material> tag;
/**
* Create a new vanilla item tag.
*
* @param identifier The identifier.
* @param tag The tag.
*/
public VanillaItemTag(@NotNull final String identifier,
@NotNull final Tag<Material> tag) {
this.identifier = identifier;
this.tag = tag;
}
/**
* Get the tag.
*
* @return The tag.
*/
public Tag<Material> getTag() {
return tag;
}
@Override
@NotNull
public String getIdentifier() {
return identifier;
}
@Override
public boolean matches(@NotNull final ItemStack itemStack) {
return tag.isTagged(itemStack.getType());
}
@Override
public @NotNull ItemStack getExampleItem() {
return new ItemStack(tag.getValues().stream().findFirst().orElse(Material.STONE));
}
}

View File

@@ -7,20 +7,12 @@ import java.util.function.Predicate
object ArgParserCustomModelData : LookupArgParser { object ArgParserCustomModelData : LookupArgParser {
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? { override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var modelData: Int? = null val arg = args.firstOrNull {
it.startsWith("custom-model-data:", ignoreCase = true)
|| it.startsWith("custom_model_data:", ignoreCase = true)
} ?: return null
for (arg in args) { val modelData = arg.split(":")[1].toIntOrNull() ?: return null
val argSplit = arg.split(":")
if (!argSplit[0].equals("custom-model-data", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
modelData = argSplit[1].toIntOrNull()
}
modelData ?: return null
meta.setCustomModelData(modelData) meta.setCustomModelData(modelData)
@@ -40,6 +32,6 @@ object ArgParserCustomModelData : LookupArgParser {
return null return null
} }
return "custom-model-data:${meta.customModelData}" return "custom_model_data:${meta.customModelData}"
} }
} }

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.internal.items
import com.willfp.eco.core.fast.fast import com.willfp.eco.core.fast.fast
import com.willfp.eco.core.items.args.LookupArgParser import com.willfp.eco.core.items.args.LookupArgParser
import com.willfp.eco.util.NamespacedKeyUtils import org.bukkit.NamespacedKey
import org.bukkit.enchantments.Enchantment 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.EnchantmentStorageMeta
@@ -16,17 +16,10 @@ object ArgParserEnchantment : LookupArgParser {
for (arg in args) { for (arg in args) {
val argSplit = arg.split(":") val argSplit = arg.split(":")
if (argSplit.size < 2) { val enchant = Enchantment.getByKey(NamespacedKey.minecraft(argSplit[0].lowercase())) ?: continue
continue val level = argSplit.getOrNull(1)?.toIntOrNull() ?: enchant.maxLevel
}
@Suppress("DEPRECATION") enchants[enchant] = level
val enchant = Enchantment.getByKey(NamespacedKeyUtils.create("minecraft", argSplit[0]))
val level = argSplit[1].toIntOrNull()
if (enchant != null && level != null) {
enchants[enchant] = level
}
} }
if (enchants.isEmpty()) { if (enchants.isEmpty()) {

View File

@@ -0,0 +1,39 @@
package com.willfp.eco.internal.items.tags
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.tag.VanillaItemTag
import org.bukkit.Keyed
import org.bukkit.Material
import org.bukkit.Tag
object VanillaItemTags {
fun register() {
// Get all tags
val allTags = Tag::class.java.declaredFields
.filter { it.type == Tag::class.java }
.mapNotNull {
val tag = it.get(null) as? Tag<*>
if (tag == null) {
null
} else {
NamedTag(it.name.lowercase(), tag)
}
}
// Register all tags
for (tag in allTags) {
if (tag.isMaterial) {
Items.registerTag(
@Suppress("UNCHECKED_CAST")
VanillaItemTag(tag.name, tag.tag as Tag<Material>)
)
}
}
}
private data class NamedTag<T : Keyed>(val name: String, val tag: Tag<T>) {
// Check if tag is material
val isMaterial: Boolean
get() = tag.values.firstOrNull() is Material
}
}

View File

@@ -12,7 +12,7 @@ object ParticleFactoryRGB : ParticleFactory {
if (Prerequisite.HAS_1_20_5.isMet) { if (Prerequisite.HAS_1_20_5.isMet) {
Particle.valueOf("DUST") Particle.valueOf("DUST")
} else { } else {
Particle.valueOf("REDSTONE") Particle.valueOf("REDSTONE_DUST")
} }
}.getOrNull() }.getOrNull()

View File

@@ -9,6 +9,7 @@ import com.willfp.eco.core.integrations.IntegrationLoader
import com.willfp.eco.core.integrations.afk.AFKManager import com.willfp.eco.core.integrations.afk.AFKManager
import com.willfp.eco.core.integrations.anticheat.AnticheatManager import com.willfp.eco.core.integrations.anticheat.AnticheatManager
import com.willfp.eco.core.integrations.antigrief.AntigriefManager import com.willfp.eco.core.integrations.antigrief.AntigriefManager
import com.willfp.eco.core.integrations.customblocks.CustomBlocksManager
import com.willfp.eco.core.integrations.customentities.CustomEntitiesManager import com.willfp.eco.core.integrations.customentities.CustomEntitiesManager
import com.willfp.eco.core.integrations.customitems.CustomItemsManager import com.willfp.eco.core.integrations.customitems.CustomItemsManager
import com.willfp.eco.core.integrations.economy.EconomyManager import com.willfp.eco.core.integrations.economy.EconomyManager
@@ -52,6 +53,7 @@ import com.willfp.eco.internal.items.ArgParserName
import com.willfp.eco.internal.items.ArgParserTexture import com.willfp.eco.internal.items.ArgParserTexture
import com.willfp.eco.internal.items.ArgParserUnbreakable import com.willfp.eco.internal.items.ArgParserUnbreakable
import com.willfp.eco.internal.items.ModernItemArgParsers import com.willfp.eco.internal.items.ModernItemArgParsers
import com.willfp.eco.internal.items.tags.VanillaItemTags
import com.willfp.eco.internal.lookup.SegmentParserGroup import com.willfp.eco.internal.lookup.SegmentParserGroup
import com.willfp.eco.internal.lookup.SegmentParserUseIfPresent import com.willfp.eco.internal.lookup.SegmentParserUseIfPresent
import com.willfp.eco.internal.particle.ParticleFactoryRGB import com.willfp.eco.internal.particle.ParticleFactoryRGB
@@ -100,6 +102,7 @@ import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefRPGHorses
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard
import com.willfp.eco.internal.spigot.integrations.customblocks.CustomBlocksOraxen
import com.willfp.eco.internal.spigot.integrations.customentities.CustomEntitiesMythicMobs import com.willfp.eco.internal.spigot.integrations.customentities.CustomEntitiesMythicMobs
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsCustomCrafting import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsCustomCrafting
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsDenizen import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsDenizen
@@ -264,6 +267,9 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
if (!Prerequisite.HAS_PAPER.isMet) { if (!Prerequisite.HAS_PAPER.isMet) {
bukkitAudiences = BukkitAudiences.create(this) bukkitAudiences = BukkitAudiences.create(this)
} }
// Init vanilla item tags
VanillaItemTags.register()
} }
override fun handleDisable() { override fun handleDisable() {
@@ -403,6 +409,9 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
// Placeholder // Placeholder
IntegrationLoader("PlaceholderAPI") { PlaceholderManager.addIntegration(PlaceholderIntegrationPAPI()) }, IntegrationLoader("PlaceholderAPI") { PlaceholderManager.addIntegration(PlaceholderIntegrationPAPI()) },
// Custom Blocks
IntegrationLoader("Oraxen") { CustomBlocksManager.register(CustomBlocksOraxen(this)) },
// Misc // Misc
IntegrationLoader("mcMMO") { McmmoManager.register(McmmoIntegrationImpl()) }, IntegrationLoader("mcMMO") { McmmoManager.register(McmmoIntegrationImpl()) },
IntegrationLoader("Multiverse-Inventories") { IntegrationLoader("Multiverse-Inventories") {

View File

@@ -0,0 +1,54 @@
package com.willfp.eco.internal.spigot.integrations.customblocks
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.blocks.Blocks
import com.willfp.eco.core.blocks.CustomBlock
import com.willfp.eco.core.blocks.TestableBlock
import com.willfp.eco.core.blocks.provider.BlockProvider
import com.willfp.eco.core.integrations.customblocks.CustomBlocksIntegration
import com.willfp.eco.util.namespacedKeyOf
import io.th0rgal.oraxen.api.OraxenBlocks
import io.th0rgal.oraxen.api.events.OraxenItemsLoadedEvent
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
class CustomBlocksOraxen(
private val plugin: EcoPlugin
) : CustomBlocksIntegration, Listener {
override fun registerProvider() {
plugin.eventManager.registerListener(this)
}
override fun getPluginName(): String {
return "Oraxen"
}
@EventHandler
@Suppress("UNUSED_PARAMETER")
fun onItemRegister(event: OraxenItemsLoadedEvent) {
Blocks.registerBlockProvider(OraxenProvider())
}
private class OraxenProvider : BlockProvider("oraxen") {
override fun provideForKey(key: String): TestableBlock? {
// The key
if (!OraxenBlocks.isOraxenBlock(key)) {
return null
}
val namespacedKey = namespacedKeyOf("oraxen", key)
return CustomBlock(
namespacedKey,
{ block ->
// TODO: Implement this
TODO("Not yet implemented")
},
{ location ->
OraxenBlocks.place(key, location)
location.block
}
)
}
}
}

View File

@@ -9,7 +9,8 @@ import java.util.UUID
import kotlin.jvm.optionals.getOrNull import kotlin.jvm.optionals.getOrNull
class HologramFancyHolograms : HologramIntegration { class HologramFancyHolograms : HologramIntegration {
private val manager = FancyHologramsPlugin.get().hologramManager private val manager
get() = FancyHologramsPlugin.get().hologramManager
override fun createHologram(location: Location, contents: List<String>): Hologram { override fun createHologram(location: Location, contents: List<String>): Hologram {
val id = UUID.randomUUID().toString() val id = UUID.randomUUID().toString()
@@ -19,7 +20,7 @@ class HologramFancyHolograms : HologramIntegration {
data.isPersistent = false data.isPersistent = false
val holo = manager.create(data) val holo = manager.create(data)
FancyHologramsPlugin.get().hologramManager.addHologram(holo) manager.addHologram(holo)
return HologramImplFancyHolograms(id) return HologramImplFancyHolograms(id)
} }

View File

@@ -1,2 +1,2 @@
version = 6.72.0 version = 6.73.2
kotlin.incremental.useClasspathSnapshot=false kotlin.incremental.useClasspathSnapshot=false