Something went wrong. Try again.
the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
Something went wrong. Try again.
20 kB · 771 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771#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"
// 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 thisAbstractContainerMenu::AbstractContainerMenu(){ containerId = 0;
changeUid = 0;
quickcraftType = -1; quickcraftStatus = 0;
m_bNeedsRendered = false;}
AbstractContainerMenu::~AbstractContainerMenu(){ for( unsigned int i = 0; i < slots.size(); i++ ) { delete slots.at(i); }}
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){ containerListeners.push_back(listener);
vector<shared_ptr<ItemInstance> > *items = getItems(); listener->refreshContainer(this, items); delete items; 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++) { 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)) { // 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++) { (*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, bool looped) // 4J Added looped param{ shared_ptr<ItemInstance> clickedEntity = nullptr; shared_ptr<Inventory> inventory = player->inventory;
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 == SLOT_CLICKED_OUTSIDE) { if (inventory->getCarried() != NULL) { if (slotIndex == SLOT_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) { 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 oldType = piiClicked->id;
// 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) { 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); } } } } } } 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(); } if (carried->count >= c) { 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); } } 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 creativevoid AbstractContainerMenu::loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player){ while( clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player, true) != NULL) { }}
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 boolbool 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;}
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 Addedbool AbstractContainerMenu::isValidIngredient(shared_ptr<ItemInstance> item, int slotId){ return true;}