Jump to content

Recommended Posts

Posted

Hi,

 

I'm having trouble with opening my GUI, as the tile entity (extending ITickableTileEntity, among others) will erase all stored variables, retrieved from NBT. So this isn't a problem with NBT. Also, this is a 1.15 problem.

I've tracked down the exact time that the variables reset, and it's when the GUI's screen is opened, createTileEntity() is triggered in the Block class, recreating the tile entity and overwriting the variables.

Is there a way to stop this?

 

Here's a snippet from my block's class.

@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
  return TileEntityTypes.TILE.get().create();
}

@Override
public boolean hasTileEntity(BlockState state) {
  return true;
}

 

Thanks for your help in advance, I'd be willing to send more code snippets and answer any questions.

Posted
  On 9/24/2020 at 10:07 PM, Jack Richard said:

I'm having trouble with opening my GUI, as the tile entity (extending ITickableTileEntity, among others) will erase all stored variables

Expand  

It's like there are two sides of the game that need to be synchronized, hmmmmmmmmmmmmm.

 

The client and server will not be synchronized under normal conditions, you must specify which variable you would like to sync and when (most likely in your container).

Posted
  On 9/24/2020 at 10:26 PM, ChampionAsh5357 said:

It's like there are two sides of the game that need to be synchronized, hmmmmmmmmmmmmm.

 

The client and server will not be synchronized under normal conditions, you must specify which variable you would like to sync and when (most likely in your container).

Expand  

Does it help to say when I add...

@Override
public void tick() {
	System.out.println(variable);
}

...I always get the result, whether or not world.isRemote()?

 

I use...

@Override
public CompoundNBT getUpdateTag() {
  CompoundNBT tagCompound = new CompoundNBT();
  tagCompound.putString("variable", variable);
  return tagCompound;
}

@Override
public void handleUpdateTag(CompoundNBT tag) {
  this.read(tag);
}

@Override
public void read(CompoundNBT compound)
{
  super.read(compound);
  this.inventory = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
  ItemStackHelper.loadAllItems(compound, this.inventory);
  setVariable(compound.getString("variable"));
}

@Override
public CompoundNBT write(CompoundNBT compound)
{
  super.write(compound);
  ItemStackHelper.saveAllItems(compound, this.inventory);
  compound.putString("variable", getVariable());

  return compound;
}

to synchronize the data.

 

Thanks.

Posted
  On 9/24/2020 at 11:11 PM, Jack Richard said:

this.inventory = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY); ItemStackHelper.loadAllItems(compound, this.inventory);

Expand  

This looks like copy and paste of an IInventory class, use the IItemHandler instead. You should not use the vanilla method to create your inventory.

 

  On 9/24/2020 at 11:11 PM, Jack Richard said:

@Override public CompoundNBT getUpdateTag() { CompoundNBT tagCompound = new CompoundNBT(); tagCompound.putString("variable", variable); return tagCompound; } @Override public void handleUpdateTag(CompoundNBT tag) { this.read(tag); }

Expand  

Ah yes, synchronization on block update. Something completely unnecessary when it comes to GUI. Those are synced through slots. This should only be used if you have a TER present.

  On 9/24/2020 at 11:11 PM, Jack Richard said:

...I always get the result, whether or not world.isRemote()?

Expand  

Then you fell into a trap of confirmation bias. Just because you get the same result doesn't mean it was synced correctly. It just means you probably executed the same code on both sides when it should only be on one and then synced.

Posted
  On 9/24/2020 at 11:37 PM, ChampionAsh5357 said:

Ah yes, synchronization on block update. Something completely unnecessary when it comes to GUI. Those are synced through slots. This should only be used if you have a TER present.

Then you fell into a trap of confirmation bias. Just because you get the same result doesn't mean it was synced correctly. It just means you probably executed the same code on both sides when it should only be on one and then synced.

Expand  

I forgot to mention I send Messages from the client to the server, so I am doing some syncing, I believe.

Posted
  On 9/24/2020 at 11:59 PM, Jack Richard said:

I forgot to mention I send Messages from the client to the server, so I am doing some syncing, I believe.

Expand  

Yes. Synchronization the wrong direction. Always good.

 

I doubt you need to synchronize from the client->server as this probably just uses a standard inventory and primitives.  In that case, you only need to sync from server->client. Which, you are still neglecting to listen and do.

 

Please show your entire tile entity, block, container, and screen code. I am curious on what you're doing and how you're doing it since I'm pretty sure it's some variation of vanilla code which will not work in most cases.

Posted
  On 9/25/2020 at 1:07 AM, ChampionAsh5357 said:

Yes. Synchronization the wrong direction. Always good.

 

I doubt you need to synchronize from the client->server as this probably just uses a standard inventory and primitives.  In that case, you only need to sync from server->client. Which, you are still neglecting to listen and do.

 

Please show your entire tile entity, block, container, and screen code. I am curious on what you're doing and how you're doing it since I'm pretty sure it's some variation of vanilla code which will not work in most cases.

Expand  
public class ServerContainer extends Container {

    public ServerTileEntity entity;

    public ServerContainer(final int windowId, final PlayerInventory playerInventory, final PacketBuffer data) {
        this(windowId, playerInventory, getTileEntity(playerInventory, data));
    }

    public ServerContainer(final int windowId, final PlayerInventory playerInventory,
                           final TileEntity tileEntity) {
        super(ContainerTypes.SERVER.get(), windowId);

        this.entity = (ServerTileEntity) tileEntity;

        int startX = 8;
        int startY = 84;
        int slotSizePlus2 = 18;

        for (int row = 0; row < 3; ++row) {
            for (int column = 0; column < 9; ++column) {
                this.addSlot(new Slot(playerInventory, 9 + (row * 9) + column, startX + (column * slotSizePlus2),
                        startY + (row * slotSizePlus2)));
            }
        }

        int hotbarY = 142;
        for (int column = 0; column < 9; ++column) {
            this.addSlot(new Slot(playerInventory, column, startX + (column * slotSizePlus2), hotbarY));
        }

        this.addSlot(new CustomSlot(entity, 0, 7, 35));
    }

    @Override
    public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
        ItemStack itemstack = ItemStack.EMPTY;
        Slot slot = this.inventorySlots.get(index);
        if (slot != null && slot.getHasStack()) {
            ItemStack itemstack1 = slot.getStack();
            itemstack = itemstack1.copy();
            if (index < 36) {
                if (!this.mergeItemStack(itemstack1, 36, this.inventorySlots.size(), true)) {
                    return ItemStack.EMPTY;
                }
            } else if (!this.mergeItemStack(itemstack1, 0, 36, false)) {
                return ItemStack.EMPTY;
            }

            if (itemstack1.isEmpty()) {
                slot.putStack(ItemStack.EMPTY);
            } else {
                slot.onSlotChanged();
            }
        }
        return itemstack;
    }

    @Override
    public boolean canInteractWith(PlayerEntity playerIn) {
        return true;
    }

    private static ServerTileEntity getTileEntity(final PlayerInventory playerInventory,
                                                 final PacketBuffer data) {
        Objects.requireNonNull(playerInventory, "playerInventory cannot be null");
        Objects.requireNonNull(data, "data cannot be null");
        final TileEntity tileAtPos = playerInventory.player.world.getTileEntity(data.readBlockPos());

        if (tileAtPos instanceof ServerTileEntity) {
            return (ServerTileEntity) tileAtPos;
        }
        throw new IllegalStateException("Tile entity is not correct! " + tileAtPos);
    }

}
@OnlyIn(Dist.CLIENT)
public class ServerScreen extends ContainerScreen<ServerContainer> {

    private static final ResourceLocation TEXTURES = new ResourceLocation("modid:textures/gui/server.png");
    private final PlayerInventory player;
    private ServerTileEntity entity;
    private TextFieldWidget carrierName;

    public ServerScreen(ServerContainer container, PlayerInventory player, ITextComponent title) {
        super(container, player, title);
        this.player = player;
        this.entity = getTileEntity(player, container);
        this.guiLeft = 0;
        this.guiTop = 0;
        this.xSize = 176;
        this.ySize = 166;
    }

    @Override
    protected void init() {
        super.init();

        int x = (this.width - this.xSize) / 2;
        int y = (this.height - this.ySize) / 2;

        this.carrierName = new TextFieldWidget(font, x + 84, y + 11, 86, 18, "Carrier Name");
        this.carrierName.setMaxStringLength(13);
        this.carrierName.setEnableBackgroundDrawing(false);
        this.carrierName.setVisible(true);
        this.carrierName.setTextColor(16777215);
        this.carrierName.setText(this.entity.getCarrierName());
        System.out.println(this.entity.getCarrierName());
        System.out.println("Above set");
    }

    private static ServerTileEntity getTileEntity(final PlayerInventory playerInventory, final ServerContainer container) {
        Objects.requireNonNull(playerInventory, "playerInventory cannot be null");
        final TileEntity tileAtPos = playerInventory.player.world.getTileEntity(container.entity.getPos());

        if (tileAtPos instanceof ServerTileEntity) {
            return (ServerTileEntity) tileAtPos;
        }
        throw new IllegalStateException("Tile entity is not correct! " + tileAtPos);
    }

    @Override
    public void render(final int mouseX, final int mouseY, final float partialTicks) {
        this.renderBackground();
        this.carrierName.render(mouseX, mouseY, partialTicks);
        super.render(mouseX, mouseY, partialTicks);
        this.renderHoveredToolTip(mouseX, mouseY);
    }

    @Override
    public boolean mouseClicked(double p_mouseClicked_1_, double p_mouseClicked_3_, int p_mouseClicked_5_) {
        this.carrierName.mouseClicked(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_);
        return super.mouseClicked(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_);
    }

    @Override
    protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
        RenderSystem.color4f(1.0f, 1.0f, 1.0f, 1.0f);
        this.getMinecraft().getTextureManager().bindTexture(TEXTURES);

        int x = (this.width - this.xSize) / 2;
        int y = (this.height - this.ySize) / 2;

        this.blit(x, y, 0, 0, 176, 166);
        this.font.drawString("Server", x + 10, y + 10, 16777215);

        this.entity.setCarrierName(carrierName.getText());
        ModClass.INSTANCE.sendToServer(new CarrierServerSync(carrierName.getText(), this.entity.getPos()));
    }

    @Override
    protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
        super.drawGuiContainerForegroundLayer(mouseX, mouseY);

        int x = (this.width - this.xSize) / 2;
        int y = (this.height - this.ySize) / 2;

        this.addButton(new Button(x + 30, y + 33, 50, 20, "Register", new Button.IPressable() {
            @Override
            public void onPress(Button p_onPress_1_) {
                System.out.println("pressed");
                if (!entity.getStackInSlot(0).isEmpty()) {
                    System.out.println("not empty");
                    if (entity.getStackInSlot(0).getStack().getTag() != null) {
                        System.out.println("not null");
                        CompoundNBT compoundNBT = entity.getStackInSlot(0).getTag().copy();
                        compoundNBT.putString("carrier", carrierName.getText());
                        entity.getStackInSlot(0).setTag(compoundNBT);
                    } else {
                        System.out.println("null");
                        CompoundNBT compoundNBT = new CompoundNBT();
                        compoundNBT.putString("carrier", carrierName.getText());
                        entity.getStackInSlot(0).getStack().setTag(compoundNBT);
                    }
                }
            }
        }));

        this.addButton(carrierName);
    }

}
public class ServerTileEntity extends TileEntity implements INamedContainerProvider, ITickableTileEntity, IInventory {

    private NonNullList<ItemStack> inventory = NonNullList.<ItemStack>withSize(1, ItemStack.EMPTY);
    private IItemHandlerModifiable items = createHandler();
    private LazyOptional<IItemHandlerModifiable> itemHandler = LazyOptional.of(() -> items);
    private String carrierName = "";

    public ServerTileEntity(TileEntityType<?> tileEntityTypeIn) {
        super(tileEntityTypeIn);
    }

    public ServerTileEntity(){
        super(TileEntityTypes.SERVER.get());
    }

    @Override
    public ITextComponent getDisplayName() {
        return new TranslationTextComponent("container.server");
    }

    @Override
    public Container createMenu(int p_createMenu_1_, PlayerInventory p_createMenu_2_, PlayerEntity p_createMenu_3_) {
        return new ServerContainer(p_createMenu_1_, p_createMenu_2_, this);
    }

    @Override
    public void tick() {
        
    }

    @Override
    public SUpdateTileEntityPacket getUpdatePacket() {
        CompoundNBT tagCompound = new CompoundNBT();
        tagCompound.putString("carrier", carrierName);
        this.write(tagCompound);
        SUpdateTileEntityPacket pack = new SUpdateTileEntityPacket(pos, 0, tagCompound);
        return pack;
    }

    @Override
    public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) {
        this.read(pkt.getNbtCompound());
    }

    @Override
    public CompoundNBT getUpdateTag() {
        CompoundNBT tagCompound = new CompoundNBT();
        tagCompound.putString("carrier", carrierName);
        return tagCompound;
    }

    @Override
    public void handleUpdateTag(CompoundNBT tag) {
        this.read(tag);
    }

    public void setCarrierName(String carrierName) {
        this.carrierName = carrierName;
    }

    public String getCarrierName() {
        return this.carrierName;
    }

    @Override
    public int getSizeInventory() {
        return inventory.size();
    }

    @Override
    public boolean isEmpty() {
        for(ItemStack stack : this.inventory) {
            if(!stack.isEmpty()) return false;
        }
        return true;
    }

    @Override
    public ItemStack getStackInSlot(int index) {
        return inventory.get(index);
    }

    @Override
    public ItemStack decrStackSize(int index, int count) {
        return ItemStackHelper.getAndSplit(this.inventory, index, count);
    }

    @Override
    public void setInventorySlotContents(int index, ItemStack stack) {
        this.inventory.set(index, stack);
    }

    @Override
    public ItemStack removeStackFromSlot(int index) {
        return ItemStackHelper.getAndRemove(this.inventory, index);
    }

    @Override
    public boolean isUsableByPlayer(PlayerEntity player) {
        return true;
    }

    @Override
    public void clear() {
        this.inventory.clear();
    }

    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nonnull Direction side) {
        if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            return itemHandler.cast();
        }
        return super.getCapability(cap, side);
    }

    @Override
    public void read(CompoundNBT compound)
    {
        super.read(compound);
        this.inventory = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
        ItemStackHelper.loadAllItems(compound, this.inventory);
        setCarrierName(compound.getString("carrier"));
    }

    private IItemHandlerModifiable createHandler() {
        return new InvWrapper(this);
    }

    @Override
    public CompoundNBT write(CompoundNBT compound)
    {
        super.write(compound);
        ItemStackHelper.saveAllItems(compound, this.inventory);
        compound.putString("carrier", getCarrierName());

        return compound;
    }

}
public class Server extends Block {

    private static final VoxelShape SHAPE = Block.makeCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 32.0D, 16.0D);

    public static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING;

    public Server(Properties properties) {
        super(properties);

        this.setDefaultState(this.getStateContainer().getBaseState().with(FACING, Direction.NORTH));
    }

    @Override
    public TileEntity createTileEntity(BlockState state, IBlockReader world) {
        return TileEntityTypes.SERVER.get().create();
    }

    @Override
    public boolean hasTileEntity(BlockState state) {
        return true;
    }

    @Override
    protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
        builder.add(FACING);
    }

    @Override
    public BlockState getStateForPlacement(BlockItemUseContext context) {
        return this.getDefaultState().with(FACING, context.getPlacementHorizontalFacing().getOpposite());
    }

    @Override
    public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
        return SHAPE;
    }

    @Override
    public ActionResultType onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) {
        TileEntity te = worldIn.getTileEntity(pos);
        if (te != null && te instanceof ServerTileEntity && !worldIn.isRemote) {
            NetworkHooks.openGui((ServerPlayerEntity) player, (ServerTileEntity) te, pos);
        }

        return super.onBlockActivated(state, worldIn, pos, player, handIn, hit);
    }

}

 

My goal is to get the data from the TextFieldWidget, and save it in NBT tags, and be able to retreive it later, putting the text back in the field.

Yes, I know; most of this code won't be the "recommended way" of doing any of this, I've been really trying though.

 

Let me know if you need any more information.

Thanks.

Posted
  On 9/25/2020 at 1:17 AM, Jack Richard said:

TileEntity implements INamedContainerProvider, ITickableTileEntity, IInventory

Expand  

You are using IInventory. Go and fix that and properly attach it with capabilities. But I won't be so stingy since you have been trying and cooperating so apologies for my agressiveness.

 

As a precursor, try to avoid using Server or Client in your names, it confuses everyone.

  On 9/25/2020 at 1:17 AM, Jack Richard said:

tagCompound.putString("carrier", carrierName); this.write(tagCompound);

Expand  

You're writing the carrier name twice?

  On 9/25/2020 at 1:17 AM, Jack Richard said:

ModClass.INSTANCE.sendToServer(new CarrierServerSync(carrierName.getText(), this.entity.getPos()));

Expand  

You're doing this every tick, only send it when the button is pressed.

  On 9/25/2020 at 1:17 AM, Jack Richard said:

if (entity.getStackInSlot(0).getStack().getTag() != null) { System.out.println("not null"); CompoundNBT compoundNBT = entity.getStackInSlot(0).getTag().copy(); compoundNBT.putString("carrier", carrierName.getText()); entity.getStackInSlot(0).setTag(compoundNBT); } else { System.out.println("null"); CompoundNBT compoundNBT = new CompoundNBT(); compoundNBT.putString("carrier", carrierName.getText()); entity.getStackInSlot(0).getStack().setTag(compoundNBT); }

Expand  

This should not really be handled on the client once again. This is not necessary if you send the information to the server. You will need to resync the values anyways whenever the inventory is opened regardless.

Finally, if your container is not registered using IForgeContainerType, then the packet information will never be sent to the client. You should also store the block pos and not the te itself. That's rather pointless to do as all it's used for sending the position back to the server. The tile entity will still not store the position anyways.

Posted
  On 9/25/2020 at 1:31 AM, ChampionAsh5357 said:

You are using IInventory. Go and fix that and properly attach it with capabilities. But I won't be so stingy since you have been trying and cooperating so apologies for my agressiveness.

Expand  

I understand that IInventory is not accepted, so I'll be working to fix that soon. No problem, I'm just happy with whatever you're able to contribute. 

 

  On 9/25/2020 at 1:31 AM, ChampionAsh5357 said:

As a precursor, try to avoid using Server or Client in your names, it confuses everyone.

Expand  

Yeah, that wasn't the best choice.

 

  On 9/25/2020 at 1:31 AM, ChampionAsh5357 said:

You're writing the carrier name twice?

Expand  

I guess so. I was a little confused once functions like getUpdatePacket() and onDataPacket() were used.

 

  On 9/25/2020 at 1:31 AM, ChampionAsh5357 said:

You're doing this every tick, only send it when the button is pressed.

This should not really be handled on the client once again. This is not necessary if you send the information to the server. You will need to resync the values anyways whenever the inventory is opened regardless.

Expand  

I'm sending the data every tick, the button writes the data to an item in the one slot of the GUI. Here's the code for the .sendtoServer() handler:

public static void handle(CarrierServerSync msg, Supplier<NetworkEvent.Context> ctx) {
        ctx.get().enqueueWork(() -> {
            PlayerEntity sender = ctx.get().getSender();
            ServerTileEntity server = getTileEntity(sender.inventory, msg.tileEntity);
            server.setCarrierName(msg.data);
        });
        ctx.get().setPacketHandled(true);
    }

    private static ServerTileEntity getTileEntity(final PlayerInventory playerInventory, final BlockPos tileEntity) {
        Objects.requireNonNull(playerInventory, "playerInventory cannot be null");
        final TileEntity tileAtPos = playerInventory.player.world.getTileEntity(tileEntity);

        if (tileAtPos instanceof ServerTileEntity) {
            return (ServerTileEntity) tileAtPos;
        }
        throw new IllegalStateException("Tile entity is not correct! " + tileAtPos);
    }

This is probably not the best way to do this...

 

  On 9/25/2020 at 1:31 AM, ChampionAsh5357 said:

This should not really be handled on the client once again. This is not necessary if you send the information to the server. You will need to resync the values anyways whenever the inventory is opened regardless.

Finally, if your container is not registered using IForgeContainerType, then the packet information will never be sent to the client. You should also store the block pos and not the te itself. That's rather pointless to do as all it's used for sending the position back to the server. The tile entity will still not store the position anyways.

Expand  

Luckily, I do have my container, messages, and tile entity registered. 

Looping back to my original theory, is Block#createTileEntity() run when you open a GUI?

 

Thanks again.

Posted
  On 9/25/2020 at 1:43 AM, Jack Richard said:

I'm sending the data every tick, the button writes the data to an item in the one slot of the GUI. Here's the code for the .sendtoServer() handler:

Expand  

That still makes no sense. You're just bottlenecking the network. The data doesn't change until you send it. Also, the button shouldn't be the one doing it. It should be handled on the server once again. NOTHING should be handled on the client itself. It all gets synchronized via the gui. Only thing that doesn't is the string which should be what you send on button click.

  On 9/25/2020 at 1:43 AM, Jack Richard said:

Luckily, I do have my container, messages, and tile entity registered. 

Expand  

You missed the part where I said IForgeContainerType. Doesn't matter if their registered. If it's not using the correct type it won't send the packet.

  On 9/25/2020 at 1:43 AM, Jack Richard said:

Looping back to my original theory, is Block#createTileEntity() run when you open a GUI?

Expand  

Not being rude, the original theory is wrong. The client doesn't hold data from the server. It will be reinitialized since it's pulling information from the empty client container.

Posted
  On 9/25/2020 at 1:53 AM, ChampionAsh5357 said:

That still makes no sense. You're just bottlenecking the network. The data doesn't change until you send it. Also, the button shouldn't be the one doing it. It should be handled on the server once again. NOTHING should be handled on the client itself. It all gets synchronized via the gui. Only thing that doesn't is the string which should be what you send on button click.

You missed the part where I said IForgeContainerType. Doesn't matter if their registered. If it's not using the correct type it won't send the packet.

Not being rude, the original theory is wrong. The client doesn't hold data from the server. It will be reinitialized since it's pulling information from the empty client container.

Expand  

I know, it's very confusing, and frankly, I might just rework the GUI if I can't get this to work, anyway.

Is it possible to get data from the Screen class to the TileEntity class? 

 

Also, should I implement IForgeContainerType in my Container class?

I understand, the original theory was a little far-fetched. So an empty client container could be it? Just trying to understand.

 

Thanks again.

Posted
  On 9/25/2020 at 2:04 AM, Jack Richard said:

Is it possible to get data from the Screen class to the TileEntity class? 

Expand  

Yes, that's the use of a packet through the network. But that should only be sent as needed as otherwise you just bottleneck the network creating more issues.

  On 9/25/2020 at 2:04 AM, Jack Richard said:

Also, should I implement IForgeContainerType in my Container class?

Expand  

No, that should be used in your registry instance for your ContainerType.

  On 9/25/2020 at 2:04 AM, Jack Richard said:

So an empty client container could be it? Just trying to understand.

Expand  

Imagine it like this. You have two instances, a server and the client. The server creates a container with a specific window id. The client creates a container with the same window id and a screen that can get information from the container. The server container sends default information to the client container which is read by the screen. A client screen clicks something, which gets sent as a packet to the server container, which updates the client container, which updates the screen. Note that the client creates a new instance of the container on open so the information needs to be synced. By default, only slots and tracked integers are synced. If you want to handle something else, you need to send it yourself.

Posted

You can send data from client (in this case screen), to the server (container/tileentity) using packets.

And no, please read what he said again:

  Quote

Finally, if your container is not registered using IForgeContainerType, then the packet information will never be sent to the client.

Expand  

 

 

Posted
  On 9/25/2020 at 2:18 AM, ChampionAsh5357 said:

Yes, that's the use of a packet through the network. But that should only be sent as needed as otherwise you just bottleneck the network creating more issues.

No, that should be used in your registry instance for your ContainerType.

Expand  

Got it, and got it.

 

  On 9/25/2020 at 2:18 AM, ChampionAsh5357 said:

Imagine it like this. You have two instances, a server and the client. The server creates a container with a specific window id. The client creates a container with the same window id and a screen that can get information from the container. The server container sends default information to the client container which is read by the screen. A client screen clicks something, which gets sent as a packet to the server container, which updates the client container, which updates the screen. Note that the client creates a new instance of the container on open so the information needs to be synced. By default, only slots and tracked integers are synced. If you want to handle something else, you need to send it yourself.

Expand  

Thanks for explaining it to me, I'll try to wrap my head around that, and send an update soon.

 

Thank you!

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.