Jump to content

[SOLVED] 1.16.5 - setBlock() usage from my custom Item.use() override makes only temporary changes to the world


Recommended Posts

Posted (edited)

I was asked to make a separate thread for this instead of tacking on to another setBlock() question, so here goes.

I'm just testing out trying to modify the world with setBlock(), and it's just not behaving like I'd expect.  

The other question answered my own questions about the integer parameters for setBlock(), so I'm now passing in Constants.BlockFlags.DEFAULT.  This really is just like the behavior of the setBlockAndUpdate() method anyway.... which I was trying at one point.

The behavior I'm seeing is that the blocks appear in the world, but disappear when interacting with them and the previous blocks (if any) reappear.  All of these blocks are reverted and are not saved if I quit to title and restart the world.  I can climb on them and bump off of them, but that's about it.

This is launching from the Forge MDK runClient configuration.  (Edit: specifically, forge-1.16.5-36.1.4-mdk via IntelliJ IDEA)

Most people's questions about setBlock() seem quite straightforward and like it just works for them.

It's almost like a problem passing in immediate variables that get deleted when they go out of scope ... but the few examples I find are using defaultBlockState() and aren't calling new or anything... ?

I can use the ModBlocks.MYBLOCK blocks normally within the game otherwise... as in, place them as in game blocks from creative/survival mode, etc.. they only misbehave from the Item.use() override...

Other changes to the current chunk made after inserting these blocks from normal creative/survival game interactions are saved.

 

package com.mydomain.testmod;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.command.arguments.BlockStateArgument;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.common.util.Constants;

public class ItemTest extends Item {

    public ItemTest(Properties prop) {
        super(prop);
    }

    @Override
    public ActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
        if (world.isClientSide)
        {
            if (hand == Hand.MAIN_HAND)
            {
                BlockPos pos = new BlockPos(player.position());// RayTraceUtil.getTargetBlockPos(player, world, 25);
                Block targetBlock = ModBlocks.MYBLOCK.get();

                if(pos != null) {
                    for (int y = 0; y < 10; y++) {
                        for (int i = -5; i <= 5; i++) {
                            if ((i != 0) || (y > 1)) {
                                world.setBlock(pos.offset(5, y, i), targetBlock.defaultBlockState(), Constants.BlockFlags.DEFAULT);
                            }

                            world.setBlock(pos.offset(i, y, 5), targetBlock.defaultBlockState(), Constants.BlockFlags.DEFAULT);
                            world.setBlock(pos.offset(-5, y, i), targetBlock.defaultBlockState(), Constants.BlockFlags.DEFAULT);
                            world.setBlock(pos.offset(i, y, -5), targetBlock.defaultBlockState(), Constants.BlockFlags.DEFAULT);
                        }
                    }

                    return ActionResult.pass(player.getItemInHand(hand));
                }
            }
        }

        return super.use(world, player, hand);
    }
}

The item is registered like so:

public class ModItems {
    public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, TestMod.MODID);

    public static final RegistryObject<Item> ITEMTEST = ITEMS.register("itemtest", () -> new ItemTest(new Item.Properties().tab(ItemGroup.TAB_MISC)));

    public static void init() {
    	ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus());
    }
}

... and the block:

public class ModBlocks {
	public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, TestMod.MODID);
	
    public static final RegistryObject<Block> MYBLOCK = register("myblock", () -> new Block(AbstractBlock.Properties.of(Material.STONE).requiresCorrectToolForDrops().sound(SoundType.STONE)));

    static void init() {
    	BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus());
    }

    private static <T extends Block> RegistryObject<T> registerNoItem(String name, Supplier<T> block) {
    	return BLOCKS.register(name, block);
    }

    private static <T extends Block> RegistryObject<T> register(String name, Supplier<T> block) {
    	RegistryObject<T>  ret = registerNoItem(name, block);
    	ModItems.ITEMS.register(name, () -> new BlockItem(ret.get(), new Item.Properties().tab(ItemGroup.TAB_BUILDING_BLOCKS)));
    	return ret;
    }
}

 

Usually, I'd have made my own thread from the start... but the other thread basically was answering my main question already (setBlock integer parameter usage), so...  :)

Edited by wintermaker
is this how you mark solved?
Posted
3 minutes ago, ChampionAsh5357 said:

You messed up your check. You're only supposed to execute when not on the client.

Ok... I knew that was a potential issue when running on a server... but I thought in single player mode there was only the client anyway.  (I'm pretty new)

So... apparently this is running twice, from both the client and a local server instance that's just not listening for external connections?  Obviously so... as something happened in both conditions.

I mean, it makes sense.  I'm not sure why I didn't try that.  Thanks!

  • wintermaker changed the title to [SOLVED] 1.16.5 - setBlock() usage from my custom Item.use() override makes only temporary changes to the world

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hi everyone, I'm currently developing a Forge 1.21 mod for Minecraft and I want to display a custom HUD overlay for a minigame. My goal: When the game starts, all players should see an item/block icon (from the base game, not a custom texture) plus its name/text in the HUD – similar to how the bossbar overlay works. The HUD should appear centered above the hotbar (or at a similar prominent spot), and update dynamically (icon and name change as the target item changes). What I've tried: I looked at many online tutorials and several GitHub repos (e.g. SeasonHUD, MiniHUD), but most of them use NeoForge or Forge versions <1.20 that provide the IGuiOverlay API (e.g. implements IGuiOverlay, RegisterGuiOverlaysEvent). In Forge 1.21, it seems that neither IGuiOverlay nor RegisterGuiOverlaysEvent exist anymore – at least, I can't import them and they are missing from the docs and code completion. I tried using RenderLevelStageEvent as a workaround but it is probably not intended for custom HUDs. I am not using NeoForge, and switching the project to NeoForge is currently not an option for me. I tried to look at the original minecraft source code to see how elements like hearts, hotbar etc are drawn on the screen but I am too new to Minecraft modding to understand. What I'm looking for: What is the correct way to add a custom HUD element (icon + text) in Forge 1.21, given that the previous overlay API is missing? Is there a new recommended event, callback, or method in Forge 1.21 for custom HUD overlays, or is everyone just using a workaround? Is there a minimal open-source example repo for Forge 1.21 that demonstrates a working HUD overlay without relying on NeoForge or deprecated Forge APIs? My ideal solution: Centered HUD element with an in-game item/block icon (from the base game's assets, e.g. a diamond or any ItemStack / Item) and its name as text, with a transparent background rectangle. It should be visible to the players when the mini game is running. Easy to update the item (e.g. static variable or other method), so it can change dynamically during the game. Any help, code snippets, or up-to-date references would be really appreciated! If this is simply not possible right now in Forge 1.21, it would also help to know that for sure. Thank you very much in advance!
    • The simple answer is there is not an easy way. You would need to know how to program in Java, as well as at least some familiarity with how Forge works so you could port the differences. You would also need the sourcecode for the original mod, and permission from the author to modify it, if they did not use some sort of open source license. So it's not impossible, but it would take some effort, but doing so would open up a whole new world of possibilities for you!
    • Does it still crash if you remove holdmyitems? Looks like that mod doesn't work on a server as far as I can tell from the error.  
    • Crashes the server when trying to start. Error code -1. Log  
  • Topics

×
×
  • Create New...

Important Information

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