Jump to content

Recommended Posts

Posted

My goal is to create a block. Right-clicking on the block opens a GUI, a simple window that contains an EditBox and a button. When I press the button, the value of the EditBox should be saved persistently, so that in every gaming session, it is retrieved and automatically inserted back into the window when I right-click again.

The GUI is implemented with the following code:

public class PadGui extends Screen {
...
    public PadGui(String title, BlockState padblockState, String stage, BlockEntity blockEntity) {
        super(Component.literal(title));
        this.title = title;
        this.padBlockState = padblockState;
        this.stage = stage;
        this.blockEntity = (PadBlockEntity) blockEntity;
    }

  	@Override
    protected void init() {
      super.init();
      ...
      LabelWidget passwordLabel = new LabelWidget(this.width / 2 - widthRef / 2, heightRef - 10, "Password", true);
      this.inputPassword = new EditBox(this.font, this.width / 2 - widthRef / 2, heightRef, widthRef, 20, Component.literal("Password"));
      Button.Builder confirmInsertBtnBuilder = new Button.Builder(Component.literal("Save Password"), button -> this.onSavePassword(inputPassword.getValue()));
      confirmInsertBtnBuilder.width(widthRef);
      confirmInsertBtnBuilder.pos(this.width / 2 - widthRef / 2, heightRef + 65);
      confirmInsertButton = confirmInsertBtnBuilder.build();
      confirmInsertButton.active = false;

      addRenderableWidget(passwordLabel);
      addRenderableWidget(inputPassword);
      addRenderableWidget(confirmInsertButton);
	}

    private void onSavePassword(String password) {
      this.blockEntity.setPassword(password);
      onClose();
    }

    @Override
      public void onClose() {
        PadBlockPacket padBlockPacket = new PadBlockPacket(this.blockEntity.getPos(), this.blockEntity.getSupportBlockPos(), this.blockEntity.getPassword());
        PadLockDoorMod.INSTANCE.sendToServer(padBlockPacket);
        Minecraft.getInstance().setScreen(null);
    }
}

This is code for BlockEntity:
 

public class PadBlockEntity extends BlockEntity {
    private BlockPos pos;
    private BlockPos supportBlockPos;
    private String password;
  
    public PadBlockEntity(BlockPos pos, BlockState state) {
        super(PadLockDoorMod.PAD_BLOCK_ENTITY.get(), pos, state);
        this.pos = pos;
    }

    public BlockPos getPos() {
        return pos;
    }

    public void setPos(BlockPos pos) {
        this.pos = pos;
    }

    public BlockPos getSupportBlockPos() {
        return supportBlockPos;
    }

    public void setSupportBlockPos(BlockPos supportBlockpos) {
        this.supportBlockPos = supportBlockpos;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    protected void saveAdditional(CompoundTag nbt) {
        super.saveAdditional(nbt);
        nbt.putString("password", this.getPassword());
        nbt.putLong("pos", this.getPos().asLong());
        nbt.putLong("supportBlockPos", this.getSupportBlockPos().asLong());
    }

    @Override
    public void load(CompoundTag nbt) {
        super.load(nbt);
        this.password = nbt.getString("password");
        this.pos = BlockPos.of(nbt.getLong("pos"));
        this.supportBlockPos = BlockPos.of(nbt.getLong("supportBlockPos"));
    }

    @Override
    public CompoundTag getUpdateTag() {
        super.getUpdateTag();
        return saveWithoutMetadata();
    }

    @Override
    public void handleUpdateTag(CompoundTag nbt) {
        super.handleUpdateTag(nbt);
        this.load(nbt);
    }
}

From this code, my doubts begin. If I understand correctly, getUpdateTag is called by the server, and handleUpdateTag is called by the client to synchronize data from the server to the client, right?

Then I read from here https://forge.gemwire.uk/wiki/SimpleChannel that to synchronize data from the client to the server, I need to send a data packet to the server using SimpleChannel. So, I created a class representing the message, a class representing the packet, and then registered the SimpleChannel with the message in the mod's main class.

This is the class representing the packet. It contains the encode and decode methods for the packet data:
 

public class PadBlockPacket {
    private BlockPos pos;
    private BlockPos supportBlockPos;
    private final String password;

    public PadBlockPacket(BlockPos pos, BlockPos supportBlockPos, String password) {
        this.pos = pos;
        this.supportBlockPos = supportBlockPos;
        this.password = password;
    }
    public void encode(FriendlyByteBuf friendlyByteBuf) {
        friendlyByteBuf.writeBlockPos(this.supportBlockPos);
        friendlyByteBuf.writeBlockPos(this.pos);
        friendlyByteBuf.writeUtf(this.password);
    }

    public static PadBlockPacket decode(FriendlyByteBuf buffer) {
        BlockPos supportBlockPos = buffer.readBlockPos();
        BlockPos pos = buffer.readBlockPos();
        String password = buffer.readUtf(32767);
        return new PadBlockPacket(pos, supportBlockPos, password);
    }

    public BlockPos getPos() {
        return pos;
    }

    public BlockPos getSupportBlockPos() {
        return supportBlockPos;
    }

    public String getPassword() {
        return password;
    }
}

This is the packet handler:
 

public class PadLockPacketServerHandler {
    public static void handle(PadBlockPacket padBlockPacket, Supplier<NetworkEvent.Context> ctx) {
        ctx.get().enqueueWork(() -> {
            ServerPlayer player = ctx.get().getSender();
            Level level = player.level;
            BlockPos pos = padBlockPacket.getPos();
            BlockPos supportBlockPos = padBlockPacket.getSupportBlockPos();
            String password = padBlockPacket.getPassword();
            PadBlockEntity blockEntity = (PadBlockEntity) level.getBlockEntity(pos);
            blockEntity.setPos(pos);
            blockEntity.setSupportBlockPos(supportBlockPos);
            blockEntity.setPassword(password);
        });
        ctx.get().setPacketHandled(true);
    }
}

I assume that the encode method is called by the client, and the decode and handle methods are called by the server when it receives data from the packet through SimpleChannel, right?

Finally, this is how I register the SimpleChannel and the message in the main class of the mod:
 

public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(
  new ResourceLocation(MODID, "main"),
  () -> PROTOCOL_VERSION,
  PROTOCOL_VERSION::equals,
  PROTOCOL_VERSION::equals
);

public PadLockDoorMod() {
    IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();

    ...
    INSTANCE.registerMessage(0, PadBlockPacket.class, PadBlockPacket::encode, PadBlockPacket::decode, PadLockPacketServerHandler::handle);
}


However, this doesn't work; currently, the client and server data aren't synchronized. It seems that when clicking the button in the GUI, the BlockEntity isn't updated on the server thread. So, I have two questions:

  1. Is the approach for persisting block information and the GUI correct?
  2. In the tutorial at the link above, it's also mentioned to use a packet handler for client-server data, showing this code:
    // In Packet class
    public static void handle(MyClientMessage msg, Supplier<NetworkEvent.Context> ctx) {
        ctx.get().enqueueWork(() ->
            // Make sure it's only executed on the physical client
            DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientPacketHandlerClass.handlePacket(msg, ctx))
        );
        ctx.get().setPacketHandled(true);
    }
    
    // In ClientPacketHandlerClass
    public static void handlePacket(MyClientMessage msg, Supplier<NetworkEvent.Context> ctx) {
        // Do stuff
    }

    This confuses me because I had previously understood that to synchronize data from the server to the client, it was sufficient to implement the getUpdateTag and handleUpdateTag methods on the BlockEntity and not use data packets in this case. In that case, how should the handlePacket method be implemented in my situation?

 

I would like to know if my current understanding of how data synchronization between the client and server works is correct or incorrect and incomplete. Thank you for your help.

Posted

I managed to solve it.

I'm not sure why exactly, but in my class that extends EntityBlock, if I implement the newBlockEntity method like this:

@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
  return new PadBlockEntity(pos, state);
}

it doesn't work. But it does work if I do it this way:

@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
	return PadLockDoorMod.PAD_BLOCK_ENTITY.get().create(pos, state);
}

I don't know why. Maybe you could help me with this, please.

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,  I'm using Forge 47.3.0 for Minecraft 1.20.1 I apologise if this is obvious I am very new to modding for Minecraft. I sucessfully made a mod that launched without errors or crashes (without it doing anything) but in order to add the features I need, I need to add "Custom Portal API [Forge]" as a dependency. However no matter the way I've tried to acheive this, it crashes. I am pretty sure it's not the way I'm putting it in the repositories, the dependencies or the way I'm refrencing it, as I've a hundred diffrent combinations and multiple Maven methods. And on all those diffrent variations I still get this crash: pastebin.com/UhumzZCZ Any tips would be invaluable as I've been loosing my mind over this!
    • Hi, i'm really having problems trying to set the texture to my custom item. I thought i'm doing everything correctly, but all i see is the missing texture block for my item. I am trying this for over a week now and getting really frustrated. The only time i could make the texture work, was when i used an older Forge version (52.0.1) for Minecraft (1.21.4). Was there a fundamental change for textures and models somewhere between versions that i'm missing? I started with Forge 54.1.0 and had this problem, so in my frustration i tried many things: Upgrading to Forge 54.1.1, created multiple new projects, workspaces, redownloaded everything and setting things up multiple times, as it was suggested in an older thread. Therea are no errors in the console logs, but maybe i'm blind, so i pasted the console logs to pastebin anyway: https://pastebin.com/zAM8RiUN The only time i see an error is when i change the models JSON file to an incorrect JSON which makes sense and that suggests to me it is actually reading the JSON file.   I set the github repository to public, i would be so thankful if anyone could take a look and tell me what i did wrong: https://github.com/xLorkin/teleport_pug_forge   As a note: i'm pretty new to modding, this is my first mod ever. But i'm used to programming. I had some up and downs, but through reading the documentation, using google and experimenting, i could solve all other problems. I only started modding for Minecraft because my son is such a big fan and wanted this mod.
    • Please read the FAQ (link in orange bar at top of page), and post logs as described there.
    • Hello fellow Minecrafters! I recently returned to Minecraft and realized I needed a wiki that displays basic information easily and had great user navigation. That’s why I decided to build: MinecraftSearch — a site by a Minecraft fan, for Minecraft fans. Key Features So Far Straight-to-the-Point Info: No extra fluff; just the essentials on items, mobs, recipes, loot and more. Clean & Intuitive Layout: Easy navigation so you spend less time scrolling and more time playing. Optimized Search: Search for anything—items, mobs, blocks—and get results instantly. What I’m Thinking of Adding More data/information: Catch chances for fishing rod, traveling villager trades, biomes info and a lot more. The website is still under development and need a lot more data added. Community Contributions: Potential for user-uploaded tips for items/mobs/blocks in the future. Feature Requests Welcome: Your ideas could shape how the wiki evolves! You can see my roadmap at the About page https://minecraftsearch.com/about I’d love for you to check out MinecraftSearch and see if it helps you find the info you need faster. Feedback is crucial—I want to develop this further based on what the community needs most, so please let me know what you think. Thanks, and happy crafting!
    • Instructions on how to install newer Java can be found in the FAQ
  • Topics

×
×
  • Create New...

Important Information

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