Compare commits

...

32 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
Auxilor
a9a961ff2b Added FancyHolograms integration 2024-07-20 12:49:07 +01:00
Auxilor
25d572c0db Added AutocrafterPatch 2024-07-20 09:59:58 +01:00
Auxilor
8a4243e434 Fixed XP price 2024-07-19 20:01:20 +01:00
Auxilor
6c40670f5e Updated to 6.72.0 2024-07-19 19:46:26 +01:00
Auxilor
6e94f3cee8 Added support for multiple display modules per plugin 2024-07-19 19:46:26 +01:00
Auxilor
4968d3ff22 Updated to 6.71.6 2024-07-14 16:04:21 +01:00
Auxilor
eecd80be1c Fixed display name 2024-07-14 16:04:14 +01:00
Auxilor
52c1b52f6d Fixed tab completion bug 2024-07-12 18:18:40 +01:00
Auxilor
f321296227 Updated to 6.71.5 2024-07-12 18:08:35 +01:00
Auxilor
ddd12db420 Fixed ExtendedPersistentDataContainerFactory 2024-07-12 18:07:53 +01:00
Auxilor
bd09791b5b Improved command tab-completion 2024-07-08 18:49:29 +01:00
Auxilor
ce9549f03d Updated to 6.71.4 2024-07-08 15:14:24 +01:00
Auxilor
52367dbb95 Fixed Java 17 compatibility 2024-07-08 15:14:18 +01:00
Auxilor
0080c32c23 Updated to 6.71.3 2024-06-25 02:30:45 +01:00
Auxilor
581094a930 Fixed DurabilityUtils 2024-06-25 02:30:37 +01:00
Auxilor
5d9c8775e8 Updated to 6.71.2 2024-06-24 18:44:16 +01:00
Auxilor
9ab51d2c87 Added fix for TopInventory on pre-1.21 2024-06-24 18:42:32 +01:00
Auxilor
b0de341d7f Updated to 6.71.1 2024-06-23 16:45:17 +01:00
Auxilor
1bada835ea Added 1.21 item arg parsers 2024-06-23 14:20:49 +01:00
71 changed files with 1775 additions and 133 deletions

View File

@@ -22,6 +22,7 @@ dependencies {
implementation(project(path = ":eco-core:core-plugin", configuration = "shadow")) implementation(project(path = ":eco-core:core-plugin", configuration = "shadow"))
implementation(project(":eco-core:core-proxy")) implementation(project(":eco-core:core-proxy"))
implementation(project(":eco-core:core-backend")) implementation(project(":eco-core:core-backend"))
implementation(project(":eco-core:core-backend-modern"))
implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_17_R1", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_18_R1", configuration = "reobf"))
implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf")) implementation(project(path = ":eco-core:core-nms:v1_18_R2", configuration = "reobf"))
@@ -96,6 +97,9 @@ allprojects {
// HuskPlugins // HuskPlugins
maven("https://repo.william278.net/releases") maven("https://repo.william278.net/releases")
// FancyHolograms
maven("https://repo.fancyplugins.de/releases")
} }
dependencies { dependencies {

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core; package com.willfp.eco.core;
import com.google.common.collect.ImmutableList;
import com.willfp.eco.core.command.impl.PluginCommand; import com.willfp.eco.core.command.impl.PluginCommand;
import com.willfp.eco.core.config.base.ConfigYml; import com.willfp.eco.core.config.base.ConfigYml;
import com.willfp.eco.core.config.base.LangYml; import com.willfp.eco.core.config.base.LangYml;
@@ -36,6 +37,8 @@ import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -120,9 +123,17 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
/** /**
* The display module for the plugin. * The display module for the plugin.
*
* @deprecated Plugins can now have multiple display modules.
*/ */
@Deprecated(since = "6.72.0")
private DisplayModule displayModule; private DisplayModule displayModule;
/**
* The display modules for the plugin.
*/
private List<DisplayModule> displayModules = new ArrayList<>();
/** /**
* The logger for the plugin. * The logger for the plugin.
*/ */
@@ -555,10 +566,15 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
* Default code to be executed after the server is up. * Default code to be executed after the server is up.
*/ */
public final void afterLoad() { public final void afterLoad() {
this.displayModule = createDisplayModule(); DisplayModule module = createDisplayModule();
if (module != null) {
Display.registerDisplayModule(module);
this.displayModules.add(module);
}
if (this.getDisplayModule() != null) { for (DisplayModule displayModule : this.loadDisplayModules()) {
Display.registerDisplayModule(this.getDisplayModule()); Display.registerDisplayModule(displayModule);
this.displayModules.add(displayModule);
} }
if (Prerequisite.HAS_PROTOCOLLIB.isMet()) { if (Prerequisite.HAS_PROTOCOLLIB.isMet()) {
@@ -899,14 +915,25 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
* Create the display module for the plugin. * Create the display module for the plugin.
* *
* @return The display module, or null. * @return The display module, or null.
* @deprecated Use {@link #loadDisplayModules()} instead.
*/ */
@Nullable @Nullable
@Deprecated(since = "6.72.0")
protected DisplayModule createDisplayModule() { protected DisplayModule createDisplayModule() {
Validate.isTrue(this.getDisplayModule() == null, "Display module exists!"); Validate.isTrue(this.getDisplayModule() == null, "Display module exists!");
return null; return null;
} }
/**
* Load display modules.
*
* @return The display modules.
*/
protected List<DisplayModule> loadDisplayModules() {
return new ArrayList<>();
}
/** /**
* Get the minimum version of eco to use the plugin. * Get the minimum version of eco to use the plugin.
* *
@@ -1156,12 +1183,23 @@ public abstract class EcoPlugin extends JavaPlugin implements PluginLike, Regist
* Get the plugin's display module. * Get the plugin's display module.
* *
* @return The display module. * @return The display module.
* @deprecated Use {@link #getDisplayModules()} instead.
*/ */
@Nullable @Nullable
@Deprecated(since = "6.72.0", forRemoval = true)
public DisplayModule getDisplayModule() { public DisplayModule getDisplayModule() {
return this.displayModule; return this.displayModule;
} }
/**
* Get the plugin's display modules.
*
* @return The display modules.
*/
public List<DisplayModule> getDisplayModules() {
return ImmutableList.copyOf(this.displayModules);
}
/** /**
* Get if the plugin is outdated. * Get if the plugin is outdated.
* *

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

@@ -211,12 +211,22 @@ public final class Display {
new ArrayList<>() new ArrayList<>()
); );
modules.removeIf(it -> it.getPluginName().equalsIgnoreCase(module.getPluginName()));
modules.add(module); modules.add(module);
REGISTERED_MODULES.put(module.getWeight(), modules); REGISTERED_MODULES.put(module.getWeight(), modules);
} }
/**
* Unregister a display module.
*
* @param module The module.
*/
public static void unregisterDisplayModule(@NotNull final DisplayModule module) {
for (List<DisplayModule> modules : REGISTERED_MODULES.values()) {
modules.remove(module);
}
}
private Display() { private Display() {
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,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

@@ -158,11 +158,8 @@ public final class DurabilityUtils {
} }
if (item.getItemMeta() instanceof Damageable meta) { if (item.getItemMeta() instanceof Damageable meta) {
meta.setDamage(meta.getDamage() - repair); meta.setDamage(Math.max(0, meta.getDamage() - repair));
if (meta.getDamage() < 0) {
meta.setDamage(0);
}
item.setItemMeta((ItemMeta) meta); item.setItemMeta((ItemMeta) meta);
} }
} }

View File

@@ -0,0 +1,19 @@
group = "com.willfp"
version = rootProject.version
dependencies {
compileOnly(project(":eco-core:core-backend"))
compileOnly("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
}
tasks {
compileJava {
options.release = 21
}
compileKotlin {
kotlinOptions {
jvmTarget = "21"
}
}
}

View File

@@ -0,0 +1,13 @@
package com.willfp.eco.internal.compat.modern.entities
import com.willfp.eco.core.entities.Entities
import com.willfp.eco.internal.compat.modern.entities.parsers.EntityArgParserJumpStrength
import com.willfp.eco.internal.compat.modern.entities.parsers.EntityArgParserScale
import com.willfp.eco.internal.entities.ModernEntityArgParsers
class ModernEntityArgParsersImpl: ModernEntityArgParsers {
override fun registerAll() {
Entities.registerArgParser(EntityArgParserScale)
Entities.registerArgParser(EntityArgParserJumpStrength)
}
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.internal.entities package com.willfp.eco.internal.compat.modern.entities.parsers
import com.willfp.eco.core.entities.args.EntityArgParseResult import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser import com.willfp.eco.core.entities.args.EntityArgParser
@@ -28,7 +28,7 @@ object EntityArgParserJumpStrength : EntityArgParser {
return@EntityArgParseResult false return@EntityArgParseResult false
} }
val inst = it.getAttribute(Attribute.HORSE_JUMP_STRENGTH) ?: return@EntityArgParseResult false val inst = it.getAttribute(Attribute.GENERIC_JUMP_STRENGTH) ?: return@EntityArgParseResult false
inst.value >= attributeValue inst.value >= attributeValue
}, },
{ {
@@ -36,8 +36,8 @@ object EntityArgParserJumpStrength : EntityArgParser {
return@EntityArgParseResult return@EntityArgParseResult
} }
it.getAttribute(Attribute.HORSE_JUMP_STRENGTH)?.baseValue = attributeValue it.getAttribute(Attribute.GENERIC_JUMP_STRENGTH)?.baseValue = attributeValue
} }
) )
} }
} }

View File

@@ -0,0 +1,45 @@
package com.willfp.eco.internal.compat.modern.entities.parsers
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.attribute.Attribute
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Phantom
import org.bukkit.entity.Slime
object EntityArgParserScale : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var attributeValue: Double? = null
for (arg in args) {
val argSplit = arg.split(":")
if (!argSplit[0].equals("scale", ignoreCase = true)) {
continue
}
if (argSplit.size < 2) {
continue
}
attributeValue = argSplit[1].toDoubleOrNull()
}
attributeValue ?: return null
return EntityArgParseResult(
{
if (it !is LivingEntity) {
return@EntityArgParseResult false
}
val inst = it.getAttribute(Attribute.GENERIC_SCALE) ?: return@EntityArgParseResult false
inst.value >= attributeValue
},
{
if (it !is LivingEntity) {
return@EntityArgParseResult
}
it.getAttribute(Attribute.GENERIC_SCALE)?.baseValue = attributeValue
}
)
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.internal.compat.modern.items
import com.willfp.eco.core.items.Items
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserFireResistant
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserGlint
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserItemName
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserMaxDamage
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserMaxStackSize
import com.willfp.eco.internal.compat.modern.items.parsers.ArgParserTrim
import com.willfp.eco.internal.items.ModernItemArgParsers
class ModernItemArgParsersImpl : ModernItemArgParsers {
override fun registerAll() {
Items.registerArgParser(ArgParserTrim)
Items.registerArgParser(ArgParserFireResistant)
Items.registerArgParser(ArgParserGlint)
Items.registerArgParser(ArgParserItemName)
Items.registerArgParser(ArgParserMaxDamage)
Items.registerArgParser(ArgParserMaxStackSize)
}
}

View File

@@ -0,0 +1,14 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.FlagArgParser
import org.bukkit.inventory.meta.ItemMeta
object ArgParserFireResistant : FlagArgParser("fire_resistant") {
override fun apply(meta: ItemMeta) {
meta.isFireResistant = true
}
override fun test(meta: ItemMeta): Boolean {
return meta.isFireResistant
}
}

View File

@@ -0,0 +1,14 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.FlagArgParser
import org.bukkit.inventory.meta.ItemMeta
object ArgParserGlint : FlagArgParser("glint") {
override fun apply(meta: ItemMeta) {
meta.setEnchantmentGlintOverride(true)
}
override fun test(meta: ItemMeta): Boolean {
return meta.hasEnchantmentGlintOverride()
}
}

View File

@@ -0,0 +1,27 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.ValueArgParser
import com.willfp.eco.util.StringUtils
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.minimessage.MiniMessage
import org.bukkit.inventory.meta.ItemMeta
object ArgParserItemName : ValueArgParser<Component>("item_name") {
override fun parse(arg: String): Component {
return StringUtils.formatToComponent(arg)
}
override fun apply(meta: ItemMeta, value: Component) {
meta.itemName(value)
}
override fun test(meta: ItemMeta): String? {
if (!meta.hasItemName()) {
return null
}
val name = MiniMessage.miniMessage().serialize(meta.itemName())
return name
}
}

View File

@@ -0,0 +1,31 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.ValueArgParser
import org.bukkit.inventory.meta.Damageable
import org.bukkit.inventory.meta.ItemMeta
object ArgParserMaxDamage : ValueArgParser<Int>("max_damage") {
override fun parse(arg: String): Int? {
return arg.toIntOrNull()
}
override fun apply(meta: ItemMeta, value: Int) {
if (meta !is Damageable) {
return
}
meta.setMaxDamage(value)
}
override fun test(meta: ItemMeta): String? {
if (meta !is Damageable) {
return null
}
if (!meta.hasMaxDamage()) {
return null
}
return meta.maxDamage.toString()
}
}

View File

@@ -0,0 +1,22 @@
package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.internal.items.templates.ValueArgParser
import org.bukkit.inventory.meta.ItemMeta
object ArgParserMaxStackSize : ValueArgParser<Int>("max_stack_size") {
override fun parse(arg: String): Int? {
return arg.toIntOrNull()
}
override fun apply(meta: ItemMeta, value: Int) {
meta.setMaxStackSize(value)
}
override fun test(meta: ItemMeta): String? {
if (!meta.hasMaxStackSize()) {
return null
}
return meta.maxStackSize.toString()
}
}

View File

@@ -1,4 +1,4 @@
package com.willfp.eco.internal.items package com.willfp.eco.internal.compat.modern.items.parsers
import com.willfp.eco.core.items.args.LookupArgParser import com.willfp.eco.core.items.args.LookupArgParser
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
@@ -23,7 +23,11 @@ object ArgParserTrim : LookupArgParser {
if (!argSplit[0].equals("trim", ignoreCase = true)) { if (!argSplit[0].equals("trim", ignoreCase = true)) {
continue continue
} }
@Suppress("DEPRECATION")
material = Registry.TRIM_MATERIAL.get(NamespacedKey.minecraft(argSplit.getOrElse(1) {""})) material = Registry.TRIM_MATERIAL.get(NamespacedKey.minecraft(argSplit.getOrElse(1) {""}))
@Suppress("DEPRECATION")
pattern = Registry.TRIM_PATTERN.get(NamespacedKey.minecraft(argSplit.getOrElse(2) {""})) pattern = Registry.TRIM_PATTERN.get(NamespacedKey.minecraft(argSplit.getOrElse(2) {""}))
} }
@@ -43,6 +47,11 @@ object ArgParserTrim : LookupArgParser {
override fun serializeBack(meta: ItemMeta): String? { override fun serializeBack(meta: ItemMeta): String? {
val trim = (meta as? ArmorMeta)?.trim ?: return null val trim = (meta as? ArmorMeta)?.trim ?: return null
return "trim:${trim.material.key.key.lowercase()}:${trim.pattern.key.key.lowercase()}" @Suppress("DEPRECATION")
val materialKey = Registry.TRIM_MATERIAL.getKey(trim.material) ?: return null
@Suppress("DEPRECATION")
val patternKey = Registry.TRIM_PATTERN.getKey(trim.pattern) ?: return null
return "trim:${materialKey.key.lowercase()}:${patternKey.key.lowercase()}"
} }
} }

View File

@@ -0,0 +1,19 @@
@file:Suppress("UnstableApiUsage")
package com.willfp.eco.internal.compat.modern.recipes
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.recipes.AutocrafterPatch
import org.bukkit.event.EventHandler
import org.bukkit.event.block.CrafterCraftEvent
class AutocrafterPatchImpl: AutocrafterPatch {
@EventHandler
fun preventEcoRecipes(event: CrafterCraftEvent) {
if (!EcoPlugin.getPluginNames().contains(event.recipe.key.namespace)) {
return
}
event.isCancelled = true
}
}

View File

@@ -13,3 +13,15 @@ dependencies {
compileOnly("org.yaml:snakeyaml:1.33") compileOnly("org.yaml:snakeyaml:1.33")
compileOnly("com.moandjiezana.toml:toml4j:0.7.2") compileOnly("com.moandjiezana.toml:toml4j:0.7.2")
} }
tasks {
compileJava {
options.release = 17
}
compileKotlin {
kotlinOptions {
jvmTarget = "17"
}
}
}

View File

@@ -126,14 +126,19 @@ abstract class HandledCommand(
* @return The tab completion results. * @return The tab completion results.
*/ */
private fun CommandBase.handleTabComplete(sender: CommandSender, args: List<String>): List<String> { private fun CommandBase.handleTabComplete(sender: CommandSender, args: List<String>): List<String> {
if (!sender.hasPermission(permission)) return emptyList() if (!sender.hasPermission(permission)) {
return emptyList()
}
if (args.size == 1) { if (args.size == 1) {
val completions = subcommands.filter { sender.hasPermission(it.permission) }.map { it.name } val completions = mutableListOf<String>()
val list = mutableListOf<String>() StringUtil.copyPartialMatches(
args[0],
subcommands.filter { sender.hasPermission(it.permission) }.map { it.name },
completions
)
StringUtil.copyPartialMatches(args[0], completions, list)
if (completions.isNotEmpty()) { if (completions.isNotEmpty()) {
return completions return completions
} }
@@ -156,9 +161,11 @@ abstract class HandledCommand(
} }
val completions = tabComplete(sender, args).toMutableList() val completions = tabComplete(sender, args).toMutableList()
if (sender is Player) { if (sender is Player) {
completions.addAll(tabComplete(sender, args)) completions.addAll(tabComplete(sender, args))
} }
return completions.sorted() return completions.sorted()
} }
} }

View File

@@ -0,0 +1,68 @@
package com.willfp.eco.internal.compat
import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.proxy.exceptions.ProxyError
private const val BASE_PACKAGE = "com.willfp.eco.internal.compat.modern"
private val isModern = Prerequisite.HAS_PAPER.isMet && Prerequisite.HAS_1_21.isMet
internal annotation class ModernCompatibilityProxy(
val location: String
)
private val cache = mutableMapOf<Class<*>, Any>()
object ModernCompatibilityScope {
inline fun <reified T> loadProxy(): T {
return loadCompatibilityProxy(T::class.java)
}
inline fun <reified T> useProxy(block: T.() -> Any?) {
val proxy = loadProxy<T>()
with(proxy) {
block()
}
}
}
fun <R> ifModern(block: ModernCompatibilityScope.() -> R) {
if (!isModern) {
return
}
block(ModernCompatibilityScope)
}
fun <T> loadCompatibilityProxy(clazz: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return cache.getOrPut(clazz) {
loadProxyUncached(clazz)
} as T
}
private fun loadProxyUncached(clazz: Class<*>): Any {
val proxy = clazz.getAnnotation(ModernCompatibilityProxy::class.java)
val location = proxy?.location ?: throw IllegalArgumentException("Class ${clazz.name} is not a proxy")
val className = "$BASE_PACKAGE.$location"
try {
val found = Class.forName(className)
val constructor = found.getConstructor()
val instance = constructor.newInstance()
if (!clazz.isInstance(instance)) {
throw ProxyError(
"Modern compatibility proxy class $className does not implement ${clazz.name}",
ClassCastException()
)
}
return instance
} catch (e: ClassNotFoundException) {
throw ProxyError("Could not find modern compatibility proxy class $className", e)
} catch (e: NoSuchMethodException) {
throw ProxyError("Could not find no-args constructor for modern compatibility proxy class $className", e)
}
}

View File

@@ -40,4 +40,4 @@ object EntityArgParserFlySpeed : EntityArgParser {
} }
) )
} }
} }

View File

@@ -0,0 +1,8 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.internal.compat.ModernCompatibilityProxy
@ModernCompatibilityProxy("entities.ModernEntityArgParsersImpl")
interface ModernEntityArgParsers {
fun registerAll()
}

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.internal.gui.menu package com.willfp.eco.internal.gui.menu
import com.willfp.eco.core.Eco
import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.gui.menu.events.CaptiveItemChangeEvent import com.willfp.eco.core.gui.menu.events.CaptiveItemChangeEvent
import com.willfp.eco.core.items.isEcoEmpty import com.willfp.eco.core.items.isEcoEmpty
import com.willfp.eco.core.recipe.parts.EmptyTestableItem import com.willfp.eco.core.recipe.parts.EmptyTestableItem
@@ -20,9 +22,23 @@ fun Player.forceRenderedInventory(menu: RenderedInventory) {
trackedForceRendered[this.uniqueId] = menu trackedForceRendered[this.uniqueId] = menu
} }
// Workaround because 1.21 has OpenInventory as an interface instead of an abstract class like in previous versions
interface TopInventoryProxy {
fun getTopInventory(player: Player): Inventory
}
private val Player.topInventory: Inventory
get() {
return if (!Prerequisite.HAS_1_21.isMet) {
Eco.get().ecoPlugin.getProxy(TopInventoryProxy::class.java).getTopInventory(this)
} else {
this.openInventory.topInventory
}
}
val Player.renderedInventory: RenderedInventory? val Player.renderedInventory: RenderedInventory?
get() = trackedForceRendered[this.uniqueId] get() = trackedForceRendered[this.uniqueId]
?: this.openInventory.topInventory.asRenderedInventory() ?: this.topInventory.asRenderedInventory()
class RenderedInventory( class RenderedInventory(
val menu: EcoMenu, val menu: EcoMenu,

View File

@@ -49,4 +49,4 @@ object ArgParserColor : LookupArgParser {
return "color:#${Integer.toHexString(meta.color.asRGB())}" return "color:#${Integer.toHexString(meta.color.asRGB())}"
} }
} }

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,16 +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
}
val enchant = Enchantment.getByKey(NamespacedKeyUtils.create("minecraft", argSplit[0])) enchants[enchant] = level
val level = argSplit[1].toIntOrNull()
if (enchant != null && level != null) {
enchants[enchant] = level
}
} }
if (enchants.isEmpty()) { if (enchants.isEmpty()) {

View File

@@ -61,4 +61,4 @@ object ArgParserEntity : LookupArgParser {
return state.spawnedType?.let { "entity:${state.spawnedType!!.name}" } ?: return null return state.spawnedType?.let { "entity:${state.spawnedType!!.name}" } ?: return null
} }
} }

View File

@@ -1,44 +1,30 @@
package com.willfp.eco.internal.items package com.willfp.eco.internal.items
import com.willfp.eco.core.items.args.LookupArgParser import com.willfp.eco.internal.items.templates.ValueArgParser
import com.willfp.eco.util.StringUtils import com.willfp.eco.util.StringUtils
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate import java.util.function.Predicate
object ArgParserName : LookupArgParser { object ArgParserName : ValueArgParser<String>("name") {
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? { override fun parse(arg: String): String {
var name: String? = null return arg
}
for (arg in args) { override fun apply(meta: ItemMeta, value: String) {
if (!arg.lowercase().startsWith("name:")) { val formatted = StringUtils.format(value)
continue
}
name = arg.substring(5, arg.length)
}
name ?: return null
val formatted = StringUtils.format(name)
// I don't know why it says it's redundant, the compiler yells at me // I don't know why it says it's redundant, the compiler yells at me
@Suppress("UsePropertyAccessSyntax", "RedundantSuppression", "DEPRECATION") @Suppress("UsePropertyAccessSyntax", "RedundantSuppression", "DEPRECATION")
meta.setDisplayName(formatted) meta.setDisplayName(formatted)
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
@Suppress("DEPRECATION")
testMeta.displayName == formatted
}
} }
override fun serializeBack(meta: ItemMeta): String? { override fun test(meta: ItemMeta): String? {
if (!meta.hasDisplayName()) { if (!meta.hasDisplayName()) {
return null return null
} }
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
return "name:\"${meta.displayName}\"" return meta.displayName
} }
} }

View File

@@ -44,4 +44,4 @@ object ArgParserTexture : LookupArgParser {
return "texture:${SkullUtils.getSkullTexture(meta)}" return "texture:${SkullUtils.getSkullTexture(meta)}"
} }
} }

View File

@@ -1,38 +1,14 @@
package com.willfp.eco.internal.items package com.willfp.eco.internal.items
import com.willfp.eco.core.items.args.LookupArgParser import com.willfp.eco.internal.items.templates.FlagArgParser
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate
object ArgParserUnbreakable : LookupArgParser {
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var unbreakable = false
for (arg in args) {
if (arg.equals("unbreakable", true)) {
unbreakable = true
}
}
if (!unbreakable) {
return null
}
object ArgParserUnbreakable : FlagArgParser("unbreakable") {
override fun apply(meta: ItemMeta) {
meta.isUnbreakable = true meta.isUnbreakable = true
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
testMeta.isUnbreakable
}
} }
override fun serializeBack(meta: ItemMeta): String? { override fun test(meta: ItemMeta): Boolean {
if (!meta.isUnbreakable) { return meta.isUnbreakable
return null
}
return "unbreakable"
} }
} }

View File

@@ -0,0 +1,8 @@
package com.willfp.eco.internal.items
import com.willfp.eco.internal.compat.ModernCompatibilityProxy
@ModernCompatibilityProxy("items.ModernItemArgParsersImpl")
interface ModernItemArgParsers {
fun registerAll()
}

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

@@ -0,0 +1,44 @@
package com.willfp.eco.internal.items.templates
import com.willfp.eco.core.items.args.LookupArgParser
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate
abstract class FlagArgParser(
protected val flag: String
) : LookupArgParser {
abstract fun apply(meta: ItemMeta)
abstract fun test(meta: ItemMeta): Boolean
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var has = false
for (arg in args) {
if (arg.equals(flag, true)) {
has = true
}
}
if (!has) {
return null
}
apply(meta)
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
test(testMeta)
}
}
override fun serializeBack(meta: ItemMeta): String? {
if (!test(meta)) {
return null
}
return flag
}
}

View File

@@ -0,0 +1,50 @@
package com.willfp.eco.internal.items.templates
import com.willfp.eco.core.items.args.LookupArgParser
import com.willfp.eco.util.StringUtils
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import java.util.function.Predicate
abstract class ValueArgParser<T: Any>(
protected val flag: String
) : LookupArgParser {
abstract fun parse(arg: String): T?
abstract fun apply(meta: ItemMeta, value: T)
abstract fun test(meta: ItemMeta): String?
override fun parseArguments(args: Array<out String>, meta: ItemMeta): Predicate<ItemStack>? {
var argument: String? = null
for (arg in args) {
if (!arg.lowercase().startsWith("${flag}:")) {
continue
}
argument = arg.substring(flag.length + 1, arg.length)
}
argument ?: return null
val parsed = parse(argument) ?: return null
apply(meta, parsed)
return Predicate {
val testMeta = it.itemMeta ?: return@Predicate false
test(testMeta) == parsed
}
}
override fun serializeBack(meta: ItemMeta): String? {
val test = test(meta)
if (test.isNullOrBlank()) {
return null
}
return "${flag}:\"$test\""
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.internal.particle package com.willfp.eco.internal.particle
import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.particle.ParticleFactory import com.willfp.eco.core.particle.ParticleFactory
import com.willfp.eco.core.particle.SpawnableParticle import com.willfp.eco.core.particle.SpawnableParticle
import org.bukkit.Color import org.bukkit.Color
@@ -7,6 +8,14 @@ import org.bukkit.Location
import org.bukkit.Particle import org.bukkit.Particle
object ParticleFactoryRGB : ParticleFactory { object ParticleFactoryRGB : ParticleFactory {
private val dustParticle = runCatching {
if (Prerequisite.HAS_1_20_5.isMet) {
Particle.valueOf("DUST")
} else {
Particle.valueOf("REDSTONE_DUST")
}
}.getOrNull()
override fun getNames() = listOf( override fun getNames() = listOf(
"color", "color",
"rgb", "rgb",
@@ -30,7 +39,9 @@ object ParticleFactoryRGB : ParticleFactory {
override fun spawn(location: Location, amount: Int) { override fun spawn(location: Location, amount: Int) {
val world = location.world ?: return val world = location.world ?: return
world.spawnParticle(Particle.REDSTONE, location, amount, 0.0, 0.0, 0.0, 0.0, options) val particle = dustParticle ?: return
world.spawnParticle(particle, location, amount, 0.0, 0.0, 0.0, 0.0, options)
} }
} }
} }

View File

@@ -8,6 +8,11 @@ import org.bukkit.entity.Player
import java.util.UUID import java.util.UUID
import kotlin.math.roundToInt import kotlin.math.roundToInt
private fun getXPNeededForLevel(level: Int): Int {
// XP Formula from NMS Player
return if (level >= 30) 112 + (level - 30) * 9 else (if (level >= 15) 37 + (level - 15) * 5 else 7 + level * 2)
}
object PriceFactoryXP : PriceFactory { object PriceFactoryXP : PriceFactory {
override fun getNames() = listOf( override fun getNames() = listOf(
"xp", "xp",
@@ -25,15 +30,37 @@ object PriceFactoryXP : PriceFactory {
) : Price { ) : Price {
private val multipliers = mutableMapOf<UUID, Double>() private val multipliers = mutableMapOf<UUID, Double>()
override fun canAfford(player: Player, multiplier: Double): Boolean = override fun canAfford(player: Player, multiplier: Double): Boolean {
player.totalExperience >= getValue(player, multiplier) var totalExperience = 0
for (level in 0 until player.level) {
totalExperience += getXPNeededForLevel(level)
}
totalExperience += (player.exp * getXPNeededForLevel(player.level)).toInt()
return totalExperience >= getValue(player, multiplier).roundToInt()
}
override fun pay(player: Player, multiplier: Double) { override fun pay(player: Player, multiplier: Double) {
player.totalExperience -= getValue(player, multiplier).roundToInt() takeXP(player, getValue(player, multiplier).roundToInt())
}
private fun takeXP(player: Player, amount: Int) {
val currentLevel = player.level
val currentExp = player.exp * getXPNeededForLevel(currentLevel)
if (currentExp >= amount) {
player.exp = (currentExp - amount) / getXPNeededForLevel(currentLevel)
} else {
// Handle recursive level down
player.exp = 1f
player.level = (currentLevel - 1).coerceAtLeast(0)
takeXP(player, (amount - currentExp).toInt())
}
} }
override fun giveTo(player: Player, multiplier: Double) { override fun giveTo(player: Player, multiplier: Double) {
player.totalExperience += getValue(player, multiplier).roundToInt() player.giveExp(getValue(player, multiplier).roundToInt())
} }
override fun getValue(player: Player, multiplier: Double): Double { override fun getValue(player: Player, multiplier: Double): Double {

View File

@@ -0,0 +1,7 @@
package com.willfp.eco.internal.recipes
import com.willfp.eco.internal.compat.ModernCompatibilityProxy
import org.bukkit.event.Listener
@ModernCompatibilityProxy("recipes.AutocrafterPatchImpl")
interface AutocrafterPatch: Listener

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R2
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R3
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_20_R1
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_20_R2
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_20_R3
import com.willfp.eco.internal.gui.menu.TopInventoryProxy
import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory
class TopInventory: TopInventoryProxy {
override fun getTopInventory(player: Player): Inventory {
return player.openInventory.topInventory
}
}

View File

@@ -43,15 +43,13 @@ class DisplayName : DisplayNameProxy {
val nmsComponent = displayName.toNMS() val nmsComponent = displayName.toNMS()
val nmsEntity = entity.handle val nmsEntity = entity.handle
nmsEntity.isCustomNameVisible
val entityData = SynchedEntityData.Builder(nmsEntity).build()
entityData.set(displayNameAccessor, Optional.of(nmsComponent), true)
entityData.set(customNameVisibleAccessor, visible, true)
val packet = ClientboundSetEntityDataPacket( val packet = ClientboundSetEntityDataPacket(
nmsEntity.id, nmsEntity.id,
entityData.packDirty() ?: throw IllegalStateException("No packed entity data") listOf(
SynchedEntityData.DataValue.create(displayNameAccessor, Optional.of(nmsComponent)),
SynchedEntityData.DataValue.create(customNameVisibleAccessor, visible)
)
) )
player.sendPacket(Packet(packet)) player.sendPacket(Packet(packet))

View File

@@ -10,6 +10,7 @@ import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import java.lang.reflect.Field
class ExtendedPersistentDataContainerFactory : ExtendedPersistentDataContainerFactoryProxy { class ExtendedPersistentDataContainerFactory : ExtendedPersistentDataContainerFactoryProxy {
private val registry: CraftPersistentDataTypeRegistry private val registry: CraftPersistentDataTypeRegistry
@@ -21,7 +22,15 @@ class ExtendedPersistentDataContainerFactory : ExtendedPersistentDataContainerFa
*/ */
val item = CraftItemStack.asCraftCopy(ItemStack(Material.STONE)) val item = CraftItemStack.asCraftCopy(ItemStack(Material.STONE))
val pdc = item.itemMeta!!.persistentDataContainer val pdc = item.itemMeta!!.persistentDataContainer
this.registry = CraftPersistentDataContainer::class.java.getDeclaredField("registry")
// Cross-version compatibility:
val registryField: Field = try {
CraftPersistentDataContainer::class.java.getDeclaredField("registry")
} catch (e: NoSuchFieldException) {
CraftPersistentDataContainer::class.java.superclass.getDeclaredField("registry")
}
this.registry = registryField
.apply { isAccessible = true }.get(pdc) as CraftPersistentDataTypeRegistry .apply { isAccessible = true }.get(pdc) as CraftPersistentDataTypeRegistry
} }

View File

@@ -66,6 +66,7 @@ dependencies {
compileOnly("net.william278.huskclaims:huskclaims-bukkit:1.0.1") compileOnly("net.william278.huskclaims:huskclaims-bukkit:1.0.1")
compileOnly("net.william278:husktowns:2.6.1") compileOnly("net.william278:husktowns:2.6.1")
compileOnly("com.github.jojodmo:ItemBridge:b0054538c1") compileOnly("com.github.jojodmo:ItemBridge:b0054538c1")
compileOnly("de.oliver:FancyHolograms:2.3.0")
compileOnly(fileTree("../../lib") { compileOnly(fileTree("../../lib") {
include("*.jar") include("*.jar")

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
@@ -20,16 +21,46 @@ import com.willfp.eco.core.items.Items
import com.willfp.eco.core.packet.PacketListener import com.willfp.eco.core.packet.PacketListener
import com.willfp.eco.core.particle.Particles import com.willfp.eco.core.particle.Particles
import com.willfp.eco.core.price.Prices import com.willfp.eco.core.price.Prices
import com.willfp.eco.internal.compat.ifModern
import com.willfp.eco.internal.data.MavenVersionToStringAdapter import com.willfp.eco.internal.data.MavenVersionToStringAdapter
import com.willfp.eco.internal.data.VersionToStringAdapter import com.willfp.eco.internal.data.VersionToStringAdapter
import com.willfp.eco.internal.entities.* import com.willfp.eco.internal.entities.EntityArgParserAdult
import com.willfp.eco.internal.items.* import com.willfp.eco.internal.entities.EntityArgParserAttackDamage
import com.willfp.eco.internal.entities.EntityArgParserAttackSpeed
import com.willfp.eco.internal.entities.EntityArgParserBaby
import com.willfp.eco.internal.entities.EntityArgParserCharged
import com.willfp.eco.internal.entities.EntityArgParserEquipment
import com.willfp.eco.internal.entities.EntityArgParserExplosionRadius
import com.willfp.eco.internal.entities.EntityArgParserFlySpeed
import com.willfp.eco.internal.entities.EntityArgParserFollowRange
import com.willfp.eco.internal.entities.EntityArgParserHealth
import com.willfp.eco.internal.entities.EntityArgParserKnockback
import com.willfp.eco.internal.entities.EntityArgParserKnockbackResistance
import com.willfp.eco.internal.entities.EntityArgParserName
import com.willfp.eco.internal.entities.EntityArgParserNoAI
import com.willfp.eco.internal.entities.EntityArgParserSilent
import com.willfp.eco.internal.entities.EntityArgParserSize
import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements
import com.willfp.eco.internal.entities.EntityArgParserSpeed
import com.willfp.eco.internal.entities.ModernEntityArgParsers
import com.willfp.eco.internal.items.ArgParserColor
import com.willfp.eco.internal.items.ArgParserCustomModelData
import com.willfp.eco.internal.items.ArgParserEnchantment
import com.willfp.eco.internal.items.ArgParserEntity
import com.willfp.eco.internal.items.ArgParserFlag
import com.willfp.eco.internal.items.ArgParserHead
import com.willfp.eco.internal.items.ArgParserName
import com.willfp.eco.internal.items.ArgParserTexture
import com.willfp.eco.internal.items.ArgParserUnbreakable
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
import com.willfp.eco.internal.price.PriceFactoryEconomy import com.willfp.eco.internal.price.PriceFactoryEconomy
import com.willfp.eco.internal.price.PriceFactoryXP import com.willfp.eco.internal.price.PriceFactoryXP
import com.willfp.eco.internal.price.PriceFactoryXPLevels import com.willfp.eco.internal.price.PriceFactoryXPLevels
import com.willfp.eco.internal.recipes.AutocrafterPatch
import com.willfp.eco.internal.spigot.arrows.ArrowDataListener import com.willfp.eco.internal.spigot.arrows.ArrowDataListener
import com.willfp.eco.internal.spigot.data.DataListener import com.willfp.eco.internal.spigot.data.DataListener
import com.willfp.eco.internal.spigot.data.DataYml import com.willfp.eco.internal.spigot.data.DataYml
@@ -37,21 +68,57 @@ import com.willfp.eco.internal.spigot.data.PlayerBlockListener
import com.willfp.eco.internal.spigot.data.ProfileHandler import com.willfp.eco.internal.spigot.data.ProfileHandler
import com.willfp.eco.internal.spigot.data.storage.ProfileSaver import com.willfp.eco.internal.spigot.data.storage.ProfileSaver
import com.willfp.eco.internal.spigot.drops.CollatedRunnable import com.willfp.eco.internal.spigot.drops.CollatedRunnable
import com.willfp.eco.internal.spigot.eventlisteners.* import com.willfp.eco.internal.spigot.eventlisteners.EntityDeathByEntityListeners
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 import com.willfp.eco.internal.spigot.eventlisteners.armor.ArmorChangeEventListeners
import com.willfp.eco.internal.spigot.eventlisteners.armor.ArmorListener import com.willfp.eco.internal.spigot.eventlisteners.armor.ArmorListener
import com.willfp.eco.internal.spigot.gui.GUIListener import com.willfp.eco.internal.spigot.gui.GUIListener
import com.willfp.eco.internal.spigot.integrations.afk.AFKIntegrationCMI import com.willfp.eco.internal.spigot.integrations.afk.AFKIntegrationCMI
import com.willfp.eco.internal.spigot.integrations.afk.AFKIntegrationEssentials import com.willfp.eco.internal.spigot.integrations.afk.AFKIntegrationEssentials
import com.willfp.eco.internal.spigot.integrations.anticheat.* import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatAAC
import com.willfp.eco.internal.spigot.integrations.antigrief.* import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatAlice
import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatMatrix
import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatNCP
import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatSpartan
import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatVulcan
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefBentoBox
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV10
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCrashClaim
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFabledSkyBlock
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefHuskClaims
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefHuskTowns
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefIridiumSkyblock
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefKingdoms
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefLands
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefPvPManager
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.AntigriefTowny
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.* 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.CustomItemsExecutableItems
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemBridge
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsMythicMobs
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsScyther
import com.willfp.eco.internal.spigot.integrations.customrecipes.CustomRecipeCustomCrafting import com.willfp.eco.internal.spigot.integrations.customrecipes.CustomRecipeCustomCrafting
import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault
import com.willfp.eco.internal.spigot.integrations.entitylookup.EntityLookupModelEngine import com.willfp.eco.internal.spigot.integrations.entitylookup.EntityLookupModelEngine
import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI
import com.willfp.eco.internal.spigot.integrations.hologram.HologramDecentHolograms import com.willfp.eco.internal.spigot.integrations.hologram.HologramDecentHolograms
import com.willfp.eco.internal.spigot.integrations.hologram.HologramFancyHolograms
import com.willfp.eco.internal.spigot.integrations.hologram.HologramHolographicDisplays import com.willfp.eco.internal.spigot.integrations.hologram.HologramHolographicDisplays
import com.willfp.eco.internal.spigot.integrations.mcmmo.McmmoIntegrationImpl import com.willfp.eco.internal.spigot.integrations.mcmmo.McmmoIntegrationImpl
import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration import com.willfp.eco.internal.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration
@@ -97,8 +164,11 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
Items.registerArgParser(ArgParserName) Items.registerArgParser(ArgParserName)
Items.registerArgParser(ArgParserHead) Items.registerArgParser(ArgParserHead)
Items.registerArgParser(ArgParserEntity) Items.registerArgParser(ArgParserEntity)
if (Prerequisite.HAS_1_20.isMet) {
Items.registerArgParser(ArgParserTrim) ifModern {
useProxy<ModernItemArgParsers> {
registerAll()
}
} }
Entities.registerArgParser(EntityArgParserName) Entities.registerArgParser(EntityArgParserName)
@@ -108,7 +178,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
Entities.registerArgParser(EntityArgParserFlySpeed) Entities.registerArgParser(EntityArgParserFlySpeed)
Entities.registerArgParser(EntityArgParserFollowRange) Entities.registerArgParser(EntityArgParserFollowRange)
Entities.registerArgParser(EntityArgParserHealth) Entities.registerArgParser(EntityArgParserHealth)
Entities.registerArgParser(EntityArgParserJumpStrength)
Entities.registerArgParser(EntityArgParserKnockback) Entities.registerArgParser(EntityArgParserKnockback)
Entities.registerArgParser(EntityArgParserKnockbackResistance) Entities.registerArgParser(EntityArgParserKnockbackResistance)
Entities.registerArgParser(EntityArgParserSize) Entities.registerArgParser(EntityArgParserSize)
@@ -121,6 +190,12 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
Entities.registerArgParser(EntityArgParserSilent) Entities.registerArgParser(EntityArgParserSilent)
Entities.registerArgParser(EntityArgParserEquipment) Entities.registerArgParser(EntityArgParserEquipment)
ifModern {
useProxy<ModernEntityArgParsers> {
registerAll()
}
}
Prices.registerPriceFactory(PriceFactoryEconomy) Prices.registerPriceFactory(PriceFactoryEconomy)
Prices.registerPriceFactory(PriceFactoryXPLevels) Prices.registerPriceFactory(PriceFactoryXPLevels)
Prices.registerPriceFactory(PriceFactoryXP) Prices.registerPriceFactory(PriceFactoryXP)
@@ -192,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() {
@@ -299,6 +377,7 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
IntegrationLoader("CMI") { HologramManager.register(HologramCMI()) }, IntegrationLoader("CMI") { HologramManager.register(HologramCMI()) },
IntegrationLoader("DecentHolograms") { HologramManager.register(HologramDecentHolograms()) }, IntegrationLoader("DecentHolograms") { HologramManager.register(HologramDecentHolograms()) },
//IntegrationLoader("GHolo") { HologramManager.register(HologramGHolo()) }, //IntegrationLoader("GHolo") { HologramManager.register(HologramGHolo()) },
IntegrationLoader("FancyHolograms") { HologramManager.register(HologramFancyHolograms()) },
// AFK // AFK
IntegrationLoader("Essentials") { AFKManager.register(AFKIntegrationEssentials()) }, IntegrationLoader("Essentials") { AFKManager.register(AFKIntegrationEssentials()) },
@@ -330,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") {
@@ -363,6 +445,10 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
listeners.add(NaturalExpGainListenersSpigot()) listeners.add(NaturalExpGainListenersSpigot())
} }
ifModern {
listeners += loadProxy<AutocrafterPatch>()
}
return listeners return listeners
} }

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

@@ -0,0 +1,46 @@
package com.willfp.eco.internal.spigot.integrations.hologram
import com.willfp.eco.core.integrations.hologram.Hologram
import com.willfp.eco.core.integrations.hologram.HologramIntegration
import de.oliver.fancyholograms.api.FancyHologramsPlugin
import de.oliver.fancyholograms.api.data.TextHologramData
import org.bukkit.Location
import java.util.UUID
import kotlin.jvm.optionals.getOrNull
class HologramFancyHolograms : HologramIntegration {
private val manager
get() = FancyHologramsPlugin.get().hologramManager
override fun createHologram(location: Location, contents: List<String>): Hologram {
val id = UUID.randomUUID().toString()
val data = TextHologramData(id, location)
data.text = contents
data.isPersistent = false
val holo = manager.create(data)
manager.addHologram(holo)
return HologramImplFancyHolograms(id)
}
override fun getPluginName(): String {
return "FancyHolograms"
}
inner class HologramImplFancyHolograms(
private val id: String,
) : Hologram {
override fun remove() {
val hologram = manager.getHologram(id).getOrNull() ?: return
manager.removeHologram(hologram)
}
override fun setContents(contents: List<String>) {
val hologram = manager.getHologram(id).getOrNull() ?: return
val data = hologram.data as? TextHologramData ?: return
data.text = contents
}
}
}

View File

@@ -1,10 +1,8 @@
package com.willfp.eco.internal.spigot.recipes package com.willfp.eco.internal.spigot.recipes
import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.recipe.Recipes import com.willfp.eco.core.recipe.Recipes
import org.bukkit.Keyed import org.bukkit.Keyed
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.event.inventory.CraftItemEvent import org.bukkit.event.inventory.CraftItemEvent
@@ -17,6 +15,7 @@ class CraftingRecipeListener(val plugin: EcoPlugin) : Listener {
if (!EcoPlugin.getPluginNames().contains(event.recipe.namespace)) { if (!EcoPlugin.getPluginNames().contains(event.recipe.namespace)) {
return return
} }
if (event.recipe.key.contains("_displayed")) { if (event.recipe.key.contains("_displayed")) {
event.isCancelled = true event.isCancelled = true
} }

View File

@@ -59,4 +59,4 @@ class WrappedCraftItemEvent(
event.result = Event.Result.DENY event.result = Event.Result.DENY
event.isCancelled = true event.isCancelled = true
} }
} }

View File

@@ -61,3 +61,4 @@ softdepend:
- PlayerPoints - PlayerPoints
- Denizen - Denizen
- RoyaleEconomy - RoyaleEconomy
- FancyHolograms

View File

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

View File

@@ -29,4 +29,5 @@ include(":eco-core:core-nms:v1_20_R3")
include(":eco-core:core-nms:v1_21") include(":eco-core:core-nms:v1_21")
include(":eco-core:core-proxy") include(":eco-core:core-proxy")
include(":eco-core:core-plugin") include(":eco-core:core-plugin")
include(":eco-core:core-backend") include(":eco-core:core-backend")
include(":eco-core:core-backend-modern")