From 396e819b9b435c85c569adc2dd8cebd99fe07655 Mon Sep 17 00:00:00 2001 From: StevenSYS <139715581+StevenSYS@users.noreply.github.com> Date: Fri, 27 Mar 2026 01:19:33 +0000 Subject: [PATCH] Made the Java creative inventory more complete. --- .../Windows64Media/loc/en-EN/strings.lang | 3 + .../Windows64Media/loc/stringsGeneric.xml | 8 +- .../Common/UI/IUIScene_CreativeMenu.cpp | 16 +- .../Common/UI/IUIScene_CreativeMenu.h | 16 +- .../UI/Screens/AbstractContainerScreen.cpp | 9 +- .../UI/Screens/AbstractContainerScreen.h | 2 +- .../UI/Screens/CreativeInventoryScreen.cpp | 938 +++++++++--------- .../UI/Screens/CreativeInventoryScreen.h | 117 ++- 8 files changed, 585 insertions(+), 524 deletions(-) diff --git a/Minecraft.Assets/Windows64Media/loc/en-EN/strings.lang b/Minecraft.Assets/Windows64Media/loc/en-EN/strings.lang index 752552227..2a3a90f32 100644 --- a/Minecraft.Assets/Windows64Media/loc/en-EN/strings.lang +++ b/Minecraft.Assets/Windows64Media/loc/en-EN/strings.lang @@ -4760,6 +4760,9 @@ Would you like to unlock the full game? Food + + Search Items + Structures diff --git a/Minecraft.Assets/Windows64Media/loc/stringsGeneric.xml b/Minecraft.Assets/Windows64Media/loc/stringsGeneric.xml index 36b521dd0..ec3b88e28 100644 --- a/Minecraft.Assets/Windows64Media/loc/stringsGeneric.xml +++ b/Minecraft.Assets/Windows64Media/loc/stringsGeneric.xml @@ -1,4 +1,4 @@ - + New Downloadable Content is available! Access it from the Minecraft Store button on the Main Menu. @@ -6044,6 +6044,10 @@ Would you like to unlock the full game now? Food + + Search Items + + Structures @@ -8811,4 +8815,4 @@ All Ender Chests in a world are linked. Items placed into an Ender Chest are acc Cure - \ No newline at end of file + diff --git a/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.cpp b/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.cpp index 28a3773b4..2f609340b 100644 --- a/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.cpp +++ b/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.cpp @@ -469,6 +469,11 @@ void IUIScene_CreativeMenu::staticCtor() { ITEM(Item::carrotGolden_Id) ITEM(Item::pumpkinPie_Id) +// 4jcraft: Search +#ifdef ENABLE_JAVA_GUIS + DEF(eCreativeInventory_Search) +#endif + // Tools, Armour and Weapons (Complete) DEF(eCreativeInventory_ToolsArmourWeapons) ITEM(Item::compass_Id) @@ -856,6 +861,13 @@ void IUIScene_CreativeMenu::staticCtor() { specs[eCreativeInventoryTab_Food] = new TabSpec(L"Food", IDS_GROUPNAME_FOOD, 1, foodGroup); +// 4jcraft +#ifdef ENABLE_JAVA_GUIS + ECreative_Inventory_Groups searchGroup[] = {eCreativeInventory_Search}; + specs[eCreativeInventoryTab_Search] = + new TabSpec(L"Search Items", IDS_GROUPNAME_SEARCH, 1, searchGroup); +#endif + ECreative_Inventory_Groups toolsGroup[] = { eCreativeInventory_ToolsArmourWeapons}; specs[eCreativeInventoryTab_ToolsWeaponsArmor] = @@ -898,7 +910,7 @@ IUIScene_CreativeMenu::IUIScene_CreativeMenu() { m_bCarryingCreativeItem = false; m_creativeSlotX = m_creativeSlotY = m_inventorySlotX = m_inventorySlotY = 0; - // 4J JEV - Settup Tabs + // 4J JEV - Setup Tabs for (int i = 0; i < eCreativeInventoryTab_COUNT; i++) { m_tabDynamicPos[i] = 0; m_tabPage[i] = 0; @@ -1523,4 +1535,4 @@ void IUIScene_CreativeMenu::BuildFirework( } list->push_back(firework); -} +} \ No newline at end of file diff --git a/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h b/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h index 02967ac5a..fc2cb071e 100644 --- a/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h +++ b/Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.h @@ -7,20 +7,24 @@ class SimpleContainer; class IUIScene_CreativeMenu : public virtual IUIScene_AbstractContainerMenu { public: - // 4J Stu - These map directly to the tabs seenon the screen + // 4J Stu - These map directly to the tabs seen on the screen enum ECreativeInventoryTabs { eCreativeInventoryTab_BuildingBlocks = 0, eCreativeInventoryTab_Decorations, eCreativeInventoryTab_RedstoneAndTransport, eCreativeInventoryTab_Materials, eCreativeInventoryTab_Food, +// 4jcraft: java search tab +#ifdef ENABLE_JAVA_GUIS + eCreativeInventoryTab_Search, +#endif eCreativeInventoryTab_ToolsWeaponsArmor, eCreativeInventoryTab_Brewing, eCreativeInventoryTab_Misc, eCreativeInventoryTab_COUNT, }; - // 4J Stu - These are logical groupings of items, and be be combined for + // 4J Stu - These are logical groupings of items, and are combined for // tabs on-screen enum ECreative_Inventory_Groups { eCreativeInventory_BuildingBlocks, @@ -29,6 +33,10 @@ public: eCreativeInventory_Transport, eCreativeInventory_Materials, eCreativeInventory_Food, +// 4jcraft +#ifdef ENABLE_JAVA_GUIS + eCreativeInventory_Search, +#endif eCreativeInventory_ToolsArmourWeapons, eCreativeInventory_Brewing, eCreativeInventory_Potions_Basic, @@ -97,7 +105,7 @@ public: virtual void loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, std::shared_ptr player) {} // do nothing }* itemPickerMenu; - + // 4jcraft: changed these two from public to protected for the java UI static std::vector > categoryGroups[eCreativeInventoryGroupsCount]; @@ -148,4 +156,4 @@ protected: static void BuildFirework(std::vector >* list, uint8_t type, int color, int sulphur, bool flicker, bool trail, int fadeColor = -1); -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp index a3b16edc5..bf608e7ee 100644 --- a/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp +++ b/Minecraft.Client/UI/Screens/AbstractContainerScreen.cpp @@ -306,9 +306,10 @@ void AbstractContainerScreen::mouseClicked(int x, int y, int buttonNum) { } if (slotId != -1) { - bool quickKey = slotId != AbstractContainerMenu::SLOT_CLICKED_OUTSIDE && - (Keyboard::isKeyDown(Keyboard::KEY_LSHIFT) || - Keyboard::isKeyDown(Keyboard::KEY_RSHIFT)); + bool quickKey = + slotId != AbstractContainerMenu::SLOT_CLICKED_OUTSIDE && + (Keyboard::isKeyDown(Keyboard::KEY_LSHIFT) || + Keyboard::isKeyDown(Keyboard::KEY_RSHIFT)); minecraft->gameMode->handleInventoryMouseClick( menu->containerId, slotId, buttonNum, quickKey, minecraft->player); @@ -341,4 +342,4 @@ void AbstractContainerScreen::tick() { Screen::tick(); if (!minecraft->player->isAlive() || minecraft->player->removed) minecraft->player->closeContainer(); -} \ No newline at end of file +} diff --git a/Minecraft.Client/UI/Screens/AbstractContainerScreen.h b/Minecraft.Client/UI/Screens/AbstractContainerScreen.h index da3d3e625..ace3ec4bf 100644 --- a/Minecraft.Client/UI/Screens/AbstractContainerScreen.h +++ b/Minecraft.Client/UI/Screens/AbstractContainerScreen.h @@ -42,4 +42,4 @@ public: virtual void slotsChanged(std::shared_ptr container); virtual bool isPauseScreen(); virtual void tick(); -}; \ No newline at end of file +}; diff --git a/Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp index aea796309..98e2a3aec 100644 --- a/Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp +++ b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.cpp @@ -15,513 +15,533 @@ #include // Static member initialization -int CreativeInventoryScreen::selectedTabIndex = IUIScene_CreativeMenu::eCreativeInventoryTab_BuildingBlocks; -std::shared_ptr CreativeInventoryScreen::basicInventory = std::make_shared(0, L"", false, ITEMS_PER_PAGE); +int CreativeInventoryScreen::selectedTabIndex = + IUIScene_CreativeMenu::eCreativeInventoryTab_BuildingBlocks; +int CreativeInventoryScreen::tabIconIds + [IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT] = { + // Building Blocks + Tile::redBrick_Id, + + // Decorations + Tile::rose_Id, + + // Redstone & Transportation + Item::redStone_Id, + + // Materials + Item::stick_Id, + + // Food + Item::apple_Id, + +// Fix for it not compiling with shiggy +#ifdef ENABLE_JAVA_GUIS + // Search Items + Item::compass_Id, +#endif + + // Tools, Weapons & Armor + Item::hatchet_iron_Id, + + // Brewing + Item::potion_Id, + + // Materials + Item::bucket_lava_Id}; +std::shared_ptr CreativeInventoryScreen::basicInventory = + std::make_shared(0, L"", false, ITEMS_PER_PAGE); +ItemRenderer* CreativeInventoryScreen::itemRenderer = new ItemRenderer(); +std::shared_ptr CreativeInventoryScreen::tabIcons + [IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT]; // ContainerCreative implementation -CreativeInventoryScreen::ContainerCreative::ContainerCreative(std::shared_ptr player) : AbstractContainerMenu() -{ - std::shared_ptr inventoryplayer = player->inventory; - - // Add creative inventory slots (5 rows x 9 columns = 45 slots) - for (int i = 0; i < ROWS; ++i) - { - for (int j = 0; j < COLUMNS; ++j) - { - addSlot(new Slot(basicInventory, i * COLUMNS + j, 9 + j * 18, 18 + i * 18)); - } - } - - // Add hotbar slots (9 slots at bottom) - for (int k = 0; k < 9; ++k) - { - addSlot(new Slot(inventoryplayer, k, 9 + k * 18, 112)); - } - - scrollTo(0.0f); +CreativeInventoryScreen::ContainerCreative::ContainerCreative( + std::shared_ptr player) + : AbstractContainerMenu() { + std::shared_ptr inventoryplayer = player->inventory; + + // Add creative inventory slots (5 rows x 9 columns = 45 slots) + for (int i = 0; i < ROWS; i++) { + for (int j = 0; j < COLUMNS; j++) { + addSlot(new Slot(basicInventory, i * COLUMNS + j, 9 + j * 18, + 18 + i * 18)); + } + } + + // Add hotbar slots (9 slots at bottom) + for (int k = 0; k < 9; k++) { + addSlot(new Slot(inventoryplayer, k, 9 + k * 18, 112)); + } + + scrollTo(0.0f); + + for (int i = 0; i < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; + i++) { + tabIcons[i] = std::shared_ptr( + new ItemInstance(tabIconIds[i], 1, 0)); + } } -bool CreativeInventoryScreen::ContainerCreative::stillValid(std::shared_ptr player) -{ - return true; +bool CreativeInventoryScreen::ContainerCreative::stillValid( + std::shared_ptr player) { + return true; } -std::shared_ptr CreativeInventoryScreen::ContainerCreative::clicked(int slotIndex, int buttonNum, int clickType, std::shared_ptr player) -{ - std::shared_ptr inventory = player->inventory; - std::shared_ptr carried = inventory->getCarried(); - - // Handle clicks outside the GUI - if (slotIndex == SLOT_CLICKED_OUTSIDE) - { - // Drop the carried item - if (carried != NULL) - { - if (buttonNum == 0) - { - player->drop(carried, true); - inventory->setCarried(std::shared_ptr()); - } - else if (buttonNum == 1) - { - std::shared_ptr single = carried->copy(); - single->count = 1; - player->drop(single, true); - carried->count--; - if (carried->count <= 0) - { - inventory->setCarried(std::shared_ptr()); - } - } - } - return std::shared_ptr(); - } - - // Validate slot index - if (slotIndex < 0 || slotIndex >= (int)slots.size()) - { - return std::shared_ptr(); - } - - Slot* slot = slots.at(slotIndex); - - // Handle creative inventory slots (0-44) - if (slotIndex >= 0 && slotIndex < ITEMS_PER_PAGE) - { - std::shared_ptr slotItem = slot->getItem(); - - // Handle SWAP (number key) - copy item to hotbar - if (clickType == CLICK_SWAP) - { - if (slotItem != NULL && buttonNum >= 0 && buttonNum < 9) - { - std::shared_ptr copy = slotItem->copy(); - copy->count = copy->getMaxStackSize(); - inventory->setItem(buttonNum, copy); - } - return std::shared_ptr(); - } - - // Handle CLONE (middle click) - if (clickType == CLICK_CLONE) - { - if (slotItem != NULL) - { - std::shared_ptr copy = slotItem->copy(); - copy->count = copy->getMaxStackSize(); - inventory->setCarried(copy); - } - return std::shared_ptr(); - } - - // Handle normal clicks - if (slotItem != NULL) - { - if (buttonNum == 0) // Left click - { - std::shared_ptr copy = slotItem->copy(); - copy->count = copy->getMaxStackSize(); - inventory->setCarried(copy); - } - else if (buttonNum == 1) // Right click - { - std::shared_ptr copy = slotItem->copy(); - copy->count = 1; - inventory->setCarried(copy); - } - } - else if (carried != NULL) - { - // Clicking on empty creative slot with item - clear the carried item - inventory->setCarried(std::shared_ptr()); - } - - return std::shared_ptr(); - } - - // For hotbar slots (45-53), use normal container behavior - return AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player); +std::shared_ptr +CreativeInventoryScreen::ContainerCreative::clicked( + int slotIndex, int buttonNum, int clickType, + std::shared_ptr player) { + std::shared_ptr inventory = player->inventory; + std::shared_ptr carried = inventory->getCarried(); + + // Handle clicks outside the GUI + if (slotIndex == SLOT_CLICKED_OUTSIDE) { + // Drop the carried item + if (carried != NULL) { + if (buttonNum == 0) { + player->drop(carried, true); + inventory->setCarried(std::shared_ptr()); + } else if (buttonNum == 1) { + std::shared_ptr single = carried->copy(); + single->count = 1; + player->drop(single, true); + carried->count--; + if (carried->count <= 0) { + inventory->setCarried(std::shared_ptr()); + } + } + } + return std::shared_ptr(); + } + + // Validate slot index + if (slotIndex < 0 || slotIndex >= (int)slots.size()) { + return std::shared_ptr(); + } + + Slot* slot = slots.at(slotIndex); + + // Handle creative inventory slots (0-44) + if (slotIndex >= 0 && slotIndex < ITEMS_PER_PAGE) { + std::shared_ptr slotItem = slot->getItem(); + + // Handle SWAP (number key) - copy item to hotbar + if (clickType == CLICK_SWAP) { + if (slotItem != NULL && buttonNum >= 0 && buttonNum < 9) { + std::shared_ptr copy = slotItem->copy(); + copy->count = copy->getMaxStackSize(); + inventory->setItem(buttonNum, copy); + } + return std::shared_ptr(); + } + + // Handle CLONE (middle click) + if (clickType == CLICK_CLONE) { + if (slotItem != NULL) { + std::shared_ptr copy = slotItem->copy(); + copy->count = copy->getMaxStackSize(); + inventory->setCarried(copy); + } + return std::shared_ptr(); + } + + // Handle normal clicks + if (slotItem != NULL) { + if (buttonNum == 0) // Left click + { + std::shared_ptr copy = slotItem->copy(); + copy->count = copy->getMaxStackSize(); + inventory->setCarried(copy); + } else if (buttonNum == 1) // Right click + { + std::shared_ptr copy = slotItem->copy(); + copy->count = 1; + inventory->setCarried(copy); + } + } else if (carried != NULL) { + // Clicking on empty creative slot with item - clear the carried + // item + inventory->setCarried(std::shared_ptr()); + } + + return std::shared_ptr(); + } + + // For hotbar slots (45-53), use normal container behavior + return AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, + player); } -void CreativeInventoryScreen::ContainerCreative::scrollTo(float pos) -{ - int i = (itemList.size() + COLUMNS - 1) / COLUMNS - ROWS; - int j = (int)((double)(pos * (float)i) + 0.5); - - if (j < 0) - { - j = 0; - } - - for (int k = 0; k < ROWS; ++k) - { - for (int l = 0; l < COLUMNS; ++l) - { - int i1 = l + (k + j) * COLUMNS; - - if (i1 >= 0 && i1 < (int)itemList.size()) - { - basicInventory->setItem(l + k * COLUMNS, itemList[i1]); - } - else - { - basicInventory->setItem(l + k * COLUMNS, std::shared_ptr()); - } - } - } +void CreativeInventoryScreen::ContainerCreative::scrollTo(float pos) { + int i = (itemList.size() + COLUMNS - 1) / COLUMNS - ROWS; + int j = (int)((double)(pos * (float)i) + 0.5); + + if (j < 0) { + j = 0; + } + + for (int k = 0; k < ROWS; k++) { + for (int l = 0; l < COLUMNS; l++) { + int i1 = l + (k + j) * COLUMNS; + + if (i1 >= 0 && i1 < (int)itemList.size()) { + basicInventory->setItem(l + k * COLUMNS, itemList[i1]); + } else { + basicInventory->setItem(l + k * COLUMNS, + std::shared_ptr()); + } + } + } } -bool CreativeInventoryScreen::ContainerCreative::canScroll() -{ - return itemList.size() > ITEMS_PER_PAGE; +bool CreativeInventoryScreen::ContainerCreative::canScroll() { + return itemList.size() > ITEMS_PER_PAGE; } -CreativeInventoryScreen::CreativeInventoryScreen(std::shared_ptr player) - : AbstractContainerScreen(new ContainerCreative(player)) -{ - this->player = player; - player->containerMenu = menu; - - currentScroll = 0.0f; - isScrolling = false; - wasClicking = false; - isLeftMouseDown = false; - - imageHeight = 136; - imageWidth = 195; +CreativeInventoryScreen::CreativeInventoryScreen(std::shared_ptr player) + : AbstractContainerScreen(new ContainerCreative(player)) { + this->player = player; + player->containerMenu = menu; + + currentScroll = 0.0f; + isScrolling = false; + wasClicking = false; + isLeftMouseDown = false; + + imageHeight = 136; + imageWidth = 195; } -void CreativeInventoryScreen::removed() -{ - AbstractContainerScreen::removed(); +void CreativeInventoryScreen::removed() { AbstractContainerScreen::removed(); } + +void CreativeInventoryScreen::init() { + buttons.clear(); + + int i = selectedTabIndex; + selectedTabIndex = -1; + setCurrentCreativeTab(i); } -void CreativeInventoryScreen::init() -{ - buttons.clear(); - - int i = selectedTabIndex; - selectedTabIndex = -1; - setCurrentCreativeTab(i); -} - -void CreativeInventoryScreen::updateEvents() -{ +void CreativeInventoryScreen::updateEvents() { #ifdef ENABLE_JAVA_GUIS - // Handle mouse wheel scrolling. - // We use ButtonDown with the scroll actions rather than GetScrollDelta() because - // both share s_scrollTicksForButtonPressed; whichever is called first in a tick - // zeroes it, so GetScrollDelta() would return 0 if hotbar scroll ran first. - // ButtonDown/ScrollSnap() snapshots once per tick so all callers see the same value. - if (needsScrollBars()) - { - ContainerCreative* container = (ContainerCreative*)menu; - int totalRows = ((int)container->itemList.size() + COLUMNS - 1) / COLUMNS; - int scrollableRows = totalRows - ROWS; - if (scrollableRows > 0) - { - float step = 1.0f / (float)scrollableRows; - if (InputManager.ButtonDown(0, MINECRAFT_ACTION_LEFT_SCROLL)) - { - currentScroll -= step; - currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); - container->scrollTo(currentScroll); - } - else if (InputManager.ButtonDown(0, MINECRAFT_ACTION_RIGHT_SCROLL)) - { - currentScroll += step; - currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); - container->scrollTo(currentScroll); - } - } - } + // Handle mouse wheel scrolling. + // We use ButtonDown with the scroll actions rather than GetScrollDelta() + // because both share s_scrollTicksForButtonPressed; whichever is called + // first in a tick zeroes it, so GetScrollDelta() would return 0 if hotbar + // scroll ran first. ButtonDown/ScrollSnap() snapshots once per tick so all + // callers see the same value. + if (needsScrollBars()) { + ContainerCreative* container = (ContainerCreative*)menu; + int totalRows = + ((int)container->itemList.size() + COLUMNS - 1) / COLUMNS; + int scrollableRows = totalRows - ROWS; + if (scrollableRows > 0) { + float step = 1.0f / (float)scrollableRows; + if (InputManager.ButtonDown(0, MINECRAFT_ACTION_LEFT_SCROLL)) { + currentScroll -= step; + currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); + container->scrollTo(currentScroll); + } else if (InputManager.ButtonDown(0, + MINECRAFT_ACTION_RIGHT_SCROLL)) { + currentScroll += step; + currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); + container->scrollTo(currentScroll); + } + } + } #endif - Screen::updateEvents(); + Screen::updateEvents(); } -void CreativeInventoryScreen::containerTick() -{ +void CreativeInventoryScreen::containerTick() {} + +void CreativeInventoryScreen::tick() { Screen::tick(); } + +void CreativeInventoryScreen::keyPressed(wchar_t eventCharacter, int eventKey) { + AbstractContainerScreen::keyPressed(eventCharacter, eventKey); } -void CreativeInventoryScreen::tick() -{ - Screen::tick(); +void CreativeInventoryScreen::mouseClicked(int x, int y, int buttonNum) { + if (buttonNum == 0) isLeftMouseDown = true; + + Screen::mouseClicked(x, y, buttonNum); + + if (buttonNum == 0 || buttonNum == 1) { + int mouseX = x - (width - imageWidth) / 2; + int mouseY = y - (height - imageHeight) / 2; + + // Check for tab clicks first; let mouseReleased handle the actual tab + // switch + for (int tab = 0; + tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; tab++) { + if (isMouseOverTab(tab, mouseX, mouseY)) { + return; + } + } + + // Determine which slot (if any) was clicked + Slot* slot = findSlot(x, y); + + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + bool clickedOutside = + (x < xo || y < yo || x >= xo + imageWidth || y >= yo + imageHeight); + + int slotId = -1; + if (slot != NULL) slotId = slot->index; + if (clickedOutside) + slotId = AbstractContainerMenu::SLOT_CLICKED_OUTSIDE; + + if (slotId == -1) return; + + bool quickKey = slotId != AbstractContainerMenu::SLOT_CLICKED_OUTSIDE && + (Keyboard::isKeyDown(Keyboard::KEY_LSHIFT) || + Keyboard::isKeyDown(Keyboard::KEY_RSHIFT)); + int clickType = quickKey ? AbstractContainerMenu::CLICK_QUICK_MOVE + : AbstractContainerMenu::CLICK_PICKUP; + + // 4jcraft: bypass AbstractContainerScreen::mouseClicked / + // handleInventoryMouseClick here intentionally. The normal path sends a + // ContainerClickPacket to the server, where player->containerMenu is + // still the InventoryMenu (45 slots). Creative slot indices 0-44 are + // valid in ContainerCreative but not in InventoryMenu, and hotbar + // indices 45-53 exceed InventoryMenu's slot count entirely, causing an + // out-of-range crash in AbstractContainerMenu::clicked on the server + // side. Instead we apply the click locally and sync hotbar changes via + // SetCreativeModeSlotPacket. + menu->clicked(slotId, buttonNum, clickType, minecraft->player); + + // 4jcraft: sync hotbar slot changes to the server using + // SetCreativeModeSlotPacket. The packet handler + // (PlayerConnection::handleSetCreativeModeSlot) validates slots against + // InventoryMenu coordinates where the hotbar starts at + // USE_ROW_SLOT_START (36), so we must offset the local hotbar index + // (0-8) accordingly. + if (slotId >= ITEMS_PER_PAGE && slotId < ITEMS_PER_PAGE + 9) { + int hotbarSlot = slotId - ITEMS_PER_PAGE; + std::shared_ptr hotbarItem = + minecraft->player->inventory->getItem(hotbarSlot); + minecraft->gameMode->handleCreativeModeItemAdd( + hotbarItem, hotbarSlot + InventoryMenu::USE_ROW_SLOT_START); + } + } } -void CreativeInventoryScreen::keyPressed(wchar_t eventCharacter, int eventKey) -{ - AbstractContainerScreen::keyPressed(eventCharacter, eventKey); +void CreativeInventoryScreen::mouseReleased(int x, int y, int buttonNum) { + if (buttonNum == 0) isLeftMouseDown = false; + + if (buttonNum == 0) { + int mouseX = x - (width - imageWidth) / 2; + int mouseY = y - (height - imageHeight) / 2; + + // Check for tab clicks + for (int tab = 0; + tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; tab++) { + if (isMouseOverTab(tab, mouseX, mouseY)) { + setCurrentCreativeTab(tab); + return; + } + } + } + + AbstractContainerScreen::mouseReleased(x, y, buttonNum); } -void CreativeInventoryScreen::mouseClicked(int x, int y, int buttonNum) -{ - if (buttonNum == 0) isLeftMouseDown = true; +void CreativeInventoryScreen::render(int xm, int ym, float a) { + // Java: drawDefaultBackground() + renderBackground(); - Screen::mouseClicked(x, y, buttonNum); + // Handle scrollbar dragging + bool mouseDown = isLeftMouseDown; + int left = (width - imageWidth) / 2; + int top = (height - imageHeight) / 2; + int x1 = left + 175; + int y1 = top + 18; + int x2 = x1 + 14; + int y2 = y1 + 112; - if (buttonNum == 0 || buttonNum == 1) - { - int i = x - (width - imageWidth) / 2; - int j = y - (height - imageHeight) / 2; + if (!wasClicking && mouseDown && xm >= x1 && ym >= y1 && xm < x2 && + ym < y2) { + isScrolling = needsScrollBars(); + } - // Check for tab clicks first; let mouseReleased handle the actual tab switch - for (int tab = 0; tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; ++tab) - { - if (isMouseOverTab(tab, i, j)) - { - return; - } - } + if (!mouseDown) { + isScrolling = false; + } - // Determine which slot (if any) was clicked - Slot *slot = findSlot(x, y); + wasClicking = mouseDown; - int xo = (width - imageWidth) / 2; - int yo = (height - imageHeight) / 2; - bool clickedOutside = (x < xo || y < yo || x >= xo + imageWidth || y >= yo + imageHeight); + if (isScrolling) { + currentScroll = ((float)(ym - y1) - 7.5f) / ((float)(y2 - y1) - 15.0f); + currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); + ((ContainerCreative*)menu)->scrollTo(currentScroll); + } - int slotId = -1; - if (slot != NULL) slotId = slot->index; - if (clickedOutside) slotId = AbstractContainerMenu::SLOT_CLICKED_OUTSIDE; - - if (slotId == -1) return; - - bool quickKey = slotId != AbstractContainerMenu::SLOT_CLICKED_OUTSIDE && - (Keyboard::isKeyDown(Keyboard::KEY_LSHIFT) || Keyboard::isKeyDown(Keyboard::KEY_RSHIFT)); - int clickType = quickKey ? AbstractContainerMenu::CLICK_QUICK_MOVE : AbstractContainerMenu::CLICK_PICKUP; - - // 4jcraft: bypass AbstractContainerScreen::mouseClicked / handleInventoryMouseClick - // here intentionally. The normal path sends a ContainerClickPacket to the server, - // where player->containerMenu is still the InventoryMenu (45 slots). Creative slot - // indices 0-44 are valid in ContainerCreative but not in InventoryMenu, and hotbar - // indices 45-53 exceed InventoryMenu's slot count entirely, causing an out-of-range - // crash in AbstractContainerMenu::clicked on the server side. - // Instead we apply the click locally and sync hotbar changes via SetCreativeModeSlotPacket. - menu->clicked(slotId, buttonNum, clickType, minecraft->player); - - // 4jcraft: sync hotbar slot changes to the server using SetCreativeModeSlotPacket. - // The packet handler (PlayerConnection::handleSetCreativeModeSlot) validates slots - // against InventoryMenu coordinates where the hotbar starts at USE_ROW_SLOT_START (36), - // so we must offset the local hotbar index (0-8) accordingly. - if (slotId >= ITEMS_PER_PAGE && slotId < ITEMS_PER_PAGE + 9) - { - int hotbarSlot = slotId - ITEMS_PER_PAGE; - std::shared_ptr hotbarItem = minecraft->player->inventory->getItem(hotbarSlot); - minecraft->gameMode->handleCreativeModeItemAdd(hotbarItem, hotbarSlot + InventoryMenu::USE_ROW_SLOT_START); - } - } + AbstractContainerScreen::render(xm, ym, a); } -void CreativeInventoryScreen::mouseReleased(int x, int y, int buttonNum) -{ - if (buttonNum == 0) isLeftMouseDown = false; - - if (buttonNum == 0) - { - int i = x - (width - imageWidth) / 2; - int j = y - (height - imageHeight) / 2; - - // Check for tab clicks - for (int tab = 0; tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; ++tab) - { - if (isMouseOverTab(tab, i, j)) - { - setCurrentCreativeTab(tab); - return; - } - } - } - - AbstractContainerScreen::mouseReleased(x, y, buttonNum); -} - -void CreativeInventoryScreen::render(int xm, int ym, float a) -{ - // Java: drawDefaultBackground() - renderBackground(); - - // Handle scrollbar dragging - bool mouseDown = isLeftMouseDown; - int i = (width - imageWidth) / 2; - int j = (height - imageHeight) / 2; - int k = i + 175; - int l = j + 18; - int i1 = k + 14; - int j1 = l + 112; - - if (!wasClicking && mouseDown && xm >= k && ym >= l && xm < i1 && ym < j1) - { - isScrolling = needsScrollBars(); - } - - if (!mouseDown) - { - isScrolling = false; - } - - wasClicking = mouseDown; - - if (isScrolling) - { - currentScroll = ((float)(ym - l) - 7.5f) / ((float)(j1 - l) - 15.0f); - currentScroll = std::max(0.0f, std::min(1.0f, currentScroll)); - ((ContainerCreative*)menu)->scrollTo(currentScroll); - } - - AbstractContainerScreen::render(xm, ym, a); -} - -void CreativeInventoryScreen::renderLabels() -{ +void CreativeInventoryScreen::renderLabels() { #ifdef ENABLE_JAVA_GUIS - if (IUIScene_CreativeMenu::specs && selectedTabIndex >= 0 && selectedTabIndex < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT) - { - IUIScene_CreativeMenu::TabSpec* spec = IUIScene_CreativeMenu::specs[selectedTabIndex]; - if (spec) - { - std::wstring tabName = app.GetString(spec->m_descriptionId); - font->draw(tabName, 8, 6, 0x404040); - } - } + if (IUIScene_CreativeMenu::specs && selectedTabIndex >= 0 && + selectedTabIndex < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT) { + IUIScene_CreativeMenu::TabSpec* spec = + IUIScene_CreativeMenu::specs[selectedTabIndex]; + if (spec) { + std::wstring tabName = app.GetString(spec->m_descriptionId); + font->draw(tabName, 8, 6, 0x404040); + } + } #endif } -void CreativeInventoryScreen::renderBg(float a) -{ - int x = (width - imageWidth) / 2; - int y = (height - imageHeight) / 2; +void CreativeInventoryScreen::renderBg(float a) { + int x = (width - imageWidth) / 2; + int y = (height - imageHeight) / 2; #ifdef ENABLE_JAVA_GUIS - // Render all non-selected tabs first - for (int tab = 0; tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; ++tab) - { - if (tab != selectedTabIndex) - { - drawTab(tab); - } - } - - // Load and render main creative inventory background - int tex = minecraft->textures->loadTexture(TN_GUI_CREATIVE_TAB_ITEMS); - glColor4f(1, 1, 1, 1); - minecraft->textures->bind(tex); - blit(x, y, 0, 0, imageWidth, imageHeight); - - // Render scrollbar - tex = minecraft->textures->loadTexture(TN_GUI_CREATIVE_TABS); - minecraft->textures->bind(tex); - - int scrollX = x + 175; - int scrollY = y + 18; - int scrollHeight = 112; - - if (needsScrollBars()) - { - int scrollPos = (int)((float)(scrollHeight - 17) * currentScroll); - blit(scrollX, scrollY + scrollPos, 232, 0, 12, 15); - } - else - { - blit(scrollX, scrollY + (scrollHeight - 17) / 2, 244, 0, 12, 15); - } - - // Render selected tab last (on top) - drawTab(selectedTabIndex); + static int itemsTex = + minecraft->textures->loadTexture(TN_GUI_CREATIVE_TAB_ITEMS); + static int searchTex = + minecraft->textures->loadTexture(TN_GUI_CREATIVE_TAB_ITEM_SEARCH); + static int scrollTex = + minecraft->textures->loadTexture(TN_GUI_CREATIVE_TABS); + // Render all non-selected tabs first + for (int tab = 0; tab < IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT; + tab++) { + if (tab != selectedTabIndex) { + drawTab(tab); + } + } + + // Load and render main creative inventory background + glColor4f(1, 1, 1, 1); + minecraft->textures->bind((selectedTabIndex == 5) ? searchTex : itemsTex); + blit(x, y, 0, 0, imageWidth, imageHeight); + + // Render scrollbar + minecraft->textures->bind(scrollTex); + + int scrollX = x + 175; + int scrollY = y + 18; + int scrollHeight = 112; + + if (needsScrollBars()) { + int scrollPos = (int)((float)(scrollHeight - 17) * currentScroll); + blit(scrollX, scrollY + scrollPos, 232, 0, 12, 15); + } else { + blit(scrollX, scrollY, 244, 0, 12, 15); + } + + // Render selected tab last (on top) + drawTab(selectedTabIndex); #endif } -void CreativeInventoryScreen::setCurrentCreativeTab(int tab) -{ - if (tab < 0 || tab >= IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT) - return; - - int oldTab = selectedTabIndex; - selectedTabIndex = tab; - - ContainerCreative* container = (ContainerCreative*)menu; - container->itemList.clear(); - - // Populate itemList from the tab's category groups - if (IUIScene_CreativeMenu::specs && IUIScene_CreativeMenu::specs[tab]) - { - IUIScene_CreativeMenu::TabSpec* spec = IUIScene_CreativeMenu::specs[tab]; - - // Add items from static groups - for (int i = 0; i < spec->m_staticGroupsCount; ++i) - { - int groupIdx = spec->m_staticGroupsA[i]; - if (groupIdx >= 0 && groupIdx < IUIScene_CreativeMenu::eCreativeInventoryGroupsCount) - { - auto& group = IUIScene_CreativeMenu::categoryGroups[groupIdx]; - for (auto& item : group) - { - container->itemList.push_back(item); - } - } - } - } - - currentScroll = 0.0f; - container->scrollTo(0.0f); +void CreativeInventoryScreen::setCurrentCreativeTab(int tab) { + if (tab < 0 || tab >= IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT) + return; + + int oldTab = selectedTabIndex; + selectedTabIndex = tab; + + ContainerCreative* container = (ContainerCreative*)menu; + container->itemList.clear(); + + // Populate itemList from the tab's category groups + if (IUIScene_CreativeMenu::specs && IUIScene_CreativeMenu::specs[tab]) { + IUIScene_CreativeMenu::TabSpec* spec = + IUIScene_CreativeMenu::specs[tab]; + + // Add items from static groups + for (int i = 0; i < spec->m_staticGroupsCount; i++) { + int groupIdx = spec->m_staticGroupsA[i]; + if (groupIdx >= 0 && + groupIdx < + IUIScene_CreativeMenu::eCreativeInventoryGroupsCount) { + auto& group = IUIScene_CreativeMenu::categoryGroups[groupIdx]; + for (auto& item : group) { + container->itemList.push_back(item); + } + } + } + } + + currentScroll = 0.0f; + container->scrollTo(0.0f); } -void CreativeInventoryScreen::selectTab(int tab) -{ - setCurrentCreativeTab(tab); +void CreativeInventoryScreen::selectTab(int tab) { setCurrentCreativeTab(tab); } + +bool CreativeInventoryScreen::needsScrollBars() { + return ((ContainerCreative*)menu)->canScroll(); } -bool CreativeInventoryScreen::needsScrollBars() -{ - return ((ContainerCreative*)menu)->canScroll(); +bool CreativeInventoryScreen::isMouseOverTab(int tab, int mouseX, int mouseY) { + int tabColumn = tab % 6; + int x = tabColumn * 28; + int y = 0; + + if (tabColumn == 5) { + x = imageWidth - 28 + 2; + } else if (tabColumn > 0) { + x += tabColumn; + } + + if (tab < 6) { + y -= 32; + } else { + y = imageHeight; + } + + return ((mouseX >= x && mouseX <= x + 28) && + (mouseY >= y && mouseY <= y + 32)); } -bool CreativeInventoryScreen::isMouseOverTab(int tab, int mouseX, int mouseY) -{ - int i = tab; - int j = 28 * i; - int k = 0; - - if (i > 0) - { - j += i; - } - - // Tabs are in the top row - k = k - 32; - - return mouseX >= j && mouseX <= j + 28 && mouseY >= k && mouseY <= k + 32; -} - -void CreativeInventoryScreen::drawTab(int tab) -{ +void CreativeInventoryScreen::drawTab(int tab) { #ifdef ENABLE_JAVA_GUIS - bool isSelected = (tab == selectedTabIndex); - int i = tab; - int j = i * 28; - int k = 0; - int l = (width - imageWidth) / 2 + 28 * i; - int i1 = (height - imageHeight) / 2; - int j1 = 32; - - if (isSelected) - { - k += 32; - } - - if (i > 0) - { - l += i; - } - - // Tabs are in the top row - i1 = i1 - 28; - - // Render tab background - int tex = minecraft->textures->loadTexture(TN_GUI_CREATIVE_TABS); - minecraft->textures->bind(tex); - glColor4f(1, 1, 1, 1); - blit(l, i1, j, k, 28, 32); - - // TODO: Render tab icon (would need item icons) + bool isSelected = (selectedTabIndex == tab); + bool tabFirstRow = (tab < 6); + int left = (width - imageWidth) / 2; + int top = (height - imageHeight) / 2; + int tabColumn = tab % 6; + int sy = 0; + int x = left + 28 * tabColumn; + int y = top; + static int tex = minecraft->textures->loadTexture(TN_GUI_CREATIVE_TABS); + + if (isSelected) { + sy += 32; + } + + if (tabColumn == 5) { + x = left + imageWidth - 28; + } else if (tabColumn > 0) { + x += tabColumn; + } + + // Tabs are in the top row + if (tabFirstRow) { + y -= 28; + } else { + sy += 64; + y += imageHeight - 4; + } + + // Render tab background + glDisable(GL_LIGHTING); + minecraft->textures->bind(tex); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + blit(x, y, tabColumn * 28, sy, 28, 32); + + // Render tab icon + x += 6; + y += 8 + (tabFirstRow ? 1 : -1); + glEnable(GL_LIGHTING); + glEnable(GL_RESCALE_NORMAL); + Lighting::turnOnGui(); + itemRenderer->renderGuiItem(font, minecraft->textures, tabIcons[tab], x, y); + itemRenderer->renderGuiItemDecorations(font, minecraft->textures, + tabIcons[tab], x, y); + glDisable(GL_LIGHTING); #endif -} +} \ No newline at end of file diff --git a/Minecraft.Client/UI/Screens/CreativeInventoryScreen.h b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.h index 4ce1659f4..987ec9a88 100644 --- a/Minecraft.Client/UI/Screens/CreativeInventoryScreen.h +++ b/Minecraft.Client/UI/Screens/CreativeInventoryScreen.h @@ -9,63 +9,76 @@ class SimpleContainer; class Inventory; class Slot; -class CreativeInventoryScreen : public AbstractContainerScreen -{ +class CreativeInventoryScreen : public AbstractContainerScreen { private: - static constexpr int ROWS = 5; - static constexpr int COLUMNS = 9; - static constexpr int ITEMS_PER_PAGE = ROWS * COLUMNS; // 45 items (9x5 grid) - - // Currently selected creative tab index - static int selectedTabIndex; - - // Temporary inventory for creative mode items - static std::shared_ptr basicInventory; - - // Amount scrolled in Creative mode inventory (0 = top, 1 = bottom) - float currentScroll; - - bool isScrolling; - - // True if the left mouse button is currently being held - bool isLeftMouseDown; + static constexpr int ROWS = 5; + static constexpr int COLUMNS = 9; + static constexpr int ITEMS_PER_PAGE = + ROWS * COLUMNS; // 45 items (9x5 grid) - // True if the left mouse button was held down last time render was called - bool wasClicking; + // Currently selected creative tab index + static int selectedTabIndex; + + // Array of item ids for the tab icons + static int tabIconIds[IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT]; + + // Temporary inventory for creative mode items + static std::shared_ptr basicInventory; + + // Item renderer for the tab icons + static ItemRenderer* itemRenderer; + + // Array of tab icons + static std::shared_ptr + tabIcons[IUIScene_CreativeMenu::eCreativeInventoryTab_COUNT]; + + // Amount scrolled in Creative mode inventory (0 = top, 1 = bottom) + float currentScroll; + + bool isScrolling; + + // True if the left mouse button is currently being held + bool isLeftMouseDown; + + // True if the left mouse button was held down last time render was called + bool wasClicking; + + std::shared_ptr player; - std::shared_ptr player; - public: - class ContainerCreative : public AbstractContainerMenu - { - public: - std::vector> itemList; - - ContainerCreative(std::shared_ptr player); - virtual bool stillValid(std::shared_ptr player); - virtual std::shared_ptr clicked(int slotIndex, int buttonNum, int clickType, std::shared_ptr player); - void scrollTo(float pos); - bool canScroll(); - }; - + class ContainerCreative : public AbstractContainerMenu { + public: + std::vector> itemList; + + ContainerCreative(std::shared_ptr player); + virtual bool stillValid(std::shared_ptr player); + virtual std::shared_ptr clicked( + int slotIndex, int buttonNum, int clickType, + std::shared_ptr player); + void scrollTo(float pos); + bool canScroll(); + }; + public: - CreativeInventoryScreen(std::shared_ptr player); - virtual void removed(); - virtual void init(); - virtual void containerTick(); - virtual void tick(); - virtual void updateEvents(); - virtual void keyPressed(wchar_t eventCharacter, int eventKey); - virtual void mouseClicked(int x, int y, int buttonNum); - virtual void mouseReleased(int x, int y, int buttonNum); - virtual void render(int xm, int ym, float a); + CreativeInventoryScreen(std::shared_ptr player); + virtual void removed(); + virtual void init(); + virtual void containerTick(); + virtual void tick(); + virtual void updateEvents(); + virtual void keyPressed(wchar_t eventCharacter, int eventKey); + virtual void mouseClicked(int x, int y, int buttonNum); + virtual void mouseReleased(int x, int y, int buttonNum); + virtual void render(int xm, int ym, float a); + protected: - virtual void renderLabels(); - virtual void renderBg(float a); + virtual void renderLabels(); + virtual void renderBg(float a); + private: - void setCurrentCreativeTab(int tab); - void selectTab(int tab); - bool needsScrollBars(); - bool isMouseOverTab(int tab, int mouseX, int mouseY); - void drawTab(int tab); + void setCurrentCreativeTab(int tab); + void selectTab(int tab); + bool needsScrollBars(); + bool isMouseOverTab(int tab, int mouseX, int mouseY); + void drawTab(int tab); };