diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.World/AbstractContainerMenu.cpp | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.World/AbstractContainerMenu.cpp')
| -rw-r--r-- | Minecraft.World/AbstractContainerMenu.cpp | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/Minecraft.World/AbstractContainerMenu.cpp b/Minecraft.World/AbstractContainerMenu.cpp new file mode 100644 index 00000000..71d30feb --- /dev/null +++ b/Minecraft.World/AbstractContainerMenu.cpp @@ -0,0 +1,537 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.item.h" +#include "Slot.h" +#include "AbstractContainerMenu.h" + +// 4J Stu - The java does not have ctor here (being an abstract) but we need one to initialise the member variables +// 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 *>(); +} + +AbstractContainerMenu::~AbstractContainerMenu() +{ + delete lastSlots; + for( unsigned int i = 0; i < slots->size(); 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); + 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); + + + vector<shared_ptr<ItemInstance> > *items = getItems(); + listener->refreshContainer(this, items); + delete items; + broadcastChanges(); +} + +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++) + { + items->push_back((*it)->getItem()); + } + return items; +} + +void AbstractContainerMenu::sendData(int id, int value) +{ + AUTO_VAR(itEnd, containerListeners->end()); + for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++) + { + (*it)->setContainerData(this, id, value); + } +} + +void AbstractContainerMenu::broadcastChanges() +{ + for (unsigned int i = 0; i < slots->size(); 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; + m_bNeedsRendered = true; + + AUTO_VAR(itEnd, containerListeners->end()); + for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++) + { + (*it)->slotChanged(this, i, expected); + } + } + } +} + +bool AbstractContainerMenu::needsRendered() +{ + bool needsRendered = m_bNeedsRendered; + m_bNeedsRendered = false; + + for (unsigned int i = 0; i < slots->size(); 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; + needsRendered = true; + } + } + + return needsRendered; +} + +bool AbstractContainerMenu::clickMenuButton(shared_ptr<Player> player, int buttonId) +{ + return false; +} + +Slot *AbstractContainerMenu::getSlotFor(shared_ptr<Container> c, int index) +{ + 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)) + { + return slot; + } + } + return NULL; +} + +Slot *AbstractContainerMenu::getSlot(int index) +{ + return slots->at(index); +} + +shared_ptr<ItemInstance> AbstractContainerMenu::quickMoveStack(shared_ptr<Player> player, int slotIndex) +{ + Slot *slot = slots->at(slotIndex); + if (slot != NULL) + { + return slot->getItem(); + } + return nullptr; +} + +shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player) +{ + shared_ptr<ItemInstance> clickedEntity = nullptr; + shared_ptr<Inventory> inventory = player->inventory; + + if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1)) + { + if (slotIndex == CLICKED_OUTSIDE) + { + if (inventory->getCarried() != NULL) + { + if (slotIndex == CLICKED_OUTSIDE) + { + if (buttonNum == 0) + { + player->drop(inventory->getCarried()); + inventory->setCarried(nullptr); + } + if (buttonNum == 1) + { + player->drop(inventory->getCarried()->remove(1)); + if (inventory->getCarried()->count == 0) inventory->setCarried(nullptr); + } + + } + } + } + else if (clickType == CLICK_QUICK_MOVE) + { + 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(); + + 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); + } + } + } + } + } + else + { + if (slotIndex < 0) return nullptr; + + Slot *slot = slots->at(slotIndex); + if (slot != NULL) + { + shared_ptr<ItemInstance> clicked = slot->getItem(); + shared_ptr<ItemInstance> carried = inventory->getCarried(); + + if (clicked != NULL) + { + clickedEntity = clicked->copy(); + } + + if (clicked == NULL) + { + if (carried != NULL && slot->mayPlace(carried)) + { + int c = buttonNum == 0 ? carried->count : 1; + if (c > slot->getMaxStackSize()) + { + c = slot->getMaxStackSize(); + } + slot->set(carried->remove(c)); + if (carried->count == 0) + { + inventory->setCarried(nullptr); + } + } + } + // 4J Added for dyable armour and combinining damaged items + else if (buttonNum == 1 && mayCombine(slot, carried)) + { + shared_ptr<ItemInstance> combined = slot->combine(carried); + if(combined != NULL) + { + slot->set(combined); + if(!player->abilities.instabuild) carried->remove(1); + if (carried->count == 0) + { + inventory->setCarried(nullptr); + } + } + } + else if (slot->mayPickup(player)) + { + if (carried == NULL) + { + // pick up to empty hand + int c = buttonNum == 0 ? clicked->count : (clicked->count + 1) / 2; + shared_ptr<ItemInstance> removed = slot->remove(c); + + inventory->setCarried(removed); + if (clicked->count == 0) + { + slot->set(nullptr); + } + slot->onTake(player, inventory->getCarried()); + } + else if (slot->mayPlace(carried)) + { + // put down and/or pick up + if (clicked->id != carried->id || clicked->getAuxValue() != carried->getAuxValue() || !ItemInstance::tagMatches(clicked, carried)) + { + // no match, replace + if (carried->count <= slot->getMaxStackSize()) + { + slot->set(carried); + inventory->setCarried(clicked); + } + } + else + { + // match, attempt to fill slot + int c = buttonNum == 0 ? carried->count : 1; + if (c > slot->getMaxStackSize() - clicked->count) + { + c = slot->getMaxStackSize() - clicked->count; + } + if (c > carried->getMaxStackSize() - clicked->count) + { + c = carried->getMaxStackSize() - clicked->count; + } + carried->remove(c); + if (carried->count == 0) + { + inventory->setCarried(nullptr); + } + clicked->count += c; + } + } + else + { + // pick up to non-empty hand + if (clicked->id == carried->id && carried->getMaxStackSize() > 1 && (!clicked->isStackedByData() || clicked->getAuxValue() == carried->getAuxValue()) + && ItemInstance::tagMatches(clicked, carried)) + { + int c = clicked->count; + if (c > 0 && c + carried->count <= carried->getMaxStackSize()) + { + carried->count += c; + clicked = slot->remove(c); + if (clicked->count == 0) slot->set(nullptr); + slot->onTake(player, inventory->getCarried()); + } + } + } + + + } + slot->setChanged(); + } + } + } + else if (clickType == CLICK_SWAP && buttonNum >= 0 && buttonNum < 9) + { + Slot *slot = slots->at(slotIndex); + if (slot->mayPickup(player)) + { + shared_ptr<ItemInstance> current = inventory->getItem(buttonNum); + bool canMove = current == NULL || (slot->container == inventory && slot->mayPlace(current)); + int freeSlot = -1; + + if (!canMove) + { + freeSlot = inventory->getFreeSlot(); + canMove |= freeSlot > -1; + } + + if (slot->hasItem() && canMove) + { + shared_ptr<ItemInstance> taking = slot->getItem(); + inventory->setItem(buttonNum, taking); + + if ((slot->container == inventory && slot->mayPlace(current)) || current == NULL) + { + slot->remove(taking->count); + slot->set(current); + slot->onTake(player, taking); + } + else if (freeSlot > -1) + { + inventory->add(current); + slot->remove(taking->count); + slot->set(nullptr); + slot->onTake(player, taking); + } + } + else if (!slot->hasItem() && current != NULL && slot->mayPlace(current)) + { + inventory->setItem(buttonNum, nullptr); + slot->set(current); + } + } + } + else if (clickType == CLICK_CLONE && player->abilities.instabuild && inventory->getCarried() == NULL && slotIndex >= 0) + { + Slot *slot = slots->at(slotIndex); + if (slot != NULL && slot->hasItem()) + { + shared_ptr<ItemInstance> copy = slot->getItem()->copy(); + copy->count = copy->getMaxStackSize(); + inventory->setCarried(copy); + } + } + return clickedEntity; +} + +// 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); +} + +bool AbstractContainerMenu::mayCombine(Slot *slot, shared_ptr<ItemInstance> item) +{ + return false; +} + +void AbstractContainerMenu::removed(shared_ptr<Player> player) +{ + shared_ptr<Inventory> inventory = player->inventory; + if (inventory->getCarried() != NULL) + { + player->drop(inventory->getCarried()); + inventory->setCarried(nullptr); + } +} + +void AbstractContainerMenu::slotsChanged()// 4J used to take a shared_ptr<Container> but wasn't using it, so removed to simplify things +{ + broadcastChanges(); +} + +bool AbstractContainerMenu::isPauseScreen() +{ + return false; +} + +void AbstractContainerMenu::setItem(unsigned int slot, shared_ptr<ItemInstance> item) +{ + getSlot(slot)->set(item); +} + +void AbstractContainerMenu::setAll(ItemInstanceArray *items) +{ + for (unsigned int i = 0; i < items->length; i++) + { + getSlot(i)->set( (*items)[i] ); + } +} + +void AbstractContainerMenu::setData(int id, int value) +{ +} + +short AbstractContainerMenu::backup(shared_ptr<Inventory> inventory) +{ + changeUid++; + return changeUid; +} + +bool AbstractContainerMenu::isSynched(shared_ptr<Player> player) +{ + return !(unSynchedPlayers.find(player) != unSynchedPlayers.end()); +} + +void AbstractContainerMenu::setSynched(shared_ptr<Player> player, bool synched) +{ + if (synched) + { + AUTO_VAR(it, unSynchedPlayers.find(player)); + + if(it != unSynchedPlayers.end()) unSynchedPlayers.erase( it ); + } + else + { + unSynchedPlayers.insert(player); + } +} + +// 4J Stu - Brought a few changes in this function forward from 1.2 to make it return a bool +bool AbstractContainerMenu::moveItemStackTo(shared_ptr<ItemInstance> itemStack, int startSlot, int endSlot, bool backwards) +{ + bool anythingChanged = false; + + int destSlot = startSlot; + if (backwards) + { + destSlot = endSlot - 1; + } + + // find stackable slots first + if (itemStack->isStackable()) + { + while (itemStack->count > 0 && ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot))) + { + + 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) ) + { + int totalStack = target->count + itemStack->count; + if (totalStack <= itemStack->getMaxStackSize()) + { + itemStack->count = 0; + target->count = totalStack; + slot->setChanged(); + anythingChanged = true; + } + else if (target->count < itemStack->getMaxStackSize()) + { + itemStack->count -= (itemStack->getMaxStackSize() - target->count); + target->count = itemStack->getMaxStackSize(); + slot->setChanged(); + anythingChanged = true; + } + } + + if (backwards) + { + destSlot--; + } + else + { + destSlot++; + } + } + } + + // find empty slot + if (itemStack->count > 0) + { + if (backwards) + { + destSlot = endSlot - 1; + } + else + { + destSlot = startSlot; + } + while ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot)) + { + Slot *slot = slots->at(destSlot); + shared_ptr<ItemInstance> target = slot->getItem(); + + if (target == NULL) + { + slot->set(itemStack->copy()); + slot->setChanged(); + itemStack->count = 0; + anythingChanged = true; + break; + } + + if (backwards) + { + destSlot--; + } + else + { + destSlot++; + } + } + } + return anythingChanged; +} + +bool AbstractContainerMenu::isOverrideResultClick(int slotNum, int buttonNum) +{ + return false; +} |
