Jump to content

jonaskohl

Members
  • Posts

    9
  • Joined

  • Last visited

Posts posted by jonaskohl

  1. I am trying to implement a right-click interaction between a vanilla tool and a vanilla block (so I can't use onBlockActivated or onItemUse). Everything is working fine except my call to ItemStack#attemptDamageItem, because the PlayerEntity I get from PlayerInteractEvent.RightClickBlock#getPlayer() is an instance of ClientPlayerEntity, not a ServerPlayerEntity. However, ItemStack#attemptDamageItem expects a ServerPlayerEntity only. I tried passing in null as the damager parameter, and this almost works, but the item doesn't break when reaching 0 durability. This may be, because the ITEM_DURABILITY_CHANGED trigger never fires when damager is null. Now my question: How can I get access to a ServerPlayerEntity instance, or alternatively, how can I make sure the item breaks when reaching 0 durability?

    My code looks as follows:

    Spoiler
    @SubscribeEvent
    public void onInteract(PlayerInteractEvent.RightClickBlock event) {
        World world = event.getWorld();
        ItemStack stack = event.getItemStack();
        BlockPos pos = event.getPos();
        BlockState state = world.getBlockState(pos);
        Direction face = event.getFace();
        PlayerEntity player = event.getPlayer();
    
        if (stack.getItem() instanceof ShearsItem && state.getBlock().equals(Blocks.GRASS_BLOCK) && Objects.equals(face, Direction.UP)) {
            if (!player.isCreative()) {
                if (player instanceof ServerPlayerEntity)
                    stack.attemptDamageItem(1, world.rand, (ServerPlayerEntity) player);
                else
                    stack.attemptDamageItem(1, world.rand, null);
            }
    
            BlockState above = world.getBlockState(pos.up());
            world.setBlockState(
                    pos,
                    ModBlocks.LAWN_BLOCK
                            .get()
                            .getDefaultState()
                            .with(LawnBlock.SNOWY, above.matchesBlock(Blocks.SNOW_BLOCK) || above.matchesBlock(Blocks.SNOW))
                            .with(LawnBlock.FACING, player.getHorizontalFacing().getOpposite())
            );
    
            world.playSound(player, pos, SoundEvents.BLOCK_GRASS_PLACE, SoundCategory.BLOCKS, 1.0F, 1.0F);
            player.swing(event.getHand(), true);
        }
    }

     

     

  2. I'm trying to add a custom tree to my mod. I'm using the following method to register the tree:

    //// == ElderTree.java == ////
    public class ElderTree extends Tree {
        @Nullable
        @Override
        protected ConfiguredFeature<BaseTreeFeatureConfig, ?> getTreeFeature(Random randomIn, boolean largeHive) {
            return (ConfiguredFeature<BaseTreeFeatureConfig, ?>) ModFeatures.ELDER_TREE.get();
        }
    }
    
    //// == ModFeatures.java == ////
    // [...]
    public static final Lazy<ConfiguredFeature<? extends IFeatureConfig, ?>> ELDER_TREE = register("elder_tree", () ->
            Feature.TREE.withConfiguration(Configs.ELDER_TREE_CONFIG)
                        .withPlacement(Features.Placements.HEIGHTMAP_PLACEMENT)
                        .withPlacement(Placements.ELDER_TREE_PLACEMENT)
    );
    // [...]
    public static final class Configs {
        public static final BaseTreeFeatureConfig ELDER_TREE_CONFIG;
    	// [...]
        static {
          ELDER_TREE_CONFIG = new BaseTreeFeatureConfig.Builder(
            new SimpleBlockStateProvider(ModBlocks.ELDER_LOG.get().getDefaultState()),
            new SimpleBlockStateProvider(ModBlocks.ELDER_LEAVES.get().getDefaultState()),
            //                                       Radius             | Offset    | Height
            new BlobFoliagePlacer(FeatureSpread.create(2), FeatureSpread.create(0), 3),
            //                      Base height | Height Rand A | Height Rand B
            new StraightTrunkPlacer(4, 2, 0),
            new TwoLayerFeature(1, 0, 1)
          )
            .setIgnoreVines()
            .build();
        }
    	// [...]
    }

    But whenever I try to grow a sapling or generate a new world, Minecraft crashes with the following exception:

    [13:25:21] [Server thread/FATAL] [minecraft/ThreadTaskExecutor]: Error executing task on Server
    java.lang.ClassCastException: net.minecraft.world.gen.feature.DecoratedFeatureConfig cannot be cast to net.minecraft.world.gen.feature.BaseTreeFeatureConfig
    	at net.minecraft.block.trees.Tree.attemptGrowTree(Tree.java:28) ~[forge:?] {re:classloading}
    	at team.mixxit.allotment.blocks.ModSapling.placeTree(ModSapling.java:50) ~[?:?] {re:classloading}
    	at team.mixxit.allotment.blocks.ModSapling.grow(ModSapling.java:71) ~[?:?] {re:classloading}
    	at net.minecraft.item.BoneMealItem.applyBonemeal(BoneMealItem.java:73) ~[forge:?] {re:classloading}
    	at net.minecraft.item.BoneMealItem.onItemUse(BoneMealItem.java:36) ~[forge:?] {re:classloading}
    	at net.minecraftforge.common.ForgeHooks.onPlaceItemIntoWorld(ForgeHooks.java:613) ~[forge:?] {re:classloading}
    	at net.minecraft.item.ItemStack.onItemUse(ItemStack.java:191) ~[forge:?] {re:classloading}
    	at net.minecraft.server.management.PlayerInteractionManager.func_219441_a(PlayerInteractionManager.java:359) ~[forge:?] {re:classloading}
    	at net.minecraft.network.play.ServerPlayNetHandler.processTryUseItemOnBlock(ServerPlayNetHandler.java:986) ~[forge:?] {re:classloading}
    	at net.minecraft.network.play.client.CPlayerTryUseItemOnBlockPacket.processPacket(CPlayerTryUseItemOnBlockPacket.java:45) ~[forge:?] {re:classloading}
    	at net.minecraft.network.play.client.CPlayerTryUseItemOnBlockPacket.processPacket(CPlayerTryUseItemOnBlockPacket.java:12) ~[forge:?] {re:classloading}
    	at net.minecraft.network.PacketThreadUtil.lambda$checkThreadAndEnqueue$0(PacketThreadUtil.java:19) ~[forge:?] {re:classloading}
    	at net.minecraft.util.concurrent.TickDelayedTask.run(TickDelayedTask.java:20) ~[forge:?] {re:classloading}
    	at net.minecraft.util.concurrent.ThreadTaskExecutor.run(ThreadTaskExecutor.java:139) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.util.concurrent.RecursiveEventLoop.run(RecursiveEventLoop.java:22) ~[forge:?] {re:classloading}
    	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:758) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:159) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.util.concurrent.ThreadTaskExecutor.driveOne(ThreadTaskExecutor.java:109) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.server.MinecraftServer.driveOneInternal(MinecraftServer.java:741) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.server.MinecraftServer.driveOne(MinecraftServer.java:735) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.util.concurrent.ThreadTaskExecutor.driveUntil(ThreadTaskExecutor.java:122) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.server.MinecraftServer.runScheduledTasks(MinecraftServer.java:721) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.server.MinecraftServer.func_240802_v_(MinecraftServer.java:667) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at net.minecraft.server.MinecraftServer.lambda$startServer$0(MinecraftServer.java:233) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_241] {}

    It seems that ConfiguredFeature#withPlacement(ConfiguredPlacement<?>) is the culprit, as it adds a DecoratedFeatureConfig to the feature. What is the proper way to add a placement rule to a tree?

  3. I want to add a recipe to my mod that has a block (let's say wooden planks) and a vanilla tool (let's say an axe) and I want the axe to loose durability when used in crafting. This is what I got so far (inside of ModRecipeProvider#registerRecipes):

    Ingredient axeIngredients = Ingredient.fromItems(
        () -> Items.WOODEN_AXE,
        () -> Items.STONE_AXE,
        () -> Items.GOLDEN_AXE,
        () -> Items.IRON_AXE,
        () -> Items.DIAMOND_AXE,
        () -> Items.NETHERITE_AXE
    );
    
    ShapelessRecipeBuilder.shapelessRecipe(ModBlocks.CHIPPED_OAK_PLANK.get())
        .addIngredient(Blocks.OAK_PLANKS)
        .addIngredient(axeIngredients)
        .addCriterion("has_plank", hasItem(Blocks.OAK_PLANKS))
        .build(consumer);

    However, this will consume the axe completely when crafted. How can I make the axe stay inside of the crafting grid and lose one point of durability?

    (Forge 1.16)

  4. I am using the following snippet inside of an onBlockClicked event listener to strip a custom log.

    Spoiler
    
    @SubscribeEvent
    public static void onBlockClicked(PlayerInteractEvent.RightClickBlock event) {
        final int FLAG_BLOCK_UPDATE = 1;
        final int FLAG_SEND_TO_CLIENTS = 2;
        final int FLAG_FORCE_RERENDER_MAIN_THREAD = 8;
    
        if (event.getItemStack().getItem() instanceof AxeItem) {
            World world = event.getWorld();
            BlockPos blockpos = event.getPos();
            BlockState blockstate = world.getBlockState(blockpos);
            Block block = BLOCK_STRIPPING_MAP.get(blockstate.getBlock());
            if (block != null) {
                PlayerEntity playerentity = event.getPlayer();
                world.playSound(playerentity, blockpos, SoundEvents.ITEM_AXE_STRIP, SoundCategory.BLOCKS, 1.0F, 1.0F);
                if (!world.isRemote) {
                    world.setBlockState(blockpos, block.getDefaultState()
                            .with(RotatedPillarBlock.AXIS,
                                  blockstate.get(RotatedPillarBlock.AXIS)),
                             FLAG_BLOCK_UPDATE | FLAG_SEND_TO_CLIENTS | FLAG_FORCE_RERENDER_MAIN_THREAD);
                    if (playerentity != null) {
                        playerentity.swingArm(event.getHand());
                        event.getItemStack().damageItem(1, playerentity, (entityIn) -> {
                            entityIn.sendBreakAnimation(event.getHand());
                        });
                    }
                }
            }
        }
    }

     

    Everything works as expected, except the axe doesn't "swing" as it does with vanilla blocks. It just does nothing. I tried using

    playerentity.swingArm(event.getHand());

    but that does absolutely nothing. How can I achieve a swinging tool?

  5. In my mod I have several custom flower types (instances of FlowerBlock), which I register using the DeferredRegister. Now I want to add them to the composter's registry of compostable items. I know I need to add them to ComposterBlock.CHANCES, but I don't know when exactly I need to do this. When I call ComposterBlock.CHANCES.put() in my mod's main class's constructor, I get a NullPointerException with the message 'Registry Object not present: my_mod:my_flower', even though I created the flower objects before I tried to register them. I suspect I need to call this at a later time, but I couldn't find any information about this anywhere.

×
×
  • Create New...

Important Information

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