Skip to content

Commit

Permalink
[1.20.4] BlockTagIngredient Backport (#989)
Browse files Browse the repository at this point in the history
  • Loading branch information
IThundxr authored Jun 8, 2024
1 parent 1d3161a commit 8ef74db
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 4 deletions.
10 changes: 6 additions & 4 deletions src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
import net.neoforged.neoforge.common.conditions.OrCondition;
import net.neoforged.neoforge.common.conditions.TagEmptyCondition;
import net.neoforged.neoforge.common.conditions.TrueCondition;
import net.neoforged.neoforge.common.crafting.BlockTagIngredient;
import net.neoforged.neoforge.common.crafting.CompoundIngredient;
import net.neoforged.neoforge.common.crafting.DifferenceIngredient;
import net.neoforged.neoforge.common.crafting.IngredientType;
Expand Down Expand Up @@ -203,7 +204,7 @@ public class NeoForgeMod {

/**
* Reach Distance represents the distance at which a player may interact with the world. The default is 4.5 blocks. Players in creative mode have an additional 0.5 blocks of block reach.
*
*
* @see IPlayerExtension#getBlockReach()
* @see IPlayerExtension#canReach(BlockPos, double)
*/
Expand Down Expand Up @@ -231,7 +232,7 @@ public class NeoForgeMod {
/**
* Attack Range represents the distance at which a player may attack an entity. The default is 3 blocks. Players in creative mode have an additional 2 blocks of entity reach.
* The default of 3.0 is technically considered a bug by Mojang - see MC-172289 and MC-92484. However, updating this value would allow for longer-range attacks on vanilla servers, which makes some people mad.
*
*
* @see IPlayerExtension#getEntityReach()
* @see IPlayerExtension#canReach(Entity, double)
* @see IPlayerExtension#canReach(Vec3, double)
Expand All @@ -240,7 +241,7 @@ public class NeoForgeMod {

/**
* Step Height Addition modifies the amount of blocks an entity may walk up without jumping.
*
*
* @see IEntityExtension#getStepHeight()
*/
public static final Holder<Attribute> STEP_HEIGHT = ATTRIBUTES.register("step_height", () -> new RangedAttribute("neoforge.step_height", 0.0D, -512.0D, 512.0D).setSyncable(true));
Expand Down Expand Up @@ -399,6 +400,7 @@ public class NeoForgeMod {
public static final DeferredHolder<IngredientType<?>, IngredientType<NBTIngredient>> NBT_INGREDIENT_TYPE = INGREDIENT_TYPES.register("nbt", () -> new IngredientType<>(NBTIngredient.CODEC, NBTIngredient.CODEC_NONEMPTY));
public static final DeferredHolder<IngredientType<?>, IngredientType<DifferenceIngredient>> DIFFERENCE_INGREDIENT_TYPE = INGREDIENT_TYPES.register("difference", () -> new IngredientType<>(DifferenceIngredient.CODEC, DifferenceIngredient.CODEC_NONEMPTY));
public static final DeferredHolder<IngredientType<?>, IngredientType<IntersectionIngredient>> INTERSECTION_INGREDIENT_TYPE = INGREDIENT_TYPES.register("intersection", () -> new IngredientType<>(IntersectionIngredient.CODEC, IntersectionIngredient.CODEC_NONEMPTY));
public static final DeferredHolder<IngredientType<?>, IngredientType<BlockTagIngredient>> BLOCK_TAG_INGREDIENT = INGREDIENT_TYPES.register("block_tag", () -> new IngredientType<>(BlockTagIngredient.CODEC));

private static final DeferredRegister<Codec<? extends ICondition>> CONDITION_CODECS = DeferredRegister.create(NeoForgeRegistries.Keys.CONDITION_CODECS, NeoForgeVersion.MOD_ID);
public static final DeferredHolder<Codec<? extends ICondition>, Codec<AndCondition>> AND_CONDITION = CONDITION_CODECS.register("and", () -> AndCondition.CODEC);
Expand Down Expand Up @@ -567,7 +569,7 @@ public ResourceLocation getFlowingTexture() {
* Used in place of {@link DamageSources#magic()} for damage dealt by {@link MobEffects#POISON}.
* <p>
* May also be used by mods providing poison-like effects.
*
*
* @see {@link Tags.DamageTypes#IS_POISON}
*/
public static final ResourceKey<DamageType> POISON_DAMAGE = ResourceKey.create(Registries.DAMAGE_TYPE, new ResourceLocation(NeoForgeVersion.MOD_ID, "poison"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.common.crafting;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.neoforged.neoforge.common.NeoForgeMod;

/**
* {@link Ingredient} that matches {@link ItemStack}s of {@link Block}s from a {@link TagKey<Block>}, useful in cases
* like {@code "minecraft:convertable_to_mud"} where there isn't an accompanying item tag
* <p>
* Notice: This should not be used as a replacement for the normal {@link Ingredient#of(TagKey)},
* This should only be used when there is no way an item tag can be used in your use case
*/
public class BlockTagIngredient extends Ingredient {
public static final Codec<BlockTagIngredient> CODEC = RecordCodecBuilder.create(i -> i
.group(TagKey.codec(Registries.BLOCK).fieldOf("tag").forGetter(BlockTagIngredient::getTag))
.apply(i, BlockTagIngredient::new));

protected final TagKey<Block> tag;
@Nullable
protected ItemStack[] itemStacks;

public BlockTagIngredient(TagKey<Block> tag) {
super(Stream.of(new BlockTagValue(tag)), NeoForgeMod.BLOCK_TAG_INGREDIENT);
this.tag = tag;
}

@Override
public ItemStack[] getItems() {
List<ItemStack> list = new ArrayList<>();

for (Value value : values) {
list.addAll(value.getItems());
}

return itemStacks = list.toArray(ItemStack[]::new);
}

@Override
public boolean test(@Nullable ItemStack stack) {
if (stack == null) {
return false;
}

this.getItems();
for (ItemStack itemStack : itemStacks) {
if (itemStack.is(stack.getItem())) {
return true;
}
}

return false;
}

public TagKey<Block> getTag() {
return tag;
}

@Override
public IngredientType<?> getType() {
return NeoForgeMod.BLOCK_TAG_INGREDIENT.get();
}

public record BlockTagValue(TagKey<Block> tag) implements Ingredient.Value {
@Override
public Collection<ItemStack> getItems() {
List<ItemStack> list = new ArrayList<>();

for (Holder<Block> holder : BuiltInRegistries.BLOCK.getTagOrEmpty(this.tag)) {
ItemStack stack = new ItemStack(holder.value());
if (!stack.isEmpty()) {
list.add(stack);
}
}

if (list.isEmpty())
list.add(new ItemStack(Blocks.BARRIER).setHoverName(Component.literal("Empty Tag: " + this.tag.location())));

return list;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_item": {
"conditions": {
"items": [
{
"items": [
"minecraft:water_bucket"
]
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "neotests_block_tag_ingredient:block_tag"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_item"
]
],
"rewards": {
"recipes": [
"neotests_block_tag_ingredient:block_tag"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"type": "neoforge:block_tag",
"tag": "minecraft:convertable_to_mud"
},
{
"item": "minecraft:water_bucket"
}
],
"result": {
"item": "minecraft:mud"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.CrafterBlock;
import net.minecraft.world.level.block.entity.CrafterBlockEntity;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.neoforged.neoforge.attachment.AttachmentType;
import net.neoforged.neoforge.common.crafting.BlockTagIngredient;
import net.neoforged.neoforge.common.crafting.NBTIngredient;
import net.neoforged.neoforge.registries.NeoForgeRegistries;
import net.neoforged.testframework.DynamicTest;
Expand All @@ -34,6 +36,37 @@

@ForEachTest(groups = "crafting.ingredient")
public class IngredientTests {
@GameTest
@EmptyTemplate
@TestHolder(description = "Tests if BlockTagIngredient works")
static void blockTagIngredient(final DynamicTest test, final RegistrationHelper reg) {
reg.addProvider(event -> new RecipeProvider(event.getGenerator().getPackOutput()) {
@Override
protected void buildRecipes(RecipeOutput output) {
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, Items.MUD)
.requires(new TestEnabledIngredient(new BlockTagIngredient(BlockTags.CONVERTABLE_TO_MUD), test.framework(), test.id()))
.requires(Items.WATER_BUCKET)
.unlockedBy("has_item", has(Items.WATER_BUCKET))
.save(output, new ResourceLocation(reg.modId(), "block_tag"));
}
});

test.onGameTest(helper -> helper
.startSequence()
.thenExecute(() -> helper.setBlock(1, 1, 1, Blocks.CRAFTER.defaultBlockState().setValue(BlockStateProperties.ORIENTATION, FrontAndTop.UP_NORTH).setValue(CrafterBlock.CRAFTING, true)))
.thenExecute(() -> helper.setBlock(1, 2, 1, Blocks.CHEST))

.thenMap(() -> helper.requireBlockEntity(1, 1, 1, CrafterBlockEntity.class))
.thenExecute(crafter -> crafter.setItem(0, Items.DIRT.getDefaultInstance()))
.thenExecute(crafter -> crafter.setItem(1, Items.WATER_BUCKET.getDefaultInstance()))
.thenIdle(3)

.thenExecute(() -> helper.pulseRedstone(1, 1, 2, 2))
.thenExecuteAfter(7, () -> helper.assertContainerContains(1, 2, 1, Items.MUD))

.thenSucceed());
}

@GameTest
@EmptyTemplate
@TestHolder(description = "Tests if partial NBT ingredients match the correct stacks")
Expand Down

0 comments on commit 8ef74db

Please sign in to comment.