Posted May 5, 20223 yr Hey Guys, i'm trying to create a custom Jukebox which allows starting and stopping the current disc. I've added a play and stop button in my Menu Screen to controll the play state but for some reason nothing happens if i click my buttons. Menu: Spoiler public class JukeBoxMenu extends AbstractContainerMenu { private final ContainerLevelAccess levelAccess; private final InvWrapper playerInvWrapper; private final ItemStackHandler container; private int lastHotBarIndex, lastInventoryIndex, lastJukeBoxIndex, discPlayerSlotIndex; private final JukeboxBlockEntity blockEntity; public JukeBoxMenu(int containerId, Inventory inventory, JukeboxBlockEntity blockEntity, ContainerLevelAccess levelAccess) { super(Vanilla_PlusMenuTypes.JUKE_BOX_MENU, containerId); this.levelAccess = levelAccess; this.playerInvWrapper = new InvWrapper(inventory); this.container = blockEntity.getContainer(); this.blockEntity = blockEntity; setupJukeBoxSlots(); setupPlayerSlots(); } private void setupJukeBoxSlots() { int slotIndex = 0; slotIndex = placeCol(8, 3, 4, slotIndex); slotIndex = placeCol(8 + 18, 3, 4, slotIndex); this.discPlayerSlotIndex = slotIndex; addSlot(new SlotItemHandler(this.container, slotIndex++, 80, 30)); slotIndex = placeCol(134, 3, 4, slotIndex); placeCol(134 + 18, 3, 4, slotIndex); lastJukeBoxIndex = slots.size(); } private int placeCol(int x, int y, int amount, int startIndex) { for (int i = 0; i < amount; i++) { addSlot(new SlotItemHandler(this.container, startIndex++, x, y + 18 * i)); } return startIndex; } private void setupPlayerSlots() { int index = 0; //Hot bar for (int col = 0; col < 9; col++) { addSlot(new SlotItemHandler(this.playerInvWrapper, index++, 8 + 18 * col, 83 + 18 * 3)); } lastHotBarIndex = slots.size(); //Inventory for (int row = 0; row < 3; row++) { for (int col = 0; col < 9; col++) { addSlot(new SlotItemHandler(this.playerInvWrapper, index++, 8 + 18 * col, 79 + 18 * row)); } } lastInventoryIndex = slots.size(); } @Override public ItemStack quickMoveStack(Player pPlayer, int pIndex) { ItemStack slotItemStack = slots.get(pIndex).getItem(); if (slotItemStack.isEmpty()) return ItemStack.EMPTY; if (pIndex < lastJukeBoxIndex) { //Handle Jukebox Inventory Shift-Click if (pIndex == this.discPlayerSlotIndex) { //Try to move it into the Jukebox storage slotItemStack = moveToJukeBoxInventory(slotItemStack); //Move it to the player inventory if the jukebox storage is full if (!slotItemStack.isEmpty()) { slotItemStack = moveToPlayerInventory(slotItemStack); } } else { slotItemStack = moveToPlayerInventory(slotItemStack); } } else { slotItemStack = moveToJukeBoxInventory(slotItemStack); } Slot slot = slots.get(pIndex); slot.set(slotItemStack); slot.setChanged(); return ItemStack.EMPTY; } private ItemStack moveToPlayerInventory(int slotIndex, ItemStack itemStack) { Slot currentCurrentSlot = getSlot(slotIndex); //Check if slot exist if (currentCurrentSlot == null) return itemStack; //Try to place Item into the Player Slot if (currentCurrentSlot.mayPlace(itemStack)) { itemStack = currentCurrentSlot.safeInsert(itemStack); currentCurrentSlot.setChanged(); } return itemStack; } @Override public boolean stillValid(Player pPlayer) { return stillValid(this.levelAccess, pPlayer, Blocks.JUKEBOX); } private ItemStack moveToPlayerInventory(ItemStack stack) { //Check Space in hot-bar for (int i = lastJukeBoxIndex; i < lastHotBarIndex; i++) { stack = moveToPlayerInventory(i, stack); //Check if there are no items left if (stack.isEmpty()) { break; } } //Check Space in Inventory if (!stack.isEmpty()) { for (int i = lastHotBarIndex; i < lastInventoryIndex; i++) { stack = moveToPlayerInventory(i, stack); //Check if there are no items left if (stack.isEmpty()) { break; } } } return stack; } private ItemStack moveToJukeBoxInventory(ItemStack stack) { //Handle Player Inventory Shift-Click for (int i = 0; i < lastJukeBoxIndex; i++) { if (i == discPlayerSlotIndex) continue; Slot currentCurrentSlot = getSlot(i); //Check if slot exist if (currentCurrentSlot == null) break; //Try to place Item into the Player Slot if (currentCurrentSlot.mayPlace(stack)) { stack = currentCurrentSlot.safeInsert(stack); currentCurrentSlot.setChanged(); } } return stack; } public boolean isPlaying() { return this.blockEntity.isPlaying(); } public BlockPos getPosition() { return this.blockEntity.getBlockPos(); } public void startPlaying() { this.blockEntity.play(); } public void stopPlaying() { this.blockEntity.stop(); } public Level getLevel() { return this.blockEntity.getLevel(); } public void update() { levelAccess.execute((level, pos) -> { level.sendBlockUpdated(pos, blockEntity.getBlockState(), blockEntity.getBlockState(), 2); }); } public boolean hasDisc() { return !blockEntity.getContainer().getCurrentRecord().isEmpty(); } } MenuScreen: Spoiler public class JukeBoxScreen extends AbstractContainerScreen<JukeBoxMenu> { private final ImagePredicateButton playButton, stopButton; private static final ResourceLocation BACKGROUND = new ResourceLocation(Vanilla_Plus.MOD_ID, "textures/gui/jukebox.png"); private static final ResourceLocation PLAY_BUTTON = new ResourceLocation(Vanilla_Plus.MOD_ID, "textures/gui/play_button.png"); private static final ResourceLocation STOP_BUTTON = new ResourceLocation(Vanilla_Plus.MOD_ID, "textures/gui/stop_button.png"); public JukeBoxScreen(JukeBoxMenu pMenu, Inventory pPlayerInventory, Component pTitle) { super(pMenu, pPlayerInventory, pTitle); this.playButton = new ImagePredicateButton(0, 0, 12, 12, PLAY_BUTTON, pButton -> { Vanilla_PlusNetwork.getInstance().sendToServer(new RequestJukeboxUpdate(true)); }, (pButton, pPoseStack, pMouseX, pMouseY) -> { renderTooltip(pPoseStack, Translation.of("jukebox.button.play"), pMouseX, pMouseY); }, () -> !pMenu.isPlaying() && pMenu.hasDisc()); this.stopButton = new ImagePredicateButton(0, 0, 12, 12, STOP_BUTTON, pButton -> { Vanilla_PlusNetwork.getInstance().sendToServer(new RequestJukeboxUpdate(false)); }, (pButton, pPoseStack, pMouseX, pMouseY) -> { renderTooltip(pPoseStack, Translation.of("jukebox.button.stop"), pMouseX, pMouseY); }, pMenu::isPlaying); } @Override protected void init() { super.init(); titleLabelX = (imageWidth - font.width(title)) / 2; titleLabelY = 4; inventoryLabelX = (imageWidth - font.width(playerInventoryTitle)) / 2; inventoryLabelY = titleLabelY + 60; removeWidget(this.playButton); this.playButton.x = getGuiLeft() + imageWidth / 2 - 26; this.playButton.y = getGuiTop() + 32; addRenderableWidget(this.playButton); removeWidget(this.stopButton); this.stopButton.x = getGuiLeft() + imageWidth / 2 + 14; this.stopButton.y = getGuiTop() + 32; addRenderableWidget(this.stopButton); } @Override protected void renderBg(PoseStack pPoseStack, float pPartialTick, int pMouseX, int pMouseY) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1F, 1F, 1F, 1F); RenderSystem.setShaderTexture(0, BACKGROUND); int x = (width - imageWidth) / 2; int y = (height - imageWidth) / 2; blit(pPoseStack, x, y, 0, 0, imageWidth, imageHeight, 256, 256); } } Packet: Spoiler @RequiredArgsConstructor public class RequestJukeboxUpdate { private final boolean playingState; public RequestJukeboxUpdate(FriendlyByteBuf buf) { this.playingState = buf.readBoolean(); } public void toBytes(FriendlyByteBuf buf) { buf.writeBoolean(this.playingState); } public void handle(Supplier<NetworkEvent.Context> ctx) { ctx.get().enqueueWork(() -> { if (ctx.get().getSender().containerMenu instanceof JukeBoxMenu menu) { if (!menu.hasDisc()) return; if (this.playingState) { menu.startPlaying(); } else { menu.stopPlaying(); } menu.update(); } }); ctx.get().setPacketHandled(true); } } BlockEntity: Spoiler public class JukeboxBlockEntity extends BlockEntity implements Clearable { private static final int PLAY_RECORD_EVENT = 1010; @Getter private final JukeboxContainer container = new JukeboxContainer(); @Getter private boolean isPlaying; private ItemStack lastDisc = ItemStack.EMPTY; private boolean firstTickDone = false; public JukeboxBlockEntity(BlockPos pWorldPosition, BlockState pBlockState) { super(Vanilla_PlusBlockEntities.JUKEBOX_BLOCK_ENTITY, pWorldPosition, pBlockState); container.addListener((handler, slot) -> { if (level != null && !level.isClientSide()) { if (slot == 8) { if (!lastDisc.equals(handler.getStackInSlot(slot))) { stop(); } } setChanged(); } }); isPlaying = pBlockState.getValue(JukeboxBlock.HAS_RECORD); container.getCurrentRecord(); } public void load(CompoundTag pTag) { super.load(pTag); this.isPlaying = pTag.getBoolean("isPlaying"); container.deserializeNBT(pTag.getCompound("Inventory")); lastDisc = container.getCurrentRecord(); } protected void saveAdditional(CompoundTag pTag) { super.saveAdditional(pTag); pTag.putBoolean("isPlaying", this.isPlaying); pTag.put("Inventory", container.serializeNBT()); } public ItemStack getRecord() { return this.container.getCurrentRecord(); } public void setRecord(ItemStack pRecord) { this.container.setCurrentRecord(pRecord); this.setChanged(); } @Override public void clearContent() { this.container.clear(); } public void play() { if (!getRecord().isEmpty()) { this.isPlaying = true; setChanged(); if (hasLevel()) { level.setBlock(worldPosition, getBlockState().setValue(JukeboxBlock.HAS_RECORD, true), 2); level.levelEvent(PLAY_RECORD_EVENT, worldPosition, Item.getId(getRecord().getItem())); } } } public void stop() { this.isPlaying = false; setChanged(); if (hasLevel()) { level.setBlock(worldPosition, getBlockState().setValue(JukeboxBlock.HAS_RECORD, false), 2); level.levelEvent(PLAY_RECORD_EVENT, worldPosition, 0); } } @Nullable @Override public Packet<ClientGamePacketListener> getUpdatePacket() { return ClientboundBlockEntityDataPacket.create(this); } @Override public CompoundTag getUpdateTag() { CompoundTag tag = super.getUpdateTag(); saveAdditional(tag); return tag; } public static <T extends BlockEntity> void tick(Level level, BlockPos pos, BlockState blockState, T be) { if (be instanceof JukeboxBlockEntity blockEntity) { if (!blockEntity.firstTickDone && blockEntity.isPlaying()) { //Start playing again when the blockEntity ticks the first time blockEntity.play(); } } } } Edited May 6, 20223 yr by Skyriis
May 6, 20223 yr Author 10 hours ago, diesieben07 said: These fields should not be in the packet. At most they allow the user to cheat. The server already knows this information. They where unused anyway. I've removed them from the Packet and updated the code above. My Problem still remains
May 6, 20223 yr Author 28 minutes ago, diesieben07 said: I don't see anything that would even happen if the packet is received, except the server setting the block state. Is that all that you expected It should change "isPlaying" variable too. (in the play / stop method of the blockentity)
May 6, 20223 yr Author Just now, diesieben07 said: How have you checked whether it does or not? If i check it in the Packet (using the menu.isPlaying method) it'll show the correct value but if i check it in the menu screen it shows the old / default value.
May 6, 20223 yr Author 6 minutes ago, diesieben07 said: The packet updates the server. Your screen is client side. Do i need to send another packet to the client?
May 6, 20223 yr Author Okay my client get's updated now but for some reason the value resets if i close and reopen the menu
May 6, 20223 yr Author i guess that thing get's invoked when i open my container but why? container.addListener((handler, slot) -> { if (slot == 8) { stop(); } setChanged(); }); it should only get invoked if "onContentsChanged" get's called
May 6, 20223 yr Author Okay next problem. the blockentity doesn't play anything when i log out and log in again. I guess i have to run the level.levelEvent(PLAY_RECORD_EVENT, worldPosition, Item.getId(getRecord().getItem())); when the blockentity gets loaded but is there a method for that? Edited May 6, 20223 yr by Skyriis
May 6, 20223 yr Author 12 minutes ago, diesieben07 said: You have to do it in your BlockEntity's ticker i should run level.levelEvent(PLAY_RECORD_EVENT, worldPosition, Item.getId(getRecord().getItem())); every tick? Wouldn't that cause the disc to go crasy? Edited May 6, 20223 yr by Skyriis
May 6, 20223 yr Author 53 minutes ago, diesieben07 said: No, you need to do it on the first tick. how do i check if it's the first tick or not? Edited May 6, 20223 yr by Skyriis
May 6, 20223 yr Author 14 minutes ago, diesieben07 said: You make a boolean. Okay i made a boolean and it started the disc but i can't stop it anymore. (i've updated the code above). EDIT nvm i forgot to update the boolean Edited May 6, 20223 yr by Skyriis
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.