aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/AbstractContainerMenu.cpp
diff options
context:
space:
mode:
authordaoge <3523206925@qq.com>2026-03-03 03:04:10 +0800
committerGitHub <noreply@github.com>2026-03-03 03:04:10 +0800
commitb3feddfef372618c8a9d7a0abcaf18cfad866c18 (patch)
tree267761c3bb39241ba5c347bfbe2254d06686e287 /Minecraft.World/AbstractContainerMenu.cpp
parent84c31a2331f7a0ec85b9d438992e244f60e5020f (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.cpp344
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