Skyriis Posted May 5, 2022 Share Posted May 5, 2022 (edited) 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, 2022 by Skyriis Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 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 Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 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) Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 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. Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 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? Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 Okay my client get's updated now but for some reason the value resets if i close and reopen the menu Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 updated the code above Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 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 Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 (edited) 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, 2022 by Skyriis Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 (edited) 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, 2022 by Skyriis Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 (edited) 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, 2022 by Skyriis Quote Link to comment Share on other sites More sharing options...
Skyriis Posted May 6, 2022 Author Share Posted May 6, 2022 (edited) 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, 2022 by Skyriis Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.