From ebc0bc7d186ada60ce26eb9b0e6a27c1495e861e Mon Sep 17 00:00:00 2001
From: TheDeathlyCow <53499406+TheDeathlyCow@users.noreply.github.com>
Date: Tue, 24 Sep 2024 05:46:27 +1200
Subject: [PATCH] Modify Enchantment and Fabric Component Map Builder
Extensions (#4085)
* modify effects event
* give impaling fire aspect
* add fabric component map builder
* change interface name to match event
* gametests for weird impaling enchantment
* fix checkstyle issues
* fabric map builder javadoc
* modify effects javadoc
* fix checkstyle issues
* prefer extension methods over add
* add enchantment source
* fix missing asterisk on fabricitemstack javadoc
* switch to enchantment builder
* fix effects list
* fix checkstyle
* add note on exclusive set to javadoc
* add fabric component builder extensions to default component testmod
* remove threadlocal usage from mixin
* remove modid prefix from accessors
* remove unused import
* fix recursive invoker
* add test to automatically check modified item name
(cherry picked from commit d5debaed0eca08cac9450317d46810a9194c22dd)
---
fabric-item-api-v1/build.gradle | 2 +-
.../fabric/api/item/v1/EnchantmentEvents.java | 38 +++++
.../fabric/api/item/v1/EnchantmentSource.java | 55 +++++++
.../item/v1/FabricComponentMapBuilder.java | 74 ++++++++++
.../fabric/api/item/v1/FabricItemStack.java | 2 +-
.../fabric/impl/item/EnchantmentUtil.java | 80 +++++++++++
.../mixin/item/ComponentMapBuilderMixin.java | 65 +++++++++
.../item/EnchantmentBuilderAccessor.java | 43 ++++++
.../mixin/item/RegistryLoaderMixin.java | 66 +++++++++
.../resources/fabric-item-api-v1.mixins.json | 5 +-
.../src/main/resources/fabric.mod.json | 3 +-
.../item/CustomEnchantmentEffectsTest.java | 76 ++++++++++
.../test/item/DefaultItemComponentTest.java | 13 ++
.../CustomEnchantmentEffectsGameTest.java | 91 ++++++++++++
.../DefaultItemComponentGameTest.java | 18 +++
.../enchantment/weird_impaling.json | 42 ++++++
.../gametest/structure/bedrock_platform.snbt | 136 ++++++++++++++++++
.../src/testmod/resources/fabric.mod.json | 4 +-
18 files changed, 808 insertions(+), 5 deletions(-)
create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentSource.java
create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricComponentMapBuilder.java
create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/impl/item/EnchantmentUtil.java
create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ComponentMapBuilderMixin.java
create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentBuilderAccessor.java
create mode 100644 fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/RegistryLoaderMixin.java
create mode 100644 fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomEnchantmentEffectsTest.java
create mode 100644 fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/CustomEnchantmentEffectsGameTest.java
create mode 100644 fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/enchantment/weird_impaling.json
create mode 100644 fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/gametest/structure/bedrock_platform.snbt
diff --git a/fabric-item-api-v1/build.gradle b/fabric-item-api-v1/build.gradle
index e54321e6e..4c7c582bc 100644
--- a/fabric-item-api-v1/build.gradle
+++ b/fabric-item-api-v1/build.gradle
@@ -1,6 +1,6 @@
version = getSubprojectVersion(project)
-moduleDependencies(project, ['fabric-api-base'])
+moduleDependencies(project, ['fabric-api-base', 'fabric-resource-loader-v0'])
testDependencies(project, [
':fabric-content-registries-v0',
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java
index 83cc8c3c8..4c6cac1f0 100644
--- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentEvents.java
@@ -18,6 +18,7 @@ package net.fabricmc.fabric.api.item.v1;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.item.ItemStack;
+import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.entry.RegistryEntry;
import net.fabricmc.fabric.api.event.Event;
@@ -64,6 +65,27 @@ public final class EnchantmentEvents {
}
);
+ /**
+ * An event that allows an {@link Enchantment} to be modified without needing to fully override an enchantment.
+ *
+ *
This should only be used to modify the behavior of external enchantments, where 'external' means
+ * either vanilla or from another mod. For instance, a mod might add a bleed effect to Sharpness (and only Sharpness).
+ * For your own enchantments, you should simply define them in your mod's data pack. See the
+ * Enchantment Definition page on the Minecraft Wiki
+ * for more information.
+ *
+ *
Note: If you wish to modify the exclusive set of the enchantment, consider extending the
+ * {@linkplain net.minecraft.registry.tag.EnchantmentTags relevant tag} through your mod's data pack instead.
+ */
+ public static final Event MODIFY = EventFactory.createArrayBacked(
+ Modify.class,
+ callbacks -> (key, builder, source) -> {
+ for (Modify callback : callbacks) {
+ callback.modify(key, builder, source);
+ }
+ }
+ );
+
@FunctionalInterface
public interface AllowEnchanting {
/**
@@ -82,4 +104,20 @@ public final class EnchantmentEvents {
EnchantingContext enchantingContext
);
}
+
+ @FunctionalInterface
+ public interface Modify {
+ /**
+ * Modifies the effects of an {@link Enchantment}.
+ *
+ * @param key The ID of the enchantment
+ * @param builder The enchantment builder
+ * @param source The source of the enchantment
+ */
+ void modify(
+ RegistryKey key,
+ Enchantment.Builder builder,
+ EnchantmentSource source
+ );
+ }
}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentSource.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentSource.java
new file mode 100644
index 000000000..81db2eb69
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/EnchantmentSource.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.item.v1;
+
+/**
+ * Determines where an enchantment has been loaded from.
+ */
+public enum EnchantmentSource {
+ /**
+ * An enchantment loaded from the vanilla data pack.
+ */
+ VANILLA(true),
+ /**
+ * An enchantment loaded from mods' bundled resources.
+ *
+ * This includes the additional builtin data packs registered by mods
+ * with Fabric Resource Loader.
+ */
+ MOD(true),
+ /**
+ * An enchantment loaded from an external data pack.
+ */
+ DATA_PACK(false);
+
+ private final boolean builtin;
+
+ EnchantmentSource(boolean builtin) {
+ this.builtin = builtin;
+ }
+
+ /**
+ * Returns whether this enchantment source is builtin and bundled in the vanilla or mod resources.
+ *
+ *
{@link #VANILLA} and {@link #MOD} are builtin.
+ *
+ * @return {@code true} if builtin, {@code false} otherwise
+ */
+ public boolean isBuiltin() {
+ return builtin;
+ }
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricComponentMapBuilder.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricComponentMapBuilder.java
new file mode 100644
index 000000000..d911a80a1
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricComponentMapBuilder.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.api.item.v1;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import net.minecraft.component.ComponentType;
+
+/**
+ * Fabric-provided extensions for {@link net.minecraft.component.ComponentMap.Builder}.
+ *
+ *
Note: This interface is automatically implemented on all component map builders via Mixin and interface injection.
+ */
+@ApiStatus.NonExtendable
+public interface FabricComponentMapBuilder {
+ /**
+ * Gets the current value for the component type in the builder, or creates and adds a new value if it is not present.
+ *
+ * @param type The component type
+ * @param fallback The supplier for the default data value if the type is not in this map yet. The value given by this supplier
+ * may not be null.
+ * @param The type of the component data
+ * @return Returns the current value in the map builder, or the default value provided by the fallback if not present
+ * @see #getOrEmpty(ComponentType)
+ */
+ default T getOrCreate(ComponentType type, Supplier<@NotNull T> fallback) {
+ throw new AssertionError("Implemented in Mixin");
+ }
+
+ /**
+ * Gets the current value for the component type in the builder, or creates and adds a new value if it is not present.
+ *
+ * @param type The component type
+ * @param defaultValue The default data value if the type is not in this map yet
+ * @param The type of the component data
+ * @return Returns the current value in the map builder, or the default value if not present
+ */
+ default T getOrDefault(ComponentType type, @NotNull T defaultValue) {
+ Objects.requireNonNull(defaultValue, "Cannot insert null values to component map builder");
+ return getOrCreate(type, () -> defaultValue);
+ }
+
+ /**
+ * For list component types specifically, returns a mutable list of values currently held in the builder for the given
+ * component type. If the type is not registered to this builder yet, this will create and add a new empty list to the builder
+ * for the type, and return that.
+ *
+ * @param type The component type. The component must be a list-type.
+ * @param The type of the component entry data
+ * @return Returns a mutable list of values for the type.
+ */
+ default List getOrEmpty(ComponentType> type) {
+ throw new AssertionError("Implemented in Mixin");
+ }
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java
index 1be59c035..4fb71479e 100644
--- a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/api/item/v1/FabricItemStack.java
@@ -23,7 +23,7 @@ import net.minecraft.registry.entry.RegistryEntry;
import net.fabricmc.fabric.api.util.TriState;
-/*
+/**
* Fabric-provided extensions for {@link ItemStack}.
* This interface is automatically implemented on all item stacks via Mixin and interface injection.
*/
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/impl/item/EnchantmentUtil.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/impl/item/EnchantmentUtil.java
new file mode 100644
index 000000000..defbb3b1b
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/impl/item/EnchantmentUtil.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.impl.item;
+
+import java.util.List;
+
+import net.minecraft.component.ComponentType;
+import net.minecraft.enchantment.Enchantment;
+import net.minecraft.registry.RegistryKey;
+import net.minecraft.resource.Resource;
+import net.minecraft.resource.ResourcePackSource;
+
+import net.fabricmc.fabric.api.item.v1.EnchantmentEvents;
+import net.fabricmc.fabric.api.item.v1.EnchantmentSource;
+import net.fabricmc.fabric.impl.resource.loader.BuiltinModResourcePackSource;
+import net.fabricmc.fabric.impl.resource.loader.FabricResource;
+import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator;
+import net.fabricmc.fabric.mixin.item.EnchantmentBuilderAccessor;
+
+public class EnchantmentUtil {
+ @SuppressWarnings("unchecked")
+ public static Enchantment modify(RegistryKey key, Enchantment originalEnchantment, EnchantmentSource source) {
+ Enchantment.Builder builder = Enchantment.builder(originalEnchantment.definition());
+ EnchantmentBuilderAccessor accessor = (EnchantmentBuilderAccessor) builder;
+
+ builder.exclusiveSet(originalEnchantment.exclusiveSet());
+ accessor.getEffectMap().addAll(originalEnchantment.effects());
+
+ originalEnchantment.effects().stream()
+ .forEach(component -> {
+ if (component.value() instanceof List> valueList) {
+ // component type cast is checked by the value
+ accessor.invokeGetEffectsList((ComponentType>) component.type())
+ .addAll(valueList);
+ }
+ });
+
+ EnchantmentEvents.MODIFY.invoker().modify(key, builder, source);
+
+ return new Enchantment(
+ originalEnchantment.description(),
+ accessor.getDefinition(),
+ accessor.getExclusiveSet(),
+ accessor.getEffectMap().build()
+ );
+ }
+
+ public static EnchantmentSource determineSource(Resource resource) {
+ if (resource != null) {
+ ResourcePackSource packSource = ((FabricResource) resource).getFabricPackSource();
+
+ if (packSource == ResourcePackSource.BUILTIN) {
+ return EnchantmentSource.VANILLA;
+ } else if (packSource == ModResourcePackCreator.RESOURCE_PACK_SOURCE || packSource instanceof BuiltinModResourcePackSource) {
+ return EnchantmentSource.MOD;
+ }
+ }
+
+ // If not builtin or mod, assume external data pack.
+ // It might also be a virtual enchantment injected via mixin instead of being loaded
+ // from a resource, but we can't determine that here.
+ return EnchantmentSource.DATA_PACK;
+ }
+
+ private EnchantmentUtil() { }
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ComponentMapBuilderMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ComponentMapBuilderMixin.java
new file mode 100644
index 000000000..f2fc2a83b
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/ComponentMapBuilderMixin.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import net.minecraft.component.ComponentMap;
+import net.minecraft.component.ComponentType;
+
+import net.fabricmc.fabric.api.item.v1.FabricComponentMapBuilder;
+
+@Mixin(ComponentMap.Builder.class)
+abstract class ComponentMapBuilderMixin implements FabricComponentMapBuilder {
+ @Shadow
+ @Final
+ private Reference2ObjectMap, Object> components;
+
+ @Shadow
+ public abstract ComponentMap.Builder add(ComponentType type, @Nullable T value);
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T getOrCreate(ComponentType type, Supplier<@NotNull T> fallback) {
+ if (!this.components.containsKey(type)) {
+ T defaultValue = fallback.get();
+ Objects.requireNonNull(defaultValue, "Cannot insert null values to component map builder");
+ this.add(type, defaultValue);
+ }
+
+ return (T) this.components.get(type);
+ }
+
+ @Override
+ public List getOrEmpty(ComponentType> type) {
+ // creating a new array list guarantees that the list in the map is mutable
+ List existing = new ArrayList<>(this.getOrCreate(type, Collections::emptyList));
+ this.add(type, existing);
+ return existing;
+ }
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentBuilderAccessor.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentBuilderAccessor.java
new file mode 100644
index 000000000..b0ef4e514
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/EnchantmentBuilderAccessor.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import java.util.List;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+import net.minecraft.component.ComponentMap;
+import net.minecraft.component.ComponentType;
+import net.minecraft.enchantment.Enchantment;
+import net.minecraft.registry.entry.RegistryEntryList;
+
+@Mixin(Enchantment.Builder.class)
+public interface EnchantmentBuilderAccessor {
+ @Accessor("definition")
+ Enchantment.Definition getDefinition();
+
+ @Accessor("exclusiveSet")
+ RegistryEntryList getExclusiveSet();
+
+ @Accessor("effectMap")
+ ComponentMap.Builder getEffectMap();
+
+ @Invoker("getEffectsList")
+ List invokeGetEffectsList(ComponentType> type);
+}
diff --git a/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/RegistryLoaderMixin.java b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/RegistryLoaderMixin.java
new file mode 100644
index 000000000..fd2e0930e
--- /dev/null
+++ b/fabric-item-api-v1/src/main/java/net/fabricmc/fabric/mixin/item/RegistryLoaderMixin.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.item;
+
+import com.google.gson.JsonElement;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.mojang.serialization.Decoder;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+import net.minecraft.enchantment.Enchantment;
+import net.minecraft.registry.MutableRegistry;
+import net.minecraft.registry.RegistryKey;
+import net.minecraft.registry.RegistryLoader;
+import net.minecraft.registry.RegistryOps;
+import net.minecraft.registry.entry.RegistryEntry;
+import net.minecraft.registry.entry.RegistryEntryInfo;
+import net.minecraft.resource.Resource;
+
+import net.fabricmc.fabric.impl.item.EnchantmentUtil;
+
+@Mixin(RegistryLoader.class)
+abstract class RegistryLoaderMixin {
+ @WrapOperation(
+ method = "parseAndAdd",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/registry/MutableRegistry;add(Lnet/minecraft/registry/RegistryKey;Ljava/lang/Object;Lnet/minecraft/registry/entry/RegistryEntryInfo;)Lnet/minecraft/registry/entry/RegistryEntry$Reference;"
+ )
+ )
+ @SuppressWarnings("unchecked")
+ private static RegistryEntry.Reference enchantmentKey(
+ MutableRegistry instance,
+ RegistryKey objectKey,
+ Object object,
+ RegistryEntryInfo registryEntryInfo,
+ Operation> original,
+ MutableRegistry registry,
+ Decoder decoder,
+ RegistryOps ops,
+ RegistryKey registryKey,
+ Resource resource,
+ RegistryEntryInfo entryInfo
+ ) {
+ if (object instanceof Enchantment enchantment) {
+ object = EnchantmentUtil.modify((RegistryKey) objectKey, enchantment, EnchantmentUtil.determineSource(resource));
+ }
+
+ return original.call(instance, registryKey, object, registryEntryInfo);
+ }
+}
diff --git a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json
index 920ff6492..72c8d11d0 100644
--- a/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json
+++ b/fabric-item-api-v1/src/main/resources/fabric-item-api-v1.mixins.json
@@ -6,6 +6,8 @@
"AbstractFurnaceBlockEntityMixin",
"AnvilScreenHandlerMixin",
"BrewingStandBlockEntityMixin",
+ "ComponentMapBuilderMixin",
+ "EnchantmentBuilderAccessor",
"EnchantCommandMixin",
"EnchantmentHelperMixin",
"EnchantRandomlyLootFunctionMixin",
@@ -15,7 +17,8 @@
"ItemStackMixin",
"LivingEntityMixin",
"RecipeMixin",
- "RegistriesMixin"
+ "RegistriesMixin",
+ "RegistryLoaderMixin"
],
"injectors": {
"defaultRequire": 1
diff --git a/fabric-item-api-v1/src/main/resources/fabric.mod.json b/fabric-item-api-v1/src/main/resources/fabric.mod.json
index aa9d95d37..f3c0a889e 100644
--- a/fabric-item-api-v1/src/main/resources/fabric.mod.json
+++ b/fabric-item-api-v1/src/main/resources/fabric.mod.json
@@ -32,7 +32,8 @@
"loom:injected_interfaces": {
"net/minecraft/class_1792": ["net/fabricmc/fabric/api/item/v1/FabricItem"],
"net/minecraft/class_1792\u0024class_1793": ["net/fabricmc/fabric/api/item/v1/FabricItem\u0024Settings"],
- "net/minecraft/class_1799": ["net/fabricmc/fabric/api/item/v1/FabricItemStack"]
+ "net/minecraft/class_1799": ["net/fabricmc/fabric/api/item/v1/FabricItemStack"],
+ "net/minecraft/class_9323\u0024class_9324": ["net/fabricmc/fabric/api/item/v1/FabricComponentMapBuilder"]
}
}
}
diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomEnchantmentEffectsTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomEnchantmentEffectsTest.java
new file mode 100644
index 000000000..f1ac0e6e3
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/CustomEnchantmentEffectsTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.item;
+
+import net.minecraft.component.EnchantmentEffectComponentTypes;
+import net.minecraft.enchantment.Enchantment;
+import net.minecraft.enchantment.EnchantmentLevelBasedValue;
+import net.minecraft.enchantment.effect.EnchantmentEffectTarget;
+import net.minecraft.enchantment.effect.entity.IgniteEnchantmentEffect;
+import net.minecraft.enchantment.effect.value.AddEnchantmentEffect;
+import net.minecraft.entity.EntityType;
+import net.minecraft.loot.condition.DamageSourcePropertiesLootCondition;
+import net.minecraft.loot.condition.EntityPropertiesLootCondition;
+import net.minecraft.loot.context.LootContext;
+import net.minecraft.predicate.entity.DamageSourcePredicate;
+import net.minecraft.predicate.entity.EntityPredicate;
+import net.minecraft.predicate.entity.EntityTypePredicate;
+import net.minecraft.registry.RegistryKey;
+import net.minecraft.registry.RegistryKeys;
+import net.minecraft.util.Identifier;
+
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.fabric.api.item.v1.EnchantmentEvents;
+
+public class CustomEnchantmentEffectsTest implements ModInitializer {
+ // weird impaling is a copy of impaling used for testing (just in case minecraft changes impaling for some reason)
+ public static final RegistryKey WEIRD_IMPALING = RegistryKey.of(
+ RegistryKeys.ENCHANTMENT,
+ Identifier.of("fabric-item-api-v1-testmod", "weird_impaling")
+ );
+
+ @Override
+ public void onInitialize() {
+ EnchantmentEvents.MODIFY.register(
+ (key, builder, source) -> {
+ if (source.isBuiltin() && key == WEIRD_IMPALING) {
+ // make impaling set things on fire
+ builder.addEffect(
+ EnchantmentEffectComponentTypes.POST_ATTACK,
+ EnchantmentEffectTarget.ATTACKER,
+ EnchantmentEffectTarget.VICTIM,
+ new IgniteEnchantmentEffect(EnchantmentLevelBasedValue.linear(4.0f)),
+ DamageSourcePropertiesLootCondition.builder(
+ DamageSourcePredicate.Builder.create().isDirect(true)
+ )
+ );
+
+ // add bonus impaling damage to zombie
+ builder.addEffect(
+ EnchantmentEffectComponentTypes.DAMAGE,
+ new AddEnchantmentEffect(EnchantmentLevelBasedValue.linear(2.5f)),
+ EntityPropertiesLootCondition.builder(
+ LootContext.EntityTarget.THIS,
+ EntityPredicate.Builder.create()
+ .type(EntityTypePredicate.create(EntityType.ZOMBIE))
+ )
+ );
+ }
+ }
+ );
+ }
+}
diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/DefaultItemComponentTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/DefaultItemComponentTest.java
index 3dc51c75d..b77db958b 100644
--- a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/DefaultItemComponentTest.java
+++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/DefaultItemComponentTest.java
@@ -51,6 +51,14 @@ public class DefaultItemComponentTest implements ModInitializer {
// Remove the food component from beef
builder.add(DataComponentTypes.FOOD, null);
});
+ // add a word to the start of diamond pickaxe name
+ context.modify(Items.DIAMOND_PICKAXE, builder -> {
+ Text baseName = builder.getOrCreate(
+ DataComponentTypes.ITEM_NAME,
+ Items.DIAMOND_PICKAXE::getName
+ );
+ builder.add(DataComponentTypes.ITEM_NAME, prependModifiedLiteral(baseName));
+ });
});
// Make all fireworks glint
@@ -60,4 +68,9 @@ public class DefaultItemComponentTest implements ModInitializer {
});
});
}
+
+ public static Text prependModifiedLiteral(Text name) {
+ return Text.literal("Modified ")
+ .append(name);
+ }
}
diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/CustomEnchantmentEffectsGameTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/CustomEnchantmentEffectsGameTest.java
new file mode 100644
index 000000000..f2dd926ef
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/CustomEnchantmentEffectsGameTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.test.item.gametest;
+
+import java.util.List;
+import java.util.Optional;
+
+import net.minecraft.component.EnchantmentEffectComponentTypes;
+import net.minecraft.enchantment.Enchantment;
+import net.minecraft.enchantment.effect.EnchantmentEffectEntry;
+import net.minecraft.enchantment.effect.EnchantmentValueEffect;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityType;
+import net.minecraft.entity.mob.CreeperEntity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.registry.DynamicRegistryManager;
+import net.minecraft.registry.Registry;
+import net.minecraft.registry.RegistryKeys;
+import net.minecraft.registry.entry.RegistryEntry;
+import net.minecraft.test.GameTest;
+import net.minecraft.test.GameTestException;
+import net.minecraft.test.TestContext;
+import net.minecraft.util.Hand;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.GameMode;
+
+import net.fabricmc.fabric.api.gametest.v1.FabricGameTest;
+import net.fabricmc.fabric.test.item.CustomEnchantmentEffectsTest;
+
+public class CustomEnchantmentEffectsGameTest implements FabricGameTest {
+ @GameTest(templateName = "fabric-item-api-v1-testmod:bedrock_platform")
+ public void weirdImpalingSetsFireToTargets(TestContext context) {
+ BlockPos pos = new BlockPos(3, 3, 3);
+ CreeperEntity creeper = context.spawnEntity(EntityType.CREEPER, pos);
+ PlayerEntity player = context.createMockPlayer(GameMode.CREATIVE);
+
+ ItemStack trident = Items.TRIDENT.getDefaultStack();
+ Optional> impaling = getEnchantmentRegistry(context)
+ .getEntry(CustomEnchantmentEffectsTest.WEIRD_IMPALING);
+ if (impaling.isEmpty()) {
+ throw new GameTestException("Weird Impaling enchantment is not present");
+ }
+
+ trident.addEnchantment(impaling.get(), 1);
+
+ player.setStackInHand(Hand.MAIN_HAND, trident);
+
+ context.expectEntityWithData(pos, EntityType.CREEPER, Entity::isOnFire, false);
+ player.attack(creeper);
+ context.expectEntityWithDataEnd(pos, EntityType.CREEPER, Entity::isOnFire, true);
+ }
+
+ @GameTest(templateName = EMPTY_STRUCTURE)
+ public void weirdImpalingHasTwoDamageEffects(TestContext context) {
+ Enchantment impaling = getEnchantmentRegistry(context).get(CustomEnchantmentEffectsTest.WEIRD_IMPALING);
+
+ if (impaling == null) {
+ throw new GameTestException("Weird Impaling enchantment is not present");
+ }
+
+ List> damageEffects = impaling
+ .getEffect(EnchantmentEffectComponentTypes.DAMAGE);
+
+ context.assertTrue(
+ damageEffects.size() == 2,
+ String.format("Weird Impaling has %d damage effect(s), not the expected 2", damageEffects.size())
+ );
+ context.complete();
+ }
+
+ private static Registry getEnchantmentRegistry(TestContext context) {
+ DynamicRegistryManager registryManager = context.getWorld().getRegistryManager();
+ return registryManager.get(RegistryKeys.ENCHANTMENT);
+ }
+}
diff --git a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/DefaultItemComponentGameTest.java b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/DefaultItemComponentGameTest.java
index f6856bad0..c467042dd 100644
--- a/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/DefaultItemComponentGameTest.java
+++ b/fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item/gametest/DefaultItemComponentGameTest.java
@@ -20,6 +20,7 @@ import java.util.function.Consumer;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.FireworksComponent;
+import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.test.GameTest;
@@ -28,6 +29,7 @@ import net.minecraft.test.TestContext;
import net.minecraft.text.Text;
import net.fabricmc.fabric.api.gametest.v1.FabricGameTest;
+import net.fabricmc.fabric.test.item.DefaultItemComponentTest;
public class DefaultItemComponentGameTest implements FabricGameTest {
@GameTest(templateName = EMPTY_STRUCTURE)
@@ -73,4 +75,20 @@ public class DefaultItemComponentGameTest implements FabricGameTest {
context.complete();
}
+
+ @GameTest(templateName = EMPTY_STRUCTURE)
+ public void diamondPickaxeIsRenamed(TestContext context) {
+ Item testItem = Items.DIAMOND_PICKAXE;
+ ItemStack stack = testItem.getDefaultStack();
+
+ Text itemName = stack.getOrDefault(DataComponentTypes.ITEM_NAME, Text.literal(""));
+ Text expectedName = DefaultItemComponentTest.prependModifiedLiteral(testItem.getName());
+
+ String errorMessage = "Expected '%s' to be contained in '%s', but it was not!";
+
+ // if they contain each other, then they are equal
+ context.assertTrue(itemName.contains(expectedName), errorMessage.formatted(expectedName, itemName));
+ context.assertTrue(expectedName.contains(itemName), errorMessage.formatted(itemName, expectedName));
+ context.complete();
+ }
}
diff --git a/fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/enchantment/weird_impaling.json b/fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/enchantment/weird_impaling.json
new file mode 100644
index 000000000..e091a2db8
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/enchantment/weird_impaling.json
@@ -0,0 +1,42 @@
+{
+ "description": {
+ "text": "Weird Impaling"
+ },
+ "exclusive_set": "#minecraft:exclusive_set/damage",
+ "supported_items": "#minecraft:enchantable/trident",
+ "weight": 2,
+ "max_level": 5,
+ "min_cost": {
+ "base": 1,
+ "per_level_above_first": 8
+ },
+ "max_cost": {
+ "base": 21,
+ "per_level_above_first": 8
+ },
+ "anvil_cost": 4,
+ "slots": [
+ "mainhand"
+ ],
+ "effects": {
+ "minecraft:damage": [
+ {
+ "effect": {
+ "type": "minecraft:add",
+ "value": {
+ "type": "minecraft:linear",
+ "base": 2.5,
+ "per_level_above_first": 2.5
+ }
+ },
+ "requirements": {
+ "condition": "minecraft:entity_properties",
+ "entity": "this",
+ "predicate": {
+ "type": "#minecraft:sensitive_to_impaling"
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/gametest/structure/bedrock_platform.snbt b/fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/gametest/structure/bedrock_platform.snbt
new file mode 100644
index 000000000..4bb24ae7e
--- /dev/null
+++ b/fabric-item-api-v1/src/testmod/resources/data/fabric-item-api-v1-testmod/gametest/structure/bedrock_platform.snbt
@@ -0,0 +1,136 @@
+{
+ DataVersion: 3955,
+ size: [5, 5, 5],
+ data: [
+ {pos: [0, 0, 0], state: "minecraft:bedrock"},
+ {pos: [0, 0, 1], state: "minecraft:bedrock"},
+ {pos: [0, 0, 2], state: "minecraft:bedrock"},
+ {pos: [0, 0, 3], state: "minecraft:bedrock"},
+ {pos: [0, 0, 4], state: "minecraft:bedrock"},
+ {pos: [1, 0, 0], state: "minecraft:bedrock"},
+ {pos: [1, 0, 1], state: "minecraft:bedrock"},
+ {pos: [1, 0, 2], state: "minecraft:bedrock"},
+ {pos: [1, 0, 3], state: "minecraft:bedrock"},
+ {pos: [1, 0, 4], state: "minecraft:bedrock"},
+ {pos: [2, 0, 0], state: "minecraft:bedrock"},
+ {pos: [2, 0, 1], state: "minecraft:bedrock"},
+ {pos: [2, 0, 2], state: "minecraft:bedrock"},
+ {pos: [2, 0, 3], state: "minecraft:bedrock"},
+ {pos: [2, 0, 4], state: "minecraft:bedrock"},
+ {pos: [3, 0, 0], state: "minecraft:bedrock"},
+ {pos: [3, 0, 1], state: "minecraft:bedrock"},
+ {pos: [3, 0, 2], state: "minecraft:bedrock"},
+ {pos: [3, 0, 3], state: "minecraft:bedrock"},
+ {pos: [3, 0, 4], state: "minecraft:bedrock"},
+ {pos: [4, 0, 0], state: "minecraft:bedrock"},
+ {pos: [4, 0, 1], state: "minecraft:bedrock"},
+ {pos: [4, 0, 2], state: "minecraft:bedrock"},
+ {pos: [4, 0, 3], state: "minecraft:bedrock"},
+ {pos: [4, 0, 4], state: "minecraft:bedrock"},
+ {pos: [0, 1, 0], state: "minecraft:air"},
+ {pos: [0, 1, 1], state: "minecraft:air"},
+ {pos: [0, 1, 2], state: "minecraft:air"},
+ {pos: [0, 1, 3], state: "minecraft:air"},
+ {pos: [0, 1, 4], state: "minecraft:air"},
+ {pos: [1, 1, 0], state: "minecraft:air"},
+ {pos: [1, 1, 1], state: "minecraft:air"},
+ {pos: [1, 1, 2], state: "minecraft:air"},
+ {pos: [1, 1, 3], state: "minecraft:air"},
+ {pos: [1, 1, 4], state: "minecraft:air"},
+ {pos: [2, 1, 0], state: "minecraft:air"},
+ {pos: [2, 1, 1], state: "minecraft:air"},
+ {pos: [2, 1, 2], state: "minecraft:air"},
+ {pos: [2, 1, 3], state: "minecraft:air"},
+ {pos: [2, 1, 4], state: "minecraft:air"},
+ {pos: [3, 1, 0], state: "minecraft:air"},
+ {pos: [3, 1, 1], state: "minecraft:air"},
+ {pos: [3, 1, 2], state: "minecraft:air"},
+ {pos: [3, 1, 3], state: "minecraft:air"},
+ {pos: [3, 1, 4], state: "minecraft:air"},
+ {pos: [4, 1, 0], state: "minecraft:air"},
+ {pos: [4, 1, 1], state: "minecraft:air"},
+ {pos: [4, 1, 2], state: "minecraft:air"},
+ {pos: [4, 1, 3], state: "minecraft:air"},
+ {pos: [4, 1, 4], state: "minecraft:air"},
+ {pos: [0, 2, 0], state: "minecraft:air"},
+ {pos: [0, 2, 1], state: "minecraft:air"},
+ {pos: [0, 2, 2], state: "minecraft:air"},
+ {pos: [0, 2, 3], state: "minecraft:air"},
+ {pos: [0, 2, 4], state: "minecraft:air"},
+ {pos: [1, 2, 0], state: "minecraft:air"},
+ {pos: [1, 2, 1], state: "minecraft:air"},
+ {pos: [1, 2, 2], state: "minecraft:air"},
+ {pos: [1, 2, 3], state: "minecraft:air"},
+ {pos: [1, 2, 4], state: "minecraft:air"},
+ {pos: [2, 2, 0], state: "minecraft:air"},
+ {pos: [2, 2, 1], state: "minecraft:air"},
+ {pos: [2, 2, 2], state: "minecraft:air"},
+ {pos: [2, 2, 3], state: "minecraft:air"},
+ {pos: [2, 2, 4], state: "minecraft:air"},
+ {pos: [3, 2, 0], state: "minecraft:air"},
+ {pos: [3, 2, 1], state: "minecraft:air"},
+ {pos: [3, 2, 2], state: "minecraft:air"},
+ {pos: [3, 2, 3], state: "minecraft:air"},
+ {pos: [3, 2, 4], state: "minecraft:air"},
+ {pos: [4, 2, 0], state: "minecraft:air"},
+ {pos: [4, 2, 1], state: "minecraft:air"},
+ {pos: [4, 2, 2], state: "minecraft:air"},
+ {pos: [4, 2, 3], state: "minecraft:air"},
+ {pos: [4, 2, 4], state: "minecraft:air"},
+ {pos: [0, 3, 0], state: "minecraft:air"},
+ {pos: [0, 3, 1], state: "minecraft:air"},
+ {pos: [0, 3, 2], state: "minecraft:air"},
+ {pos: [0, 3, 3], state: "minecraft:air"},
+ {pos: [0, 3, 4], state: "minecraft:air"},
+ {pos: [1, 3, 0], state: "minecraft:air"},
+ {pos: [1, 3, 1], state: "minecraft:air"},
+ {pos: [1, 3, 2], state: "minecraft:air"},
+ {pos: [1, 3, 3], state: "minecraft:air"},
+ {pos: [1, 3, 4], state: "minecraft:air"},
+ {pos: [2, 3, 0], state: "minecraft:air"},
+ {pos: [2, 3, 1], state: "minecraft:air"},
+ {pos: [2, 3, 2], state: "minecraft:air"},
+ {pos: [2, 3, 3], state: "minecraft:air"},
+ {pos: [2, 3, 4], state: "minecraft:air"},
+ {pos: [3, 3, 0], state: "minecraft:air"},
+ {pos: [3, 3, 1], state: "minecraft:air"},
+ {pos: [3, 3, 2], state: "minecraft:air"},
+ {pos: [3, 3, 3], state: "minecraft:air"},
+ {pos: [3, 3, 4], state: "minecraft:air"},
+ {pos: [4, 3, 0], state: "minecraft:air"},
+ {pos: [4, 3, 1], state: "minecraft:air"},
+ {pos: [4, 3, 2], state: "minecraft:air"},
+ {pos: [4, 3, 3], state: "minecraft:air"},
+ {pos: [4, 3, 4], state: "minecraft:air"},
+ {pos: [0, 4, 0], state: "minecraft:air"},
+ {pos: [0, 4, 1], state: "minecraft:air"},
+ {pos: [0, 4, 2], state: "minecraft:air"},
+ {pos: [0, 4, 3], state: "minecraft:air"},
+ {pos: [0, 4, 4], state: "minecraft:air"},
+ {pos: [1, 4, 0], state: "minecraft:air"},
+ {pos: [1, 4, 1], state: "minecraft:air"},
+ {pos: [1, 4, 2], state: "minecraft:air"},
+ {pos: [1, 4, 3], state: "minecraft:air"},
+ {pos: [1, 4, 4], state: "minecraft:air"},
+ {pos: [2, 4, 0], state: "minecraft:air"},
+ {pos: [2, 4, 1], state: "minecraft:air"},
+ {pos: [2, 4, 2], state: "minecraft:air"},
+ {pos: [2, 4, 3], state: "minecraft:air"},
+ {pos: [2, 4, 4], state: "minecraft:air"},
+ {pos: [3, 4, 0], state: "minecraft:air"},
+ {pos: [3, 4, 1], state: "minecraft:air"},
+ {pos: [3, 4, 2], state: "minecraft:air"},
+ {pos: [3, 4, 3], state: "minecraft:air"},
+ {pos: [3, 4, 4], state: "minecraft:air"},
+ {pos: [4, 4, 0], state: "minecraft:air"},
+ {pos: [4, 4, 1], state: "minecraft:air"},
+ {pos: [4, 4, 2], state: "minecraft:air"},
+ {pos: [4, 4, 3], state: "minecraft:air"},
+ {pos: [4, 4, 4], state: "minecraft:air"}
+ ],
+ entities: [],
+ palette: [
+ "minecraft:bedrock",
+ "minecraft:air"
+ ]
+}
diff --git a/fabric-item-api-v1/src/testmod/resources/fabric.mod.json b/fabric-item-api-v1/src/testmod/resources/fabric.mod.json
index e0c6ab03e..e56615d39 100644
--- a/fabric-item-api-v1/src/testmod/resources/fabric.mod.json
+++ b/fabric-item-api-v1/src/testmod/resources/fabric.mod.json
@@ -13,13 +13,15 @@
"net.fabricmc.fabric.test.item.CustomDamageTest",
"net.fabricmc.fabric.test.item.DefaultItemComponentTest",
"net.fabricmc.fabric.test.item.ItemUpdateAnimationTest",
- "net.fabricmc.fabric.test.item.ArmorKnockbackResistanceTest"
+ "net.fabricmc.fabric.test.item.ArmorKnockbackResistanceTest",
+ "net.fabricmc.fabric.test.item.CustomEnchantmentEffectsTest"
],
"client": [
"net.fabricmc.fabric.test.item.client.TooltipTests"
],
"fabric-gametest" : [
"net.fabricmc.fabric.test.item.gametest.BrewingStandGameTest",
+ "net.fabricmc.fabric.test.item.gametest.CustomEnchantmentEffectsGameTest",
"net.fabricmc.fabric.test.item.gametest.DefaultItemComponentGameTest",
"net.fabricmc.fabric.test.item.gametest.FurnaceGameTest",
"net.fabricmc.fabric.test.item.gametest.RecipeGameTest"