diff options
| author | daoge <3523206925@qq.com> | 2026-03-03 03:04:10 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-03 03:04:10 +0800 |
| commit | b3feddfef372618c8a9d7a0abcaf18cfad866c18 (patch) | |
| tree | 267761c3bb39241ba5c347bfbe2254d06686e287 /Minecraft.World/AbstractContainerMenu.cpp | |
| parent | 84c31a2331f7a0ec85b9d438992e244f60e5020f (diff) | |
feat: TU19 (Dec 2014) Features & Content (#155)
* try to resolve merge conflict
* feat: TU19 (Dec 2014) Features & Content (#32)
* December 2014 files
* Working release build
* Fix compilation issues
* Add sound to Windows64Media
* Add DLC content and force Tutorial DLC
* Revert "Add DLC content and force Tutorial DLC"
This reverts commit 97a43994725008e35fceb984d5549df9c8cea470.
* Disable broken light packing
* Disable breakpoint during DLC texture map load
Allows DLC loading but the DLC textures are still broken
* Fix post build not working
* ...
* fix vs2022 build
* fix cmake build
---------
Co-authored-by: Loki <lokirautio@gmail.com>
Diffstat (limited to 'Minecraft.World/AbstractContainerMenu.cpp')
| -rw-r--r-- | Minecraft.World/AbstractContainerMenu.cpp | 344 |
1 files changed, 289 insertions, 55 deletions
diff --git a/Minecraft.World/AbstractContainerMenu.cpp b/Minecraft.World/AbstractContainerMenu.cpp index 71d30feb..082e8008 100644 --- a/Minecraft.World/AbstractContainerMenu.cpp +++ b/Minecraft.World/AbstractContainerMenu.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.redstone.h" #include "Slot.h" #include "AbstractContainerMenu.h" @@ -8,46 +9,36 @@ // TODO Make sure all derived classes also call this AbstractContainerMenu::AbstractContainerMenu() { - lastSlots = new vector<shared_ptr<ItemInstance> >(); - slots = new vector<Slot *>(); containerId = 0; changeUid = 0; - m_bNeedsRendered = false; - containerListeners = new vector<ContainerListener *>(); + quickcraftType = -1; + quickcraftStatus = 0; + + m_bNeedsRendered = false; } AbstractContainerMenu::~AbstractContainerMenu() { - delete lastSlots; - for( unsigned int i = 0; i < slots->size(); i++ ) + for( unsigned int i = 0; i < slots.size(); i++ ) { - delete slots->at(i); + delete slots.at(i); } - delete slots; - delete containerListeners; } Slot *AbstractContainerMenu::addSlot(Slot *slot) { - slot->index = (int)slots->size(); - slots->push_back(slot); - lastSlots->push_back(nullptr); + slot->index = (int)slots.size(); + slots.push_back(slot); + lastSlots.push_back(nullptr); return slot; } void AbstractContainerMenu::addSlotListener(ContainerListener *listener) { - // TODO 4J Add exceptions - /* - if (containerListeners->contains(listener)) { - throw new IllegalArgumentException("Listener already listening"); - } - */ - containerListeners->push_back(listener); - + containerListeners.push_back(listener); vector<shared_ptr<ItemInstance> > *items = getItems(); listener->refreshContainer(this, items); @@ -55,11 +46,17 @@ void AbstractContainerMenu::addSlotListener(ContainerListener *listener) broadcastChanges(); } +void AbstractContainerMenu::removeSlotListener(ContainerListener *listener) +{ + AUTO_VAR(it, std::find(containerListeners.begin(), containerListeners.end(), listener) ); + if(it != containerListeners.end()) containerListeners.erase(it); +} + vector<shared_ptr<ItemInstance> > *AbstractContainerMenu::getItems() { vector<shared_ptr<ItemInstance> > *items = new vector<shared_ptr<ItemInstance> >(); - AUTO_VAR(itEnd, slots->end()); - for (AUTO_VAR(it, slots->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, slots.end()); + for (AUTO_VAR(it, slots.begin()); it != itEnd; it++) { items->push_back((*it)->getItem()); } @@ -68,8 +65,8 @@ vector<shared_ptr<ItemInstance> > *AbstractContainerMenu::getItems() void AbstractContainerMenu::sendData(int id, int value) { - AUTO_VAR(itEnd, containerListeners->end()); - for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, containerListeners.end()); + for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++) { (*it)->setContainerData(this, id, value); } @@ -77,18 +74,20 @@ void AbstractContainerMenu::sendData(int id, int value) void AbstractContainerMenu::broadcastChanges() { - for (unsigned int i = 0; i < slots->size(); i++) + for (unsigned int i = 0; i < slots.size(); i++) { - shared_ptr<ItemInstance> current = slots->at(i)->getItem(); - shared_ptr<ItemInstance> expected = lastSlots->at(i); + shared_ptr<ItemInstance> current = slots.at(i)->getItem(); + shared_ptr<ItemInstance> expected = lastSlots.at(i); if (!ItemInstance::matches(expected, current)) { - expected = current == NULL ? nullptr : current->copy(); - (*lastSlots)[i] = expected; + // 4J Stu - Added 0 count check. There is a bug in the Java with anvils that means this broadcast + // happens while we are in the middle of quickmoving, and before the slot properly gets set to null + expected = (current == NULL || current->count == 0) ? nullptr : current->copy(); + lastSlots[i] = expected; m_bNeedsRendered = true; - AUTO_VAR(itEnd, containerListeners->end()); - for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, containerListeners.end()); + for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++) { (*it)->slotChanged(this, i, expected); } @@ -101,14 +100,14 @@ bool AbstractContainerMenu::needsRendered() bool needsRendered = m_bNeedsRendered; m_bNeedsRendered = false; - for (unsigned int i = 0; i < slots->size(); i++) + for (unsigned int i = 0; i < slots.size(); i++) { - shared_ptr<ItemInstance> current = slots->at(i)->getItem(); - shared_ptr<ItemInstance> expected = lastSlots->at(i); + shared_ptr<ItemInstance> current = slots.at(i)->getItem(); + shared_ptr<ItemInstance> expected = lastSlots.at(i); if (!ItemInstance::matches(expected, current)) { expected = current == NULL ? nullptr : current->copy(); - (*lastSlots)[i] = expected; + lastSlots[i] = expected; needsRendered = true; } } @@ -123,8 +122,8 @@ bool AbstractContainerMenu::clickMenuButton(shared_ptr<Player> player, int butto Slot *AbstractContainerMenu::getSlotFor(shared_ptr<Container> c, int index) { - AUTO_VAR(itEnd, slots->end()); - for (AUTO_VAR(it, slots->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, slots.end()); + for (AUTO_VAR(it, slots.begin()); it != itEnd; it++) { Slot *slot = *it; //slots->at(i); if (slot->isAt(c, index)) @@ -137,12 +136,12 @@ Slot *AbstractContainerMenu::getSlotFor(shared_ptr<Container> c, int index) Slot *AbstractContainerMenu::getSlot(int index) { - return slots->at(index); + return slots.at(index); } shared_ptr<ItemInstance> AbstractContainerMenu::quickMoveStack(shared_ptr<Player> player, int slotIndex) { - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL) { return slot->getItem(); @@ -150,18 +149,97 @@ shared_ptr<ItemInstance> AbstractContainerMenu::quickMoveStack(shared_ptr<Player return nullptr; } -shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player) +shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player, bool looped) // 4J Added looped param { shared_ptr<ItemInstance> clickedEntity = nullptr; shared_ptr<Inventory> inventory = player->inventory; - if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1)) + if (clickType == CLICK_QUICK_CRAFT) + { + int expectedStatus = quickcraftStatus; + quickcraftStatus = getQuickcraftHeader(buttonNum); + + if ((expectedStatus != QUICKCRAFT_HEADER_CONTINUE || quickcraftStatus != QUICKCRAFT_HEADER_END) && expectedStatus != quickcraftStatus) + { + resetQuickCraft(); + } + else if (inventory->getCarried() == NULL) + { + resetQuickCraft(); + } + else if (quickcraftStatus == QUICKCRAFT_HEADER_START) + { + quickcraftType = getQuickcraftType(buttonNum); + + if (isValidQuickcraftType(quickcraftType)) + { + quickcraftStatus = QUICKCRAFT_HEADER_CONTINUE; + quickcraftSlots.clear(); + } + else + { + resetQuickCraft(); + } + } + else if (quickcraftStatus == QUICKCRAFT_HEADER_CONTINUE) + { + Slot *slot = slots.at(slotIndex); + + if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count > quickcraftSlots.size() && canDragTo(slot)) + { + quickcraftSlots.insert(slot); + } + } + else if (quickcraftStatus == QUICKCRAFT_HEADER_END) + { + if (!quickcraftSlots.empty()) + { + shared_ptr<ItemInstance> source = inventory->getCarried()->copy(); + int remaining = inventory->getCarried()->count; + + for(AUTO_VAR(it, quickcraftSlots.begin()); it != quickcraftSlots.end(); ++it) + { + Slot *slot = *it; + if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count >= quickcraftSlots.size() && canDragTo(slot)) + { + shared_ptr<ItemInstance> copy = source->copy(); + int carry = slot->hasItem() ? slot->getItem()->count : 0; + getQuickCraftSlotCount(&quickcraftSlots, quickcraftType, copy, carry); + + if (copy->count > copy->getMaxStackSize()) copy->count = copy->getMaxStackSize(); + if (copy->count > slot->getMaxStackSize()) copy->count = slot->getMaxStackSize(); + + remaining -= copy->count - carry; + slot->set(copy); + } + } + + source->count = remaining; + if (source->count <= 0) + { + source = nullptr; + } + inventory->setCarried(source); + } + + resetQuickCraft(); + } + else + { + resetQuickCraft(); + } + } + else if (quickcraftStatus != QUICKCRAFT_HEADER_START) + { + resetQuickCraft(); + } + else if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1)) { - if (slotIndex == CLICKED_OUTSIDE) + if (slotIndex == SLOT_CLICKED_OUTSIDE) { if (inventory->getCarried() != NULL) { - if (slotIndex == CLICKED_OUTSIDE) + if (slotIndex == SLOT_CLICKED_OUTSIDE) { if (buttonNum == 0) { @@ -179,23 +257,38 @@ shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int butto } else if (clickType == CLICK_QUICK_MOVE) { - Slot *slot = slots->at(slotIndex); + if (slotIndex < 0) return nullptr; + Slot *slot = slots.at(slotIndex); if(slot != NULL && slot->mayPickup(player)) { shared_ptr<ItemInstance> piiClicked = quickMoveStack(player, slotIndex); if (piiClicked != NULL) { - //int oldSize = piiClicked->count; // 4J - Commented 1.8.2 and replaced with below int oldType = piiClicked->id; - clickedEntity = piiClicked->copy(); + // 4J Stu - We ignore the return value for loopClicks, so don't make a copy + if(!looped) + { + clickedEntity = piiClicked->copy(); + } + + // 4J Stu - Remove the reference to this before we start a recursive loop + piiClicked = nullptr; if (slot != NULL) { if (slot->getItem() != NULL && slot->getItem()->id == oldType) { - // 4J Stu - Brought forward loopClick from 1.2 to fix infinite recursion bug in creative - loopClick(slotIndex, buttonNum, true, player); + if(looped) + { + // Return a non-null value to indicate that we want to loop more + clickedEntity = shared_ptr<ItemInstance>(new ItemInstance(0,1,0)); + } + else + { + // 4J Stu - Brought forward loopClick from 1.2 to fix infinite recursion bug in creative + loopClick(slotIndex, buttonNum, true, player); + } } } } @@ -205,7 +298,7 @@ shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int butto { if (slotIndex < 0) return nullptr; - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL) { shared_ptr<ItemInstance> clicked = slot->getItem(); @@ -225,7 +318,10 @@ shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int butto { c = slot->getMaxStackSize(); } - slot->set(carried->remove(c)); + if (carried->count >= c) + { + slot->set(carried->remove(c)); + } if (carried->count == 0) { inventory->setCarried(nullptr); @@ -318,7 +414,7 @@ shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int butto } else if (clickType == CLICK_SWAP && buttonNum >= 0 && buttonNum < 9) { - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot->mayPickup(player)) { shared_ptr<ItemInstance> current = inventory->getItem(buttonNum); @@ -359,7 +455,7 @@ shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int butto } else if (clickType == CLICK_CLONE && player->abilities.instabuild && inventory->getCarried() == NULL && slotIndex >= 0) { - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL && slot->hasItem()) { shared_ptr<ItemInstance> copy = slot->getItem()->copy(); @@ -367,13 +463,66 @@ shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int butto inventory->setCarried(copy); } } + else if (clickType == CLICK_THROW && inventory->getCarried() == NULL && slotIndex >= 0) + { + Slot *slot = slots.at(slotIndex); + if (slot != NULL && slot->hasItem() && slot->mayPickup(player)) + { + shared_ptr<ItemInstance> item = slot->remove(buttonNum == 0 ? 1 : slot->getItem()->count); + slot->onTake(player, item); + player->drop(item); + } + } + else if (clickType == CLICK_PICKUP_ALL && slotIndex >= 0) + { + Slot *slot = slots.at(slotIndex); + shared_ptr<ItemInstance> carried = inventory->getCarried(); + + if (carried != NULL && (slot == NULL || !slot->hasItem() || !slot->mayPickup(player))) + { + int start = buttonNum == 0 ? 0 : slots.size() - 1; + int step = buttonNum == 0 ? 1 : -1; + + for (int pass = 0; pass < 2; pass++ ) + { + // In the first pass, we only get partial stacks. + for (int i = start; i >= 0 && i < slots.size() && carried->count < carried->getMaxStackSize(); i += step) + { + Slot *target = slots.at(i); + + if (target->hasItem() && canItemQuickReplace(target, carried, true) && target->mayPickup(player) && canTakeItemForPickAll(carried, target)) + { + if (pass == 0 && target->getItem()->count == target->getItem()->getMaxStackSize()) continue; + int count = min(carried->getMaxStackSize() - carried->count, target->getItem()->count); + shared_ptr<ItemInstance> removed = target->remove(count); + carried->count += count; + + if (removed->count <= 0) + { + target->set(nullptr); + } + target->onTake(player, removed); + } + } + } + } + + broadcastChanges(); + } return clickedEntity; } +bool AbstractContainerMenu::canTakeItemForPickAll(shared_ptr<ItemInstance> carried, Slot *target) +{ + return true; +} + // 4J Stu - Brought forward from 1.2 to fix infinite recursion bug in creative void AbstractContainerMenu::loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player) { - clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player); + while( clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player, true) != NULL) + { + } } bool AbstractContainerMenu::mayCombine(Slot *slot, shared_ptr<ItemInstance> item) @@ -460,7 +609,7 @@ bool AbstractContainerMenu::moveItemStackTo(shared_ptr<ItemInstance> itemStack, while (itemStack->count > 0 && ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot))) { - Slot *slot = slots->at(destSlot); + Slot *slot = slots.at(destSlot); shared_ptr<ItemInstance> target = slot->getItem(); if (target != NULL && target->id == itemStack->id && (!itemStack->isStackedByData() || itemStack->getAuxValue() == target->getAuxValue()) && ItemInstance::tagMatches(itemStack, target) ) @@ -506,7 +655,7 @@ bool AbstractContainerMenu::moveItemStackTo(shared_ptr<ItemInstance> itemStack, } while ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot)) { - Slot *slot = slots->at(destSlot); + Slot *slot = slots.at(destSlot); shared_ptr<ItemInstance> target = slot->getItem(); if (target == NULL) @@ -535,3 +684,88 @@ bool AbstractContainerMenu::isOverrideResultClick(int slotNum, int buttonNum) { return false; } + +int AbstractContainerMenu::getQuickcraftType(int mask) +{ + return (mask >> 2) & 0x3; +} + +int AbstractContainerMenu::getQuickcraftHeader(int mask) +{ + return mask & 0x3; +} + +int AbstractContainerMenu::getQuickcraftMask(int header, int type) +{ + return (header & 0x3) | ((type & 0x3) << 2); +} + +bool AbstractContainerMenu::isValidQuickcraftType(int type) +{ + return type == QUICKCRAFT_TYPE_CHARITABLE || type == QUICKCRAFT_TYPE_GREEDY; +} + +void AbstractContainerMenu::resetQuickCraft() +{ + quickcraftStatus = QUICKCRAFT_HEADER_START; + quickcraftSlots.clear(); +} + +bool AbstractContainerMenu::canItemQuickReplace(Slot *slot, shared_ptr<ItemInstance> item, bool ignoreSize) +{ + bool canReplace = slot == NULL || !slot->hasItem(); + + if (slot != NULL && slot->hasItem() && item != NULL && item->sameItem(slot->getItem()) && ItemInstance::tagMatches(slot->getItem(), item)) + { + canReplace |= slot->getItem()->count + (ignoreSize ? 0 : item->count) <= item->getMaxStackSize(); + } + + return canReplace; +} + +void AbstractContainerMenu::getQuickCraftSlotCount(unordered_set<Slot *> *quickCraftSlots, int quickCraftingType, shared_ptr<ItemInstance> item, int carry) +{ + switch (quickCraftingType) + { + case QUICKCRAFT_TYPE_CHARITABLE: + item->count = Mth::floor(item->count / (float) quickCraftSlots->size()); + break; + case QUICKCRAFT_TYPE_GREEDY: + item->count = 1; + break; + } + + item->count += carry; +} + +bool AbstractContainerMenu::canDragTo(Slot *slot) +{ + return true; +} + +int AbstractContainerMenu::getRedstoneSignalFromContainer(shared_ptr<Container> container) +{ + if (container == NULL) return 0; + int count = 0; + float totalPct = 0; + + for (int i = 0; i < container->getContainerSize(); i++) + { + shared_ptr<ItemInstance> item = container->getItem(i); + + if (item != NULL) + { + totalPct += item->count / (float) min(container->getMaxStackSize(), item->getMaxStackSize()); + count++; + } + } + + totalPct /= container->getContainerSize(); + return Mth::floor(totalPct * (Redstone::SIGNAL_MAX - 1)) + (count > 0 ? 1 : 0); +} + +// 4J Added +bool AbstractContainerMenu::isValidIngredient(shared_ptr<ItemInstance> item, int slotId) +{ + return true; +}
\ No newline at end of file |
