forked from Kolyah35/minecraft-pe-0.6.1
the whole game
This commit is contained in:
41
src/world/inventory/BaseContainerMenu.cpp
Executable file
41
src/world/inventory/BaseContainerMenu.cpp
Executable file
@@ -0,0 +1,41 @@
|
||||
#include "BaseContainerMenu.h"
|
||||
#include "../item/ItemInstance.h"
|
||||
|
||||
BaseContainerMenu::BaseContainerMenu( int containerType )
|
||||
: containerId(-1),
|
||||
containerType(containerType),
|
||||
listener(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void BaseContainerMenu::setListener( IContainerListener* listener )
|
||||
{
|
||||
if (!(this->listener = listener))
|
||||
return;
|
||||
|
||||
if (listener)
|
||||
listener->refreshContainer(this, lastSlots = getItems());
|
||||
}
|
||||
|
||||
void BaseContainerMenu::broadcastChanges()
|
||||
{
|
||||
//LOGI("broadcast: Base. Listener: %p\n", listener);
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
ItemList slots = getItems();
|
||||
if (slots.size() != lastSlots.size()) {
|
||||
listener->refreshContainer(this, lastSlots = slots);
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < slots.size(); i++) {
|
||||
ItemInstance& current = slots[i];
|
||||
ItemInstance& expected = lastSlots[i];
|
||||
if (!ItemInstance::matches(&expected, ¤t)) {
|
||||
expected = current;
|
||||
//LOGI("Broadcasting a change!\n");
|
||||
listener->slotChanged(this, i, expected, isResultSlot(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/world/inventory/BaseContainerMenu.h
Executable file
47
src/world/inventory/BaseContainerMenu.h
Executable file
@@ -0,0 +1,47 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_INVENTORY__BaseContainerMenu_H__
|
||||
#define NET_MINECRAFT_WORLD_INVENTORY__BaseContainerMenu_H__
|
||||
|
||||
//package net.minecraft.world.inventory;
|
||||
|
||||
#include <vector>
|
||||
#include "../item/ItemInstance.h"
|
||||
|
||||
class BaseContainerMenu;
|
||||
|
||||
class IContainerListener {
|
||||
public:
|
||||
virtual ~IContainerListener() {}
|
||||
virtual void refreshContainer(BaseContainerMenu* menu, const std::vector<ItemInstance>& items) {}
|
||||
virtual void slotChanged(BaseContainerMenu* menu, int slot, const ItemInstance& item, bool isResultSlot) {}
|
||||
virtual void setContainerData(BaseContainerMenu* menu, int id, int value) {}
|
||||
};
|
||||
|
||||
class TileEntity;
|
||||
|
||||
class BaseContainerMenu {
|
||||
public:
|
||||
typedef std::vector<ItemInstance> ItemList;
|
||||
|
||||
BaseContainerMenu(int containerType);
|
||||
virtual ~BaseContainerMenu() {}
|
||||
|
||||
virtual ItemList getItems() = 0;
|
||||
|
||||
virtual void setSlot(int slot, ItemInstance* item) = 0;
|
||||
virtual void setData( int id, int value ) {}
|
||||
|
||||
virtual void setListener(IContainerListener* listener);
|
||||
virtual void broadcastChanges();
|
||||
|
||||
virtual bool isResultSlot(int slot) { return false; }
|
||||
//virtual bool stillValid( Player* player );
|
||||
virtual bool tileEntityDestroyedIsInvalid( int tileEntityId ) = 0;
|
||||
|
||||
int containerId;
|
||||
int containerType;
|
||||
IContainerListener* listener;
|
||||
|
||||
ItemList lastSlots;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_INVENTORY__BaseContainerMenu_H__*/
|
||||
35
src/world/inventory/ContainerMenu.cpp
Executable file
35
src/world/inventory/ContainerMenu.cpp
Executable file
@@ -0,0 +1,35 @@
|
||||
#include "ContainerMenu.h"
|
||||
#include "../Container.h"
|
||||
#include "../entity/player/Player.h"
|
||||
#include "../item/ItemInstance.h"
|
||||
|
||||
ContainerMenu::ContainerMenu( Container* container, int tileEntityId /* = -1 */ )
|
||||
: super(ContainerType::CONTAINER),
|
||||
container(container),
|
||||
tileEntityId(tileEntityId)
|
||||
{
|
||||
}
|
||||
|
||||
void ContainerMenu::setSlot( int slot, ItemInstance* item )
|
||||
{
|
||||
container->setItem(slot, item);
|
||||
}
|
||||
|
||||
std::vector<ItemInstance> ContainerMenu::getItems()
|
||||
{
|
||||
std::vector<ItemInstance> out;
|
||||
for (int i = 0; i < container->getContainerSize(); ++i) {
|
||||
ItemInstance* item = container->getItem(i);
|
||||
out.push_back(item? *item : ItemInstance());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ContainerMenu::tileEntityDestroyedIsInvalid( int tileEntityId )
|
||||
{
|
||||
return (this->tileEntityId == tileEntityId);
|
||||
/*
|
||||
return (this->tileEntityId >= 0
|
||||
&& this->tileEntityId == tileEntityId);
|
||||
*/
|
||||
}
|
||||
30
src/world/inventory/ContainerMenu.h
Executable file
30
src/world/inventory/ContainerMenu.h
Executable file
@@ -0,0 +1,30 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_INVENTORY__ContainerMenu_H__
|
||||
#define NET_MINECRAFT_WORLD_INVENTORY__ContainerMenu_H__
|
||||
|
||||
//package net.minecraft.world.inventory;
|
||||
|
||||
#include "BaseContainerMenu.h"
|
||||
#include <vector>
|
||||
|
||||
class Container;
|
||||
class ItemInstance;
|
||||
|
||||
class ContainerMenu: public BaseContainerMenu
|
||||
{
|
||||
typedef BaseContainerMenu super;
|
||||
public:
|
||||
ContainerMenu(Container* container, int tileEntityId = -1);
|
||||
|
||||
virtual ~ContainerMenu() {}
|
||||
|
||||
virtual void setSlot(int slot, ItemInstance* item);
|
||||
virtual std::vector<ItemInstance> getItems();
|
||||
|
||||
virtual bool tileEntityDestroyedIsInvalid( int tileEntityId );
|
||||
|
||||
Container* container;
|
||||
protected:
|
||||
int tileEntityId;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_INVENTORY__ContainerMenu_H__*/
|
||||
92
src/world/inventory/CraftingContainer.h
Executable file
92
src/world/inventory/CraftingContainer.h
Executable file
@@ -0,0 +1,92 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_INVENTORY__None_H__
|
||||
#define NET_MINECRAFT_WORLD_INVENTORY__None_H__
|
||||
|
||||
//package net.minecraft.world.inventory;
|
||||
|
||||
#include "../Container.h"
|
||||
#include "../entity/player/Player.h"
|
||||
#include "../item/ItemInstance.h"
|
||||
//#include "AbstractContainerMenu.h"
|
||||
|
||||
class CraftingContainer: public Container
|
||||
{
|
||||
typedef Container super;
|
||||
public:
|
||||
CraftingContainer(/*AbstractContainerMenu* menu,*/ int w, int h)
|
||||
: super(ContainerType::WORKBENCH),
|
||||
size(w * h),
|
||||
width(w)/*,
|
||||
menu(menu)*/
|
||||
{
|
||||
items = new ItemInstance[size];
|
||||
}
|
||||
|
||||
~CraftingContainer() {
|
||||
delete[] items;
|
||||
}
|
||||
|
||||
ItemInstance* getItem(int slot) {
|
||||
if (slot >= getContainerSize()) {
|
||||
return NULL;
|
||||
}
|
||||
return &items[slot];
|
||||
}
|
||||
|
||||
ItemInstance* getItem(int x, int y) {
|
||||
if (x < 0 || x >= width) {
|
||||
return NULL;
|
||||
}
|
||||
int pos = x + y * width;
|
||||
return getItem(pos);
|
||||
}
|
||||
|
||||
//@itodo
|
||||
void setItem(int slot, const ItemInstance& item) {
|
||||
items[slot] = item;
|
||||
//menu->slotsChanged(this);
|
||||
}
|
||||
|
||||
ItemInstance removeItem(int slot, int count) {
|
||||
if (!items[slot].isNull()) {
|
||||
if (items[slot].count <= count) {
|
||||
ItemInstance item = items[slot];
|
||||
items[slot] = ItemInstance();
|
||||
//menu->slotsChanged(this);
|
||||
return item;
|
||||
} else {
|
||||
ItemInstance i = items[slot].remove(count);
|
||||
if (items[slot].count == 0) items[slot] = ItemInstance();
|
||||
//menu->slotsChanged(this);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return ItemInstance();
|
||||
}
|
||||
|
||||
int getContainerSize() const {
|
||||
return size;
|
||||
}
|
||||
int getMaxStackSize() const {
|
||||
return Container::LARGE_MAX_STACK_SIZE;
|
||||
}
|
||||
std::string getName() const {
|
||||
return "Crafting";
|
||||
}
|
||||
|
||||
void setContainerChanged() {}
|
||||
|
||||
bool stillValid(Player* player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void startOpen() {}
|
||||
void stopOpen() {}
|
||||
|
||||
private:
|
||||
ItemInstance* items;
|
||||
int size;
|
||||
int width;
|
||||
//AbstractContainerMenu* menu;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_INVENTORY__None_H__*/
|
||||
624
src/world/inventory/FillingContainer.cpp
Executable file
624
src/world/inventory/FillingContainer.cpp
Executable file
@@ -0,0 +1,624 @@
|
||||
#include "FillingContainer.h"
|
||||
#include "../level/tile/TreeTile.h"
|
||||
#include "../item/crafting/Recipe.h"
|
||||
#include "../../util/Mth.h"
|
||||
#include "../../nbt/CompoundTag.h"
|
||||
#include "../level/tile/StoneSlabTile.h"
|
||||
|
||||
#define MAGIX_VAL 255
|
||||
#define MAX_SLOTS 96
|
||||
|
||||
FillingContainer::FillingContainer(
|
||||
int numTotalSlots,
|
||||
int numLinkedSlots,
|
||||
int containerType,
|
||||
bool isCreative)
|
||||
: super(containerType),
|
||||
numTotalSlots(numTotalSlots),
|
||||
numLinkedSlots(numLinkedSlots),
|
||||
linkedSlots(NULL),
|
||||
_isCreative(isCreative)
|
||||
{
|
||||
if (numLinkedSlots > 0)
|
||||
linkedSlots = new LinkedSlot[numLinkedSlots];
|
||||
|
||||
items.resize(numTotalSlots);
|
||||
}
|
||||
|
||||
FillingContainer::~FillingContainer()
|
||||
{
|
||||
clearInventory();
|
||||
|
||||
if (numLinkedSlots > 0)
|
||||
delete[] linkedSlots;
|
||||
}
|
||||
|
||||
void FillingContainer::clearInventory()
|
||||
{
|
||||
for (int i = 0; i < numLinkedSlots; ++i) {
|
||||
linkedSlots[i] = LinkedSlot(i);
|
||||
}
|
||||
|
||||
//@todo: i = MAX_ -> get() transforms count=255-ptrs to real
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); i++) {
|
||||
release(i);
|
||||
}
|
||||
|
||||
items.resize(numTotalSlots);
|
||||
}
|
||||
|
||||
bool FillingContainer::removeResource( int type )
|
||||
{
|
||||
if (_isCreative) return true;
|
||||
|
||||
int slot = getSlot(type);
|
||||
if (slot < 0) return false;
|
||||
if (--items[slot]->count <= 0) release(slot);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillingContainer::removeResource( const ItemInstance& item ) {
|
||||
return removeResource(item, false) == 0;
|
||||
}
|
||||
|
||||
int FillingContainer::removeResource( const ItemInstance& item, bool requireExactAux )
|
||||
{
|
||||
if (_isCreative) return 0;
|
||||
|
||||
int count = item.count;
|
||||
while (count > 0) {
|
||||
// If any AUX value, remove any with that id
|
||||
int slot = -1;
|
||||
if (!requireExactAux && (Recipe::isAnyAuxValue(&item) || item.getAuxValue() == Recipe::ANY_AUX_VALUE))
|
||||
slot = getNonEmptySlot(item.id);
|
||||
else
|
||||
slot = getNonEmptySlot(item.id, item.getAuxValue());
|
||||
|
||||
if (slot < 0)
|
||||
return count;
|
||||
|
||||
// Try to remove all items, but if it's not enough,
|
||||
// we continue on another slot next time
|
||||
ItemInstance* slotItem = items[slot];
|
||||
int toRemove = Mth::Min(count, slotItem->count);
|
||||
slotItem->count -= toRemove;
|
||||
count -= toRemove;
|
||||
|
||||
if (slotItem->count <= 0)
|
||||
clearSlot(slot);
|
||||
//removeItem(slot, item.count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FillingContainer::hasResource( int type ) const
|
||||
{
|
||||
if (_isCreative) return true;
|
||||
|
||||
int slot = getSlot(type);
|
||||
if (slot < 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FillingContainer::swapSlots( int from, int to )
|
||||
{
|
||||
ItemInstance* tmp = items[to];
|
||||
items[to] = items[from];
|
||||
items[from] = tmp;
|
||||
}
|
||||
|
||||
bool FillingContainer::add( ItemInstance* item )
|
||||
{
|
||||
if (_isCreative) return true;
|
||||
|
||||
if (!item || item->isNull()) return true;
|
||||
|
||||
if (!item->isDamaged()) {
|
||||
int lastSize;
|
||||
do {
|
||||
lastSize = item->count;
|
||||
item->count = addResource(*item);
|
||||
} while (item->count > 0 && item->count < lastSize);
|
||||
//if (item->count == lastSize && player->abilities.instabuild) {
|
||||
// // silently destroy the item when having a full inventory
|
||||
// item->count = 0;
|
||||
// return true;
|
||||
//}
|
||||
return item->count < lastSize;
|
||||
}
|
||||
|
||||
int slot = getFreeSlot();
|
||||
if (slot >= 0) {
|
||||
items[slot] = ItemInstance::clone(item);
|
||||
// items[slot] = item;
|
||||
//items[slot]->popTime = FillingContainer::POP_TIME_DURATION;
|
||||
linkEmptySlot(slot);
|
||||
item->count = 0;
|
||||
return true;
|
||||
//} else if (player->abilities.instabuild) {
|
||||
// // silently destroy the item when having a full inventory
|
||||
// item->count = 0;
|
||||
// return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemInstance FillingContainer::removeItem( int slot, int count )
|
||||
{
|
||||
ItemInstance* item = getItem(slot);
|
||||
if (item) {
|
||||
if (count > item->count)
|
||||
count = item->count;
|
||||
item->count -= count;
|
||||
|
||||
if (item->count <= 0)
|
||||
clearSlot(slot);
|
||||
}
|
||||
|
||||
/*
|
||||
ItemList& pile = *getSlotList(slot);
|
||||
if (pile[slot] != NULL) {
|
||||
if (pile[slot]->count <= count) {
|
||||
ItemInstance item = *pile[slot];
|
||||
release(slot);
|
||||
return item;
|
||||
} else {
|
||||
ItemInstance i = pile[slot]->remove(count);
|
||||
if (pile[slot]->count == 0) release(slot);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return ItemInstance();
|
||||
}
|
||||
|
||||
void FillingContainer::setItem( int slot, ItemInstance* item )
|
||||
{
|
||||
if (slot < 0 || slot >= numTotalSlots)
|
||||
return;
|
||||
|
||||
if (ItemList* p = getSlotList(slot)) {
|
||||
ItemList& pile = *p;
|
||||
if (pile[slot]) *pile[slot] = item? *item : ItemInstance();
|
||||
else pile[slot] = new ItemInstance(item? *item : ItemInstance());
|
||||
}
|
||||
}
|
||||
|
||||
ListTag* FillingContainer::save( ListTag* listTag )
|
||||
{
|
||||
//LOGI("Save.inv-creative? %d. Size %d\n", _isCreative, items.size());
|
||||
if (!_isCreative) {
|
||||
ItemInstance selTmp;
|
||||
for (int i = 0; i < (int)items.size(); i++) {
|
||||
ItemInstance* item = items[i];
|
||||
|
||||
if (i < numLinkedSlots) {
|
||||
int slot = linkedSlots[i].inventorySlot;
|
||||
selTmp = ItemInstance(MAGIX_VAL, MAGIX_VAL, slot);
|
||||
item = &selTmp;
|
||||
}
|
||||
if (item != NULL) {
|
||||
CompoundTag* tag = new CompoundTag();
|
||||
tag->putByte("Slot", (char) i);
|
||||
|
||||
if (item->count < 0) item->count = 0;
|
||||
if (item->count > 255) item->count = 255;
|
||||
|
||||
ItemInstance iitem(*item);
|
||||
iitem.save(tag);
|
||||
//LOGI("Saving %d as : %d@%d:%d\n", i, item->id, item->getAuxValue(), item->count);
|
||||
listTag->add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return listTag;
|
||||
}
|
||||
|
||||
void FillingContainer::load( ListTag* inventoryList )
|
||||
{
|
||||
//LOGI("Load.inv-creative? %d. Size %d\n", _isCreative, items.size());
|
||||
if (_isCreative)
|
||||
return;
|
||||
|
||||
clearInventory();
|
||||
|
||||
//items = /*new*/ ItemInstance[INVENTORY_SIZE];
|
||||
for (int i = inventoryList->size()-1; i >= 0; --i) {
|
||||
Tag* t = inventoryList->get(i);
|
||||
if (t->getId() != Tag::TAG_Compound) continue;
|
||||
|
||||
CompoundTag* tag = (CompoundTag*) t;
|
||||
int slot = tag->getByte("Slot") & 0xff;
|
||||
if (slot < 0) continue;
|
||||
|
||||
ItemInstance* item = ItemInstance::fromTag(tag);
|
||||
if (item != NULL) {
|
||||
//LOGI("Loading %d as : %d@%d:%d\n", slot, item->id, item->getAuxValue(), item->count);
|
||||
// Special case! (don't we love them!). item->count == 255 means
|
||||
// we POINT to our real inventory item (from a selection slot).
|
||||
// This is ONLY AND ALWAYS used in Selection Slots at this moment.
|
||||
if (slot < numLinkedSlots) {
|
||||
if (slot < (int)items.size() && item->id == MAGIX_VAL && item->count == MAGIX_VAL) {
|
||||
int invSlot = item->getAuxValue();
|
||||
if (invSlot >= numLinkedSlots && invSlot < (int)items.size())
|
||||
linkSlot(slot, invSlot, false);
|
||||
} else { // Something's wrong, shouldnt go here
|
||||
LOGE("Error: Slot %d is selection slot (inventory size: %d) but id/count is %d/%d\n", slot, (int)items.size(), item->id, item->count);
|
||||
}
|
||||
delete item;
|
||||
continue;
|
||||
}
|
||||
|
||||
//item->count = 3;
|
||||
if (slot < MAX_SLOTS && slot >= numLinkedSlots)
|
||||
{
|
||||
// Zero count (valid before, but not anymore), destroy
|
||||
if (item->count == 0) {
|
||||
delete item;
|
||||
continue;
|
||||
}
|
||||
// Suggesting the container is larger than it is, drop the item!
|
||||
if (slot >= (int)items.size()) {
|
||||
doDrop(item, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
fixBackwardCompabilityItem(*item);
|
||||
items[slot] = item;
|
||||
}
|
||||
//else if (slot >= 100 && slot < armor.length + 100) armor[slot - 100] = item;
|
||||
else {
|
||||
if (slot >= MAX_SLOTS) {
|
||||
LOGE("Error: Too large slot ID in Inventory: %d!\n", slot);
|
||||
}
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
}
|
||||
compressLinkedSlotList(0);
|
||||
}
|
||||
|
||||
int FillingContainer::getContainerSize() const
|
||||
{
|
||||
int sz = items.size();
|
||||
if (sz != numTotalSlots) {
|
||||
LOGE("Error@getContainerSize: num items != InventorySize: %d != %d\n", sz, numTotalSlots);
|
||||
}
|
||||
return numTotalSlots;
|
||||
}
|
||||
|
||||
ItemInstance* FillingContainer::getItem( int slot )
|
||||
{
|
||||
if (slot < 0 || slot >= numTotalSlots)
|
||||
return NULL;
|
||||
|
||||
// Real inventory slot
|
||||
if (slot >= numLinkedSlots)
|
||||
return (*getSlotList(slot))[slot];
|
||||
|
||||
return getLinked(slot); //@note
|
||||
}
|
||||
|
||||
std::string FillingContainer::getName() const
|
||||
{
|
||||
return "Inventory";
|
||||
}
|
||||
|
||||
int FillingContainer::getMaxStackSize() const
|
||||
{
|
||||
return MAX_INVENTORY_STACK_SIZE;
|
||||
}
|
||||
|
||||
void FillingContainer::dropSlot( int slot, bool onlyClearContainer, bool randomly/*=false*/ )
|
||||
{
|
||||
if (slot >= 0 && slot < numLinkedSlots)
|
||||
slot = linkedSlots[slot].inventorySlot;
|
||||
if (slot < 0 || slot >= (int)items.size()) return;
|
||||
|
||||
if (items[slot] && items[slot]->count) {
|
||||
if (!onlyClearContainer)
|
||||
doDrop(items[slot]->copy(), randomly);
|
||||
items[slot]->count = 0;
|
||||
release(slot); //@itodo:
|
||||
compressLinkedSlotList(slot);
|
||||
}
|
||||
}
|
||||
|
||||
void FillingContainer::dropAll(bool onlyClearContainer)
|
||||
{
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); i++) {
|
||||
dropSlot(i, onlyClearContainer, true);
|
||||
}
|
||||
}
|
||||
|
||||
void FillingContainer::setContainerChanged()
|
||||
{
|
||||
}
|
||||
|
||||
bool FillingContainer::stillValid( Player* player )
|
||||
{
|
||||
return !player->removed;
|
||||
}
|
||||
|
||||
bool FillingContainer::contains( ItemInstance* itemInstance ) const
|
||||
{
|
||||
for (unsigned int i = 0; i < items.size(); i++) {
|
||||
if (items[i] != NULL && items[i]->matches(itemInstance)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int FillingContainer::getSlot( int tileId) const
|
||||
{
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); i++) {
|
||||
if (items[i] != NULL && items[i]->id == tileId) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FillingContainer::getSlot( int tileId, int data) const
|
||||
{
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); i++) {
|
||||
if (items[i] != NULL
|
||||
&& items[i]->id == tileId
|
||||
&& items[i]->getAuxValue() == data)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FillingContainer::getNonEmptySlot( int tileId) const
|
||||
{
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); i++) {
|
||||
if (items[i] != NULL && items[i]->id == tileId && items[i]->count > 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FillingContainer::getNonEmptySlot( int tileId, int data) const
|
||||
{
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); i++) {
|
||||
if (items[i] != NULL
|
||||
&& items[i]->id == tileId
|
||||
&& items[i]->getAuxValue() == data
|
||||
&& items[i]->count > 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FillingContainer::getNumEmptySlots() {
|
||||
int numEmpty = 0;
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); ++i) {
|
||||
if (!items[i] || items[i]->isNull())
|
||||
++numEmpty;
|
||||
}
|
||||
return numEmpty;
|
||||
}
|
||||
|
||||
int FillingContainer::getNumLinkedSlots() {
|
||||
return numLinkedSlots;
|
||||
}
|
||||
|
||||
int FillingContainer::getSlotWithRemainingSpace( const ItemInstance& item )
|
||||
{
|
||||
for (unsigned int i = 0; i < items.size(); i++) {
|
||||
if (items[i] != NULL && items[i]->id == item.id
|
||||
&& items[i]->isStackable()
|
||||
&& items[i]->count < items[i]->getMaxStackSize()
|
||||
&& items[i]->count < getMaxStackSize()
|
||||
&& (!items[i]->isStackedByData() || items[i]->getAuxValue() == item.getAuxValue())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FillingContainer::addResource( const ItemInstance& itemInstance )
|
||||
{
|
||||
int type = itemInstance.id;
|
||||
int count = itemInstance.count;
|
||||
|
||||
if (itemInstance.getMaxStackSize() == 1) {
|
||||
int slot = getFreeSlot();
|
||||
if (slot < 0) return count;
|
||||
if (items[slot] == NULL) {
|
||||
items[slot] = ItemInstance::clone(&itemInstance);
|
||||
linkEmptySlot(slot);
|
||||
} else if (items[slot]->isNull()) {
|
||||
*items[slot] = itemInstance;
|
||||
linkEmptySlot(slot);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int slot = getSlotWithRemainingSpace(itemInstance);
|
||||
if (slot < 0) slot = getFreeSlot();
|
||||
if (slot < 0) return count;
|
||||
if (items[slot] == NULL) {
|
||||
items[slot] = new ItemInstance(type, 0, itemInstance.getAuxValue());
|
||||
} else if (items[slot]->isNull()) { //@attn: added when doing chests
|
||||
*items[slot] = ItemInstance(type, 0, itemInstance.getAuxValue());
|
||||
}
|
||||
|
||||
// Add the newly added item to a selections lot, if one's free
|
||||
linkEmptySlot(slot);
|
||||
|
||||
int toAdd = count;
|
||||
|
||||
if (toAdd > items[slot]->getMaxStackSize() - items[slot]->count) {
|
||||
toAdd = items[slot]->getMaxStackSize() - items[slot]->count;
|
||||
}
|
||||
|
||||
if (toAdd > getMaxStackSize() - items[slot]->count) {
|
||||
toAdd = getMaxStackSize() - items[slot]->count;
|
||||
}
|
||||
|
||||
if (toAdd == 0) return count;
|
||||
|
||||
count -= toAdd;
|
||||
items[slot]->count += toAdd;
|
||||
//items[slot]->popTime = POP_TIME_DURATION;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int FillingContainer::getFreeSlot() const
|
||||
{
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); i++) {
|
||||
if (items[i] == NULL || items[i]->isNull()) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FillingContainer::release( int slot )
|
||||
{
|
||||
if (items[slot]) {
|
||||
delete items[slot];// @itodo
|
||||
items[slot] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void FillingContainer::clearSlot( int slot )
|
||||
{
|
||||
if (slot < 0)
|
||||
return;
|
||||
|
||||
if (slot < numLinkedSlots) {
|
||||
release(linkedSlots[slot].inventorySlot);
|
||||
linkedSlots[slot].inventorySlot = -1;
|
||||
}
|
||||
else {
|
||||
release(slot);
|
||||
}
|
||||
compressLinkedSlotList(slot);
|
||||
}
|
||||
|
||||
int FillingContainer::addItem(ItemInstance* item) {
|
||||
for (unsigned int i = numLinkedSlots; i < items.size(); ++i)
|
||||
if (!items[i]) {
|
||||
items[i] = item;
|
||||
return i;
|
||||
}
|
||||
|
||||
int newSize = items.size() + 1;
|
||||
if (_isCreative && newSize > numTotalSlots)
|
||||
numTotalSlots = newSize;
|
||||
if (newSize <= numTotalSlots) {
|
||||
items.push_back(item);
|
||||
return newSize-1;
|
||||
}
|
||||
LOGE("Error@addItem: adding an item to an already full inventory: %s!\n", item->getDescriptionId().c_str());
|
||||
delete item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FillingContainer::fixBackwardCompabilityItem( ItemInstance& item )
|
||||
{
|
||||
if (item.id == Tile::stoneSlabHalf->id)
|
||||
item.setAuxValue(item.getAuxValue() & StoneSlabTile::TYPE_MASK);
|
||||
}
|
||||
|
||||
void FillingContainer::replace( std::vector<ItemInstance> newItems, int maxCount /* = -1 */)
|
||||
{
|
||||
clearInventory();
|
||||
maxCount = maxCount < 0 ? newItems.size() : Mth::Min(newItems.size(), maxCount);
|
||||
|
||||
int base = numLinkedSlots;
|
||||
const int iMax = Mth::Min(getContainerSize() - base, maxCount);
|
||||
for (int i = 0; i < iMax; ++i) {
|
||||
replaceSlot(base + i, newItems[i].isNull()? NULL : &newItems[i]);
|
||||
//LOGI("Adding to slot: %d - %s :: %s\n", newItems[i], )
|
||||
}
|
||||
}
|
||||
|
||||
void FillingContainer::replaceSlot( int slotId, ItemInstance* ins )
|
||||
{
|
||||
if (ins) {
|
||||
if (!items[slotId])
|
||||
items[slotId] = new ItemInstance();
|
||||
*items[slotId] = *ins;
|
||||
} else {
|
||||
release(slotId);
|
||||
}
|
||||
}
|
||||
|
||||
FillingContainer::ItemList* FillingContainer::getSlotList( int& slot )
|
||||
{
|
||||
ItemList* pile = &items;
|
||||
//if (slot >= pile->size()) {
|
||||
// slot -= pile->size();
|
||||
// pile = armor;
|
||||
//}
|
||||
return pile;
|
||||
}
|
||||
|
||||
// Special for this "selection based" inventory
|
||||
bool FillingContainer::linkSlot(int selectionSlot, int inventorySlot, bool propagate) {
|
||||
if (selectionSlot < 0 || selectionSlot >= numLinkedSlots)
|
||||
return false;
|
||||
if (inventorySlot < numLinkedSlots || inventorySlot >= numTotalSlots)
|
||||
return false;
|
||||
if (inventorySlot == linkedSlots[selectionSlot].inventorySlot)
|
||||
return false;
|
||||
|
||||
if (propagate) {
|
||||
int i = 0;
|
||||
for (; i < numLinkedSlots - 1; ++i)
|
||||
if (linkedSlots[i].inventorySlot == inventorySlot) break;
|
||||
for (; i > selectionSlot; --i) {
|
||||
linkedSlots[i].inventorySlot = linkedSlots[i-1].inventorySlot;
|
||||
}
|
||||
}
|
||||
linkedSlots[selectionSlot].inventorySlot = inventorySlot;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillingContainer::linkEmptySlot( int inventorySlot )
|
||||
{
|
||||
// Check if we already got the inventory slot
|
||||
for (int i = 0; i < numLinkedSlots; ++i)
|
||||
if (linkedSlots[i].inventorySlot == inventorySlot) return true;
|
||||
|
||||
// Check if there's an empty slot to place the new resource in
|
||||
for (int i = 0; i < numLinkedSlots; ++i) {
|
||||
ItemInstance* item = getLinked(i);
|
||||
if (!item) {
|
||||
linkedSlots[i].inventorySlot = inventorySlot;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FillingContainer::compressLinkedSlotList(int slot)
|
||||
{
|
||||
int i = slot-1, j = 0;
|
||||
while (++i < numLinkedSlots) {
|
||||
linkedSlots[i-j] = linkedSlots[i];
|
||||
|
||||
ItemInstance* item = getLinked(i);
|
||||
if (!item) ++j;
|
||||
}
|
||||
for (int k = i-j; k < i; ++k)
|
||||
linkedSlots[k].inventorySlot = -1;
|
||||
}
|
||||
|
||||
void FillingContainer::doDrop( ItemInstance* item, bool randomly )
|
||||
{
|
||||
delete item;
|
||||
}
|
||||
|
||||
ItemInstance* FillingContainer::getLinked( int slot )
|
||||
{
|
||||
// sanity checking to prevent exploits
|
||||
if (slot < numLinkedSlots && slot >= 0) {
|
||||
int i = linkedSlots[slot].inventorySlot;
|
||||
return (i >= numLinkedSlots && i < numTotalSlots)? items[i] : NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
107
src/world/inventory/FillingContainer.h
Executable file
107
src/world/inventory/FillingContainer.h
Executable file
@@ -0,0 +1,107 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_INVENTORY__FILLINGCONTAINER_H__
|
||||
#define NET_MINECRAFT_WORLD_INVENTORY__FILLINGCONTAINER_H__
|
||||
|
||||
#include "../Container.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Player;
|
||||
class ListTag;
|
||||
class CompoundTag;
|
||||
|
||||
class FillingContainer: public Container
|
||||
{
|
||||
typedef Container super;
|
||||
protected:
|
||||
typedef std::vector<ItemInstance*> ItemList;
|
||||
public:
|
||||
static const int MAX_INVENTORY_STACK_SIZE = 254;
|
||||
|
||||
FillingContainer(int numTotalSlots, int numLinkedSlots, int containerType, bool isCreative);
|
||||
~FillingContainer();
|
||||
|
||||
bool hasResource(int type) const;
|
||||
bool removeResource(int type);
|
||||
bool removeResource(const ItemInstance& item);
|
||||
int removeResource(const ItemInstance& item, bool requireExactAux);
|
||||
void swapSlots(int from, int to);
|
||||
|
||||
virtual bool add(ItemInstance* item);
|
||||
ItemList* getSlotList(int& slot);
|
||||
|
||||
void dropSlot(int slot, bool onlyClearContainer, bool randomly=false);
|
||||
void dropAll(bool onlyClearContainer);
|
||||
// @itodo: keep return by value?
|
||||
ItemInstance removeItem(int slot, int count);
|
||||
|
||||
void clearSlot( int slot );
|
||||
void clearInventory();
|
||||
void clearInventoryWithDefault();
|
||||
|
||||
ListTag* save(ListTag* listTag);
|
||||
void load(ListTag* inventoryList);
|
||||
void replace( std::vector<ItemInstance> newItems, int count = -1 );
|
||||
void replaceSlot(int slotId, ItemInstance* ins);
|
||||
|
||||
void setItem(int slot, ItemInstance* item);
|
||||
ItemInstance* getItem(int slot);
|
||||
|
||||
std::string getName() const;
|
||||
int getContainerSize() const;
|
||||
int getMaxStackSize() const;
|
||||
|
||||
void setContainerChanged();
|
||||
|
||||
bool stillValid(Player* player);
|
||||
bool contains(ItemInstance* itemInstance) const;
|
||||
|
||||
void startOpen() {}
|
||||
void stopOpen() {}
|
||||
|
||||
virtual void doDrop(ItemInstance* item, bool randomly);
|
||||
|
||||
int getSlot(int tileId, int data) const;
|
||||
int getNonEmptySlot(int tileId, int data) const;
|
||||
int getNumEmptySlots();
|
||||
int getNumLinkedSlots();
|
||||
protected:
|
||||
int getSlot(int tileId) const;
|
||||
int getNonEmptySlot(int tileId) const;
|
||||
int getSlotWithRemainingSpace(const ItemInstance& item);
|
||||
int getFreeSlot() const;
|
||||
|
||||
int addResource(const ItemInstance& itemInstance);
|
||||
int addItem(ItemInstance* item);
|
||||
|
||||
void release(int slot);
|
||||
void fixBackwardCompabilityItem( ItemInstance& item );
|
||||
public:
|
||||
//
|
||||
// Linked slots
|
||||
//
|
||||
bool linkSlot(int selectionSlot, int inventorySlot, bool propagate);
|
||||
bool linkEmptySlot(int inventorySlot);
|
||||
ItemInstance* getLinked(int slot);
|
||||
void compressLinkedSlotList(int slot);
|
||||
|
||||
typedef struct LinkedSlot {
|
||||
LinkedSlot()
|
||||
: inventorySlot(-1)
|
||||
{}
|
||||
LinkedSlot(int slot)
|
||||
: inventorySlot(slot)
|
||||
{}
|
||||
|
||||
int inventorySlot;
|
||||
} LinkedSlot;
|
||||
LinkedSlot* linkedSlots;
|
||||
|
||||
int numTotalSlots;
|
||||
const int numLinkedSlots;
|
||||
protected:
|
||||
ItemList items;
|
||||
|
||||
bool _isCreative;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_INVENTORY__FILLINGCONTAINER_H__*/
|
||||
73
src/world/inventory/FurnaceMenu.cpp
Executable file
73
src/world/inventory/FurnaceMenu.cpp
Executable file
@@ -0,0 +1,73 @@
|
||||
#include "FurnaceMenu.h"
|
||||
#include "../entity/player/Player.h"
|
||||
#include "../item/ItemInstance.h"
|
||||
#include "../level/tile/entity/FurnaceTileEntity.h"
|
||||
|
||||
FurnaceMenu::FurnaceMenu( FurnaceTileEntity* furnace )
|
||||
: super(ContainerType::FURNACE),
|
||||
furnace(furnace),
|
||||
lastTickCount(0),
|
||||
lastLitTime(0),
|
||||
lastLitDuration(0)
|
||||
{
|
||||
furnaceTileEntityId = furnace->runningId;
|
||||
}
|
||||
|
||||
void FurnaceMenu::setSlot( int slot, ItemInstance* item )
|
||||
{
|
||||
furnace->setItem(slot, item);
|
||||
}
|
||||
|
||||
void FurnaceMenu::setData( int id, int value )
|
||||
{
|
||||
if (id == 0) furnace->tickCount = value;
|
||||
if (id == 1) furnace->litTime = value;
|
||||
if (id == 2) furnace->litDuration = value;
|
||||
}
|
||||
|
||||
std::vector<ItemInstance> FurnaceMenu::getItems()
|
||||
{
|
||||
std::vector<ItemInstance> out;
|
||||
for (int i = 0; i < furnace->getContainerSize(); ++i)
|
||||
out.push_back(*furnace->getItem(i));
|
||||
return out;
|
||||
}
|
||||
|
||||
void FurnaceMenu::broadcastChanges()
|
||||
{
|
||||
super::broadcastChanges();
|
||||
|
||||
if (!listener)
|
||||
return;
|
||||
|
||||
//LOGI("broadcast: Derived: data: %d, %d : %d, %d\n", furnace->tickCount, lastTickCount, furnace->litTime, lastLitTime);
|
||||
|
||||
if (furnace->tickCount != lastTickCount) {
|
||||
listener->setContainerData(this, 0, furnace->tickCount);
|
||||
lastTickCount = furnace->tickCount;
|
||||
}
|
||||
if (furnace->litTime != lastLitTime) {
|
||||
listener->setContainerData(this, 1, furnace->litTime);
|
||||
lastLitTime = furnace->litTime;
|
||||
}
|
||||
if (furnace->litDuration != lastLitDuration) {
|
||||
listener->setContainerData(this, 2, furnace->litDuration);
|
||||
lastLitDuration = furnace->litDuration;
|
||||
}
|
||||
}
|
||||
|
||||
void FurnaceMenu::setListener( IContainerListener* listener )
|
||||
{
|
||||
super::setListener(listener);
|
||||
|
||||
if (listener) {
|
||||
listener->setContainerData(this, 0, furnace->tickCount);
|
||||
listener->setContainerData(this, 1, furnace->litTime);
|
||||
listener->setContainerData(this, 2, furnace->litDuration);
|
||||
}
|
||||
}
|
||||
|
||||
bool FurnaceMenu::tileEntityDestroyedIsInvalid( int tileEntityId )
|
||||
{
|
||||
return (tileEntityId == furnaceTileEntityId);
|
||||
}
|
||||
38
src/world/inventory/FurnaceMenu.h
Executable file
38
src/world/inventory/FurnaceMenu.h
Executable file
@@ -0,0 +1,38 @@
|
||||
#ifndef NET_MINECRAFT_WORLD_INVENTORY__FurnaceMenu_H__
|
||||
#define NET_MINECRAFT_WORLD_INVENTORY__FurnaceMenu_H__
|
||||
|
||||
//package net.minecraft.world.inventory;
|
||||
|
||||
#include "BaseContainerMenu.h"
|
||||
#include <vector>
|
||||
|
||||
class FurnaceTileEntity;
|
||||
class ItemInstance;
|
||||
|
||||
class FurnaceMenu: public BaseContainerMenu
|
||||
{
|
||||
typedef BaseContainerMenu super;
|
||||
public:
|
||||
FurnaceMenu(FurnaceTileEntity* furnace);
|
||||
|
||||
virtual ~FurnaceMenu() {}
|
||||
|
||||
virtual void setSlot(int slot, ItemInstance* item);
|
||||
virtual void setData(int id, int value);
|
||||
virtual std::vector<ItemInstance> getItems();
|
||||
|
||||
virtual void broadcastChanges();
|
||||
virtual void setListener(IContainerListener* listener);
|
||||
|
||||
virtual bool tileEntityDestroyedIsInvalid( int tileEntityId );
|
||||
|
||||
FurnaceTileEntity* furnace;
|
||||
|
||||
int furnaceTileEntityId;
|
||||
private:
|
||||
int lastTickCount;
|
||||
int lastLitTime;
|
||||
int lastLitDuration;
|
||||
};
|
||||
|
||||
#endif /*NET_MINECRAFT_WORLD_INVENTORY__FurnaceMenu_H__*/
|
||||
Reference in New Issue
Block a user