Jump to content

[1.18.2] Method for iterating over blocks belonging to a tag


Daeruin

Recommended Posts

Is there a handy way to get all the blocks that belong to a tag and then iterate over them? For example, I'm generating global loot modifiers and would like to iterate over all the leaf blocks to create loot modifiers for them. From my searching, it seems there was a method for that in 1.16, but it no longer exists in 1.18.

Back in 1.12 I used the HarvestDropsEvent and just checked if the block was an instance of BlockLeaves. Much more efficient.

Edited by Daeruin
Link to comment
Share on other sites

Quote

Back in 1.12 I used the HarvestDropsEvent and just checked if the block was an instance of BlockLeaves. Much more efficient.

And wrong, you should have been using the ore dictionary 🙂

 

Vanilla would use

Registry.BLOCK.getTag(BlockTags.LEAVES)

but i guess the correct way to do it with forge is?

ForgeRegistries.BLOCKS.tags().getTag(BlockTags.LEAVES)

 

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

17 hours ago, warjort said:

Vanilla would use

Registry.BLOCK.getTag(BlockTags.LEAVES)

but i guess the correct way to do it with forge is?

ForgeRegistries.BLOCKS.tags().getTag(BlockTags.LEAVES)

Both of these produced an empty list during data generation. Seems like it should have worked, though.

15 hours ago, Luis_ST said:

the correct way would be BlockState#is with BlockTags.LEAVES,

but GLMs do not use Blocks, in this case it would be ItemStack#is with ItemTags.LEAVES

That is a great way to check if an individual block or item has the tag. It does not let me find all blocks or items that have the tag. I guess I could iterate over every block/item and use that method to find which ones have the tag. I was hoping for something a little more efficient.

I am using the LootItemBlockStatePropertyCondition as part of my loot modifiers, and it takes Blocks as input.

Link to comment
Share on other sites

Datapacks are not loaded during datagen. Datagen is where you generate them. 🙂

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

5 hours ago, Daeruin said:

Hmmm, iterating over all the blocks and items and checking their tags showed that nothing seems to have tags during data generation of global loot modifiers.

Why did you need the Tag values in Data generation, what exactly did you try to achieve?

Link to comment
Share on other sites

19 hours ago, Luis_ST said:

Why did you need the Tag values in Data generation, what exactly did you try to achieve?

I said it in my initial post. I'm trying to generate loot modifiers for a bunch of items. All of the items have the same tag. It seemed like I should be able to just grab the tag, iterate over the items, and generate the loot modifier for each one that way.

Link to comment
Share on other sites

NOTE: What is below is not fully tested, I just wrote it and tested it once to see if it works.

I've never used GLMs so I had a go at implementing your requirement, this is what I found out (this is using the forge-1.19 mdk's example mod as a base):

 

First I create src/main/resource/data/forge/loot_modifiers/global_loot_modifiers.json to specify the modification files

{
  "replace": false,
  "entries": [
    "examplemod:leaves"
  ]
}

The added the mentioned modification in src/main/resources/data/examplemod/loot_modifiers/leaves.json

{
  "conditions": [
    {
      "condition": "examplemod:blocktag",
      "blocktag": "minecraft:leaves"
    }
  ],
  "type": "examplemod:singleitem",
  "item": "minecraft:diamond"
}

Suprisingly, there is no loot condition for block tags so I had to write that

public class BlockTagLootItemCondition implements LootItemCondition {
	final TagKey<Block> blockTag;

    BlockTagLootItemCondition(TagKey<Block> blockTag) {
       this.blockTag = blockTag;
   }

   public LootItemConditionType getType() {
       return ExampleMod.BLOCK_TAG_LOOT_ITEM.get();
   }

   public Set<LootContextParam<?>> getReferencedContextParams() {
       return ImmutableSet.of(LootContextParams.BLOCK_STATE);
   }

   public boolean test(LootContext p_81772_) {
       BlockState blockstate = p_81772_.getParamOrNull(LootContextParams.BLOCK_STATE);
       return blockstate != null && blockstate.is(this.blockTag);
   }

   public static class Serializer implements net.minecraft.world.level.storage.loot.Serializer<BlockTagLootItemCondition> {
       public void serialize(JsonObject p_81795_, BlockTagLootItemCondition p_81796_, JsonSerializationContext p_81797_) {
           p_81795_.addProperty("blocktag", p_81796_.blockTag.location().toString());
       }

       public BlockTagLootItemCondition deserialize(JsonObject p_81805_, JsonDeserializationContext p_81806_) {
    	   ResourceLocation resourcelocation = new ResourceLocation(GsonHelper.getAsString(p_81805_, "blocktag"));
    	   TagKey<Block> blockTag = TagKey.create(Registry.BLOCK_REGISTRY, resourcelocation);
    	   return new BlockTagLootItemCondition(blockTag);
       }
   }
}

Then write my actual modifier. This is a simple one that lets you define one item to add to the drops.

public class SingleItemLootModifier extends LootModifier {
    public static final Supplier<Codec<SingleItemLootModifier>> CODEC = Suppliers.memoize(() -> RecordCodecBuilder.create(inst -> codecStart(inst)
    		.and(ForgeRegistries.ITEMS.getCodec().fieldOf("item").forGetter(m -> m.item))
            .apply(inst, SingleItemLootModifier::new)
    ));
	 
	 private final Item item;

	 public SingleItemLootModifier(LootItemCondition[] conditions, Item item) {
		super(conditions);
		this.item = item;
	}

	  @Override
	public Codec<? extends IGlobalLootModifier> codec() {
		  return CODEC.get();
	}

	@Override
	protected @NotNull ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
        generatedLoot.add(new ItemStack(item, 1));
	    return generatedLoot;
	}
}

Finally I have register the new condition and loot modifier in the main example mod class


    public static final DeferredRegister<LootItemConditionType> LOOT_ITEM_CONDITIONS = DeferredRegister.create(Registry.LOOT_ITEM_REGISTRY, MODID);
    public static final RegistryObject<LootItemConditionType> BLOCK_TAG_LOOT_ITEM = LOOT_ITEM_CONDITIONS.register("blocktag", () -> new LootItemConditionType(new BlockTagLootItemCondition.Serializer()));

    public static final DeferredRegister<Codec<? extends IGlobalLootModifier>> GLM = DeferredRegister.create(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, MODID);
    public static final RegistryObject<Codec<SingleItemLootModifier>> SINGLE_ITEM_LOOT_MODIFIER = GLM.register("singleitem", SingleItemLootModifier.CODEC);
    
    public ExampleMod()
    {
        IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();

        // Register the commonSetup method for modloading
        modEventBus.addListener(this::commonSetup);

        // Register the Deferred Register to the mod event bus so blocks get registered
        BLOCKS.register(modEventBus);
        // Register the Deferred Register to the mod event bus so items get registered
        ITEMS.register(modEventBus);
      
        // NEW REGISTRIES HERE!
        LOOT_ITEM_CONDITIONS.register(modEventBus);
        GLM.register(modEventBus);

        // Register ourselves for server and other game events we are interested in
        MinecraftForge.EVENT_BUS.register(this);

 

Now when I break anything in the BlockTags.LEAVES tag it drops a diamond.

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.