* In game

* More fixes

* Small fixes + changes

* Rename

* Fix test
This commit is contained in:
modmuss 2024-02-29 19:16:35 +00:00 committed by GitHub
parent c81ced1dbb
commit 1172e89799
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 441 additions and 709 deletions

View file

@ -18,6 +18,7 @@ package net.fabricmc.fabric.test.lookup.item;
import static net.fabricmc.fabric.test.lookup.FabricApiLookupTest.ensureException;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.item.ToolItem;
@ -41,7 +42,7 @@ public class FabricItemApiLookupTest {
// Diamonds and diamond blocks can be inspected and will also print their name.
INSPECTABLE.registerForItems((stack, ignored) -> () -> {
if (stack.hasCustomName()) {
if (stack.contains(DataComponentTypes.CUSTOM_NAME)) {
return stack.getName();
} else {
return Text.literal("Unnamed gem.");

View file

@ -44,16 +44,4 @@ public class LandPathNodeMakerMixin {
cir.setReturnValue(nodeType);
}
}
/**
* Overrides the node type for the specified position, if the position is found as neighbor block in a path.
*/
@Inject(method = "getNodeTypeFromNeighbors", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/entity/ai/pathing/LandPathNodeMaker;getCommonNodeType(Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/entity/ai/pathing/PathNodeType;"), cancellable = true)
private static void getNodeTypeFromNeighbors(BlockView world, BlockPos.Mutable pos, PathNodeType nodeType, CallbackInfoReturnable<PathNodeType> cir) {
PathNodeType neighborNodeType = LandPathNodeTypesRegistry.getPathNodeType(world.getBlockState(pos), world, pos, true);
if (neighborNodeType != null) {
cir.setReturnValue(neighborNodeType);
}
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.content.registry;
import com.llamalad7.mixinextras.sugar.Local;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.block.BlockState;
import net.minecraft.class_9316;
import net.minecraft.entity.ai.pathing.PathNodeType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.CollisionView;
import net.fabricmc.fabric.api.registry.LandPathNodeTypesRegistry;
@Mixin(class_9316.class)
public abstract class class_9316Mixin {
@Shadow
public abstract BlockState method_57623(BlockPos blockPos);
@Shadow
public abstract CollisionView method_57621();
/**
* Overrides the node type for the specified position, if the position is found as neighbor block in a path.
*/
@Inject(method = "method_57622", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/util/math/BlockPos$Mutable;set(III)Lnet/minecraft/util/math/BlockPos$Mutable;"), cancellable = true)
private void method_57622(int x, int y, int z, CallbackInfoReturnable<PathNodeType> cir, @Local BlockPos pos) {
final PathNodeType neighborNodeType = LandPathNodeTypesRegistry.getPathNodeType(method_57623(pos), method_57621(), pos, true);
if (neighborNodeType != null) {
cir.setReturnValue(neighborNodeType);
}
}
}

View file

@ -4,6 +4,7 @@
"compatibilityLevel": "JAVA_17",
"mixins": [
"AxeItemAccessor",
"class_9316Mixin",
"FarmerWorkTaskAccessor",
"GiveGiftsToHeroTaskAccessor",
"HoeItemAccessor",

View file

@ -50,7 +50,7 @@ public class AttachmentSerializingImpl {
Codec<Object> codec = (Codec<Object>) type.persistenceCodec();
if (codec != null) {
RegistryOps<NbtElement> registryOps = wrapperLookup.method_57093(NbtOps.INSTANCE);
RegistryOps<NbtElement> registryOps = wrapperLookup.getOps(NbtOps.INSTANCE);
codec.encodeStart(registryOps, entry.getValue())
.get()
.ifRight(partial -> {
@ -81,7 +81,7 @@ public class AttachmentSerializingImpl {
Codec<?> codec = type.persistenceCodec();
if (codec != null) {
RegistryOps<NbtElement> registryOps = wrapperLookup.method_57093(NbtOps.INSTANCE);
RegistryOps<NbtElement> registryOps = wrapperLookup.getOps(NbtOps.INSTANCE);
codec.parse(registryOps, compound.get(key))
.get()
.ifRight(partial -> {

View file

@ -253,7 +253,7 @@ public class CommonAttachmentTests {
private static DynamicRegistryManager mockDRM() {
DynamicRegistryManager drm = mock(DynamicRegistryManager.class);
when(drm.method_57093(any())).thenReturn((RegistryOps<Object>) (Object) RegistryOps.of(NbtOps.INSTANCE, drm));
when(drm.getOps(any())).thenReturn((RegistryOps<Object>) (Object) RegistryOps.of(NbtOps.INSTANCE, drm));
return drm;
}
}

View file

@ -65,7 +65,7 @@ public abstract class FabricAdvancementProvider implements DataProvider {
*
* <p>Use {@link Advancement.Builder#build(Consumer, String)} to help build advancements.
*/
public abstract void generateAdvancement(Consumer<AdvancementEntry> consumer);
public abstract void generateAdvancement(RegistryWrapper.WrapperLookup registryLookup, Consumer<AdvancementEntry> consumer);
/**
* Return a new exporter that applies the specified conditions to any advancement it receives.
@ -80,13 +80,13 @@ public abstract class FabricAdvancementProvider implements DataProvider {
@Override
public CompletableFuture<?> run(DataWriter writer) {
final Set<Identifier> identifiers = Sets.newHashSet();
final Set<AdvancementEntry> advancements = Sets.newHashSet();
generateAdvancement(advancements::add);
return this.registryLookup.thenCompose(lookup -> {
RegistryOps<JsonElement> ops = lookup.method_57093(JsonOps.INSTANCE);
final Set<Identifier> identifiers = Sets.newHashSet();
final Set<AdvancementEntry> advancements = Sets.newHashSet();
generateAdvancement(lookup, advancements::add);
RegistryOps<JsonElement> ops = lookup.getOps(JsonOps.INSTANCE);
final List<CompletableFuture<?>> futures = new ArrayList<>();
for (AdvancementEntry advancement : advancements) {

View file

@ -72,7 +72,7 @@ public abstract class FabricBlockLootTableProvider extends BlockLootTableGenerat
}
@Override
public void accept(BiConsumer<Identifier, LootTable.Builder> biConsumer) {
public void accept(RegistryWrapper.WrapperLookup registryLookup, BiConsumer<Identifier, LootTable.Builder> biConsumer) {
generate();
for (Map.Entry<Identifier, LootTable.Builder> entry : lootTables.entrySet()) {

View file

@ -59,7 +59,7 @@ public abstract class FabricCodecDataProvider<T> implements DataProvider {
public CompletableFuture<?> run(DataWriter writer) {
return this.registriesFuture.thenCompose(lookup -> {
Map<Identifier, JsonElement> entries = new HashMap<>();
RegistryOps<JsonElement> ops = lookup.method_57093(JsonOps.INSTANCE);
RegistryOps<JsonElement> ops = lookup.getOps(JsonOps.INSTANCE);
BiConsumer<Identifier, T> provider = (id, value) -> {
JsonElement json = this.convert(id, value, ops);

View file

@ -208,7 +208,7 @@ public abstract class FabricDynamicRegistryProvider implements DataProvider {
return entries;
})
.thenCompose(entries -> {
final RegistryOps<JsonElement> dynamicOps = registries.method_57093(JsonOps.INSTANCE);
final RegistryOps<JsonElement> dynamicOps = registries.getOps(JsonOps.INSTANCE);
ArrayList<CompletableFuture<?>> futures = new ArrayList<>();
for (RegistryEntries<?> registryEntries : entries.queuedEntries.values()) {

View file

@ -41,6 +41,7 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.stat.StatType;
import net.minecraft.text.TextContent;
@ -52,21 +53,23 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
/**
* Extend this class and implement {@link FabricLanguageProvider#generateTranslations(TranslationBuilder)}.
* Make sure to use {@link FabricLanguageProvider#FabricLanguageProvider(FabricDataOutput, String)} FabricLanguageProvider} to declare what language code is being generated if it isn't {@code en_us}.
* Make sure to use {@link FabricLanguageProvider#FabricLanguageProvider(FabricDataOutput, String, CompletableFuture)} FabricLanguageProvider} to declare what language code is being generated if it isn't {@code en_us}.
*
* <p>Register an instance of the class with {@link FabricDataGenerator.Pack#addProvider} in a {@link net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint}.
*/
public abstract class FabricLanguageProvider implements DataProvider {
protected final FabricDataOutput dataOutput;
private final String languageCode;
private final CompletableFuture<RegistryWrapper.WrapperLookup> registryLookup;
protected FabricLanguageProvider(FabricDataOutput dataOutput) {
this(dataOutput, "en_us");
protected FabricLanguageProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registryLookup) {
this(dataOutput, "en_us", registryLookup);
}
protected FabricLanguageProvider(FabricDataOutput dataOutput, String languageCode) {
protected FabricLanguageProvider(FabricDataOutput dataOutput, String languageCode, CompletableFuture<RegistryWrapper.WrapperLookup> registryLookup) {
this.dataOutput = dataOutput;
this.languageCode = languageCode;
this.registryLookup = registryLookup;
}
/**
@ -74,30 +77,32 @@ public abstract class FabricLanguageProvider implements DataProvider {
*
* <p>Call {@link TranslationBuilder#add(String, String)} to add a translation.
*/
public abstract void generateTranslations(TranslationBuilder translationBuilder);
public abstract void generateTranslations(RegistryWrapper.WrapperLookup registryLookup, TranslationBuilder translationBuilder);
@Override
public CompletableFuture<?> run(DataWriter writer) {
TreeMap<String, String> translationEntries = new TreeMap<>();
generateTranslations((String key, String value) -> {
Objects.requireNonNull(key);
Objects.requireNonNull(value);
return this.registryLookup.thenCompose(lookup -> {
generateTranslations(lookup, (String key, String value) -> {
Objects.requireNonNull(key);
Objects.requireNonNull(value);
if (translationEntries.containsKey(key)) {
throw new RuntimeException("Existing translation key found - " + key + " - Duplicate will be ignored.");
if (translationEntries.containsKey(key)) {
throw new RuntimeException("Existing translation key found - " + key + " - Duplicate will be ignored.");
}
translationEntries.put(key, value);
});
JsonObject langEntryJson = new JsonObject();
for (Map.Entry<String, String> entry : translationEntries.entrySet()) {
langEntryJson.addProperty(entry.getKey(), entry.getValue());
}
translationEntries.put(key, value);
return DataProvider.writeToPath(writer, langEntryJson, getLangFilePath(this.languageCode));
});
JsonObject langEntryJson = new JsonObject();
for (Map.Entry<String, String> entry : translationEntries.entrySet()) {
langEntryJson.addProperty(entry.getKey(), entry.getValue());
}
return DataProvider.writeToPath(writer, langEntryJson, getLangFilePath(this.languageCode));
}
private Path getLangFilePath(String code) {

View file

@ -99,7 +99,7 @@ public abstract class FabricRecipeProvider extends RecipeProvider {
throw new IllegalStateException("Duplicate recipe " + identifier);
}
RegistryOps<JsonElement> registryOps = wrapperLookup.method_57093(JsonOps.INSTANCE);
RegistryOps<JsonElement> registryOps = wrapperLookup.getOps(JsonOps.INSTANCE);
JsonObject recipeJson = Util.getResult(Recipe.CODEC.encodeStart(registryOps, recipe), IllegalStateException::new).getAsJsonObject();
ConditionJsonProvider[] conditions = FabricDataGenHelper.consumeConditions(recipe);
ConditionJsonProvider.write(recipeJson, conditions);

View file

@ -84,7 +84,7 @@ public abstract class FabricTagProvider<T> extends TagProvider<T> {
/**
* Implement this method and then use {@link FabricTagProvider#getOrCreateTagBuilder} to get and register new tag builders.
*/
protected abstract void configure(RegistryWrapper.WrapperLookup arg);
protected abstract void configure(RegistryWrapper.WrapperLookup wrapperLookup);
/**
* Override to enable adding objects to the tag builder directly.

View file

@ -58,17 +58,17 @@ public final class FabricLootTableProviderImpl {
HashMap<Identifier, LootTable> builders = Maps.newHashMap();
HashMap<Identifier, ConditionJsonProvider[]> conditionMap = new HashMap<>();
provider.accept((identifier, builder) -> {
ConditionJsonProvider[] conditions = FabricDataGenHelper.consumeConditions(builder);
conditionMap.put(identifier, conditions);
return registryLookup.thenApply(lookup -> {
provider.accept(lookup, (identifier, builder) -> {
ConditionJsonProvider[] conditions = FabricDataGenHelper.consumeConditions(builder);
conditionMap.put(identifier, conditions);
if (builders.put(identifier, builder.type(lootContextType).build()) != null) {
throw new IllegalStateException("Duplicate loot table " + identifier);
}
});
if (builders.put(identifier, builder.type(lootContextType).build()) != null) {
throw new IllegalStateException("Duplicate loot table " + identifier);
}
});
return registryLookup.thenCompose(lookup -> {
RegistryOps<JsonElement> ops = lookup.method_57093(JsonOps.INSTANCE);
RegistryOps<JsonElement> ops = lookup.getOps(JsonOps.INSTANCE);
final List<CompletableFuture<?>> futures = new ArrayList<>();
for (Map.Entry<Identifier, LootTable> entry : builders.entrySet()) {

View file

@ -308,6 +308,7 @@ transitive-accessible method net/minecraft/data/server/loottable/BlockLootTableG
transitive-accessible method net/minecraft/data/client/ItemModelGenerator register (Lnet/minecraft/item/Item;Lnet/minecraft/data/client/Model;)V
transitive-accessible method net/minecraft/data/client/ItemModelGenerator register (Lnet/minecraft/item/Item;Ljava/lang/String;Lnet/minecraft/data/client/Model;)V
transitive-accessible method net/minecraft/data/client/ItemModelGenerator register (Lnet/minecraft/item/Item;Lnet/minecraft/item/Item;Lnet/minecraft/data/client/Model;)V
transitive-accessible method net/minecraft/data/client/ItemModelGenerator registerWolfArmor (Lnet/minecraft/item/Item;)V
transitive-accessible method net/minecraft/data/client/ItemModelGenerator registerCompass (Lnet/minecraft/item/Item;)V
transitive-accessible method net/minecraft/data/client/ItemModelGenerator registerClock (Lnet/minecraft/item/Item;)V
transitive-accessible method net/minecraft/data/client/ItemModelGenerator uploadArmor (Lnet/minecraft/util/Identifier;Lnet/minecraft/util/Identifier;Lnet/minecraft/util/Identifier;)V
@ -322,6 +323,7 @@ transitive-extendable method net/minecraft/data/dev/NbtProvider getName ()Ljava/
transitive-extendable method net/minecraft/data/report/BlockListProvider getName ()Ljava/lang/String;
transitive-extendable method net/minecraft/data/report/CommandSyntaxProvider getName ()Ljava/lang/String;
transitive-extendable method net/minecraft/data/report/DynamicRegistriesProvider getName ()Ljava/lang/String;
transitive-extendable method net/minecraft/data/report/ItemListProvider getName ()Ljava/lang/String;
transitive-extendable method net/minecraft/data/report/RegistryDumpProvider getName ()Ljava/lang/String;
transitive-extendable method net/minecraft/data/server/BiomeParametersProvider getName ()Ljava/lang/String;
transitive-extendable method net/minecraft/data/server/advancement/AdvancementProvider getName ()Ljava/lang/String;

View file

@ -44,6 +44,8 @@ import net.minecraft.advancement.criterion.OnKilledCriterion;
import net.minecraft.block.Block;
import net.minecraft.block.BlockKeys;
import net.minecraft.block.Blocks;
import net.minecraft.component.ComponentChanges;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.data.DataOutput;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.data.client.ItemModelGenerator;
@ -193,7 +195,13 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(DefaultCustomIngredients.nbt(new ItemStack(Items.DIAMOND_PICKAXE), false))
.input(DefaultCustomIngredients.components(
Ingredient.ofItems(Items.DIAMOND_PICKAXE),
ComponentChanges.builder()
.add(DataComponentTypes.DAMAGE, 0)
.build()
)
)
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
@ -205,10 +213,10 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
// To test: try renaming an apple to "Golden Apple" in creative with an anvil.
// That should match the recipe and give a golden apple. Any other NBT should not match.
ItemStack appleWithGoldenName = new ItemStack(Items.APPLE);
appleWithGoldenName.setCustomName(Text.literal("Golden Apple"));
appleWithGoldenName.setRepairCost(0);
appleWithGoldenName.set(DataComponentTypes.CUSTOM_NAME, Text.literal("Golden Apple"));
appleWithGoldenName.set(DataComponentTypes.REPAIR_COST, 0);
ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.GOLDEN_APPLE)
.input(DefaultCustomIngredients.nbt(appleWithGoldenName, true))
.input(DefaultCustomIngredients.components(appleWithGoldenName))
.criterion("has_apple", conditionsFromItem(Items.APPLE))
.offerTo(exporter);
@ -242,12 +250,12 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
}
private static class ExistingEnglishLangProvider extends FabricLanguageProvider {
private ExistingEnglishLangProvider(FabricDataOutput output) {
super(output);
private ExistingEnglishLangProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@Override
public void generateTranslations(TranslationBuilder translationBuilder) {
public void generateTranslations(RegistryWrapper.WrapperLookup registryLookup, TranslationBuilder translationBuilder) {
translationBuilder.add(SIMPLE_BLOCK, "Simple Block");
translationBuilder.add(new Identifier(MOD_ID, "identifier_test"), "Identifier Test");
translationBuilder.add(EntityType.ALLAY, "Allay");
@ -274,12 +282,12 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
}
private static class JapaneseLangProvider extends FabricLanguageProvider {
private JapaneseLangProvider(FabricDataOutput output) {
super(output, "ja_jp");
private JapaneseLangProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, "ja_jp", registriesFuture);
}
@Override
public void generateTranslations(TranslationBuilder translationBuilder) {
public void generateTranslations(RegistryWrapper.WrapperLookup registryLookup, TranslationBuilder translationBuilder) {
translationBuilder.add(SIMPLE_BLOCK, "シンプルブロック");
translationBuilder.add(SIMPLE_ITEM_GROUP, "データ生成項目");
translationBuilder.add("this.is.a.test", "こんにちは");
@ -361,7 +369,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
}
@Override
public void generateAdvancement(Consumer<AdvancementEntry> consumer) {
public void generateAdvancement(RegistryWrapper.WrapperLookup registryLookup, Consumer<AdvancementEntry> consumer) {
AdvancementEntry root = Advancement.Builder.create()
.display(
SIMPLE_BLOCK,
@ -406,7 +414,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
}
@Override
public void accept(BiConsumer<Identifier, LootTable.Builder> consumer) {
public void accept(RegistryWrapper.WrapperLookup registryLookup, BiConsumer<Identifier, LootTable.Builder> consumer) {
withConditions(consumer, ALWAYS_LOADED).accept(
LootTables.PIGLIN_BARTERING_GAMEPLAY,
LootTable.builder().pool(

View file

@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.damage.DamageTypes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
@ -225,7 +226,7 @@ public final class EntityEventTests implements ModInitializer {
private static ItemStack createNamedItem(Item item, String name) {
ItemStack stack = new ItemStack(item);
stack.setCustomName(Text.literal(name));
stack.set(DataComponentTypes.CUSTOM_NAME, Text.literal(name));
return stack;
}
}

View file

@ -54,9 +54,10 @@ public abstract class TestFunctionsMixin {
gameTest.tickLimit(),
gameTest.duration(),
gameTest.required(),
gameTest.requiredSuccesses(),
gameTest.manualOnly(),
gameTest.maxAttempts(),
gameTest.method_57098(),
gameTest.requiredSuccesses(),
gameTest.skyAccess(),
FabricGameTestHelper.getTestMethodInvoker(method)
);

View file

@ -1,107 +0,0 @@
/*
* 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 net.minecraft.item.FoodComponent;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.resource.featuretoggle.FeatureFlag;
import net.minecraft.util.Rarity;
import net.fabricmc.fabric.impl.item.FabricItemInternals;
/**
* @deprecated replace with {@link Item.Settings}
*/
@Deprecated
public class FabricItemSettings extends Item.Settings {
/**
* Sets the equipment slot provider of the item.
*
* @param equipmentSlotProvider the equipment slot provider
* @return this builder
* @deprecated replace with {@link FabricItem.Settings#equipmentSlot(EquipmentSlotProvider)}
*/
@Deprecated
public FabricItemSettings equipmentSlot(EquipmentSlotProvider equipmentSlotProvider) {
FabricItemInternals.computeExtraData(this).equipmentSlot(equipmentSlotProvider);
return this;
}
/**
* Sets the custom damage handler of the item.
* Note that this is only called on an ItemStack if {@link ItemStack#isDamageable()} returns true.
*
* @deprecated replace with {@link FabricItem.Settings#customDamage(CustomDamageHandler)}
* @see CustomDamageHandler
*/
@Deprecated
public FabricItemSettings customDamage(CustomDamageHandler handler) {
FabricItemInternals.computeExtraData(this).customDamage(handler);
return this;
}
// Overrides of vanilla methods
@Override
public FabricItemSettings food(FoodComponent foodComponent) {
super.food(foodComponent);
return this;
}
@Override
public FabricItemSettings maxCount(int maxCount) {
super.maxCount(maxCount);
return this;
}
@Override
public FabricItemSettings maxDamageIfAbsent(int maxDamage) {
super.maxDamageIfAbsent(maxDamage);
return this;
}
@Override
public FabricItemSettings maxDamage(int maxDamage) {
super.maxDamage(maxDamage);
return this;
}
@Override
public FabricItemSettings recipeRemainder(Item recipeRemainder) {
super.recipeRemainder(recipeRemainder);
return this;
}
@Override
public FabricItemSettings rarity(Rarity rarity) {
super.rarity(rarity);
return this;
}
@Override
public FabricItemSettings fireproof() {
super.fireproof();
return this;
}
@Override
public FabricItemSettings requires(FeatureFlag... features) {
super.requires(features);
return this;
}
}

View file

@ -1,60 +0,0 @@
/*
* 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 com.google.common.collect.Multimap;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.entry.RegistryEntry;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
/**
* Stack-aware attribute modifier callback for foreign items.
* Instead of using Mixin to change attribute modifiers in items not in your mod,
* you can use this event instead, either checking the Item itself or using a tag.
* This event provides you with a guaranteed mutable map you can put attribute modifiers in.
* Do not use for your own Item classes; see {@link FabricItem#getAttributeModifiers} instead.
* For example, the following code modifies a Diamond Helmet to give you five extra hearts when wearing.
*
* <pre>
* {@code
* ModifyItemAttributeModifiersCallback.EVENT.register((stack, slot, attributeModifiers) -> {
* if (stack.isOf(Items.DIAMOND_HELMET) && slot.getEntitySlotId() == HEAD_SLOT_ID) {
* attributeModifiers.put(EntityAttributes.GENERIC_MAX_HEALTH, MODIFIER);
* }
* });
* }
* </pre>
*/
@FunctionalInterface
public interface ModifyItemAttributeModifiersCallback {
void modifyAttributeModifiers(ItemStack stack, EquipmentSlot slot, Multimap<RegistryEntry<EntityAttribute>, EntityAttributeModifier> attributeModifiers);
Event<ModifyItemAttributeModifiersCallback> EVENT = EventFactory.createArrayBacked(
ModifyItemAttributeModifiersCallback.class,
callbacks -> (stack, slot, attributeModifiers) -> {
for (ModifyItemAttributeModifiersCallback callback : callbacks) {
callback.modifyAttributeModifiers(stack, slot, attributeModifiers);
}
}
);
}

View file

@ -16,8 +16,6 @@
package net.fabricmc.fabric.mixin.item;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
@ -31,17 +29,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.block.BlockState;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.random.Random;
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
import net.fabricmc.fabric.api.item.v1.FabricItemStack;
import net.fabricmc.fabric.api.item.v1.ModifyItemAttributeModifiersCallback;
import net.fabricmc.fabric.impl.item.ItemExtensions;
@Mixin(ItemStack.class)
@ -67,21 +61,6 @@ public abstract class ItemStackMixin implements FabricItemStack {
original.call(instance, amount, random, serverPlayerEntity, runnable);
}
@Redirect(
method = "getAttributeModifiers",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/item/Item;getAttributeModifiers(Lnet/minecraft/entity/EquipmentSlot;)Lcom/google/common/collect/Multimap;"
)
)
public Multimap<RegistryEntry<EntityAttribute>, EntityAttributeModifier> hookGetAttributeModifiers(Item item, EquipmentSlot slot) {
ItemStack stack = (ItemStack) (Object) this;
//we need to ensure it is modifiable for the callback, use linked map to preserve ordering
Multimap<RegistryEntry<EntityAttribute>, EntityAttributeModifier> attributeModifiers = LinkedHashMultimap.create(item.getAttributeModifiers(stack, slot));
ModifyItemAttributeModifiersCallback.EVENT.invoker().modifyAttributeModifiers(stack, slot, attributeModifiers);
return attributeModifiers;
}
@Redirect(
method = "isSuitableFor",
at = @At(

View file

@ -16,17 +16,19 @@
package net.fabricmc.fabric.test.item;
import net.minecraft.component.DataComponentType;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.PickaxeItem;
import net.minecraft.item.ToolMaterials;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.potion.Potions;
import net.minecraft.recipe.Ingredient;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.dynamic.Codecs;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
@ -35,6 +37,8 @@ import net.fabricmc.fabric.api.registry.FuelRegistry;
public class CustomDamageTest implements ModInitializer {
public static final Item WEIRD_PICK = new WeirdPick();
public static final DataComponentType<Integer> WEIRD = Registry.register(Registries.DATA_COMPONENT_TYPE, new Identifier("fabric-item-api-v1-testmod", "weird"),
DataComponentType.<Integer>builder().codec(Codecs.NONNEGATIVE_INT).packetCodec(PacketCodecs.VAR_INT).build());
@Override
public void onInitialize() {
@ -48,20 +52,19 @@ public class CustomDamageTest implements ModInitializer {
if (entity.isSneaking()) {
return amount;
} else {
NbtCompound tag = stack.getOrCreateNbt();
tag.putInt("weird", tag.getInt("weird") + 1);
stack.set(WEIRD, stack.getOrDefault(WEIRD, 0) + 1);
return 0;
}
};
public static class WeirdPick extends PickaxeItem {
protected WeirdPick() {
super(ToolMaterials.GOLD, 1, -2.8F, new Item.Settings().customDamage(WEIRD_DAMAGE_HANDLER));
super(ToolMaterials.GOLD, new Item.Settings().customDamage(WEIRD_DAMAGE_HANDLER));
}
@Override
public Text getName(ItemStack stack) {
int v = stack.getOrCreateNbt().getInt("weird");
int v = stack.getOrDefault(WEIRD, 0);
return super.getName(stack).copy().append(" (Weird Value: " + v + ")");
}

View file

@ -1,65 +0,0 @@
/*
* 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 java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
public class FabricItemSettingsTests implements ModInitializer {
@Override
public void onInitialize() {
// Registers an item with a custom equipment slot.
Item testItem = new Item(new Item.Settings().equipmentSlot(stack -> EquipmentSlot.CHEST));
Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "test_item"), testItem);
final List<String> missingMethods = new ArrayList<>();
for (Method method : FabricItemSettings.class.getMethods()) {
if ((method.getModifiers() & Opcodes.ACC_SYNTHETIC) != 0) {
// Ignore synthetic bridge methods
continue;
}
if ((method.getModifiers() & Opcodes.ACC_STATIC) != 0) {
// Ignore static methods
continue;
}
if (method.getReturnType() == Item.Settings.class) {
missingMethods.add(method.getName());
}
}
if (missingMethods.isEmpty()) {
return;
}
throw new IllegalStateException("Missing method overrides in FabricItemSettings: " + String.join(", ", missingMethods));
}
}

View file

@ -16,13 +16,19 @@
package net.fabricmc.fabric.test.item;
import net.minecraft.component.DataComponentType;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import net.minecraft.util.dynamic.Codecs;
import net.fabricmc.api.ModInitializer;
public class ItemUpdateAnimationTest implements ModInitializer {
public static final DataComponentType<Integer> TICKS = Registry.register(Registries.DATA_COMPONENT_TYPE, new Identifier("fabric-item-api-v1-testmod", "ticks"),
DataComponentType.<Integer>builder().codec(Codecs.NONNEGATIVE_INT).packetCodec(PacketCodecs.VAR_INT).build());
@Override
public void onInitialize() {
Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "updating_allowed"), new UpdatingItem(true));

View file

@ -1,38 +0,0 @@
/*
* 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.entity.attribute.EntityAttributeModifier;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.item.Items;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.item.v1.ModifyItemAttributeModifiersCallback;
public class ModifyItemAttributeModifiersCallbackTest implements ModInitializer {
public static final int HEAD_SLOT_ID = 3;
public static final EntityAttributeModifier MODIFIER = new EntityAttributeModifier("generic_max_health_modifier", 5.0, EntityAttributeModifier.Operation.ADDITION);
@Override
public void onInitialize() {
ModifyItemAttributeModifiersCallback.EVENT.register((stack, slot, attributeModifiers) -> {
if (stack.isOf(Items.DIAMOND_HELMET) && slot.getEntitySlotId() == HEAD_SLOT_ID) {
attributeModifiers.put(EntityAttributes.GENERIC_MAX_HEALTH, MODIFIER);
}
});
}
}

View file

@ -28,7 +28,6 @@ import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
@ -47,8 +46,7 @@ public class UpdatingItem extends Item {
@Override
public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) {
if (!world.isClient) {
NbtCompound tag = stack.getOrCreateNbt();
tag.putLong("ticks", tag.getLong("ticks") + 1);
stack.set(ItemUpdateAnimationTest.TICKS, stack.getOrDefault(ItemUpdateAnimationTest.TICKS, 0) + 1);
}
}
@ -64,7 +62,7 @@ public class UpdatingItem extends Item {
// True for 15 seconds every 30 seconds
private boolean isEnabled(ItemStack stack) {
return !stack.hasNbt() || stack.getNbt().getLong("ticks") % 600 < 300;
return !stack.contains(ItemUpdateAnimationTest.TICKS) || stack.getOrDefault(ItemUpdateAnimationTest.TICKS, 0) % 600 < 300;
}
@Override

View file

@ -20,10 +20,13 @@ import java.util.Objects;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BrewingStandBlockEntity;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.PotionContentsComponent;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.potion.PotionUtil;
import net.minecraft.potion.Potion;
import net.minecraft.potion.Potions;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.test.GameTest;
import net.minecraft.test.TestContext;
import net.minecraft.util.math.BlockPos;
@ -43,13 +46,13 @@ public class BrewingStandGameTest implements FabricGameTest {
loadFuel(blockEntity, context);
prepareForBrewing(blockEntity, new ItemStack(Items.NETHER_WART, 8),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.WATER));
setPotion(new ItemStack(Items.POTION), Potions.WATER));
brew(blockEntity, context);
assertInventory(blockEntity, "Testing vanilla brewing.",
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
new ItemStack(Items.NETHER_WART, 7),
ItemStack.EMPTY);
@ -64,13 +67,13 @@ public class BrewingStandGameTest implements FabricGameTest {
loadFuel(blockEntity, context);
prepareForBrewing(blockEntity, new ItemStack(Items.DRAGON_BREATH),
PotionUtil.setPotion(new ItemStack(Items.SPLASH_POTION), Potions.AWKWARD));
setPotion(new ItemStack(Items.SPLASH_POTION), Potions.AWKWARD));
brew(blockEntity, context);
assertInventory(blockEntity, "Testing vanilla brewing recipe remainder.",
PotionUtil.setPotion(new ItemStack(Items.LINGERING_POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.LINGERING_POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.LINGERING_POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.LINGERING_POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.LINGERING_POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.LINGERING_POTION), Potions.AWKWARD),
ItemStack.EMPTY,
ItemStack.EMPTY);
@ -86,35 +89,35 @@ public class BrewingStandGameTest implements FabricGameTest {
loadFuel(blockEntity, context);
prepareForBrewing(blockEntity, new ItemStack(CustomDamageTest.WEIRD_PICK),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.WATER));
setPotion(new ItemStack(Items.POTION), Potions.WATER));
brew(blockEntity, context);
assertInventory(blockEntity, "Testing fabric brewing recipe remainder.",
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
RecipeGameTest.withDamage(new ItemStack(CustomDamageTest.WEIRD_PICK), 1),
ItemStack.EMPTY);
prepareForBrewing(blockEntity, RecipeGameTest.withDamage(new ItemStack(CustomDamageTest.WEIRD_PICK), 10),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.WATER));
setPotion(new ItemStack(Items.POTION), Potions.WATER));
brew(blockEntity, context);
assertInventory(blockEntity, "Testing fabric brewing recipe remainder.",
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
RecipeGameTest.withDamage(new ItemStack(CustomDamageTest.WEIRD_PICK), 11),
ItemStack.EMPTY);
prepareForBrewing(blockEntity, RecipeGameTest.withDamage(new ItemStack(CustomDamageTest.WEIRD_PICK), 31),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.WATER));
setPotion(new ItemStack(Items.POTION), Potions.WATER));
brew(blockEntity, context);
assertInventory(blockEntity, "Testing fabric brewing recipe remainder.",
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
setPotion(new ItemStack(Items.POTION), Potions.AWKWARD),
ItemStack.EMPTY,
ItemStack.EMPTY);
@ -147,4 +150,9 @@ public class BrewingStandGameTest implements FabricGameTest {
BrewingStandBlockEntity.tick(context.getWorld(), POS, context.getBlockState(POS), blockEntity);
}
}
private static ItemStack setPotion(ItemStack itemStack, RegistryEntry<Potion> potion) {
itemStack.set(DataComponentTypes.POTION_CONTENTS, new PotionContentsComponent(potion));
return itemStack;
}
}

View file

@ -18,6 +18,7 @@ package net.fabricmc.fabric.test.item.gametest;
import java.util.Objects;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.passive.WolfEntity;
import net.minecraft.entity.player.HungerManager;
@ -66,7 +67,7 @@ public final class FoodGameTest implements FabricGameTest {
hungerManager.setFoodLevel(0);
hungerManager.setSaturationLevel(0);
ItemStack foodStack = FoodGameInitializer.NAME.getDefaultStack();
foodStack.setCustomName(Text.literal("enchanted_golden_apple"));
foodStack.set(DataComponentTypes.CUSTOM_NAME, Text.literal("enchanted_golden_apple"));
player.eatFood(player.getWorld(), foodStack.copy());
FoodComponent fc = FoodComponents.ENCHANTED_GOLDEN_APPLE;
int foodActual = hungerManager.getFoodLevel();
@ -86,7 +87,7 @@ public final class FoodGameTest implements FabricGameTest {
wolf.setOwner(player);
wolf.setHealth(1f);
ItemStack meat = FoodGameInitializer.NAME.getDefaultStack();
meat.setCustomName(Text.of("mutton"));
meat.set(DataComponentTypes.CUSTOM_NAME, Text.literal("mutton"));
player.setStackInHand(Hand.MAIN_HAND, meat);
player.interact(wolf, Hand.MAIN_HAND);
float wolfHealth = wolf.getHealth();

View file

@ -16,8 +16,6 @@
package net.fabricmc.fabric.test.item.gametest;
import java.util.Objects;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
@ -129,8 +127,8 @@ public class RecipeGameTest implements FabricGameTest {
throw new GameTestException("Size doesnt match. " + extraErrorInfo);
}
if (!Objects.equals(currentStack.getNbt(), expectedStack.getNbt())) {
throw new GameTestException("Nbt doesnt match. " + extraErrorInfo);
if (!ItemStack.areItemsAndNbtEqual(currentStack, expectedStack)) {
throw new GameTestException("Stack doesnt match. " + extraErrorInfo);
}
}

View file

@ -9,7 +9,7 @@
}
],
"result": {
"item": "minecraft:diamond",
"id": "minecraft:diamond",
"count": 1
}
}

View file

@ -11,9 +11,7 @@
"entrypoints": {
"main": [
"net.fabricmc.fabric.test.item.CustomDamageTest",
"net.fabricmc.fabric.test.item.FabricItemSettingsTests",
"net.fabricmc.fabric.test.item.ItemUpdateAnimationTest",
"net.fabricmc.fabric.test.item.ModifyItemAttributeModifiersCallbackTest",
"net.fabricmc.fabric.test.item.ArmorKnockbackResistanceTest",
"net.fabricmc.fabric.test.item.FoodGameInitializer"
],

View file

@ -128,11 +128,11 @@ public final class NetworkingPlayPacketTest implements ModInitializer {
public static final PacketCodec<RegistryByteBuf, OverlayPacket> CODEC = CustomPayload.codecOf(OverlayPacket::write, OverlayPacket::new);
public OverlayPacket(RegistryByteBuf buf) {
this(TextCodecs.PACKET_CODEC.decode(buf));
this(TextCodecs.REGISTRY_PACKET_CODEC.decode(buf));
}
public void write(RegistryByteBuf buf) {
TextCodecs.PACKET_CODEC.encode(buf, this.message);
TextCodecs.REGISTRY_PACKET_CODEC.encode(buf, this.message);
}
@Override

View file

@ -59,7 +59,7 @@ final class ChannelScreen extends Screen {
@Override
public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) {
this.renderBackgroundTexture(drawContext);
this.renderBackground(drawContext, mouseX, mouseY, delta);
this.channelList.render(drawContext, mouseX, mouseY, delta);
super.render(drawContext, mouseX, mouseY, delta);

View file

@ -18,20 +18,19 @@ package net.fabricmc.fabric.mixin.object.builder;
import java.util.stream.Stream;
import com.llamalad7.mixinextras.sugar.Local;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import net.minecraft.class_9306;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.DefaultedRegistry;
import net.minecraft.util.math.random.Random;
import net.minecraft.village.TradeOffer;
import net.minecraft.village.TradeOffers;
import net.minecraft.village.VillagerDataContainer;
import net.minecraft.village.VillagerType;
@Mixin(TradeOffers.TypeAwareBuyForOneEmeraldFactory.class)
@ -50,9 +49,9 @@ public abstract class TradeOffersTypeAwareBuyForOneEmeraldFactoryMixin {
/**
* To prevent "item" -> "air" trades, if the result of a type aware trade is air, make sure no offer is created.
*/
@Inject(method = "create", at = @At(value = "NEW", target = "net/minecraft/village/TradeOffer"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
private void failOnNullItem(Entity entity, Random random, CallbackInfoReturnable<TradeOffer> cir, VillagerDataContainer villagerDataContainer, ItemStack buyingItem) {
if (buyingItem.isEmpty()) { // Will return true for an "empty" item stack that had null passed in the ctor
@Inject(method = "create", at = @At(value = "NEW", target = "net/minecraft/village/TradeOffer"), cancellable = true)
private void failOnNullItem(Entity entity, Random random, CallbackInfoReturnable<TradeOffer> cir, @Local() class_9306 buyingItem) {
if (buyingItem.itemStack().isEmpty()) { // Will return true for an "empty" item stack that had null passed in the ctor
cir.setReturnValue(null); // Return null to prevent creation of empty trades
}
}

View file

@ -21,8 +21,11 @@ import static net.minecraft.command.argument.EntityArgumentType.getEntity;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
import java.util.Optional;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import net.minecraft.class_9306;
import net.minecraft.entity.Entity;
import net.minecraft.entity.passive.WanderingTraderEntity;
import net.minecraft.item.Item;
@ -48,16 +51,16 @@ public class VillagerTypeTest1 implements ModInitializer {
public void onInitialize() {
TradeOfferHelper.registerVillagerOffers(VillagerProfession.ARMORER, 1, (factories, rebalanced) -> {
Item scrap = rebalanced ? Items.NETHER_BRICK : Items.NETHERITE_SCRAP;
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.GOLD_INGOT, 3), new ItemStack(scrap, 4), new ItemStack(Items.NETHERITE_INGOT), 2, 6, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.GOLD_INGOT, 3), Optional.of(new class_9306(scrap, 4)), new ItemStack(Items.NETHERITE_INGOT), 2, 6, 0.15F)));
});
// Toolsmith is not rebalanced yet
TradeOfferHelper.registerVillagerOffers(VillagerProfession.TOOLSMITH, 1, (factories, rebalanced) -> {
Item scrap = rebalanced ? Items.NETHER_BRICK : Items.NETHERITE_SCRAP;
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.GOLD_INGOT, 3), new ItemStack(scrap, 4), new ItemStack(Items.NETHERITE_INGOT), 2, 6, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.GOLD_INGOT, 3), Optional.of(new class_9306(scrap, 4)), new ItemStack(Items.NETHERITE_INGOT), 2, 6, 0.15F)));
});
TradeOfferHelper.registerWanderingTraderOffers(1, factories -> {
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.GOLD_INGOT, 3), new ItemStack(Items.NETHERITE_SCRAP, 4), new ItemStack(Items.NETHERITE_INGOT), 2, 6, 0.35F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.GOLD_INGOT, 3), Optional.of(new class_9306(Items.NETHERITE_SCRAP, 4)), new ItemStack(Items.NETHERITE_INGOT), 2, 6, 0.35F)));
});
TradeOfferHelper.registerRebalancedWanderingTraderOffers(builder -> {
@ -65,28 +68,28 @@ public class VillagerTypeTest1 implements ModInitializer {
FOOD_POOL_ID,
5,
Registries.ITEM.stream().filter(item -> item.getFoodComponent() != null).map(
item -> new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.NETHERITE_INGOT), new ItemStack(item), 3, 4, 0.15F))
item -> new SimpleTradeFactory(new TradeOffer(new class_9306(Items.NETHERITE_INGOT), new ItemStack(item), 3, 4, 0.15F))
).toList()
);
builder.addAll(
THING_POOL_ID,
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.NETHERITE_INGOT), new ItemStack(Items.MOJANG_BANNER_PATTERN), 1, 4, 0.15F))
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.NETHERITE_INGOT), new ItemStack(Items.MOJANG_BANNER_PATTERN), 1, 4, 0.15F))
);
builder.addOffersToPool(
TradeOfferHelper.WanderingTraderOffersBuilder.BUY_ITEMS_POOL,
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.BLAZE_POWDER, 1), new ItemStack(Items.EMERALD, 4), 3, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.NETHER_WART, 5), new ItemStack(Items.EMERALD, 1), 3, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.GOLDEN_CARROT, 4), new ItemStack(Items.EMERALD, 1), 3, 4, 0.15F))
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.BLAZE_POWDER, 1), new ItemStack(Items.EMERALD, 4), 3, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.NETHER_WART, 5), new ItemStack(Items.EMERALD, 1), 3, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.GOLDEN_CARROT, 4), new ItemStack(Items.EMERALD, 1), 3, 4, 0.15F))
);
builder.addOffersToPool(
TradeOfferHelper.WanderingTraderOffersBuilder.SELL_SPECIAL_ITEMS_POOL,
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.EMERALD, 6), new ItemStack(Items.BRUSH, 1), 1, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.DIAMOND, 16), new ItemStack(Items.ELYTRA, 1), 1, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.EMERALD, 3), new ItemStack(Items.LEAD, 2), 3, 4, 0.15F))
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.EMERALD, 6), new ItemStack(Items.BRUSH, 1), 1, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.DIAMOND, 16), new ItemStack(Items.ELYTRA, 1), 1, 4, 0.15F)),
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.EMERALD, 3), new ItemStack(Items.LEAD, 2), 3, 4, 0.15F))
);
builder.addOffersToPool(
FOOD_POOL_ID,
new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.NETHERITE_INGOT), new ItemStack(Items.EGG), 3, 4, 0.15F))
new SimpleTradeFactory(new TradeOffer(new class_9306(Items.NETHERITE_INGOT), new ItemStack(Items.EGG), 3, 4, 0.15F))
);
});

View file

@ -16,6 +16,7 @@
package net.fabricmc.fabric.test.object.builder;
import net.minecraft.class_9306;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.village.TradeOffer;
@ -31,22 +32,22 @@ public class VillagerTypeTest2 implements ModInitializer {
@Override
public void onInitialize() {
TradeOfferHelper.registerVillagerOffers(VillagerProfession.WEAPONSMITH, 1, factories -> {
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.DIAMOND, 5), new ItemStack(Items.NETHERITE_INGOT), 3, 4, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.DIAMOND, 5), new ItemStack(Items.NETHERITE_INGOT), 3, 4, 0.15F)));
});
TradeOfferHelper.registerVillagerOffers(VillagerProfession.ARMORER, 1, factories -> {
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.DIAMOND, 6), new ItemStack(Items.ELYTRA), 3, 4, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.DIAMOND, 6), new ItemStack(Items.ELYTRA), 3, 4, 0.15F)));
});
TradeOfferHelper.registerVillagerOffers(VillagerProfession.ARMORER, 1, factories -> {
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.DIAMOND, 7), new ItemStack(Items.CHAINMAIL_BOOTS), 3, 4, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.DIAMOND, 7), new ItemStack(Items.CHAINMAIL_BOOTS), 3, 4, 0.15F)));
});
TradeOfferHelper.registerVillagerOffers(VillagerProfession.ARMORER, 1, factories -> {
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.DIAMOND, 8), new ItemStack(Items.CHAINMAIL_CHESTPLATE), 3, 4, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.DIAMOND, 8), new ItemStack(Items.CHAINMAIL_CHESTPLATE), 3, 4, 0.15F)));
});
TradeOfferHelper.registerVillagerOffers(VillagerProfession.ARMORER, 1, factories -> {
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.DIAMOND, 9), new ItemStack(Items.CHAINMAIL_HELMET), 3, 4, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.DIAMOND, 9), new ItemStack(Items.CHAINMAIL_HELMET), 3, 4, 0.15F)));
});
TradeOfferHelper.registerVillagerOffers(VillagerProfession.ARMORER, 1, factories -> {
factories.add(new SimpleTradeFactory(new TradeOffer(new ItemStack(Items.DIAMOND, 10), new ItemStack(Items.CHAINMAIL_LEGGINGS), 3, 4, 0.15F)));
factories.add(new SimpleTradeFactory(new TradeOffer(new class_9306(Items.DIAMOND, 10), new ItemStack(Items.CHAINMAIL_LEGGINGS), 3, 4, 0.15F)));
});
}
}

View file

@ -18,18 +18,16 @@ package net.fabricmc.fabric.api.recipe.v1.ingredient;
import java.util.List;
import java.util.Objects;
import java.util.function.UnaryOperator;
import org.jetbrains.annotations.Nullable;
import net.minecraft.component.ComponentChanges;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.recipe.Ingredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.AllIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.AnyIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.ComponentsIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.DifferenceIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.NbtIngredient;
/**
* Factory methods for the custom ingredients directly provided by Fabric API.
@ -101,42 +99,38 @@ public final class DefaultCustomIngredients {
}
/**
* Creates an ingredient that wraps another ingredient to also check for stack NBT.
* This check can either be strict (the exact NBT must match) or non-strict aka. partial (the ingredient NBT must be a subset of the stack NBT).
* Creates an ingredient that wraps another ingredient to also check for matching components.
*
* <p>In strict mode, passing a {@code null} {@code nbt} is allowed, and will only match stacks with {@code null} NBT.
* In partial mode, passing a {@code null} {@code nbt} is <strong>not</strong> allowed, as it would always match.
* <p>Use {@link ComponentChanges#builder()} to add or remove components.
* Added components are checked to match on the target stack.
* Removed components are checked to not exist in the target stack
*
* <p>See {@link NbtHelper#matches} for the non-strict matching.
*
* <p>The JSON format is as follows:
* <pre>{@code
* {
* "fabric:type": "fabric:nbt",
* "base": // base ingredient,
* "nbt": // NBT tag to match, either in JSON directly or a string representation (default: null),
* "strict": // whether to use strict matching (default: false)
* }
* }</pre>
*
* @throws IllegalArgumentException if {@code strict} is {@code false} and the NBT is {@code null}
* @throws IllegalArgumentException if {@link ComponentChanges#isEmpty} is true
*/
public static Ingredient nbt(Ingredient base, @Nullable NbtCompound nbt, boolean strict) {
public static Ingredient components(Ingredient base, ComponentChanges components) {
Objects.requireNonNull(base, "Base ingredient cannot be null");
Objects.requireNonNull(components, "Component changes cannot be null");
return new NbtIngredient(base, nbt, strict).toVanilla();
return new ComponentsIngredient(base, components).toVanilla();
}
/**
* Creates an ingredient that matches the passed template stack, including NBT.
* @see #components(Ingredient, ComponentChanges)
*/
public static Ingredient components(Ingredient base, UnaryOperator<ComponentChanges.Builder> operator) {
return components(base, operator.apply(ComponentChanges.builder()).build());
}
/**
* Creates an ingredient that matches the passed template stack, including {@link ItemStack#getComponentChanges()}.
* Note that the count of the stack is ignored.
*
* @see #nbt(Ingredient, NbtCompound, boolean)
* @see #components(Ingredient, ComponentChanges)
*/
public static Ingredient nbt(ItemStack stack, boolean strict) {
public static Ingredient components(ItemStack stack) {
Objects.requireNonNull(stack, "Stack cannot be null");
return nbt(Ingredient.ofItems(stack.getItem()), stack.getNbt(), strict);
return components(Ingredient.ofItems(stack.getItem()), stack.getComponentChanges());
}
private DefaultCustomIngredients() {

View file

@ -20,8 +20,8 @@ import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.AllIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.AnyIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.ComponentsIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.DifferenceIngredient;
import net.fabricmc.fabric.impl.recipe.ingredient.builtin.NbtIngredient;
/**
* Register builtin custom ingredients.
@ -32,6 +32,6 @@ public class CustomIngredientInit implements ModInitializer {
CustomIngredientSerializer.register(AllIngredient.SERIALIZER);
CustomIngredientSerializer.register(AnyIngredient.SERIALIZER);
CustomIngredientSerializer.register(DifferenceIngredient.SERIALIZER);
CustomIngredientSerializer.register(NbtIngredient.SERIALIZER);
CustomIngredientSerializer.register(ComponentsIngredient.SERIALIZER);
}
}

View file

@ -0,0 +1,151 @@
/*
* 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.recipe.ingredient.builtin;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.jetbrains.annotations.Nullable;
import net.minecraft.component.ComponentChanges;
import net.minecraft.component.DataComponentType;
import net.minecraft.item.ItemStack;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.recipe.Ingredient;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredient;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer;
public class ComponentsIngredient implements CustomIngredient {
public static final CustomIngredientSerializer<ComponentsIngredient> SERIALIZER = new Serializer();
private final Ingredient base;
private final ComponentChanges components;
public ComponentsIngredient(Ingredient base, ComponentChanges components) {
if (components.isEmpty()) {
throw new IllegalArgumentException("ComponentIngredient must have at least one defined component");
}
this.base = base;
this.components = components;
}
@Override
public boolean test(ItemStack stack) {
if (!base.test(stack)) return false;
// None strict matching
for (Map.Entry<DataComponentType<?>, Optional<?>> entry : components.entrySet()) {
final DataComponentType<?> type = entry.getKey();
final Optional<?> value = entry.getValue();
if (value.isPresent()) {
// Expect the stack to contain a matching component
if (!stack.contains(type)) {
return false;
}
if (!Objects.equals(value.get(), stack.get(type))) {
return false;
}
} else {
// Expect the target stack to not contain this component
if (stack.contains(type)) {
return false;
}
}
}
return true;
}
@Override
public List<ItemStack> getMatchingStacks() {
List<ItemStack> stacks = new ArrayList<>(List.of(base.getMatchingStacks()));
stacks.replaceAll(stack -> {
ItemStack copy = stack.copy();
stack.applyChanges(components);
return copy;
});
stacks.removeIf(stack -> !base.test(stack));
return stacks;
}
@Override
public boolean requiresTesting() {
return true;
}
@Override
public CustomIngredientSerializer<?> getSerializer() {
return SERIALIZER;
}
private Ingredient getBase() {
return base;
}
@Nullable
private ComponentChanges getComponents() {
return components;
}
private static class Serializer implements CustomIngredientSerializer<ComponentsIngredient> {
private static final Identifier ID = new Identifier("fabric", "components");
private static final Codec<ComponentsIngredient> ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC);
private static final Codec<ComponentsIngredient> DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC);
private static final PacketCodec<RegistryByteBuf, ComponentsIngredient> PACKET_CODEC = PacketCodec.tuple(
Ingredient.PACKET_CODEC, ComponentsIngredient::getBase,
ComponentChanges.PACKET_CODEC, ComponentsIngredient::getComponents,
ComponentsIngredient::new
);
private static Codec<ComponentsIngredient> createCodec(Codec<Ingredient> ingredientCodec) {
return RecordCodecBuilder.create(instance ->
instance.group(
ingredientCodec.fieldOf("base").forGetter(ComponentsIngredient::getBase),
ComponentChanges.CODEC.fieldOf("components").forGetter(ComponentsIngredient::getComponents)
).apply(instance, ComponentsIngredient::new)
);
}
@Override
public Identifier getIdentifier() {
return ID;
}
@Override
public Codec<ComponentsIngredient> getCodec(boolean allowEmpty) {
return allowEmpty ? ALLOW_EMPTY_CODEC : DISALLOW_EMPTY_CODEC;
}
@Override
public PacketCodec<RegistryByteBuf, ComponentsIngredient> getPacketCodec() {
return PACKET_CODEC;
}
}
}

View file

@ -1,184 +0,0 @@
/*
* 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.recipe.ingredient.builtin;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.jetbrains.annotations.Nullable;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.nbt.NbtSizeTracker;
import net.minecraft.nbt.StringNbtReader;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.recipe.Ingredient;
import net.minecraft.util.Identifier;
import net.minecraft.util.dynamic.Codecs;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredient;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer;
public class NbtIngredient implements CustomIngredient {
public static final CustomIngredientSerializer<NbtIngredient> SERIALIZER = new Serializer();
private final Ingredient base;
@Nullable
private final NbtCompound nbt;
private final boolean strict;
public NbtIngredient(Ingredient base, @Nullable NbtCompound nbt, boolean strict) {
if (nbt == null && !strict) {
throw new IllegalArgumentException("NbtIngredient can only have null NBT in strict mode");
}
this.base = base;
this.nbt = nbt;
this.strict = strict;
}
@Override
public boolean test(ItemStack stack) {
if (!base.test(stack)) return false;
if (strict) {
return Objects.equals(nbt, stack.getNbt());
} else {
return NbtHelper.matches(nbt, stack.getNbt(), true);
}
}
@Override
public List<ItemStack> getMatchingStacks() {
List<ItemStack> stacks = new ArrayList<>(List.of(base.getMatchingStacks()));
stacks.replaceAll(stack -> {
ItemStack copy = stack.copy();
if (nbt != null) {
copy.setNbt(nbt.copy());
}
return copy;
});
stacks.removeIf(stack -> !base.test(stack));
return stacks;
}
@Override
public boolean requiresTesting() {
return true;
}
@Override
public CustomIngredientSerializer<?> getSerializer() {
return SERIALIZER;
}
private Ingredient getBase() {
return base;
}
@Nullable
private NbtCompound getNbt() {
return nbt;
}
private boolean isStrict() {
return strict;
}
private static class Serializer implements CustomIngredientSerializer<NbtIngredient> {
private static final Identifier ID = new Identifier("fabric", "nbt");
// Supports decoding the NBT as a string as well as the object.
private static final Codec<NbtCompound> NBT_CODEC = Codecs.xor(
Codec.STRING, NbtCompound.CODEC
).flatXmap(either -> either.map(s -> {
try {
return DataResult.success(StringNbtReader.parse(s));
} catch (CommandSyntaxException e) {
return DataResult.error(e::getMessage);
}
}, DataResult::success), nbtCompound -> DataResult.success(Either.left(nbtCompound.asString())));
private static final Codec<NbtIngredient> ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC);
private static final Codec<NbtIngredient> DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC);
private static final PacketCodec<RegistryByteBuf, NbtCompound> NULLABLE_NBT_PACKET_CODEC = new PacketCodec<>() {
private static final NbtSizeTracker SIZE_TRACKER = NbtSizeTracker.of(PacketByteBuf.MAX_READ_NBT_SIZE);
@Override
@Nullable
public NbtCompound decode(RegistryByteBuf buf) {
if (buf.readBoolean() && buf.readNbt(SIZE_TRACKER) instanceof NbtCompound nbt) {
return nbt;
}
return null;
}
@Override
public void encode(RegistryByteBuf buf, @Nullable NbtCompound value) {
if (value == null) {
buf.writeBoolean(false);
} else {
buf.writeBoolean(true);
buf.writeNbt(value);
}
}
};
private static final PacketCodec<RegistryByteBuf, NbtIngredient> PACKET_CODEC = PacketCodec.tuple(
Ingredient.PACKET_CODEC, NbtIngredient::getBase,
NULLABLE_NBT_PACKET_CODEC, NbtIngredient::getNbt,
PacketCodecs.BOOL, NbtIngredient::isStrict,
NbtIngredient::new
);
private static Codec<NbtIngredient> createCodec(Codec<Ingredient> ingredientCodec) {
return RecordCodecBuilder.create(instance ->
instance.group(
ingredientCodec.fieldOf("base").forGetter(NbtIngredient::getBase),
NBT_CODEC.optionalFieldOf("nbt", null).forGetter(NbtIngredient::getNbt),
Codec.BOOL.optionalFieldOf("strict", false).forGetter(NbtIngredient::isStrict)
).apply(instance, NbtIngredient::new)
);
}
@Override
public Identifier getIdentifier() {
return ID;
}
@Override
public Codec<NbtIngredient> getCodec(boolean allowEmpty) {
return allowEmpty ? ALLOW_EMPTY_CODEC : DISALLOW_EMPTY_CODEC;
}
@Override
public PacketCodec<RegistryByteBuf, NbtIngredient> getPacketCodec() {
return PACKET_CODEC;
}
}
}

View file

@ -16,12 +16,12 @@
package net.fabricmc.fabric.test.recipe.ingredient;
import java.util.List;
import java.util.Objects;
import net.minecraft.component.ComponentChanges;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.recipe.Ingredient;
import net.minecraft.test.GameTest;
import net.minecraft.test.GameTestException;
@ -89,50 +89,42 @@ public class IngredientMatchTests {
}
@GameTest(templateName = FabricGameTest.EMPTY_STRUCTURE)
public void testNbtIngredient(TestContext context) {
for (boolean strict : List.of(true, false)) {
NbtCompound undamagedNbt = new NbtCompound();
undamagedNbt.putInt(ItemStack.DAMAGE_KEY, 0);
public void testComponentIngredient(TestContext context) {
final Ingredient baseIngredient = Ingredient.ofItems(Items.DIAMOND_PICKAXE, Items.NETHERITE_PICKAXE);
final Ingredient undamagedIngredient = DefaultCustomIngredients.components(
baseIngredient,
builder -> builder.add(DataComponentTypes.DAMAGE, 0)
);
final Ingredient noNameUndamagedIngredient = DefaultCustomIngredients.components(
baseIngredient,
builder -> builder
.add(DataComponentTypes.DAMAGE, 0)
.remove(DataComponentTypes.CUSTOM_NAME)
);
Ingredient nbtIngredient = DefaultCustomIngredients.nbt(Ingredient.ofItems(Items.DIAMOND_PICKAXE, Items.NETHERITE_PICKAXE), undamagedNbt, strict);
ItemStack renamedUndamagedDiamondPickaxe = new ItemStack(Items.DIAMOND_PICKAXE);
renamedUndamagedDiamondPickaxe.set(DataComponentTypes.CUSTOM_NAME, Text.literal("Renamed"));
assertEquals(true, undamagedIngredient.test(renamedUndamagedDiamondPickaxe));
assertEquals(false, noNameUndamagedIngredient.test(renamedUndamagedDiamondPickaxe));
assertEquals(2, nbtIngredient.getMatchingStacks().length);
assertEquals(Items.DIAMOND_PICKAXE, nbtIngredient.getMatchingStacks()[0].getItem());
assertEquals(Items.NETHERITE_PICKAXE, nbtIngredient.getMatchingStacks()[1].getItem());
assertEquals(undamagedNbt, nbtIngredient.getMatchingStacks()[0].getNbt());
assertEquals(undamagedNbt, nbtIngredient.getMatchingStacks()[1].getNbt());
assertEquals(false, nbtIngredient.isEmpty());
assertEquals(2, undamagedIngredient.getMatchingStacks().length);
ItemStack result0 = undamagedIngredient.getMatchingStacks()[0];
ItemStack result1 = undamagedIngredient.getMatchingStacks()[1];
// Undamaged is fine
assertEquals(true, nbtIngredient.test(new ItemStack(Items.DIAMOND_PICKAXE)));
assertEquals(true, nbtIngredient.test(new ItemStack(Items.NETHERITE_PICKAXE)));
assertEquals(Items.DIAMOND_PICKAXE, result0.getItem());
assertEquals(Items.NETHERITE_PICKAXE, result1.getItem());
assertEquals(ComponentChanges.EMPTY, result0.getComponentChanges());
assertEquals(ComponentChanges.EMPTY, result1.getComponentChanges());
assertEquals(false, undamagedIngredient.isEmpty());
// Damaged is not fine
ItemStack damagedDiamondPickaxe = new ItemStack(Items.DIAMOND_PICKAXE);
damagedDiamondPickaxe.setDamage(10);
assertEquals(false, nbtIngredient.test(damagedDiamondPickaxe));
// Undamaged is fine
assertEquals(true, undamagedIngredient.test(new ItemStack(Items.DIAMOND_PICKAXE)));
assertEquals(true, undamagedIngredient.test(new ItemStack(Items.NETHERITE_PICKAXE)));
// Renamed undamaged is only fine in partial matching
ItemStack renamedUndamagedDiamondPickaxe = new ItemStack(Items.DIAMOND_PICKAXE);
renamedUndamagedDiamondPickaxe.setCustomName(Text.literal("Renamed"));
assertEquals(!strict, nbtIngredient.test(renamedUndamagedDiamondPickaxe));
}
// Also test strict null NBT matching
Ingredient noNbtIngredient = DefaultCustomIngredients.nbt(Ingredient.ofItems(Items.APPLE), null, true);
assertEquals(1, noNbtIngredient.getMatchingStacks().length);
assertEquals(Items.APPLE, noNbtIngredient.getMatchingStacks()[0].getItem());
assertEquals(null, noNbtIngredient.getMatchingStacks()[0].getNbt());
assertEquals(false, noNbtIngredient.isEmpty());
// No NBT is fine
assertEquals(true, noNbtIngredient.test(new ItemStack(Items.APPLE)));
// NBT is not fine
ItemStack nbtApple = new ItemStack(Items.APPLE);
nbtApple.setCustomName(Text.literal("Renamed"));
assertEquals(false, noNbtIngredient.test(nbtApple));
// Damaged is not fine
ItemStack damagedDiamondPickaxe = new ItemStack(Items.DIAMOND_PICKAXE);
damagedDiamondPickaxe.setDamage(10);
assertEquals(false, undamagedIngredient.test(damagedDiamondPickaxe));
context.complete();
}

View file

@ -14,11 +14,13 @@
"item": "minecraft:diamond_pickaxe"
},
{
"fabric:type": "fabric:nbt",
"fabric:type": "fabric:components",
"base": {
"item": "minecraft:diamond_pickaxe"
},
"nbt": "{Damage:0}",
"components": {
"minecraft:damage": 0
},
"strict": false
},
{
@ -35,6 +37,6 @@
}
],
"result": {
"item": "minecraft:diamond_block"
"id": "minecraft:diamond_block"
}
}

View file

@ -30,6 +30,7 @@ import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.math.BlockPos;
@ -95,7 +96,7 @@ public class FrameBakedModel implements BakedModel {
this.frameMesh.outputTo(context.getEmitter());
// Emit a scaled-down fence for testing, trying both materials again.
RenderMaterial material = stack.hasCustomName() ? translucentEmissiveMaterial : translucentMaterial;
RenderMaterial material = stack.contains(DataComponentTypes.CUSTOM_NAME) ? translucentEmissiveMaterial : translucentMaterial;
ItemStack innerItem = Items.CRAFTING_TABLE.getDefaultStack();
BakedModel innerModel = MinecraftClient.getInstance().getItemRenderer().getModel(innerItem, null, null, 0);

View file

@ -6,7 +6,7 @@
}
],
"result": {
"item": "minecraft:diamond"
"id": "minecraft:diamond"
},
"fabric:load_conditions": [
{

View file

@ -6,7 +6,7 @@
}
],
"result": {
"item": "minecraft:diamond"
"id": "minecraft:diamond"
},
"fabric:load_conditions": [
{

View file

@ -6,7 +6,7 @@
}
],
"result": {
"item": "minecraft:diamond"
"id": "minecraft:diamond"
},
"fabric:load_conditions": [
{

View file

@ -6,7 +6,7 @@
}
],
"result": {
"item": "minecraft:diamond"
"id": "minecraft:diamond"
},
"fabric:load_conditions": [
{

View file

@ -6,7 +6,7 @@
}
],
"result": {
"item": "minecraft:dirt"
"id": "minecraft:dirt"
},
"fabric:load_conditions": [
{

View file

@ -97,7 +97,7 @@ public final class Networking implements ModInitializer {
Identifier id = buf.readIdentifier();
PacketCodec<RegistryByteBuf, D> codec = (PacketCodec<RegistryByteBuf, D>) CODEC_BY_ID.get(id);
return new OpenScreenPayload<>(id, buf.readByte(), TextCodecs.PACKET_CODEC.decode(buf), codec, codec == null ? null : codec.decode(buf));
return new OpenScreenPayload<>(id, buf.readByte(), TextCodecs.REGISTRY_PACKET_CODEC.decode(buf), codec, codec == null ? null : codec.decode(buf));
}
private void write(RegistryByteBuf buf) {

View file

@ -16,9 +16,9 @@
package net.fabricmc.fabric.test.screenhandler.item;
import net.minecraft.inventory.Inventories;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.ContainerComponent;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.collection.DefaultedList;
final class BagInventory implements ImplementedInventory {
@ -27,11 +27,7 @@ final class BagInventory implements ImplementedInventory {
BagInventory(ItemStack stack) {
this.stack = stack;
NbtCompound tag = stack.getSubNbt("Items");
if (tag != null) {
Inventories.readNbt(tag, items);
}
stack.getOrDefault(DataComponentTypes.CONTAINER, ContainerComponent.fromStacks(items));
}
@Override
@ -41,7 +37,6 @@ final class BagInventory implements ImplementedInventory {
@Override
public void markDirty() {
NbtCompound tag = stack.getOrCreateSubNbt("Items");
Inventories.writeNbt(tag, items);
stack.set(DataComponentTypes.CONTAINER, ContainerComponent.fromStacks(items));
}
}

View file

@ -243,11 +243,8 @@ transitive-accessible method net/minecraft/block/WetSpongeBlock <init> (Lnet/min
transitive-accessible method net/minecraft/block/WitherSkullBlock <init> (Lnet/minecraft/block/AbstractBlock$Settings;)V
# Constructors of non-abstract item classes
transitive-accessible method net/minecraft/item/AxeItem <init> (Lnet/minecraft/item/ToolMaterial;FFLnet/minecraft/item/Item$Settings;)V
transitive-accessible method net/minecraft/item/HoeItem <init> (Lnet/minecraft/item/ToolMaterial;IFLnet/minecraft/item/Item$Settings;)V
transitive-accessible method net/minecraft/item/MiningToolItem <init> (FFLnet/minecraft/item/ToolMaterial;Lnet/minecraft/registry/tag/TagKey;Lnet/minecraft/item/Item$Settings;)V
transitive-accessible method net/minecraft/item/MiningToolItem <init> (Lnet/minecraft/item/ToolMaterial;Lnet/minecraft/registry/tag/TagKey;Lnet/minecraft/item/Item$Settings;)V
transitive-accessible method net/minecraft/item/MusicDiscItem <init> (ILnet/minecraft/sound/SoundEvent;Lnet/minecraft/item/Item$Settings;I)V
transitive-accessible method net/minecraft/item/PickaxeItem <init> (Lnet/minecraft/item/ToolMaterial;IFLnet/minecraft/item/Item$Settings;)V
# Protected static fields of RenderPhase
transitive-accessible field net/minecraft/client/render/RenderPhase NO_TRANSPARENCY Lnet/minecraft/client/render/RenderPhase$Transparency;

View file

@ -3,8 +3,8 @@ org.gradle.parallel=true
fabric.loom.multiProjectOptimisation=true
version=0.96.4
minecraft_version=24w07a
yarn_version=+build.1
minecraft_version=24w09a
yarn_version=+build.5
loader_version=0.15.6
installer_version=0.11.1

View file

@ -55,7 +55,7 @@ include 'fabric-resource-loader-v0'
include 'fabric-screen-api-v1'
include 'fabric-screen-handler-api-v1'
include 'fabric-sound-api-v1'
include 'fabric-transfer-api-v1'
//include 'fabric-transfer-api-v1'
include 'fabric-transitive-access-wideners-v1'
include 'deprecated'