Jump to content

[1.15] Loot Table Function/Condition Issues [SOLVED]


Recommended Posts

Posted (edited)

I'm trying to add a loot table function/condition so that I can change the item that is dropped by a block based on a condition. I've tried adding both a function and a condition and I have had no success. What am I missing here?
 

This is the function that I tried.

Spoiler

package com.novamachina.ens.common.loot.function;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.novamachina.ens.common.item.tools.hammer.HammerBaseItem;
import com.novamachina.ens.common.registry.MasterRegistry;
import com.novamachina.ens.common.utility.LogUtil;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootFunction;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraft.world.storage.loot.conditions.ILootCondition;

public class UseHammerFunction extends LootFunction {

    private UseHammerFunction(ILootCondition[] conditionsIn) {
        super(conditionsIn);
        LogUtil.info("Register Hammer Function");
    }

    @Override
    protected ItemStack doApply(ItemStack stack, LootContext context) {
        LogUtil.info("Ran Hammer Function");
        BlockState state = context.get(LootParameters.BLOCK_STATE);
        ItemStack itemstack = context.get(LootParameters.TOOL);

        if(itemstack != null && state != null)
        {
            if(itemstack.getItem() instanceof HammerBaseItem)
            {
                LogUtil.info("Used Hammer");
                return new ItemStack(MasterRegistry.HAMMER_REGISTRY.getResult(state.getBlock()));
            }
        }

        return stack;
    }

    public static class Serializer extends LootFunction.Serializer<UseHammerFunction> {

        public Serializer() {
            super(new ResourceLocation("ens:use_hammer_fun"), UseHammerFunction.class);
            LogUtil.info("UseHammerFunction.Serializer called");
        }

        @Override
        public UseHammerFunction deserialize(JsonObject object,
            JsonDeserializationContext deserializationContext, ILootCondition[] conditionsIn) {
            LogUtil.info("UseHammerFunction deserialize");
            return new UseHammerFunction(conditionsIn);
        }
    }
}

 

This is the loot table that I create for the function.

Spoiler

{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "conditions": [
            {
              "condition": "minecraft:survives_explosion"
            }
          ],
          "functions": [
            {
              "function": "ens:use_hammer_fun"
            }
          ],
          "name": "minecraft:cobblestone"
        }
      ]
    }
  ]
}

 

This is the condition that I tried.

Spoiler

package com.novamachina.ens.common.loot.condition;

import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.novamachina.ens.common.item.tools.hammer.HammerBaseItem;
import com.novamachina.ens.common.utility.LogUtil;
import java.util.Set;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootParameter;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraft.world.storage.loot.conditions.ILootCondition;

public class UseHammerCondition implements ILootCondition {

    public UseHammerCondition() {
    }

    public Set<LootParameter<?>> getRequiredParameters() {
        return ImmutableSet.of(LootParameters.TOOL);
    }

    public boolean test(LootContext p_test_1_) {
        LogUtil.info("Check Used Hammer");
        ItemStack itemstack = p_test_1_.get(LootParameters.TOOL);
        return itemstack != null && itemstack.getItem() instanceof HammerBaseItem;
    }

    public static ILootCondition.IBuilder builder() {
        return UseHammerCondition::new;
    }

    public static class Serializer extends ILootCondition.AbstractSerializer<UseHammerCondition> {
        public Serializer() {
            super(new ResourceLocation("ens:use_hammer_cond"), UseHammerCondition.class);
        }

        public void serialize(JsonObject json, UseHammerCondition value, JsonSerializationContext context) {

        }

        public UseHammerCondition deserialize(JsonObject json, JsonDeserializationContext context) {
            return new UseHammerCondition();
        }
    }

}

 

This is the loot table I create for the condition.

Spoiler

{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "conditions": [
            {
              "condition": "minecraft:survives_explosion"
            },
            {
              "condition": "minecraft:inverted",
              "term": {
                "condition": "ens:use_hammer_cond"
              }
            }
          ],
          "name": "minecraft:cobblestone"
        }
      ]
    },
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "conditions": [
            {
              "condition": "minecraft:survives_explosion"
            },
            {
              "condition": "ens:use_hammer_cond"
            }
          ],
          "name": "minecraft:gravel"
        }
      ]
    }
  ]
}

 

I register both of them here.

Spoiler

public static void init(final FMLCommonSetupEvent event) {
        addRegistries();
        LootFunctionManager.registerFunction(new UseHammerFunction.Serializer());
        LootConditionManager.registerCondition(new UseHammerCondition.Serializer());
    }

 

 

Any help would be much appreciated.

 

EDIT: I'm overriding the cobblestone loot table and the loot table file is placed in data/minecraft/loot_tables/blocks

Edited by Tikaji
Some more info on issue.
Posted

I was messing with loot recently using global loot modifiers, and it worked pretty sweet. Looks very similar in setup to what you're doing here, just different way of registering I guess. Here's the link: https://github.com/MinecraftForge/MinecraftForge/blob/1.15.x/src/test/java/net/minecraftforge/debug/gameplay/loot/GlobalLootModifiersTest.java

 

And here's a link to the thread I had started while trying to figure it out, hope it helps!

https://www.minecraftforge.net/forum/topic/83671-1152-manipulate-actual-block-drops-not-what-can-drop/

 

Posted

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

Ok, so I got the Loot Modifier to work, but now I have the issue that gravel and sand will drop two of the same item. However, cobblestone drops one item using the same functionality. Why would that be?

Posted
29 minutes ago, Tikaji said:

Ok, so I got the Loot Modifier to work, but now I have the issue that gravel and sand will drop two of the same item. However, cobblestone drops one item using the same functionality. Why would that be?

Show your code.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted (edited)

Here's the modifier:

Spoiler

package com.novamachina.ens.common.loot.modifier;

import com.google.gson.JsonObject;
import com.novamachina.ens.common.item.tools.hammer.HammerBaseItem;
import com.novamachina.ens.common.registry.MasterRegistry;
import com.novamachina.ens.common.utility.LogUtil;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraft.world.storage.loot.conditions.ILootCondition;
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
import net.minecraftforge.common.loot.LootModifier;

public class UseHammerModifier extends LootModifier {

    public UseHammerModifier(ILootCondition[] conditionsIn) {
        super(conditionsIn);
    }

    @Nonnull
    @Override
    public List<ItemStack> doApply(List<ItemStack> generatedLoot, LootContext context) {
        ItemStack  tool       = context.get(LootParameters.TOOL);
        BlockState blockState = context.get(LootParameters.BLOCK_STATE);
        if (tool != null && blockState != null) {
            if (tool.getItem() instanceof HammerBaseItem) {
                List<ItemStack> newLoot     = new ArrayList<>();
                Block           returnBlock = MasterRegistry.HAMMER_REGISTRY
                    .getResult(blockState.getBlock());
                newLoot.add(new ItemStack(returnBlock));
                return newLoot;
            }
        }
        return generatedLoot;
    }

    public static class Serializer extends GlobalLootModifierSerializer<UseHammerModifier> {


        @Override
        public UseHammerModifier read(ResourceLocation location, JsonObject object,
            ILootCondition[] ailootcondition) {
            return new UseHammerModifier(ailootcondition);
        }
    }
}

 

Here is the loot modifier json:

Spoiler

{
  "type": "ens:use_hammer",
  "conditions": [
    {
      "condition": "minecraft:alternative",
      "terms": [
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:cobblestone"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:gravel"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:sand"
        }
      ]
    }
  ]
}

 

And here is the item. I assumed that I have to use the onBlockDestroyed in order to cause block drops for a custom tool. I was getting no drops with it otherwise.

Spoiler

package com.novamachina.ens.common.item.tools.hammer;

import com.google.common.collect.Sets;
import com.novamachina.ens.common.setup.ModSetup;
import com.novamachina.ens.common.setup.Registration;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.IItemTier;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ToolItem;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class HammerBaseItem extends ToolItem {

    private static final Set<Block> effectiveBlocksOn = Sets
        .newHashSet(Blocks.STONE, Blocks.DIORITE, Blocks.ANDESITE, Blocks.GRANITE,
            Blocks.NETHERRACK, Blocks.END_STONE, Blocks.COBBLESTONE,
            Registration.BLOCK_CRUSHED_DIORITE.get(), Registration.BLOCK_CRUSHED_ANDESITE.get(),
            Registration.BLOCK_CRUSHED_GRANITE.get(), Registration.BLOCK_CRUSHED_NETHERRACK.get(),
            Registration.BLOCK_CRUSHED_END_STONE.get(), Blocks.GRAVEL, Blocks.SAND,
            Registration.BLOCK_DUST.get());

    public HammerBaseItem(IItemTier tier, int maxDamage) {
        super(0.5F, 0.5F, tier, effectiveBlocksOn,
            new Item.Properties().defaultMaxDamage(maxDamage).group(ModSetup.ITEM_GROUP));
    }

    @Override
    public boolean onBlockDestroyed(ItemStack stack, World worldIn, BlockState state, BlockPos pos,
        LivingEntity entityLiving) {
        super.onBlockDestroyed(stack, worldIn, state, pos, entityLiving);
        Block.spawnDrops(state, worldIn, pos, null, entityLiving, stack);
        return false;
    }
}

 

Let me know if there is anything else. I'll step through the code and it calls the spawnDrops method twice.

Edited by Tikaji
Posted
1 hour ago, Tikaji said:

And here is the item. I assumed that I have to use the onBlockDestroyed in order to cause block drops for a custom tool. I was getting no drops with it otherwise.

You are not supposed to do that from what I can tell I haven't messed around with Global Loot Modifiers yet, but seeing as how LootModifier::doApply returns a List<ItemStack> I assume that are the drops.

 

1 hour ago, Tikaji said:

ItemStack tool = context.get(LootParameters.TOOL);

ItemStacks can never be null. Use itemStack::isEmpty

 

1 hour ago, Tikaji said:

blockState != null

I'm also unsure about this. I don't know if a BlockState will ever be null. I'd assume the default null-like value is the BlockState for AIR.

 

1 hour ago, Tikaji said:

Let me know if there is anything else. I'll step through the code and it calls the spawnDrops method twice.

Have you stepped through your LootModifier::doApply code is it called twice? Is it called at all aside from your Block.spawnDrops call?

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Posted

Ok, so I got rid of the onBlockDestroyed method, which caused doApply to only get called once, and I'm getting block drops from sand and gravel, only one item which is the expected result, but now I'm not getting anything from cobblestone. The modifier isn't being fired. My guess is something is wrong with the JSON file because that's what determines when the modifier gets fired, correct?

Posted
2 hours ago, Tikaji said:

MasterRegistry.HAMMER_REGISTRY .getResult(blockState.getBlock());

What does this look like? Do you add cobblestone to it?

10 minutes ago, Tikaji said:

My guess is something is wrong with the JSON file because that's what determines when the modifier gets fired, correct?

That would be my only idea as well, but I can't see what's wrong with it. Try setting a breakpoint in the area before global loot modifiers are called to see why your loot modifier condition is not true.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Posted (edited)
23 minutes ago, Animefan8888 said:
2 hours ago, Tikaji said:

MasterRegistry.HAMMER_REGISTRY .getResult(blockState.getBlock());

What does this look like? Do you add cobblestone to it?

I do add cobblestone to the registry. Its simply a map that takes a block as input and determines the output.

I also updated the JSON to see if any other blocks would work. The only two that work and trigger the modifier are sand and gravel. I also stripped it down to just cobblestone and it doesn't work.
Updated JSON:

Spoiler

{
  "type": "ens:use_hammer",
  "conditions": [
    {
      "condition": "minecraft:alternative",
      "terms": [
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:cobblestone"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:gravel"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:sand"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:andesite"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:diorite"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:granite"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:netherrack"
        },
        {
          "condition": "minecraft:block_state_property",
          "block": "minecraft:end_stone"
        }
      ]
    }
  ]
}

 

23 minutes ago, Animefan8888 said:

Try setting a breakpoint in the area before global loot modifiers are called to see why your loot modifier condition is not true.

As far as I can tell Blocks.getDrops (which does the correct calls to use the loot table modifiers) isn't called when my custom tool is used on anything except sand and gravel.

Edited by Tikaji
Posted
1 minute ago, Tikaji said:

As far as I can tell Blocks.getDrops (which does the correct calls to use the loot table modifiers) isn't called when my custom tool is used on anything except sand and gravel.

You either need to used the PlayerEvent.HarvestCheck event to say the player can harvest those blocks with your Hammer Item(s) or make your Hammer a Pickaxe by adding a ToolType via the Item.Properties::addToolType method.

 

I believe the first option is the most suitable.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Posted

I would assume that I need to add an event handler for this, but I'm not entirely sure exactly what I need within the handler. Got a good place to point me to for this?

Posted
6 minutes ago, Tikaji said:

Got a good place to point me to for this?

Not sure how much you know about Events but here is the documentation. You need to subscribe to the PlayerEvent.HarvestCheck event. And call HarvestCheck::setCanHarvest(true). Use the methods within the event to determine if the player is holding your Hammer and if they are say they can harvest the block.

  • Thanks 1

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

  • Tikaji changed the title to [1.15] Loot Table Function/Condition Issues [SOLVED]
Posted
10 hours ago, Tikaji said:

if (tool.getItem() instanceof HammerBaseItem)

This should also be specified by your loot json file:

https://github.com/MinecraftForge/MinecraftForge/blob/1.15.x/src/test/resources/data/global_loot_test/loot_modifiers/wheat_harvest.json#L5-L8

 

9 hours ago, Animefan8888 said:

but seeing as how LootModifier::doApply returns a List<ItemStack> I assume that are the drops.

This is correct.

 

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

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.

Announcements



×
×
  • Create New...

Important Information

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