package net.minecraft.client.gui.screens.inventory; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.mojang.blaze3d.platform.InputConstants; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Set; import java.util.function.Predicate; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.ChatFormatting; import net.minecraft.client.HotbarManager; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.SessionSearchTrees; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.player.inventory.Hotbar; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.searchtree.SearchTree; import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; import net.minecraft.core.RegistryAccess; import net.minecraft.core.HolderSet.Named; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.util.Mth; import net.minecraft.util.Unit; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ClickType; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.CreativeModeTab.Row; import net.minecraft.world.item.CreativeModeTab.Type; import net.minecraft.world.item.TooltipFlag.Default; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class CreativeModeInventoryScreen extends AbstractContainerScreen { private static final ResourceLocation SCROLLER_SPRITE = ResourceLocation.withDefaultNamespace("container/creative_inventory/scroller"); private static final ResourceLocation SCROLLER_DISABLED_SPRITE = ResourceLocation.withDefaultNamespace("container/creative_inventory/scroller_disabled"); private static final ResourceLocation[] UNSELECTED_TOP_TABS = new ResourceLocation[]{ ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_unselected_1"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_unselected_2"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_unselected_3"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_unselected_4"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_unselected_5"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_unselected_6"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_unselected_7") }; private static final ResourceLocation[] SELECTED_TOP_TABS = new ResourceLocation[]{ ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_selected_1"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_selected_2"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_selected_3"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_selected_4"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_selected_5"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_selected_6"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_top_selected_7") }; private static final ResourceLocation[] UNSELECTED_BOTTOM_TABS = new ResourceLocation[]{ ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_unselected_1"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_unselected_2"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_unselected_3"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_unselected_4"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_unselected_5"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_unselected_6"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_unselected_7") }; private static final ResourceLocation[] SELECTED_BOTTOM_TABS = new ResourceLocation[]{ ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_selected_1"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_selected_2"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_selected_3"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_selected_4"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_selected_5"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_selected_6"), ResourceLocation.withDefaultNamespace("container/creative_inventory/tab_bottom_selected_7") }; private static final int NUM_ROWS = 5; private static final int NUM_COLS = 9; private static final int TAB_WIDTH = 26; private static final int TAB_HEIGHT = 32; private static final int SCROLLER_WIDTH = 12; private static final int SCROLLER_HEIGHT = 15; static final SimpleContainer CONTAINER = new SimpleContainer(45); private static final Component TRASH_SLOT_TOOLTIP = Component.translatable("inventory.binSlot"); private static final int TEXT_COLOR = 16777215; /** * Currently selected creative inventory tab index. */ private static CreativeModeTab selectedTab = CreativeModeTabs.getDefaultTab(); /** * Amount scrolled in Creative mode inventory (0 = top, 1 = bottom) */ private float scrollOffs; /** * True if the scrollbar is being dragged */ private boolean scrolling; private EditBox searchBox; @Nullable private List originalSlots; @Nullable private Slot destroyItemSlot; private CreativeInventoryListener listener; private boolean ignoreTextInput; private boolean hasClickedOutside; private final Set> visibleTags = new HashSet(); private final boolean displayOperatorCreativeTab; private final EffectsInInventory effects; public CreativeModeInventoryScreen(LocalPlayer player, FeatureFlagSet enabledFeatures, boolean displayOperatorCreativeTab) { super(new CreativeModeInventoryScreen.ItemPickerMenu(player), player.getInventory(), CommonComponents.EMPTY); player.containerMenu = this.menu; this.imageHeight = 136; this.imageWidth = 195; this.displayOperatorCreativeTab = displayOperatorCreativeTab; this.tryRebuildTabContents(player.connection.searchTrees(), enabledFeatures, this.hasPermissions(player), player.level().registryAccess()); this.effects = new EffectsInInventory(this); } private boolean hasPermissions(Player player) { return player.canUseGameMasterBlocks() && this.displayOperatorCreativeTab; } private void tryRefreshInvalidatedTabs(FeatureFlagSet enabledFeatures, boolean hasPermissions, HolderLookup.Provider provider) { ClientPacketListener clientPacketListener = this.minecraft.getConnection(); if (this.tryRebuildTabContents(clientPacketListener != null ? clientPacketListener.searchTrees() : null, enabledFeatures, hasPermissions, provider)) { for (CreativeModeTab creativeModeTab : CreativeModeTabs.allTabs()) { Collection collection = creativeModeTab.getDisplayItems(); if (creativeModeTab == selectedTab) { if (creativeModeTab.getType() == Type.CATEGORY && collection.isEmpty()) { this.selectTab(CreativeModeTabs.getDefaultTab()); } else { this.refreshCurrentTabContents(collection); } } } } } private boolean tryRebuildTabContents( @Nullable SessionSearchTrees searchTrees, FeatureFlagSet enabledFeatures, boolean hasPermissions, HolderLookup.Provider registries ) { if (!CreativeModeTabs.tryRebuildTabContents(enabledFeatures, hasPermissions, registries)) { return false; } else { if (searchTrees != null) { List list = List.copyOf(CreativeModeTabs.searchTab().getDisplayItems()); searchTrees.updateCreativeTooltips(registries, list); searchTrees.updateCreativeTags(list); } return true; } } private void refreshCurrentTabContents(Collection items) { int i = this.menu.getRowIndexForScroll(this.scrollOffs); this.menu.items.clear(); if (selectedTab.getType() == Type.SEARCH) { this.refreshSearchResults(); } else { this.menu.items.addAll(items); } this.scrollOffs = this.menu.getScrollForRowIndex(i); this.menu.scrollTo(this.scrollOffs); } @Override public void containerTick() { super.containerTick(); if (this.minecraft != null) { LocalPlayer localPlayer = this.minecraft.player; if (localPlayer != null) { this.tryRefreshInvalidatedTabs(localPlayer.connection.enabledFeatures(), this.hasPermissions(localPlayer), localPlayer.level().registryAccess()); if (!localPlayer.hasInfiniteMaterials()) { this.minecraft.setScreen(new InventoryScreen(localPlayer)); } } } } @Override protected void slotClicked(@Nullable Slot slot, int slotId, int mouseButton, ClickType type) { if (this.isCreativeSlot(slot)) { this.searchBox.moveCursorToEnd(false); this.searchBox.setHighlightPos(0); } boolean bl = type == ClickType.QUICK_MOVE; type = slotId == -999 && type == ClickType.PICKUP ? ClickType.THROW : type; if (type != ClickType.THROW || this.minecraft.player.canDropItems()) { this.onMouseClickAction(slot, type); if (slot == null && selectedTab.getType() != Type.INVENTORY && type != ClickType.QUICK_CRAFT) { if (!this.menu.getCarried().isEmpty() && this.hasClickedOutside) { if (!this.minecraft.player.canDropItems()) { return; } if (mouseButton == 0) { this.minecraft.player.drop(this.menu.getCarried(), true); this.minecraft.gameMode.handleCreativeModeItemDrop(this.menu.getCarried()); this.menu.setCarried(ItemStack.EMPTY); } if (mouseButton == 1) { ItemStack itemStack = this.menu.getCarried().split(1); this.minecraft.player.drop(itemStack, true); this.minecraft.gameMode.handleCreativeModeItemDrop(itemStack); } } } else { if (slot != null && !slot.mayPickup(this.minecraft.player)) { return; } if (slot == this.destroyItemSlot && bl) { for (int i = 0; i < this.minecraft.player.inventoryMenu.getItems().size(); i++) { this.minecraft.player.inventoryMenu.getSlot(i).set(ItemStack.EMPTY); this.minecraft.gameMode.handleCreativeModeItemAdd(ItemStack.EMPTY, i); } } else if (selectedTab.getType() == Type.INVENTORY) { if (slot == this.destroyItemSlot) { this.menu.setCarried(ItemStack.EMPTY); } else if (type == ClickType.THROW && slot != null && slot.hasItem()) { ItemStack itemStack = slot.remove(mouseButton == 0 ? 1 : slot.getItem().getMaxStackSize()); ItemStack itemStack2 = slot.getItem(); this.minecraft.player.drop(itemStack, true); this.minecraft.gameMode.handleCreativeModeItemDrop(itemStack); this.minecraft.gameMode.handleCreativeModeItemAdd(itemStack2, ((CreativeModeInventoryScreen.SlotWrapper)slot).target.index); } else if (type == ClickType.THROW && slotId == -999 && !this.menu.getCarried().isEmpty()) { this.minecraft.player.drop(this.menu.getCarried(), true); this.minecraft.gameMode.handleCreativeModeItemDrop(this.menu.getCarried()); this.menu.setCarried(ItemStack.EMPTY); } else { this.minecraft .player .inventoryMenu .clicked(slot == null ? slotId : ((CreativeModeInventoryScreen.SlotWrapper)slot).target.index, mouseButton, type, this.minecraft.player); this.minecraft.player.inventoryMenu.broadcastChanges(); } } else if (type != ClickType.QUICK_CRAFT && slot.container == CONTAINER) { ItemStack itemStack = this.menu.getCarried(); ItemStack itemStack2 = slot.getItem(); if (type == ClickType.SWAP) { if (!itemStack2.isEmpty()) { this.minecraft.player.getInventory().setItem(mouseButton, itemStack2.copyWithCount(itemStack2.getMaxStackSize())); this.minecraft.player.inventoryMenu.broadcastChanges(); } return; } if (type == ClickType.CLONE) { if (this.menu.getCarried().isEmpty() && slot.hasItem()) { ItemStack itemStack3 = slot.getItem(); this.menu.setCarried(itemStack3.copyWithCount(itemStack3.getMaxStackSize())); } return; } if (type == ClickType.THROW) { if (!itemStack2.isEmpty()) { ItemStack itemStack3 = itemStack2.copyWithCount(mouseButton == 0 ? 1 : itemStack2.getMaxStackSize()); this.minecraft.player.drop(itemStack3, true); this.minecraft.gameMode.handleCreativeModeItemDrop(itemStack3); } return; } if (!itemStack.isEmpty() && !itemStack2.isEmpty() && ItemStack.isSameItemSameComponents(itemStack, itemStack2)) { if (mouseButton == 0) { if (bl) { itemStack.setCount(itemStack.getMaxStackSize()); } else if (itemStack.getCount() < itemStack.getMaxStackSize()) { itemStack.grow(1); } } else { itemStack.shrink(1); } } else if (!itemStack2.isEmpty() && itemStack.isEmpty()) { int j = bl ? itemStack2.getMaxStackSize() : itemStack2.getCount(); this.menu.setCarried(itemStack2.copyWithCount(j)); } else if (mouseButton == 0) { this.menu.setCarried(ItemStack.EMPTY); } else if (!this.menu.getCarried().isEmpty()) { this.menu.getCarried().shrink(1); } } else if (this.menu != null) { ItemStack itemStackx = slot == null ? ItemStack.EMPTY : this.menu.getSlot(slot.index).getItem(); this.menu.clicked(slot == null ? slotId : slot.index, mouseButton, type, this.minecraft.player); if (AbstractContainerMenu.getQuickcraftHeader(mouseButton) == 2) { for (int k = 0; k < 9; k++) { this.minecraft.gameMode.handleCreativeModeItemAdd(this.menu.getSlot(45 + k).getItem(), 36 + k); } } else if (slot != null && Inventory.isHotbarSlot(slot.getContainerSlot()) && selectedTab.getType() != Type.INVENTORY) { if (type == ClickType.THROW && !itemStackx.isEmpty() && !this.menu.getCarried().isEmpty()) { int k = mouseButton == 0 ? 1 : itemStackx.getCount(); ItemStack itemStack3 = itemStackx.copyWithCount(k); itemStackx.shrink(k); this.minecraft.player.drop(itemStack3, true); this.minecraft.gameMode.handleCreativeModeItemDrop(itemStack3); } this.minecraft.player.inventoryMenu.broadcastChanges(); } } } } } private boolean isCreativeSlot(@Nullable Slot slot) { return slot != null && slot.container == CONTAINER; } @Override protected void init() { if (this.minecraft.player.hasInfiniteMaterials()) { super.init(); this.searchBox = new EditBox(this.font, this.leftPos + 82, this.topPos + 6, 80, 9, Component.translatable("itemGroup.search")); this.searchBox.setMaxLength(50); this.searchBox.setBordered(false); this.searchBox.setVisible(false); this.searchBox.setTextColor(16777215); this.addWidget(this.searchBox); CreativeModeTab creativeModeTab = selectedTab; selectedTab = CreativeModeTabs.getDefaultTab(); this.selectTab(creativeModeTab); this.minecraft.player.inventoryMenu.removeSlotListener(this.listener); this.listener = new CreativeInventoryListener(this.minecraft); this.minecraft.player.inventoryMenu.addSlotListener(this.listener); if (!selectedTab.shouldDisplay()) { this.selectTab(CreativeModeTabs.getDefaultTab()); } } else { this.minecraft.setScreen(new InventoryScreen(this.minecraft.player)); } } @Override public void resize(Minecraft minecraft, int width, int height) { int i = this.menu.getRowIndexForScroll(this.scrollOffs); String string = this.searchBox.getValue(); this.init(minecraft, width, height); this.searchBox.setValue(string); if (!this.searchBox.getValue().isEmpty()) { this.refreshSearchResults(); } this.scrollOffs = this.menu.getScrollForRowIndex(i); this.menu.scrollTo(this.scrollOffs); } @Override public void removed() { super.removed(); if (this.minecraft.player != null && this.minecraft.player.getInventory() != null) { this.minecraft.player.inventoryMenu.removeSlotListener(this.listener); } } @Override public boolean charTyped(char codePoint, int modifiers) { if (this.ignoreTextInput) { return false; } else if (selectedTab.getType() != Type.SEARCH) { return false; } else { String string = this.searchBox.getValue(); if (this.searchBox.charTyped(codePoint, modifiers)) { if (!Objects.equals(string, this.searchBox.getValue())) { this.refreshSearchResults(); } return true; } else { return false; } } } @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { this.ignoreTextInput = false; if (selectedTab.getType() != Type.SEARCH) { if (this.minecraft.options.keyChat.matches(keyCode, scanCode)) { this.ignoreTextInput = true; this.selectTab(CreativeModeTabs.searchTab()); return true; } else { return super.keyPressed(keyCode, scanCode, modifiers); } } else { boolean bl = !this.isCreativeSlot(this.hoveredSlot) || this.hoveredSlot.hasItem(); boolean bl2 = InputConstants.getKey(keyCode, scanCode).getNumericKeyValue().isPresent(); if (bl && bl2 && this.checkHotbarKeyPressed(keyCode, scanCode)) { this.ignoreTextInput = true; return true; } else { String string = this.searchBox.getValue(); if (this.searchBox.keyPressed(keyCode, scanCode, modifiers)) { if (!Objects.equals(string, this.searchBox.getValue())) { this.refreshSearchResults(); } return true; } else { return this.searchBox.isFocused() && this.searchBox.isVisible() && keyCode != 256 ? true : super.keyPressed(keyCode, scanCode, modifiers); } } } } @Override public boolean keyReleased(int keyCode, int scanCode, int modifiers) { this.ignoreTextInput = false; return super.keyReleased(keyCode, scanCode, modifiers); } private void refreshSearchResults() { this.menu.items.clear(); this.visibleTags.clear(); String string = this.searchBox.getValue(); if (string.isEmpty()) { this.menu.items.addAll(selectedTab.getDisplayItems()); } else { ClientPacketListener clientPacketListener = this.minecraft.getConnection(); if (clientPacketListener != null) { SessionSearchTrees sessionSearchTrees = clientPacketListener.searchTrees(); SearchTree searchTree; if (string.startsWith("#")) { string = string.substring(1); searchTree = sessionSearchTrees.creativeTagSearch(); this.updateVisibleTags(string); } else { searchTree = sessionSearchTrees.creativeNameSearch(); } this.menu.items.addAll(searchTree.search(string.toLowerCase(Locale.ROOT))); } } this.scrollOffs = 0.0F; this.menu.scrollTo(0.0F); } private void updateVisibleTags(String search) { int i = search.indexOf(58); Predicate predicate; if (i == -1) { predicate = resourceLocation -> resourceLocation.getPath().contains(search); } else { String string = search.substring(0, i).trim(); String string2 = search.substring(i + 1).trim(); predicate = resourceLocation -> resourceLocation.getNamespace().contains(string) && resourceLocation.getPath().contains(string2); } BuiltInRegistries.ITEM.getTags().map(Named::key).filter(tagKey -> predicate.test(tagKey.location())).forEach(this.visibleTags::add); } @Override protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) { if (selectedTab.showTitle()) { guiGraphics.drawString(this.font, selectedTab.getDisplayName(), 8, 6, 4210752, false); } } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { if (button == 0) { double d = mouseX - this.leftPos; double e = mouseY - this.topPos; for (CreativeModeTab creativeModeTab : CreativeModeTabs.tabs()) { if (this.checkTabClicked(creativeModeTab, d, e)) { return true; } } if (selectedTab.getType() != Type.INVENTORY && this.insideScrollbar(mouseX, mouseY)) { this.scrolling = this.canScroll(); return true; } } return super.mouseClicked(mouseX, mouseY, button); } @Override public boolean mouseReleased(double mouseX, double mouseY, int button) { if (button == 0) { double d = mouseX - this.leftPos; double e = mouseY - this.topPos; this.scrolling = false; for (CreativeModeTab creativeModeTab : CreativeModeTabs.tabs()) { if (this.checkTabClicked(creativeModeTab, d, e)) { this.selectTab(creativeModeTab); return true; } } } return super.mouseReleased(mouseX, mouseY, button); } /** * Returns (if you are not on the inventoryTab) and (the flag isn't set) and (you have more than 1 page of items). */ private boolean canScroll() { return selectedTab.canScroll() && this.menu.canScroll(); } /** * Sets the current creative tab, restructuring the GUI as needed. */ private void selectTab(CreativeModeTab tab) { CreativeModeTab creativeModeTab = selectedTab; selectedTab = tab; this.quickCraftSlots.clear(); this.menu.items.clear(); this.clearDraggingState(); if (selectedTab.getType() == Type.HOTBAR) { HotbarManager hotbarManager = this.minecraft.getHotbarManager(); for (int i = 0; i < 9; i++) { Hotbar hotbar = hotbarManager.get(i); if (hotbar.isEmpty()) { for (int j = 0; j < 9; j++) { if (j == i) { ItemStack itemStack = new ItemStack(Items.PAPER); itemStack.set(DataComponents.CREATIVE_SLOT_LOCK, Unit.INSTANCE); Component component = this.minecraft.options.keyHotbarSlots[i].getTranslatedKeyMessage(); Component component2 = this.minecraft.options.keySaveHotbarActivator.getTranslatedKeyMessage(); itemStack.set(DataComponents.ITEM_NAME, Component.translatable("inventory.hotbarInfo", component2, component)); this.menu.items.add(itemStack); } else { this.menu.items.add(ItemStack.EMPTY); } } } else { this.menu.items.addAll(hotbar.load(this.minecraft.level.registryAccess())); } } } else if (selectedTab.getType() == Type.CATEGORY) { this.menu.items.addAll(selectedTab.getDisplayItems()); } if (selectedTab.getType() == Type.INVENTORY) { AbstractContainerMenu abstractContainerMenu = this.minecraft.player.inventoryMenu; if (this.originalSlots == null) { this.originalSlots = ImmutableList.copyOf(this.menu.slots); } this.menu.slots.clear(); for (int ix = 0; ix < abstractContainerMenu.slots.size(); ix++) { int n; int jx; if (ix >= 5 && ix < 9) { int k = ix - 5; int l = k / 2; int m = k % 2; n = 54 + l * 54; jx = 6 + m * 27; } else if (ix >= 0 && ix < 5) { n = -2000; jx = -2000; } else if (ix == 45) { n = 35; jx = 20; } else { int k = ix - 9; int l = k % 9; int m = k / 9; n = 9 + l * 18; if (ix >= 36) { jx = 112; } else { jx = 54 + m * 18; } } Slot slot = new CreativeModeInventoryScreen.SlotWrapper(abstractContainerMenu.slots.get(ix), ix, n, jx); this.menu.slots.add(slot); } this.destroyItemSlot = new Slot(CONTAINER, 0, 173, 112); this.menu.slots.add(this.destroyItemSlot); } else if (creativeModeTab.getType() == Type.INVENTORY) { this.menu.slots.clear(); this.menu.slots.addAll(this.originalSlots); this.originalSlots = null; } if (selectedTab.getType() == Type.SEARCH) { this.searchBox.setVisible(true); this.searchBox.setCanLoseFocus(false); this.searchBox.setFocused(true); if (creativeModeTab != tab) { this.searchBox.setValue(""); } this.refreshSearchResults(); } else { this.searchBox.setVisible(false); this.searchBox.setCanLoseFocus(true); this.searchBox.setFocused(false); this.searchBox.setValue(""); } this.scrollOffs = 0.0F; this.menu.scrollTo(0.0F); } @Override public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) { if (super.mouseScrolled(mouseX, mouseY, scrollX, scrollY)) { return true; } else if (!this.canScroll()) { return false; } else { this.scrollOffs = this.menu.subtractInputFromScroll(this.scrollOffs, scrollY); this.menu.scrollTo(this.scrollOffs); return true; } } @Override protected boolean hasClickedOutside(double mouseX, double mouseY, int guiLeft, int guiTop, int mouseButton) { boolean bl = mouseX < guiLeft || mouseY < guiTop || mouseX >= guiLeft + this.imageWidth || mouseY >= guiTop + this.imageHeight; this.hasClickedOutside = bl && !this.checkTabClicked(selectedTab, mouseX, mouseY); return this.hasClickedOutside; } protected boolean insideScrollbar(double mouseX, double mouseY) { int i = this.leftPos; int j = this.topPos; int k = i + 175; int l = j + 18; int m = k + 14; int n = l + 112; return mouseX >= k && mouseY >= l && mouseX < m && mouseY < n; } @Override public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { if (this.scrolling) { int i = this.topPos + 18; int j = i + 112; this.scrollOffs = ((float)mouseY - i - 7.5F) / (j - i - 15.0F); this.scrollOffs = Mth.clamp(this.scrollOffs, 0.0F, 1.0F); this.menu.scrollTo(this.scrollOffs); return true; } else { return super.mouseDragged(mouseX, mouseY, button, dragX, dragY); } } @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { super.render(guiGraphics, mouseX, mouseY, partialTick); this.effects.render(guiGraphics, mouseX, mouseY, partialTick); for (CreativeModeTab creativeModeTab : CreativeModeTabs.tabs()) { if (this.checkTabHovering(guiGraphics, creativeModeTab, mouseX, mouseY)) { break; } } if (this.destroyItemSlot != null && selectedTab.getType() == Type.INVENTORY && this.isHovering(this.destroyItemSlot.x, this.destroyItemSlot.y, 16, 16, mouseX, mouseY)) { guiGraphics.renderTooltip(this.font, TRASH_SLOT_TOOLTIP, mouseX, mouseY); } this.renderTooltip(guiGraphics, mouseX, mouseY); } @Override public boolean showsActiveEffects() { return this.effects.canSeeEffects(); } @Override public List getTooltipFromContainerItem(ItemStack stack) { boolean bl = this.hoveredSlot != null && this.hoveredSlot instanceof CreativeModeInventoryScreen.CustomCreativeSlot; boolean bl2 = selectedTab.getType() == Type.CATEGORY; boolean bl3 = selectedTab.getType() == Type.SEARCH; Default default_ = this.minecraft.options.advancedItemTooltips ? Default.ADVANCED : Default.NORMAL; TooltipFlag tooltipFlag = bl ? default_.asCreative() : default_; List list = stack.getTooltipLines(Item.TooltipContext.of(this.minecraft.level), this.minecraft.player, tooltipFlag); if (list.isEmpty()) { return list; } else if (bl2 && bl) { return list; } else { List list2 = Lists.newArrayList(list); if (bl3 && bl) { this.visibleTags.forEach(tagKey -> { if (stack.is(tagKey)) { list2.add(1, Component.literal("#" + tagKey.location()).withStyle(ChatFormatting.DARK_PURPLE)); } }); } int i = 1; for (CreativeModeTab creativeModeTab : CreativeModeTabs.tabs()) { if (creativeModeTab.getType() != Type.SEARCH && creativeModeTab.contains(stack)) { list2.add(i++, creativeModeTab.getDisplayName().copy().withStyle(ChatFormatting.BLUE)); } } return list2; } } @Override protected void renderBg(GuiGraphics guiGraphics, float partialTick, int mouseX, int mouseY) { for (CreativeModeTab creativeModeTab : CreativeModeTabs.tabs()) { if (creativeModeTab != selectedTab) { this.renderTabButton(guiGraphics, creativeModeTab); } } guiGraphics.blit( RenderType::guiTextured, selectedTab.getBackgroundTexture(), this.leftPos, this.topPos, 0.0F, 0.0F, this.imageWidth, this.imageHeight, 256, 256 ); this.searchBox.render(guiGraphics, mouseX, mouseY, partialTick); int i = this.leftPos + 175; int j = this.topPos + 18; int k = j + 112; if (selectedTab.canScroll()) { ResourceLocation resourceLocation = this.canScroll() ? SCROLLER_SPRITE : SCROLLER_DISABLED_SPRITE; guiGraphics.blitSprite(RenderType::guiTextured, resourceLocation, i, j + (int)((k - j - 17) * this.scrollOffs), 12, 15); } this.renderTabButton(guiGraphics, selectedTab); if (selectedTab.getType() == Type.INVENTORY) { InventoryScreen.renderEntityInInventoryFollowsMouse( guiGraphics, this.leftPos + 73, this.topPos + 6, this.leftPos + 105, this.topPos + 49, 20, 0.0625F, mouseX, mouseY, this.minecraft.player ); } } private int getTabX(CreativeModeTab tab) { int i = tab.column(); int j = 27; int k = 27 * i; if (tab.isAlignedRight()) { k = this.imageWidth - 27 * (7 - i) + 1; } return k; } private int getTabY(CreativeModeTab tab) { int i = 0; if (tab.row() == Row.TOP) { i -= 32; } else { i += this.imageHeight; } return i; } protected boolean checkTabClicked(CreativeModeTab creativeModeTab, double relativeMouseX, double relativeMouseY) { int i = this.getTabX(creativeModeTab); int j = this.getTabY(creativeModeTab); return relativeMouseX >= i && relativeMouseX <= i + 26 && relativeMouseY >= j && relativeMouseY <= j + 32; } protected boolean checkTabHovering(GuiGraphics guiGraphics, CreativeModeTab creativeModeTab, int mouseX, int mouseY) { int i = this.getTabX(creativeModeTab); int j = this.getTabY(creativeModeTab); if (this.isHovering(i + 3, j + 3, 21, 27, mouseX, mouseY)) { guiGraphics.renderTooltip(this.font, creativeModeTab.getDisplayName(), mouseX, mouseY); return true; } else { return false; } } protected void renderTabButton(GuiGraphics guiGraphics, CreativeModeTab creativeModeTab) { boolean bl = creativeModeTab == selectedTab; boolean bl2 = creativeModeTab.row() == Row.TOP; int i = creativeModeTab.column(); int j = this.leftPos + this.getTabX(creativeModeTab); int k = this.topPos - (bl2 ? 28 : -(this.imageHeight - 4)); ResourceLocation[] resourceLocations; if (bl2) { resourceLocations = bl ? SELECTED_TOP_TABS : UNSELECTED_TOP_TABS; } else { resourceLocations = bl ? SELECTED_BOTTOM_TABS : UNSELECTED_BOTTOM_TABS; } guiGraphics.blitSprite(RenderType::guiTextured, resourceLocations[Mth.clamp(i, 0, resourceLocations.length)], j, k, 26, 32); guiGraphics.pose().pushPose(); guiGraphics.pose().translate(0.0F, 0.0F, 100.0F); j += 5; k += 8 + (bl2 ? 1 : -1); ItemStack itemStack = creativeModeTab.getIconItem(); guiGraphics.renderItem(itemStack, j, k); guiGraphics.renderItemDecorations(this.font, itemStack, j, k); guiGraphics.pose().popPose(); } public boolean isInventoryOpen() { return selectedTab.getType() == Type.INVENTORY; } public static void handleHotbarLoadOrSave(Minecraft client, int index, boolean load, boolean save) { LocalPlayer localPlayer = client.player; RegistryAccess registryAccess = localPlayer.level().registryAccess(); HotbarManager hotbarManager = client.getHotbarManager(); Hotbar hotbar = hotbarManager.get(index); if (load) { List list = hotbar.load(registryAccess); for (int i = 0; i < Inventory.getSelectionSize(); i++) { ItemStack itemStack = (ItemStack)list.get(i); localPlayer.getInventory().setItem(i, itemStack); client.gameMode.handleCreativeModeItemAdd(itemStack, 36 + i); } localPlayer.inventoryMenu.broadcastChanges(); } else if (save) { hotbar.storeFrom(localPlayer.getInventory(), registryAccess); Component component = client.options.keyHotbarSlots[index].getTranslatedKeyMessage(); Component component2 = client.options.keyLoadHotbarActivator.getTranslatedKeyMessage(); Component component3 = Component.translatable("inventory.hotbarSaved", component2, component); client.gui.setOverlayMessage(component3, false); client.getNarrator().sayNow(component3); hotbarManager.save(); } } @Environment(EnvType.CLIENT) static class CustomCreativeSlot extends Slot { public CustomCreativeSlot(Container container, int i, int j, int k) { super(container, i, j, k); } @Override public boolean mayPickup(Player player) { ItemStack itemStack = this.getItem(); return super.mayPickup(player) && !itemStack.isEmpty() ? itemStack.isItemEnabled(player.level().enabledFeatures()) && !itemStack.has(DataComponents.CREATIVE_SLOT_LOCK) : itemStack.isEmpty(); } } @Environment(EnvType.CLIENT) public static class ItemPickerMenu extends AbstractContainerMenu { /** * The list of items in this container. */ public final NonNullList items = NonNullList.create(); private final AbstractContainerMenu inventoryMenu; public ItemPickerMenu(Player player) { super(null, 0); this.inventoryMenu = player.inventoryMenu; Inventory inventory = player.getInventory(); for (int i = 0; i < 5; i++) { for (int j = 0; j < 9; j++) { this.addSlot(new CreativeModeInventoryScreen.CustomCreativeSlot(CreativeModeInventoryScreen.CONTAINER, i * 9 + j, 9 + j * 18, 18 + i * 18)); } } this.addInventoryHotbarSlots(inventory, 9, 112); this.scrollTo(0.0F); } @Override public boolean stillValid(Player player) { return true; } protected int calculateRowCount() { return Mth.positiveCeilDiv(this.items.size(), 9) - 5; } protected int getRowIndexForScroll(float scrollOffs) { return Math.max((int)(scrollOffs * this.calculateRowCount() + 0.5), 0); } protected float getScrollForRowIndex(int rowIndex) { return Mth.clamp((float)rowIndex / this.calculateRowCount(), 0.0F, 1.0F); } protected float subtractInputFromScroll(float scrollOffs, double input) { return Mth.clamp(scrollOffs - (float)(input / this.calculateRowCount()), 0.0F, 1.0F); } /** * Updates the gui slot's ItemStacks based on scroll position. */ public void scrollTo(float pos) { int i = this.getRowIndexForScroll(pos); for (int j = 0; j < 5; j++) { for (int k = 0; k < 9; k++) { int l = k + (j + i) * 9; if (l >= 0 && l < this.items.size()) { CreativeModeInventoryScreen.CONTAINER.setItem(k + j * 9, this.items.get(l)); } else { CreativeModeInventoryScreen.CONTAINER.setItem(k + j * 9, ItemStack.EMPTY); } } } } public boolean canScroll() { return this.items.size() > 45; } @Override public ItemStack quickMoveStack(Player player, int index) { if (index >= this.slots.size() - 9 && index < this.slots.size()) { Slot slot = this.slots.get(index); if (slot != null && slot.hasItem()) { slot.setByPlayer(ItemStack.EMPTY); } } return ItemStack.EMPTY; } @Override public boolean canTakeItemForPickAll(ItemStack stack, Slot slot) { return slot.container != CreativeModeInventoryScreen.CONTAINER; } @Override public boolean canDragTo(Slot slot) { return slot.container != CreativeModeInventoryScreen.CONTAINER; } @Override public ItemStack getCarried() { return this.inventoryMenu.getCarried(); } @Override public void setCarried(ItemStack stack) { this.inventoryMenu.setCarried(stack); } } @Environment(EnvType.CLIENT) static class SlotWrapper extends Slot { final Slot target; public SlotWrapper(Slot slot, int index, int x, int y) { super(slot.container, index, x, y); this.target = slot; } @Override public void onTake(Player player, ItemStack stack) { this.target.onTake(player, stack); } @Override public boolean mayPlace(ItemStack stack) { return this.target.mayPlace(stack); } @Override public ItemStack getItem() { return this.target.getItem(); } @Override public boolean hasItem() { return this.target.hasItem(); } @Override public void setByPlayer(ItemStack newStack, ItemStack oldStack) { this.target.setByPlayer(newStack, oldStack); } @Override public void set(ItemStack stack) { this.target.set(stack); } @Override public void setChanged() { this.target.setChanged(); } @Override public int getMaxStackSize() { return this.target.getMaxStackSize(); } @Override public int getMaxStackSize(ItemStack stack) { return this.target.getMaxStackSize(stack); } @Nullable @Override public ResourceLocation getNoItemIcon() { return this.target.getNoItemIcon(); } @Override public ItemStack remove(int amount) { return this.target.remove(amount); } @Override public boolean isActive() { return this.target.isActive(); } @Override public boolean mayPickup(Player player) { return this.target.mayPickup(player); } } }