Merge in changes from haykam and fix some more compile errors

This commit is contained in:
hypherionmc 2024-08-17 17:05:56 +02:00 committed by modmuss
parent d93561e45c
commit aa916c5e3c
35 changed files with 454 additions and 229 deletions

View file

@ -59,12 +59,12 @@ public class FabricApiLookupTest implements ModInitializer {
Identifier chute = Identifier.of(MOD_ID, "chute");
Registry.register(Registries.BLOCK, chute, CHUTE_BLOCK);
Registry.register(Registries.ITEM, chute, CHUTE_ITEM);
CHUTE_BLOCK_ENTITY_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE, chute, FabricBlockEntityTypeBuilder.create(ChuteBlockEntity::new, CHUTE_BLOCK));
CHUTE_BLOCK_ENTITY_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE, chute, FabricBlockEntityTypeBuilder.create(ChuteBlockEntity::new, CHUTE_BLOCK).build());
Identifier cobbleGen = Identifier.of(MOD_ID, "cobble_gen");
Registry.register(Registries.BLOCK, cobbleGen, COBBLE_GEN_BLOCK);
Registry.register(Registries.ITEM, cobbleGen, COBBLE_GEN_ITEM);
COBBLE_GEN_BLOCK_ENTITY_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE, cobbleGen, FabricBlockEntityTypeBuilder.create(CobbleGenBlockEntity::new, COBBLE_GEN_BLOCK));
COBBLE_GEN_BLOCK_ENTITY_TYPE = Registry.register(Registries.BLOCK_ENTITY_TYPE, cobbleGen, FabricBlockEntityTypeBuilder.create(CobbleGenBlockEntity::new, COBBLE_GEN_BLOCK).build());
InventoryExtractableProvider extractableProvider = new InventoryExtractableProvider();
InventoryInsertableProvider insertableProvider = new InventoryInsertableProvider();

View file

@ -18,9 +18,18 @@ package net.fabricmc.fabric.test.lookup.client.entity;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.render.entity.PigEntityRenderer;
import net.minecraft.client.render.entity.state.PigEntityRenderState;
import net.minecraft.util.Identifier;
public class InspectablePigEntityRenderer extends PigEntityRenderer {
private static final Identifier TEXTURE = Identifier.ofVanilla("missingno");
public InspectablePigEntityRenderer(EntityRendererFactory.Context context) {
super(context);
}
@Override
public Identifier getTexture(PigEntityRenderState context) {
return TEXTURE;
}
}

View file

@ -316,33 +316,16 @@ public interface BiomeModificationContext {
void addFeature(GenerationStep.Feature step, RegistryKey<PlacedFeature> placedFeatureKey);
/**
* Adds a configured carver to one of this biomes generation steps.
* Adds a configured carver to this biome.
*/
void addCarver(GenerationStep.Carver step, RegistryKey<ConfiguredCarver<?>> carverKey);
void addCarver(RegistryKey<ConfiguredCarver<?>> carverKey);
/**
* Removes all carvers with the given key from one of this biomes generation steps.
* Removes all carvers with the given key from this biome.
*
* @return True if any carvers were removed.
*/
boolean removeCarver(GenerationStep.Carver step, RegistryKey<ConfiguredCarver<?>> configuredCarverKey);
/**
* Removes all carvers with the given key from all of this biomes generation steps.
*
* @return True if any carvers were removed.
*/
default boolean removeCarver(RegistryKey<ConfiguredCarver<?>> configuredCarverKey) {
boolean anyFound = false;
for (GenerationStep.Carver step : GenerationStep.Carver.values()) {
if (removeCarver(step, configuredCarverKey)) {
anyFound = true;
}
}
return anyFound;
}
boolean removeCarver(RegistryKey<ConfiguredCarver<?>> configuredCarverKey);
}
interface SpawnSettingsContext {

View file

@ -55,9 +55,9 @@ public final class BiomeModifications {
*
* @see BiomeSelectors
*/
public static void addCarver(Predicate<BiomeSelectionContext> biomeSelector, GenerationStep.Carver step, RegistryKey<ConfiguredCarver<?>> configuredCarverKey) {
public static void addCarver(Predicate<BiomeSelectionContext> biomeSelector, RegistryKey<ConfiguredCarver<?>> configuredCarverKey) {
create(configuredCarverKey.getValue()).add(ModificationPhase.ADDITIONS, biomeSelector, context -> {
context.getGenerationSettings().addCarver(step, configuredCarverKey);
context.getGenerationSettings().addCarver(configuredCarverKey);
});
}

View file

@ -205,19 +205,11 @@ public class BiomeModificationContextImpl implements BiomeModificationContext {
* possible step if they're dense lists.
*/
GenerationSettingsContextImpl() {
unfreezeCarvers();
unfreezeFeatures();
rebuildFeatures = false;
}
private void unfreezeCarvers() {
Map<GenerationStep.Carver, RegistryEntryList<ConfiguredCarver<?>>> carversByStep = new EnumMap<>(GenerationStep.Carver.class);
carversByStep.putAll(generationSettings.carvers);
generationSettings.carvers = carversByStep;
}
private void unfreezeFeatures() {
generationSettings.features = new ArrayList<>(generationSettings.features);
}
@ -226,7 +218,6 @@ public class BiomeModificationContextImpl implements BiomeModificationContext {
* Re-freeze the lists in the generation settings to immutable variants, also fixes the flower features.
*/
public void freeze() {
freezeCarvers();
freezeFeatures();
if (rebuildFeatures) {
@ -234,10 +225,6 @@ public class BiomeModificationContextImpl implements BiomeModificationContext {
}
}
private void freezeCarvers() {
generationSettings.carvers = ImmutableMap.copyOf(generationSettings.carvers);
}
private void freezeFeatures() {
generationSettings.features = ImmutableList.copyOf(generationSettings.features);
// Replace the supplier to force a rebuild next time its called.
@ -296,22 +283,18 @@ public class BiomeModificationContextImpl implements BiomeModificationContext {
}
@Override
public void addCarver(GenerationStep.Carver step, RegistryKey<ConfiguredCarver<?>> entry) {
public void addCarver(RegistryKey<ConfiguredCarver<?>> entry) {
// We do not need to delay evaluation of this since the registries are already fully built
generationSettings.carvers.put(step, plus(generationSettings.carvers.get(step), getEntry(carvers, entry)));
generationSettings.carvers = plus(generationSettings.carvers, getEntry(carvers, entry));
}
@Override
public boolean removeCarver(GenerationStep.Carver step, RegistryKey<ConfiguredCarver<?>> configuredCarverKey) {
public boolean removeCarver(RegistryKey<ConfiguredCarver<?>> configuredCarverKey) {
ConfiguredCarver<?> carver = getEntry(carvers, configuredCarverKey).value();
RegistryEntryList<ConfiguredCarver<?>> carvers = generationSettings.carvers.get(step);
if (carvers == null) return false;
List<RegistryEntry<ConfiguredCarver<?>>> genCarvers = new ArrayList<>(carvers.stream().toList());
List<RegistryEntry<ConfiguredCarver<?>>> genCarvers = new ArrayList<>(generationSettings.carvers.stream().toList());
if (genCarvers.removeIf(entry -> entry.value() == carver)) {
generationSettings.carvers.put(step, RegistryEntryList.of(genCarvers));
generationSettings.carvers = RegistryEntryList.of(genCarvers);
return true;
}

View file

@ -47,8 +47,8 @@ mutable field net/minecraft/world/biome/SpawnSettings spawnCosts Ljava/util/Map;
accessible method net/minecraft/world/biome/SpawnSettings$SpawnDensity <init> (DD)V
# Generation Settings
accessible field net/minecraft/world/biome/GenerationSettings carvers Ljava/util/Map;
mutable field net/minecraft/world/biome/GenerationSettings carvers Ljava/util/Map;
accessible field net/minecraft/world/biome/GenerationSettings carvers Lnet/minecraft/registry/entry/RegistryEntryList;
mutable field net/minecraft/world/biome/GenerationSettings carvers Lnet/minecraft/registry/entry/RegistryEntryList;
accessible field net/minecraft/world/biome/GenerationSettings features Ljava/util/List;
mutable field net/minecraft/world/biome/GenerationSettings features Ljava/util/List;
accessible field net/minecraft/world/biome/GenerationSettings flowerFeatures Ljava/util/function/Supplier;

View file

@ -16,15 +16,11 @@
package net.fabricmc.fabric.api.registry;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.loot.LootTable;
import net.minecraft.registry.RegistryKey;
@ -32,10 +28,8 @@ import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier;
import net.minecraft.village.VillagerProfession;
import net.fabricmc.fabric.impl.content.registry.util.ImmutableCollectionUtils;
import net.fabricmc.fabric.mixin.content.registry.FarmerWorkTaskAccessor;
import net.fabricmc.fabric.impl.content.registry.VillagerInteractionRegistriesImpl;
import net.fabricmc.fabric.mixin.content.registry.GiveGiftsToHeroTaskAccessor;
import net.fabricmc.fabric.mixin.content.registry.VillagerEntityAccessor;
/**
* Registries for modifying villager interactions that
@ -47,13 +41,26 @@ public final class VillagerInteractionRegistries {
private VillagerInteractionRegistries() {
}
/**
* Registers an item to be collectable (picked up from item entity)
* by any profession villagers.
*
* @param item the item to register
* @deprecated Add items to the {@linkplain net.minecraft.tag.ItemTags#VILLAGER_PICKS_UP {@code <#789950127774105602>:villager_picks_up} item tag} instead
*/
@Deprecated
public static void registerCollectable(ItemConvertible item) {
Objects.requireNonNull(item.asItem(), "Item cannot be null!");
VillagerInteractionRegistriesImpl.getCollectableRegistry().add(item.asItem());
}
/**
* Registers an item to be used in a composter by farmer villagers.
* @param item the item to register
*/
public static void registerCompostable(ItemConvertible item) {
Objects.requireNonNull(item.asItem(), "Item cannot be null!");
getCompostableRegistry().add(item.asItem());
VillagerInteractionRegistriesImpl.getCompostableRegistry().add(item.asItem());
}
/**
@ -63,7 +70,7 @@ public final class VillagerInteractionRegistries {
*/
public static void registerFood(ItemConvertible item, int foodValue) {
Objects.requireNonNull(item.asItem(), "Item cannot be null!");
Integer oldValue = getFoodRegistry().put(item.asItem(), foodValue);
Integer oldValue = VillagerInteractionRegistriesImpl.getFoodRegistry().put(item.asItem(), foodValue);
if (oldValue != null) {
LOGGER.info("Overriding previous food value of {}, was: {}, now: {}", item.asItem().toString(), oldValue, foodValue);
@ -92,12 +99,4 @@ public final class VillagerInteractionRegistries {
LOGGER.info("Overriding previous gift loot table of {} profession, was: {}, now: {}", profession.id(), oldValue, lootTable);
}
}
private static List<Item> getCompostableRegistry() {
return ImmutableCollectionUtils.getAsMutableList(FarmerWorkTaskAccessor::fabric_getCompostable, FarmerWorkTaskAccessor::fabric_setCompostables);
}
private static Map<Item, Integer> getFoodRegistry() {
return ImmutableCollectionUtils.getAsMutableMap(() -> VillagerEntity.ITEM_FOOD_VALUES, VillagerEntityAccessor::fabric_setItemFoodValues);
}
}

View file

@ -0,0 +1,48 @@
/*
* 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.content.registry;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.Item;
import net.fabricmc.fabric.impl.content.registry.util.ImmutableCollectionUtils;
import net.fabricmc.fabric.mixin.content.registry.FarmerWorkTaskAccessor;
import net.fabricmc.fabric.mixin.content.registry.VillagerEntityAccessor;
public final class VillagerInteractionRegistriesImpl {
private static final Set<Item> GATHERABLE_ITEMS = new HashSet<>();
private VillagerInteractionRegistriesImpl() {
}
public static Set<Item> getCollectableRegistry() {
return GATHERABLE_ITEMS;
}
public static List<Item> getCompostableRegistry() {
return ImmutableCollectionUtils.getAsMutableList(FarmerWorkTaskAccessor::fabric_getCompostable, FarmerWorkTaskAccessor::fabric_setCompostables);
}
public static Map<Item, Integer> getFoodRegistry() {
return ImmutableCollectionUtils.getAsMutableMap(() -> VillagerEntity.ITEM_FOOD_VALUES, VillagerEntityAccessor::fabric_setItemFoodValues);
}
}

View file

@ -0,0 +1,35 @@
/*
* 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.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ItemStack;
import net.fabricmc.fabric.impl.content.registry.VillagerInteractionRegistriesImpl;
@Mixin(VillagerEntity.class)
public class VillagerEntityMixin {
@WrapOperation(method = "canGather", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isIn(Lnet/minecraft/registry/tag/TagKey;)Z"))
private boolean useGatherableItemsSet(ItemStack stack, Operation<Boolean> original) {
return VillagerInteractionRegistriesImpl.getCollectableRegistry().contains(stack.getItem()) || original.call(stack);
}
}

View file

@ -14,7 +14,8 @@
"FireBlockMixin",
"OxidizableMixin",
"ShovelItemAccessor",
"VillagerEntityAccessor"
"VillagerEntityAccessor",
"VillagerEntityMixin"
],
"injectors": {
"defaultRequire": 1

View file

@ -21,6 +21,7 @@ import java.util.function.IntSupplier;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnReason;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
@ -52,7 +53,7 @@ public class AttachmentCopyTests implements FabricGameTest {
ServerWorld end = server.getWorld(World.END);
// using overworld and end to avoid portal code related to the nether
Entity entity = EntityType.PIG.create(overworld);
Entity entity = EntityType.PIG.create(overworld, SpawnReason.SPAWN_EGG);
Objects.requireNonNull(entity, "entity was null");
entity.setAttached(DUMMY, () -> 10);
entity.setAttached(COPY_ON_DEATH, () -> 10);
@ -73,7 +74,7 @@ public class AttachmentCopyTests implements FabricGameTest {
@GameTest(templateName = FabricGameTest.EMPTY_STRUCTURE)
public void testMobConversion(TestContext context) {
MobEntity mob = Objects.requireNonNull(EntityType.ZOMBIE.create(context.getWorld()));
MobEntity mob = Objects.requireNonNull(EntityType.ZOMBIE.create(context.getWorld(), SpawnReason.SPAWN_EGG));
mob.setAttached(DUMMY, () -> 42);
mob.setAttached(COPY_ON_DEATH, () -> 42);
MobEntity converted = mob.convertTo(EntityType.DROWNED, false);

View file

@ -37,7 +37,6 @@ import net.minecraft.data.DataProvider;
import net.minecraft.data.DataWriter;
import net.minecraft.data.server.recipe.CraftingRecipeJsonBuilder;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.recipe.Recipe;
@ -59,7 +58,8 @@ public abstract class FabricRecipeProvider extends RecipeGenerator {
protected final FabricDataOutput output;
public FabricRecipeProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
// TODO 24w33a
super(null, null);
this.output = output;
}
@ -93,7 +93,8 @@ public abstract class FabricRecipeProvider extends RecipeGenerator {
};
}
@Override
// TODO 24w33a
/*@Override
public CompletableFuture<?> run(DataWriter writer, RegistryWrapper.WrapperLookup wrapperLookup) {
Set<Identifier> generatedRecipes = Sets.newHashSet();
List<CompletableFuture<?>> list = new ArrayList<>();
@ -132,7 +133,7 @@ public abstract class FabricRecipeProvider extends RecipeGenerator {
}
});
return CompletableFuture.allOf(list.toArray(CompletableFuture[]::new));
}
}*/
/**
* Override this method to change the recipe identifier. The default implementation normalizes the namespace to the mod ID.

View file

@ -83,7 +83,6 @@ public class ModelProviderMixin {
}
}
/
@Inject(method = "run", at = @At(value = "INVOKE_ASSIGN", target = "com/google/common/collect/Maps.newHashMap()Ljava/util/HashMap;", ordinal = 0, remap = false), locals = LocalCapture.CAPTURE_FAILHARD)
private void runHead(DataWriter writer, CallbackInfoReturnable<CompletableFuture<?>> cir, Map<Block, BlockStateSupplier> map) {
fabricDataOutputThreadLocal.set(fabricDataOutput);

View file

@ -115,7 +115,8 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
public void onInitializeDataGenerator(FabricDataGenerator dataGenerator) {
final FabricDataGenerator.Pack pack = dataGenerator.createPack();
pack.addProvider(TestRecipeProvider::new);
// TODO 24w33a
//pack.addProvider(TestRecipeProvider::new);
pack.addProvider(TestModelProvider::new);
pack.addProvider(TestAdvancementProvider::new);
pack.addProvider(TestBlockLootTableProvider::new);
@ -164,7 +165,8 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
registerable.register(TEST_DYNAMIC_REGISTRY_ITEM_KEY, new DataGeneratorTestContent.TestDatagenObject(":tiny_potato:"));
}
private static class TestRecipeProvider extends FabricRecipeProvider {
// TODO 24w33a
/*private static class TestRecipeProvider extends FabricRecipeProvider {
private TestRecipeProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@ -199,7 +201,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
// - 9 undamaged pickaxes should match.
// - 1 undamaged pickaxe + 8 damaged pickaxes should match (regardless of the position).
// - 1 undamaged renamed pickaxe + 8 damaged pickaxes should match (components are not strictly matched here).
ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.DIAMOND_BLOCK)
/*ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.DIAMOND_BLOCK)
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
@ -216,27 +218,27 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.input(Ingredient.ofItems(Items.DIAMOND_PICKAXE))
.criterion("has_pickaxe", conditionsFromItem(Items.DIAMOND_PICKAXE))
.offerTo(exporter);
.offerTo(exporter);*/
// Test AND
// To test: charcoal should give a torch, but coal should not.
ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.TORCH)
/*ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.TORCH)
// charcoal only
.input(DefaultCustomIngredients.all(Ingredient.fromTag(ItemTags.COALS), Ingredient.ofItems(Items.CHARCOAL)))
.criterion("has_charcoal", conditionsFromItem(Items.CHARCOAL))
.offerTo(exporter);
.offerTo(exporter);*/
// Test OR
// To test: a golden pickaxe or a golden shovel should give a block of gold.
ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.GOLD_BLOCK)
/*ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.GOLD_BLOCK)
.input(DefaultCustomIngredients.any(Ingredient.ofItems(Items.GOLDEN_PICKAXE), Ingredient.ofItems(Items.GOLDEN_SHOVEL)))
.criterion("has_pickaxe", conditionsFromItem(Items.GOLDEN_PICKAXE))
.criterion("has_shovel", conditionsFromItem(Items.GOLDEN_SHOVEL))
.offerTo(exporter);
.offerTo(exporter);*/
// Test difference
// To test: only copper, netherite and emerald should match the recipe.
ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.BEACON)
/*ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, Items.BEACON)
.input(DefaultCustomIngredients.difference(
DefaultCustomIngredients.any(
Ingredient.fromTag(ItemTags.BEACON_PAYMENT_ITEMS),
@ -245,7 +247,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
.criterion("has_payment", conditionsFromTag(ItemTags.BEACON_PAYMENT_ITEMS))
.offerTo(exporter);
}
}
}*/
private static class ExistingEnglishLangProvider extends FabricLanguageProvider {
private ExistingEnglishLangProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
@ -257,7 +259,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
translationBuilder.add(SIMPLE_BLOCK, "Simple Block");
translationBuilder.add(Identifier.of(MOD_ID, "identifier_test"), "Identifier Test");
translationBuilder.add(EntityType.ALLAY, "Allay");
translationBuilder.add(EntityAttributes.GENERIC_ARMOR, "Generic Armor");
translationBuilder.add(EntityAttributes.ARMOR, "Generic Armor");
try {
Optional<Path> path = dataOutput.getModContainer().findPath("assets/testmod/lang/en_us.base.json");

View file

@ -1,7 +1,27 @@
/*
* 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.object.builder.v1.block.entity;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import com.mojang.datafixers.types.Type;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@ -9,8 +29,83 @@ import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.util.math.BlockPos;
public class FabricBlockEntityTypeBuilder {
public static <T extends BlockEntity> BlockEntityType<T> create(BiFunction<BlockPos, BlockState, T> factory, Block... blocks) {
return new BlockEntityType<>(factory::apply, Set.of(blocks));
/**
* Fabric's version of BlockEntityType.Builder with additional convenience methods.
*
* <p>Alternatively, use the access widener for {@link BlockEntityType.BlockEntityFactory}
* in Fabric Transitive Access Wideners (v1).
*
* @deprecated Use {@link BlockEntityType.Builder} directly.
*/
@Deprecated
public final class FabricBlockEntityTypeBuilder<T extends BlockEntity> {
private final Factory<? extends T> factory;
private final List<Block> blocks;
private FabricBlockEntityTypeBuilder(Factory<? extends T> factory, List<Block> blocks) {
this.factory = factory;
this.blocks = blocks;
}
/**
* @deprecated Use {@link BlockEntityType.Builder#create(BlockEntityType.BlockEntityFactory, Block...)}.
*/
@Deprecated
public static <T extends BlockEntity> FabricBlockEntityTypeBuilder<T> create(Factory<? extends T> factory, Block... blocks) {
List<Block> blocksList = new ArrayList<>(blocks.length);
Collections.addAll(blocksList, blocks);
return new FabricBlockEntityTypeBuilder<>(factory, blocksList);
}
/**
* Adds a supported block for the block entity type.
*
* @param block the supported block
* @return this builder
* @deprecated Use {@link BlockEntityType.Builder#create(BlockEntityType.BlockEntityFactory, Block...)}.
*/
@Deprecated
public FabricBlockEntityTypeBuilder<T> addBlock(Block block) {
this.blocks.add(block);
return this;
}
/**
* Adds supported blocks for the block entity type.
*
* @param blocks the supported blocks
* @return this builder
* @deprecated Use {@link BlockEntityType.Builder#create(BlockEntityType.BlockEntityFactory, Block...)}.
*/
@Deprecated
public FabricBlockEntityTypeBuilder<T> addBlocks(Block... blocks) {
Collections.addAll(this.blocks, blocks);
return this;
}
/**
* @deprecated Use {@link BlockEntityType.Builder#build()}.
*/
@Deprecated
public BlockEntityType<T> build() {
return build(null);
}
/**
* @deprecated Use {@link BlockEntityType.Builder#build(Type)}.
*/
@Deprecated
public BlockEntityType<T> build(Type<?> type) {
return new BlockEntityType<T>(factory::create, new HashSet<>(blocks));
}
/**
* @deprecated Use {@link BlockEntityType.BlockEntityFactory}.
*/
@FunctionalInterface
@Deprecated
public interface Factory<T extends BlockEntity> {
T create(BlockPos blockPos, BlockState blockState);
}
}

View file

@ -53,7 +53,7 @@ public class BlockEntityTypeBuilderTest implements ModInitializer {
static final Block SECOND_MULTI_BETRAYAL_BLOCK = new BetrayalBlock(MapColor.YELLOW);
private static final Identifier BLOCK_ENTITY_TYPE_ID = ObjectBuilderTestConstants.id("betrayal_block");
public static final BlockEntityType<?> BLOCK_ENTITY_TYPE = FabricBlockEntityTypeBuilder.create(BetrayalBlockEntity::new, INITIAL_BETRAYAL_BLOCK, ADDED_BETRAYAL_BLOCK, FIRST_MULTI_BETRAYAL_BLOCK, SECOND_MULTI_BETRAYAL_BLOCK);
public static final BlockEntityType<?> BLOCK_ENTITY_TYPE = FabricBlockEntityTypeBuilder.create(BetrayalBlockEntity::new, INITIAL_BETRAYAL_BLOCK, ADDED_BETRAYAL_BLOCK, FIRST_MULTI_BETRAYAL_BLOCK, SECOND_MULTI_BETRAYAL_BLOCK).build();
@Override
public void onInitialize() {

View file

@ -62,9 +62,8 @@ public interface CustomIngredientSerializer<T extends CustomIngredient> {
* <p>Codecs are used to read the ingredient from the recipe JSON files.
*
* @see Ingredient#ALLOW_EMPTY_CODEC
* @see Ingredient#DISALLOW_EMPTY_CODEC
*/
MapCodec<T> getCodec(boolean allowEmpty);
MapCodec<T> getCodec();
/**
* {@return the packet codec for serializing this ingredient}.

View file

@ -16,14 +16,19 @@
package net.fabricmc.fabric.impl.recipe.ingredient;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.item.Item;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.registry.entry.RegistryEntryList;
import org.jetbrains.annotations.Nullable;
import net.minecraft.item.ItemStack;
@ -71,7 +76,7 @@ public class CustomIngredientImpl extends Ingredient {
private final CustomIngredient customIngredient;
public CustomIngredientImpl(CustomIngredient customIngredient) {
super(Stream.empty());
super(RegistryEntryList.empty());
this.customIngredient = customIngredient;
}
@ -87,9 +92,9 @@ public class CustomIngredientImpl extends Ingredient {
}
@Override
public ItemStack[] getMatchingStacks() {
public List<RegistryEntry<Item>> getMatchingStacks() {
if (this.matchingStacks == null) {
this.matchingStacks = customIngredient.getMatchingStacks().toArray(ItemStack[]::new);
this.matchingStacks = customIngredient.toVanilla().getMatchingStacks();
}
return this.matchingStacks;
@ -100,11 +105,12 @@ public class CustomIngredientImpl extends Ingredient {
return stack != null && customIngredient.test(stack);
}
@Override
// TODO 24w33a
/*@Override
public boolean isEmpty() {
// We don't want to resolve the matching stacks,
// as this might cause the ingredient to use outdated tags when it's done too early.
// So we just return false when the matching stacks haven't been resolved yet (i.e. when the field is null).
return matchingStacks != null && matchingStacks.length == 0;
}
}*/
}

View file

@ -19,6 +19,7 @@ package net.fabricmc.fabric.impl.recipe.ingredient.builtin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
@ -30,18 +31,13 @@ import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer;
public class AllIngredient extends CombinedIngredient {
private static final MapCodec<AllIngredient> ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC);
private static final MapCodec<AllIngredient> DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC);
private static MapCodec<AllIngredient> createCodec(Codec<Ingredient> ingredientCodec) {
return ingredientCodec
.listOf()
.fieldOf("ingredients")
.xmap(AllIngredient::new, AllIngredient::getIngredients);
}
private static final MapCodec<AllIngredient> CODEC = Ingredient.CODEC
.listOf()
.fieldOf("ingredients")
.xmap(AllIngredient::new, AllIngredient::getIngredients);
public static final CustomIngredientSerializer<AllIngredient> SERIALIZER =
new Serializer<>(Identifier.of("fabric", "all"), AllIngredient::new, ALLOW_EMPTY_CODEC, DISALLOW_EMPTY_CODEC);
new Serializer<>(Identifier.of("fabric", "all"), AllIngredient::new, CODEC);
public AllIngredient(List<Ingredient> ingredients) {
super(ingredients);
@ -61,7 +57,7 @@ public class AllIngredient extends CombinedIngredient {
@Override
public List<ItemStack> getMatchingStacks() {
// There's always at least one sub ingredient, so accessing ingredients[0] is safe.
List<ItemStack> previewStacks = new ArrayList<>(Arrays.asList(ingredients.get(0).getMatchingStacks()));
List<ItemStack> previewStacks = ingredients.get(0).getMatchingStacks().stream().map(a -> new ItemStack(a)).collect(Collectors.toCollection(ArrayList::new));
for (int i = 1; i < ingredients.size(); ++i) {
Ingredient ing = ingredients.get(i);

View file

@ -23,25 +23,22 @@ import java.util.List;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer;
public class AnyIngredient extends CombinedIngredient {
private static final MapCodec<AnyIngredient> ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC);
private static final MapCodec<AnyIngredient> DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC);
private static MapCodec<AnyIngredient> createCodec(Codec<Ingredient> ingredientCodec) {
return ingredientCodec
.listOf()
.fieldOf("ingredients")
.xmap(AnyIngredient::new, AnyIngredient::getIngredients);
}
private static final MapCodec<AnyIngredient> CODEC = Ingredient.CODEC
.listOf()
.fieldOf("ingredients")
.xmap(AnyIngredient::new, AnyIngredient::getIngredients);
public static final CustomIngredientSerializer<AnyIngredient> SERIALIZER =
new CombinedIngredient.Serializer<>(Identifier.of("fabric", "any"), AnyIngredient::new, ALLOW_EMPTY_CODEC, DISALLOW_EMPTY_CODEC);
new CombinedIngredient.Serializer<>(Identifier.of("fabric", "any"), AnyIngredient::new, CODEC);
public AnyIngredient(List<Ingredient> ingredients) {
super(ingredients);
@ -60,13 +57,11 @@ public class AnyIngredient extends CombinedIngredient {
@Override
public List<ItemStack> getMatchingStacks() {
List<ItemStack> previewStacks = new ArrayList<>();
for (Ingredient ingredient : ingredients) {
previewStacks.addAll(Arrays.asList(ingredient.getMatchingStacks()));
}
return previewStacks;
return ingredients.stream().<ItemStack>mapMulti((ingredient, consumer) -> {
for (RegistryEntry<Item> entry : ingredient.getMatchingStacks()) {
consumer.accept(new ItemStack(entry));
}
}).toList();
}
@Override

View file

@ -61,14 +61,12 @@ abstract class CombinedIngredient implements CustomIngredient {
static class Serializer<I extends CombinedIngredient> implements CustomIngredientSerializer<I> {
private final Identifier identifier;
private final MapCodec<I> allowEmptyCodec;
private final MapCodec<I> disallowEmptyCodec;
private final MapCodec<I> codec;
private final PacketCodec<RegistryByteBuf, I> packetCodec;
Serializer(Identifier identifier, Function<List<Ingredient>, I> factory, MapCodec<I> allowEmptyCodec, MapCodec<I> disallowEmptyCodec) {
Serializer(Identifier identifier, Function<List<Ingredient>, I> factory, MapCodec<I> codec) {
this.identifier = identifier;
this.allowEmptyCodec = allowEmptyCodec;
this.disallowEmptyCodec = disallowEmptyCodec;
this.codec = codec;
this.packetCodec = Ingredient.PACKET_CODEC.collect(PacketCodecs.toList())
.xmap(factory, I::getIngredients);
}
@ -79,8 +77,8 @@ abstract class CombinedIngredient implements CustomIngredient {
}
@Override
public MapCodec<I> getCodec(boolean allowEmpty) {
return allowEmpty ? allowEmptyCodec : disallowEmptyCodec;
public MapCodec<I> getCodec() {
return codec;
}
@Override

View file

@ -16,13 +16,11 @@
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.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.jetbrains.annotations.Nullable;
@ -84,16 +82,13 @@ public class ComponentsIngredient implements CustomIngredient {
@Override
public List<ItemStack> getMatchingStacks() {
List<ItemStack> stacks = new ArrayList<>(List.of(base.getMatchingStacks()));
stacks.replaceAll(stack -> {
ItemStack copy = stack.copy();
return base.getMatchingStacks().stream().map(entry -> {
var stack = new ItemStack(entry);
copy.applyChanges(components);
stack.applyChanges(components);
return copy;
});
stacks.removeIf(stack -> !base.test(stack));
return stacks;
return stack;
}).filter(stack -> base.test(stack)).toList();
}
@Override
@ -117,31 +112,26 @@ public class ComponentsIngredient implements CustomIngredient {
private static class Serializer implements CustomIngredientSerializer<ComponentsIngredient> {
private static final Identifier ID = Identifier.of("fabric", "components");
private static final MapCodec<ComponentsIngredient> ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC);
private static final MapCodec<ComponentsIngredient> DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC);
private static final MapCodec<ComponentsIngredient> CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
Ingredient.CODEC.fieldOf("base").forGetter(ComponentsIngredient::getBase),
ComponentChanges.CODEC.fieldOf("components").forGetter(ComponentsIngredient::getComponents)
).apply(instance, ComponentsIngredient::new)
);
private static final PacketCodec<RegistryByteBuf, ComponentsIngredient> PACKET_CODEC = PacketCodec.tuple(
Ingredient.PACKET_CODEC, ComponentsIngredient::getBase,
ComponentChanges.PACKET_CODEC, ComponentsIngredient::getComponents,
ComponentsIngredient::new
);
private static MapCodec<ComponentsIngredient> createCodec(Codec<Ingredient> ingredientCodec) {
return RecordCodecBuilder.mapCodec(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 MapCodec<ComponentsIngredient> getCodec(boolean allowEmpty) {
return allowEmpty ? ALLOW_EMPTY_CODEC : DISALLOW_EMPTY_CODEC;
public MapCodec<ComponentsIngredient> getCodec() {
return CODEC;
}
@Override

View file

@ -60,14 +60,16 @@ public class CustomDataIngredient implements CustomIngredient {
@Override
public List<ItemStack> getMatchingStacks() {
List<ItemStack> stacks = new ArrayList<>(List.of(base.getMatchingStacks()));
return List.of();
// TODO 24w33a port
/*List<ItemStack> stacks = new ArrayList<>(List.of(base.getMatchingStacks()));
stacks.replaceAll(stack -> {
ItemStack copy = stack.copy();
copy.apply(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT, existingNbt -> NbtComponent.of(existingNbt.copyNbt().copyFrom(this.nbt)));
return copy;
});
stacks.removeIf(stack -> !base.test(stack));
return stacks;
return stacks;*/
}
@Override
@ -91,8 +93,12 @@ public class CustomDataIngredient implements CustomIngredient {
private static class Serializer implements CustomIngredientSerializer<CustomDataIngredient> {
private static final Identifier ID = Identifier.of("fabric", "custom_data");
private static final MapCodec<CustomDataIngredient> ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC);
private static final MapCodec<CustomDataIngredient> DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC);
private static final MapCodec<CustomDataIngredient> CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
Ingredient.CODEC.fieldOf("base").forGetter(CustomDataIngredient::getBase),
StringNbtReader.NBT_COMPOUND_CODEC.fieldOf("nbt").forGetter(CustomDataIngredient::getNbt)
).apply(instance, CustomDataIngredient::new)
);
private static final PacketCodec<RegistryByteBuf, CustomDataIngredient> PACKET_CODEC = PacketCodec.tuple(
Ingredient.PACKET_CODEC, CustomDataIngredient::getBase,
@ -100,23 +106,14 @@ public class CustomDataIngredient implements CustomIngredient {
CustomDataIngredient::new
);
private static MapCodec<CustomDataIngredient> createCodec(Codec<Ingredient> ingredientCodec) {
return RecordCodecBuilder.mapCodec(instance ->
instance.group(
ingredientCodec.fieldOf("base").forGetter(CustomDataIngredient::getBase),
StringNbtReader.NBT_COMPOUND_CODEC.fieldOf("nbt").forGetter(CustomDataIngredient::getNbt)
).apply(instance, CustomDataIngredient::new)
);
}
@Override
public Identifier getIdentifier() {
return ID;
}
@Override
public MapCodec<CustomDataIngredient> getCodec(boolean allowEmpty) {
return allowEmpty ? ALLOW_EMPTY_CODEC : DISALLOW_EMPTY_CODEC;
public MapCodec<CustomDataIngredient> getCodec() {
return CODEC;
}
@Override

View file

@ -50,9 +50,11 @@ public class DifferenceIngredient implements CustomIngredient {
@Override
public List<ItemStack> getMatchingStacks() {
List<ItemStack> stacks = new ArrayList<>(List.of(base.getMatchingStacks()));
stacks.removeIf(subtracted);
return stacks;
return List.of();
// TODO 24w33a port
//List<ItemStack> stacks = new ArrayList<>(List.of(base.getMatchingStacks()));
//stacks.removeIf(subtracted);
//return stacks;
}
@Override
@ -75,31 +77,26 @@ public class DifferenceIngredient implements CustomIngredient {
private static class Serializer implements CustomIngredientSerializer<DifferenceIngredient> {
private static final Identifier ID = Identifier.of("fabric", "difference");
private static final MapCodec<DifferenceIngredient> ALLOW_EMPTY_CODEC = createCodec(Ingredient.ALLOW_EMPTY_CODEC);
private static final MapCodec<DifferenceIngredient> DISALLOW_EMPTY_CODEC = createCodec(Ingredient.DISALLOW_EMPTY_CODEC);
private static final MapCodec<DifferenceIngredient> CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
Ingredient.CODEC.fieldOf("base").forGetter(DifferenceIngredient::getBase),
Ingredient.CODEC.fieldOf("subtracted").forGetter(DifferenceIngredient::getSubtracted)
).apply(instance, DifferenceIngredient::new)
);
private static final PacketCodec<RegistryByteBuf, DifferenceIngredient> PACKET_CODEC = PacketCodec.tuple(
Ingredient.PACKET_CODEC, DifferenceIngredient::getBase,
Ingredient.PACKET_CODEC, DifferenceIngredient::getSubtracted,
DifferenceIngredient::new
);
private static MapCodec<DifferenceIngredient> createCodec(Codec<Ingredient> ingredientCodec) {
return RecordCodecBuilder.mapCodec(instance ->
instance.group(
ingredientCodec.fieldOf("base").forGetter(DifferenceIngredient::getBase),
ingredientCodec.fieldOf("subtracted").forGetter(DifferenceIngredient::getSubtracted)
).apply(instance, DifferenceIngredient::new)
);
}
@Override
public Identifier getIdentifier() {
return ID;
}
@Override
public MapCodec<DifferenceIngredient> getCodec(boolean allowEmpty) {
return allowEmpty ? ALLOW_EMPTY_CODEC : DISALLOW_EMPTY_CODEC;
public MapCodec<DifferenceIngredient> getCodec() {
return CODEC;
}
@Override

View file

@ -19,6 +19,9 @@ package net.fabricmc.fabric.mixin.recipe.ingredient;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -35,12 +38,13 @@ import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientPacketCodec;
@Mixin(Ingredient.class)
public class IngredientMixin implements FabricIngredient {
@Inject(method = "createCodec", at = @At("RETURN"), cancellable = true)
// TODO 24w33a
/*@Inject(method = "createCodec", at = @At("RETURN"), cancellable = true)
private static void injectCodec(boolean allowEmpty, CallbackInfoReturnable<Codec<Ingredient>> cir) {
Codec<CustomIngredient> customIngredientCodec = CustomIngredientImpl.CODEC.dispatch(
CustomIngredientImpl.TYPE_KEY,
CustomIngredient::getSerializer,
serializer -> serializer.getCodec(allowEmpty));
CustomIngredientSerializer::getCodec);
cir.setReturnValue(Codec.either(customIngredientCodec, cir.getReturnValue()).xmap(
either -> either.map(CustomIngredient::toVanilla, ingredient -> ingredient),
@ -49,7 +53,7 @@ public class IngredientMixin implements FabricIngredient {
return customIngredient == null ? Either.right(ingredient) : Either.left(customIngredient);
}
));
}
}*/
@ModifyExpressionValue(
method = "<clinit>",

View file

@ -47,8 +47,8 @@ public class ShapelessRecipeMixin {
private boolean fabric_requiresTesting = false;
@Inject(at = @At("RETURN"), method = "<init>")
private void cacheRequiresTesting(String group, CraftingRecipeCategory category, ItemStack output, DefaultedList<Ingredient> input, CallbackInfo ci) {
for (Ingredient ingredient : input) {
private void cacheRequiresTesting(String group, CraftingRecipeCategory category, ItemStack result, List<Ingredient> ingredients, CallbackInfo ci) {
for (Ingredient ingredient : ingredients) {
if (ingredient.requiresTesting()) {
fabric_requiresTesting = true;
break;

View file

@ -1,8 +1,8 @@
accessWidener v2 named
extendable class net/minecraft/recipe/Ingredient
accessible method net/minecraft/recipe/Ingredient <init> (Ljava/util/stream/Stream;)V
accessible field net/minecraft/recipe/Ingredient matchingStacks [Lnet/minecraft/item/ItemStack;
accessible method net/minecraft/recipe/Ingredient <init> (Lnet/minecraft/registry/entry/RegistryEntryList;)V
accessible field net/minecraft/recipe/Ingredient matchingStacks Ljava/util/List;
accessible field net/minecraft/network/ClientConnection channel Lio/netty/channel/Channel;

View file

@ -16,15 +16,18 @@
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.component.type.NbtComponent;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.recipe.Ingredient;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.test.GameTest;
import net.minecraft.test.GameTestException;
import net.minecraft.test.TestContext;
@ -39,9 +42,9 @@ public class IngredientMatchTests {
public void testAllIngredient(TestContext context) {
Ingredient allIngredient = DefaultCustomIngredients.all(Ingredient.ofItems(Items.APPLE, Items.CARROT), Ingredient.ofItems(Items.STICK, Items.CARROT));
assertEquals(1, allIngredient.getMatchingStacks().length);
assertEquals(Items.CARROT, allIngredient.getMatchingStacks()[0].getItem());
assertEquals(false, allIngredient.isEmpty());
assertEquals(1, allIngredient.getMatchingStacks().size());
assertEquals(Items.CARROT, allIngredient.getMatchingStacks().getFirst());
assertEquals(false, allIngredient.getMatchingStacks().isEmpty());
assertEquals(false, allIngredient.test(new ItemStack(Items.APPLE)));
assertEquals(true, allIngredient.test(new ItemStack(Items.CARROT)));
@ -49,8 +52,8 @@ public class IngredientMatchTests {
Ingredient emptyAllIngredient = DefaultCustomIngredients.all(Ingredient.ofItems(Items.APPLE), Ingredient.ofItems(Items.STICK));
assertEquals(0, emptyAllIngredient.getMatchingStacks().length);
assertEquals(true, emptyAllIngredient.isEmpty());
assertEquals(0, emptyAllIngredient.getMatchingStacks().size());
assertEquals(true, emptyAllIngredient.getMatchingStacks().isEmpty());
assertEquals(false, emptyAllIngredient.test(new ItemStack(Items.APPLE)));
assertEquals(false, emptyAllIngredient.test(new ItemStack(Items.STICK)));
@ -62,12 +65,12 @@ public class IngredientMatchTests {
public void testAnyIngredient(TestContext context) {
Ingredient anyIngredient = DefaultCustomIngredients.any(Ingredient.ofItems(Items.APPLE, Items.CARROT), Ingredient.ofItems(Items.STICK, Items.CARROT));
assertEquals(4, anyIngredient.getMatchingStacks().length);
assertEquals(Items.APPLE, anyIngredient.getMatchingStacks()[0].getItem());
assertEquals(Items.CARROT, anyIngredient.getMatchingStacks()[1].getItem());
assertEquals(Items.STICK, anyIngredient.getMatchingStacks()[2].getItem());;
assertEquals(Items.CARROT, anyIngredient.getMatchingStacks()[3].getItem());
assertEquals(false, anyIngredient.isEmpty());
assertEquals(4, anyIngredient.getMatchingStacks().size());
assertEquals(Items.APPLE, anyIngredient.getMatchingStacks().getFirst());
assertEquals(Items.CARROT, anyIngredient.getMatchingStacks().get(1));
assertEquals(Items.STICK, anyIngredient.getMatchingStacks().get(2));
assertEquals(Items.CARROT, anyIngredient.getMatchingStacks().get(3));
assertEquals(false, anyIngredient.getMatchingStacks().isEmpty());
assertEquals(true, anyIngredient.test(new ItemStack(Items.APPLE)));
assertEquals(true, anyIngredient.test(new ItemStack(Items.CARROT)));
@ -80,9 +83,9 @@ public class IngredientMatchTests {
public void testDifferenceIngredient(TestContext context) {
Ingredient differenceIngredient = DefaultCustomIngredients.difference(Ingredient.ofItems(Items.APPLE, Items.CARROT), Ingredient.ofItems(Items.STICK, Items.CARROT));
assertEquals(1, differenceIngredient.getMatchingStacks().length);
assertEquals(Items.APPLE, differenceIngredient.getMatchingStacks()[0].getItem());
assertEquals(false, differenceIngredient.isEmpty());
assertEquals(1, differenceIngredient.getMatchingStacks().size());
assertEquals(Items.APPLE, differenceIngredient.getMatchingStacks().getFirst());
assertEquals(false, differenceIngredient.getMatchingStacks().isEmpty());
assertEquals(true, differenceIngredient.test(new ItemStack(Items.APPLE)));
assertEquals(false, differenceIngredient.test(new ItemStack(Items.CARROT)));
@ -110,15 +113,15 @@ public class IngredientMatchTests {
assertEquals(true, undamagedIngredient.test(renamedUndamagedDiamondPickaxe));
assertEquals(false, noNameUndamagedIngredient.test(renamedUndamagedDiamondPickaxe));
assertEquals(3, undamagedIngredient.getMatchingStacks().length);
ItemStack result0 = undamagedIngredient.getMatchingStacks()[0];
ItemStack result1 = undamagedIngredient.getMatchingStacks()[1];
assertEquals(3, undamagedIngredient.getMatchingStacks().size());
ItemStack result0 = undamagedIngredient.getMatchingStacks().getFirst().value().getDefaultStack();
ItemStack result1 = undamagedIngredient.getMatchingStacks().get(1).value().getDefaultStack();
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());
assertEquals(false, undamagedIngredient.getMatchingStacks().isEmpty());
// Undamaged is fine
assertEquals(true, undamagedIngredient.test(new ItemStack(Items.DIAMOND_PICKAXE)));
@ -189,10 +192,10 @@ public class IngredientMatchTests {
stack.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(rejectedNbt2));
assertEquals(false, customDataIngredient.test(stack));
ItemStack[] matchingStacks = customDataIngredient.getMatchingStacks();
assertEquals(1, matchingStacks.length);
assertEquals(Items.STICK, matchingStacks[0].getItem());
assertEquals(NbtComponent.of(requiredNbt), matchingStacks[0].get(DataComponentTypes.CUSTOM_DATA));
List<RegistryEntry<Item>> matchingStacks = customDataIngredient.getMatchingStacks();
assertEquals(1, matchingStacks.size());
assertEquals(Items.STICK, matchingStacks.getFirst().value());
assertEquals(NbtComponent.of(requiredNbt), matchingStacks.getFirst().value().getDefaultStack().get(DataComponentTypes.CUSTOM_DATA));
context.complete();
}

View file

@ -57,7 +57,7 @@ public class SerializationTests {
JsonElement json = JsonParser.parseString(ingredientJson);
try {
Ingredient.DISALLOW_EMPTY_CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(JsonParseException::new);
Ingredient.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(JsonParseException::new);
throw new GameTestException("Using a custom ingredient inside an array ingredient should have failed.");
} catch (JsonParseException e) {
context.complete();
@ -77,7 +77,7 @@ public class SerializationTests {
Ingredient ingredient = DefaultCustomIngredients.all(
Ingredient.ofItems(Items.STONE)
);
Codec<Ingredient> ingredientCodec = allowEmpty ? Ingredient.ALLOW_EMPTY_CODEC : Ingredient.DISALLOW_EMPTY_CODEC;
Codec<Ingredient> ingredientCodec = Ingredient.CODEC;
JsonObject json = ingredientCodec.encodeStart(JsonOps.INSTANCE, ingredient).getOrThrow(IllegalStateException::new).getAsJsonObject();
context.assertTrue(json.toString().equals(ingredientJson), "Unexpected json: " + json);
// Make sure that we can deserialize it

View file

@ -0,0 +1,33 @@
/*
* 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.registry.sync.client;
import java.util.List;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SerializableRegistries;
@Mixin(targets = "net/minecraft/client/network/ClientRegistries$DynamicRegistries")
public interface ClientRegistriesDynamicRegistriesAccessor {
@Accessor
Map<RegistryKey<? extends Registry<?>>, List<SerializableRegistries.SerializedRegistryEntry>> getDynamicRegistries();
}

View file

@ -0,0 +1,52 @@
/*
* 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.registry.sync.client;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Coerce;
import net.minecraft.client.network.ClientRegistries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryLoader;
import net.minecraft.registry.SerializableRegistries;
import net.minecraft.resource.ResourceFactory;
import net.fabricmc.fabric.impl.registry.sync.DynamicRegistriesImpl;
@Mixin(ClientRegistries.class)
public class ClientRegistriesMixin {
/**
* Keep the pre-24w04a behavior of removing empty registries, even if the client knows that registry.
*/
@WrapOperation(method = "method_62155", at = @At(value = "FIELD", target = "Lnet/minecraft/registry/RegistryLoader;SYNCED_REGISTRIES:Ljava/util/List;", opcode = Opcodes.GETSTATIC))
private List<RegistryLoader.Entry<?>> skipEmptyRegistries(Operation<List<RegistryLoader.Entry<?>>> operation, ResourceFactory resourceFactory, @Coerce ClientRegistriesDynamicRegistriesAccessor storage, boolean bl) {
Map<RegistryKey<? extends Registry<?>>, List<SerializableRegistries.SerializedRegistryEntry>> dynamicRegistries = storage.getDynamicRegistries();
List<RegistryLoader.Entry<?>> result = new ArrayList<>(operation.call());
result.removeIf(entry -> DynamicRegistriesImpl.SKIP_EMPTY_SYNC_REGISTRIES.contains(entry.key()) && !dynamicRegistries.containsKey(entry.key()));
return result;
}
}

View file

@ -48,8 +48,7 @@ public final class Registration {
public static final Item OCTAGONAL_COLUMN_ITEM = register("octagonal_column", new BlockItem(OCTAGONAL_COLUMN_BLOCK, new Item.Settings()));
public static final Item RIVERSTONE_ITEM = register("riverstone", new BlockItem(RIVERSTONE_BLOCK, new Item.Settings()));
// TODO 24w33a Is build(null) still required here?
public static final BlockEntityType<FrameBlockEntity> FRAME_BLOCK_ENTITY_TYPE = register("frame", FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAME_BLOCKS));
public static final BlockEntityType<FrameBlockEntity> FRAME_BLOCK_ENTITY_TYPE = register("frame", FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAME_BLOCKS).build());
private static <T extends Block> T register(String path, T block) {
return Registry.register(Registries.BLOCK, RendererTest.id(path), block);

View file

@ -47,7 +47,7 @@ public class ScreenHandlerTest implements ModInitializer {
public static final Item POSITIONED_BAG = new PositionedBagItem(new Item.Settings().maxCount(1));
public static final Block BOX = new BoxBlock(AbstractBlock.Settings.copy(Blocks.OAK_WOOD));
public static final Item BOX_ITEM = new BlockItem(BOX, new Item.Settings());
public static final BlockEntityType<BoxBlockEntity> BOX_ENTITY = FabricBlockEntityTypeBuilder.create(BoxBlockEntity::new, BOX);
public static final BlockEntityType<BoxBlockEntity> BOX_ENTITY = FabricBlockEntityTypeBuilder.create(BoxBlockEntity::new, BOX).build();
public static final ScreenHandlerType<BagScreenHandler> BAG_SCREEN_HANDLER = new ScreenHandlerType<>(BagScreenHandler::new, FeatureFlags.VANILLA_FEATURES);
public static final ScreenHandlerType<PositionedBagScreenHandler> POSITIONED_BAG_SCREEN_HANDLER = new ExtendedScreenHandlerType<>(PositionedBagScreenHandler::new, PositionedBagScreenHandler.BagData.PACKET_CODEC);
public static final ScreenHandlerType<BoxScreenHandler> BOX_SCREEN_HANDLER = new ExtendedScreenHandlerType<>(BoxScreenHandler::new, BlockPos.PACKET_CODEC.cast());

View file

@ -47,7 +47,7 @@ public class TransferTestInitializer implements ModInitializer {
registerBlock(FLUID_CHUTE, "fluid_chute");
Registry.register(Registries.ITEM, Identifier.of(MOD_ID, "extract_stick"), EXTRACT_STICK);
FLUID_CHUTE_TYPE = FabricBlockEntityTypeBuilder.create(FluidChuteBlockEntity::new, FLUID_CHUTE);
FLUID_CHUTE_TYPE = FabricBlockEntityTypeBuilder.create(FluidChuteBlockEntity::new, FLUID_CHUTE).build();
Registry.register(Registries.BLOCK_ENTITY_TYPE, Identifier.of(MOD_ID, "fluid_chute"), FLUID_CHUTE_TYPE);
FluidStorage.SIDED.registerForBlocks((world, pos, state, be, direction) -> CreativeStorage.WATER, INFINITE_WATER_SOURCE);

View file

@ -16,17 +16,17 @@ include 'fabric-api-catalog'
include 'fabric-api-base'
include 'fabric-api-lookup-api-v1'
//include 'fabric-biome-api-v1'
include 'fabric-biome-api-v1'
include 'fabric-block-api-v1'
include 'fabric-block-view-api-v2'
include 'fabric-blockrenderlayer-v1'
//include 'fabric-client-tags-api-v1'
include 'fabric-client-tags-api-v1'
include 'fabric-command-api-v2'
include 'fabric-content-registries-v0'
//include 'fabric-convention-tags-v2'
include 'fabric-convention-tags-v2'
include 'fabric-crash-report-info-v1'
//include 'fabric-data-attachment-api-v1'
//include 'fabric-data-generation-api-v1'
include 'fabric-data-attachment-api-v1'
include 'fabric-data-generation-api-v1'
include 'fabric-dimensions-v1'
include 'fabric-entity-events-v1'
include 'fabric-events-interaction-v0'
@ -42,7 +42,7 @@ include 'fabric-model-loading-api-v1'
include 'fabric-networking-api-v1'
include 'fabric-object-builder-api-v1'
include 'fabric-particles-v1'
//include 'fabric-recipe-api-v1'
include 'fabric-recipe-api-v1'
include 'fabric-registry-sync-v0'
include 'fabric-renderer-api-v1'
include 'fabric-renderer-indigo'