Преглед изворни кода

finished work on inventory system

Kolja Strohm пре 3 година
родитељ
комит
0870c1fb7d

+ 22 - 0
FactoryCraft/Area.cpp

@@ -0,0 +1,22 @@
+#include "Area.h"
+
+Direction opposite( Direction dir )
+{
+    switch( dir )
+    {
+    case NORTH:
+        return SOUTH;
+    case EAST:
+        return WEST;
+    case SOUTH:
+        return NORTH;
+    case WEST:
+        return EAST;
+    case TOP:
+        return BOTTOM;
+    case BOTTOM:
+        return TOP;
+    default:
+        return NO_DIRECTION;
+    }
+}

+ 14 - 1
FactoryCraft/Area.h

@@ -7,4 +7,17 @@ struct Area
     int endX;
     int endY;
     int dimensionId;
-};
+};
+
+enum Direction
+{
+    NO_DIRECTION = 0,
+    NORTH = 1,
+    EAST = 2,
+    SOUTH = 4,
+    WEST = 8,
+    TOP = 16,
+    BOTTOM = 32
+};
+
+Direction opposite( Direction dir );

+ 11 - 8
FactoryCraft/Block.cpp

@@ -1,6 +1,8 @@
 #include "Block.h"
+#include "Inventory.h"
 
-Block::Block( BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos )
+Block::Block( const BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos )
+    : Inventory( pos )
 {
     transparent = false;
     passable = false;
@@ -17,7 +19,6 @@ Block::Block( BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos )
     maxTickTimeout = -1;
     tickSource = 0;
     currentTickTimeout = 0;
-    this->pos = pos;
 }
 
 void Block::tick( TickQueue *zQueue )
@@ -64,7 +65,7 @@ bool Block::isTickSource() const
     return tickSource;
 }
 
-BlockType *Block::zBlockType() const
+const BlockType *Block::zBlockType() const
 {
     return zType;
 }
@@ -104,15 +105,17 @@ float Block::getSpeedModifier() const
     return speedModifier;
 }
 
-const Framework::Vec3<int> &Block::getPos() const
+const Framework::Vec3<int> Block::getPos() const
 {
-    return pos;
+    return location;
 }
 
 
-BasicBlockItem::BasicBlockItem( ItemType *zType, const char *name )
+BasicBlockItem::BasicBlockItem( const ItemType *zType, const char *name )
     : Item( zType, name )
-{}
+{
+    placeable = 1;
+}
 
 bool BasicBlockItem::canBeStackedWith( Item *zItem ) const
 {
@@ -132,7 +135,7 @@ bool BasicBlockItem::canBeStackedWith( Item *zItem ) const
 }
 
 
-BasicBlockItemType::BasicBlockItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType )
+BasicBlockItemType::BasicBlockItemType( int id, ItemSkillLevelUpRule *levelUpRule, const ItemType *zBrokenType )
     : ItemType( id, levelUpRule, zBrokenType )
 {}
 

+ 9 - 21
FactoryCraft/Block.h

@@ -5,6 +5,7 @@
 #include "ReferenceCounter.h"
 #include "EventThrower.h"
 #include "Item.h"
+#include "Inventory.h"
 
 #include <Trie.h>
 #include <Vec3.h>
@@ -14,23 +15,11 @@ class ItemType;
 class Chunk;
 class BasicBlockItemType;
 
-enum Direction
-{
-    NORTH,
-    EAST,
-    SOUTH,
-    WEST,
-    TOP,
-    BOTTOM,
-    DIRECTION_COUNT
-};
-
 class TickQueue;
 
-class Block : public virtual Framework::ReferenceCounter
+class Block : public Inventory
 {
 private:
-    BlockType *type;
     int ticksLeftCounter;
     int currentTickTimeout;
     bool wasTicked;
@@ -42,11 +31,10 @@ protected:
     float hp;
     float maxHP;
     float hardness;
-    BlockType *zType;
+    const BlockType *zType;
     ItemType *zTool;
     float speedModifier;
-    Block *neighbours[ DIRECTION_COUNT ];
-    Framework::Vec3<int> pos;
+    Block *neighbours[ 6 ];
 
     int minTickTimeout;
     int maxTickTimeout;
@@ -67,13 +55,13 @@ protected:
     virtual void onPostTick() = 0;
 
 public:
-    Block( BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos );
+    Block( const BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos );
 
     void tick( TickQueue *zQueue );
     void postTick();
 
     bool isTickSource() const;
-    BlockType *zBlockType() const;
+    const BlockType *zBlockType() const;
     bool isTransparent() const;
     bool isPassable() const;
     float getHP() const;
@@ -81,7 +69,7 @@ public:
     float getHardness() const;
     ItemType *zEffectiveTool() const;
     float getSpeedModifier() const;
-    const Framework::Vec3<int> &getPos() const;
+    const Framework::Vec3<int> getPos() const;
 
     friend Chunk;
     friend BlockType;
@@ -99,7 +87,7 @@ protected:
     float speedModifier;
 
 public:
-    BasicBlockItem( ItemType *zType, const char *name );
+    BasicBlockItem( const ItemType *zType, const char *name );
     virtual bool canBeStackedWith( Item *zItem ) const override;
 
     friend BasicBlockItemType;
@@ -109,7 +97,7 @@ public:
 class BasicBlockItemType : public ItemType
 {
 protected:
-    BasicBlockItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType );
+    BasicBlockItemType( int id, ItemSkillLevelUpRule *levelUpRule, const ItemType *zBrokenType );
     virtual void loadSuperItem( Item *zItem, Framework::Reader *zReader ) const override;
     virtual void saveSuperItem( Item *zItem, Framework::Writer *zWriter ) const override;
     void initializeItem( BasicBlockItem *zItem, bool transparent, bool passable, float hp, float maxHP, float hardness, int toolId, float speedModifier ) const;

+ 2 - 1
FactoryCraft/Constants.h

@@ -7,4 +7,5 @@
 #define AIR_LEVEL_Z_OFFSET 99
 #define MIN_AIR_LEVEL 100
 #define MAX_AIR_LEVEL 400
-#define NUM_TICK_WORKERS 4
+#define NUM_TICK_WORKERS 4
+#define ITEM_CACHE_SIZE 256

+ 30 - 0
FactoryCraft/Dimension.cpp

@@ -47,7 +47,37 @@ void Dimension::addChunk( Chunk *chunk )
     char addr[ 9 ];
     getAddrOf( chunk->getCenter(), addr );
     if( !chunks->z( addr ) )
+    {
         chunks->set( addr, chunk );
+        getAddrOf( chunk->getCenter() + Punkt( 1, 0 ), addr );
+        Chunk *zChunk = chunks->z( addr );
+        if( zChunk )
+        {
+            zChunk->setNeighbor( EAST, chunk );
+            chunk->setNeighbor( WEST, chunk );
+        }
+        getAddrOf( chunk->getCenter() + Punkt( -1, 0 ), addr );
+        zChunk = chunks->z( addr );
+        if( zChunk )
+        {
+            zChunk->setNeighbor( WEST, chunk );
+            chunk->setNeighbor( EAST, chunk );
+        }
+        getAddrOf( chunk->getCenter() + Punkt( 0, 1 ), addr );
+        zChunk = chunks->z( addr );
+        if( zChunk )
+        {
+            zChunk->setNeighbor( NORTH, chunk );
+            chunk->setNeighbor( SOUTH, chunk );
+        }
+        getAddrOf( chunk->getCenter() + Punkt( 0, -1 ), addr );
+        zChunk = chunks->z( addr );
+        if( zChunk )
+        {
+            zChunk->setNeighbor( SOUTH, chunk ); // TODO: correct this in setBlock
+            chunk->setNeighbor( NORTH, chunk );
+        }
+    }
     else
         chunk->release();
 }

+ 2 - 1
FactoryCraft/Entity.h

@@ -4,10 +4,11 @@
 #include <Vec3.h>
 
 #include "Effect.h"
+#include "Inventory.h"
 
 class EntityType;
 
-class Entity : public virtual Framework::ReferenceCounter
+class Entity : public Inventory
 {
 private:
     float maxHP;

+ 7 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -119,6 +119,7 @@
     <ClInclude Include="GrasslandBiom.h" />
     <ClInclude Include="Inventory.h" />
     <ClInclude Include="Item.h" />
+    <ClInclude Include="ItemFilter.h" />
     <ClInclude Include="ItemSkill.h" />
     <ClInclude Include="ItemSlot.h" />
     <ClInclude Include="ItemStack.h" />
@@ -140,6 +141,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="AddChunkUpdate.cpp" />
+    <ClCompile Include="Area.cpp" />
     <ClCompile Include="BasicBlock.cpp" />
     <ClCompile Include="BasicInterpolator.cpp" />
     <ClCompile Include="BiomGenerator.cpp" />
@@ -150,7 +152,12 @@
     <ClCompile Include="Dimension.cpp" />
     <ClCompile Include="DimensionGenerator.cpp" />
     <ClCompile Include="GrasslandBiom.cpp" />
+    <ClCompile Include="Inventory.cpp" />
     <ClCompile Include="Item.cpp" />
+    <ClCompile Include="ItemFilter.cpp" />
+    <ClCompile Include="ItemSkill.cpp" />
+    <ClCompile Include="ItemSlot.cpp" />
+    <ClCompile Include="ItemStack.cpp" />
     <ClCompile Include="ItemType.cpp" />
     <ClCompile Include="Noise.cpp" />
     <ClCompile Include="OverworldDimension.cpp" />

+ 33 - 15
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -1,12 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <Filter Include="Headerdateien">
-      <UniqueIdentifier>{e46426ac-18aa-4bc5-a08b-5243ab201396}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Quelldateien">
-      <UniqueIdentifier>{479ff7ea-4fb5-4721-88d5-6f98e4e2ea07}</UniqueIdentifier>
-    </Filter>
     <Filter Include="events">
       <UniqueIdentifier>{f323a7f5-5758-46c2-b0fd-6cebe18074f1}</UniqueIdentifier>
     </Filter>
@@ -58,14 +52,11 @@
     <Filter Include="world\loader">
       <UniqueIdentifier>{12fac988-c4d8-4db8-b4a8-1c025f117866}</UniqueIdentifier>
     </Filter>
+    <Filter Include="server">
+      <UniqueIdentifier>{479ff7ea-4fb5-4721-88d5-6f98e4e2ea07}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="Datenbank.h">
-      <Filter>Headerdateien</Filter>
-    </ClInclude>
-    <ClInclude Include="Server.h">
-      <Filter>Headerdateien</Filter>
-    </ClInclude>
     <ClInclude Include="Event.h">
       <Filter>events</Filter>
     </ClInclude>
@@ -195,13 +186,22 @@
     <ClInclude Include="Area.h">
       <Filter>world</Filter>
     </ClInclude>
+    <ClInclude Include="ItemFilter.h">
+      <Filter>items</Filter>
+    </ClInclude>
+    <ClInclude Include="Server.h">
+      <Filter>server</Filter>
+    </ClInclude>
+    <ClInclude Include="Datenbank.h">
+      <Filter>server</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>server</Filter>
     </ClCompile>
     <ClCompile Include="Datenbank.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>server</Filter>
     </ClCompile>
     <ClCompile Include="BlockType.cpp">
       <Filter>world</Filter>
@@ -213,7 +213,7 @@
       <Filter>world\blocks</Filter>
     </ClCompile>
     <ClCompile Include="Start.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>server</Filter>
     </ClCompile>
     <ClCompile Include="StaticInitializerOrder.cpp">
       <Filter>static</Filter>
@@ -272,5 +272,23 @@
     <ClCompile Include="AddChunkUpdate.cpp">
       <Filter>world\update</Filter>
     </ClCompile>
+    <ClCompile Include="ItemStack.cpp">
+      <Filter>items</Filter>
+    </ClCompile>
+    <ClCompile Include="ItemSlot.cpp">
+      <Filter>items</Filter>
+    </ClCompile>
+    <ClCompile Include="ItemSkill.cpp">
+      <Filter>items</Filter>
+    </ClCompile>
+    <ClCompile Include="ItemFilter.cpp">
+      <Filter>items</Filter>
+    </ClCompile>
+    <ClCompile Include="Inventory.cpp">
+      <Filter>items</Filter>
+    </ClCompile>
+    <ClCompile Include="Area.cpp">
+      <Filter>world</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 371 - 0
FactoryCraft/Inventory.cpp

@@ -0,0 +1,371 @@
+#include "Inventory.h"
+#include "ItemFilter.h"
+#include "Constants.h"
+#include "Area.h"
+
+using namespace Framework;
+
+InventoryInteraction::InventoryInteraction( Inventory *current, Inventory *other, Direction dir )
+    : current( current ),
+    other( other ),
+    dir( dir )
+{
+    lock();
+}
+
+InventoryInteraction::InventoryInteraction( const InventoryInteraction &interaction )
+    : InventoryInteraction( interaction.current, interaction.other, interaction.dir )
+{}
+
+InventoryInteraction::~InventoryInteraction()
+{
+    unlock();
+}
+
+void InventoryInteraction::lock()
+{
+    if( !current || !other ) return;
+    if( current->location.x < other->location.x )
+    {
+        current->cs.Enter();
+        other->cs.Enter();
+        return;
+    }
+    else if( current->location.x == other->location.x )
+    {
+        if( current->location.y < other->location.y )
+        {
+            current->cs.Enter();
+            other->cs.Enter();
+            return;
+        }
+        else if( current->location.y == other->location.y )
+        {
+            if( current->location.z < other->location.z )
+            {
+                current->cs.Enter();
+                other->cs.Enter();
+                return;
+            }
+        }
+    }
+    other->cs.Enter();
+    current->cs.Enter();
+}
+
+void InventoryInteraction::unlock()
+{
+    if( !current || !other ) return;
+    if( current->location.x < other->location.x )
+    {
+        current->cs.Leave();
+        other->cs.Leave();
+        return;
+    }
+    else if( current->location.x == other->location.x )
+    {
+        if( current->location.y < other->location.y )
+        {
+            current->cs.Leave();
+            other->cs.Leave();
+            return;
+        }
+        else if( current->location.y == other->location.y )
+        {
+            if( current->location.z < other->location.z )
+            {
+                current->cs.Leave();
+                other->cs.Leave();
+                return;
+            }
+        }
+    }
+    other->cs.Leave();
+    current->cs.Leave();
+}
+
+void InventoryInteraction::transaction( Inventory *zSource, Inventory *zTarget, ItemFilter *zFilter, Direction sourceView, Direction targetView, int count )
+{
+    auto sourceSlot = zSource->pullSlotsOrder->getIterator();
+    for( auto targetSlot = zTarget->pushSlotsOrder->getIterator(); targetSlot; )
+    {
+        int amount = count;
+        if( !targetSlot->isFull() )
+        {
+            if( targetSlot->zStack() )
+            {
+                Array<ItemSlot *> *zSurceListe = zSource->itemCache->safeGet( targetSlot->zStack()->zItem()->zItemType()->getId(), 0 );
+                if( zSurceListe )
+                {
+                    Array<int> toDelete;
+                    int index = 0;
+                    for( auto sourceSlot = zSurceListe->getIterator(); sourceSlot; sourceSlot++, index++ )
+                    {
+                        if( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) )
+                            continue;
+                        int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), sourceView ), count );
+                        int tmp = number;
+                        if( number > 0 && zSource->allowPullStack( sourceSlot, sourceView ) && zTarget->allowPushStack( targetSlot, targetView, sourceSlot->zStack()->zItem(), tmp ) )
+                        {
+                            number = MIN( number, tmp );
+                            ItemStack *stack = sourceSlot->takeItemsOut( number, dir );
+                            if( stack )
+                            {
+                                if( !sourceSlot->zStack() )
+                                    toDelete.add( index, 0 );
+                                targetSlot->addItems( stack, dir );
+                                zSource->afterPullStack( sourceSlot, sourceView, targetSlot->zStack()->zItem(), number );
+                                zTarget->afterPushStack( targetSlot, targetView, targetSlot->zStack()->zItem(), number );
+                                if( stack->getSize() )
+                                    throw stack;
+                                stack->release();
+                                count -= number;
+                                if( count == 0 )
+                                    break;
+                            }
+                        }
+                    }
+                    for( auto indexToDelete = toDelete.getIterator(); indexToDelete; indexToDelete++ )
+                        zSurceListe->remove( indexToDelete );
+                    if( count == 0 )
+                        return;
+                }
+            }
+            else
+            {
+                while( sourceSlot && ( !sourceSlot->zStack() || ( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) ) ) )
+                    sourceSlot++;
+                if( !sourceSlot )
+                    return;
+                int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), sourceView ), count );
+                int tmp = number;
+                if( number > 0 && zSource->allowPullStack( sourceSlot, sourceView ) && zTarget->allowPushStack( targetSlot, targetView, sourceSlot->zStack()->zItem(), tmp ) )
+                {
+                    number = MIN( number, tmp );
+                    ItemStack *stack = sourceSlot->takeItemsOut( number, dir );
+                    if( stack )
+                    {
+                        zSource->updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
+                        targetSlot->addItems( stack, dir );
+                        zTarget->updateCache( targetSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
+                        zSource->afterPullStack( sourceSlot, sourceView, targetSlot->zStack()->zItem(), number );
+                        zTarget->afterPushStack( targetSlot, targetView, targetSlot->zStack()->zItem(), number );
+                        if( stack->getSize() )
+                            throw stack;
+                        stack->release();
+                        count -= number;
+                        if( count == 0 )
+                            return;
+                    }
+                }
+            }
+        }
+        if( amount == count || targetSlot->isFull() )
+            targetSlot++;
+    }
+}
+
+
+InventoryInteraction &InventoryInteraction::operator=( const InventoryInteraction &data )
+{
+    if( &data == this ) return *this;
+    unlock();
+    current = data.current;
+    other = data.other;
+    dir = data.dir;
+    lock();
+    return *this;
+}
+
+void InventoryInteraction::endInteraction()
+{
+    unlock();
+    current = 0;
+    other = 0;
+}
+
+void InventoryInteraction::pullItems( int count, ItemFilter *zFilter )
+{
+    if( !current || !other ) return;
+    transaction( other, current, zFilter, opposite( dir ), dir, count );
+}
+
+void InventoryInteraction::pushItems( int count, ItemFilter *zFilter )
+{
+    if( !current || !other ) return;
+    transaction( current, other, zFilter, dir, opposite( dir ), count );
+}
+
+
+Inventory::Inventory( const Framework::Vec3<float> location )
+{
+    pullSlotsOrder = new Framework::RCArray<ItemSlot>();
+    pushSlotsOrder = new Framework::RCArray<ItemSlot>();
+    itemCache = new Framework::HashMap<int, Framework::Array<ItemSlot *> *>( ITEM_CACHE_SIZE, std::_Identity<int>() );
+}
+
+Inventory::~Inventory()
+{
+    pullSlotsOrder->release();
+    pushSlotsOrder->release();
+    itemCache->release();
+}
+
+void Inventory::updateCache( ItemSlot *zSlot, int beforeKey )
+{
+    int key = zSlot->zStack()->zItem()->zItemType()->getId();
+    if( key == beforeKey )
+        return;
+    if( beforeKey >= 0 )
+    {
+        auto tmp = itemCache->safeGet( key, 0 );
+        if( tmp )
+            tmp->removeValue( zSlot );
+    }
+    if( zSlot->zStack() )
+    {
+        auto tmp = itemCache->safeGet( key, 0 );
+        if( !tmp )
+        {
+            tmp = new Array<ItemSlot *>();
+            itemCache->put( key, tmp );
+        }
+        tmp->add( zSlot, 0 );
+    }
+}
+
+void Inventory::addSlot( ItemSlot *slot )
+{
+    cs.Enter();
+    int pullPrio = slot->getPullPriority();
+    int pushPrio = slot->getPushPriority();
+    int index = 0;
+    for( auto iterator = pullSlotsOrder->getIterator(); iterator; iterator++, index++ )
+    {
+        if( iterator->getPullPriority() > pullPrio )
+            break;
+    }
+    pullSlotsOrder->add( dynamic_cast<ItemSlot *>( slot->getThis() ), index );
+    index = 0;
+    for( auto iterator = pushSlotsOrder->getIterator(); iterator; iterator++, index++ )
+    {
+        if( iterator->getPushPriority() > pushPrio )
+            break;
+    }
+    pullSlotsOrder->add( slot, index );
+    updateCache( slot, -1 );
+    cs.Leave();
+}
+
+bool Inventory::allowPullStack( ItemSlot *zSlot, Direction dir )
+{
+    return true;
+}
+
+bool Inventory::allowPushStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int &count )
+{
+    return true;
+}
+
+void Inventory::afterPullStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int count )
+{}
+
+void Inventory::afterPushStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int count )
+{}
+
+void Inventory::localTransaction( Array< ItemSlot * > *zSourceSlots, Array< ItemSlot * > *zTargetSlots, ItemFilter *zFilter, int count )
+{
+    cs.Enter();
+    auto sourceSlot = zSourceSlots->getIterator();
+    for( auto targetSlot = zTargetSlots->getIterator(); targetSlot; )
+    {
+        int amount = count;
+        if( !targetSlot->isFull() )
+        {
+            if( targetSlot->zStack() )
+            {
+                Array<ItemSlot *> *zSurceListe = itemCache->safeGet( targetSlot->zStack()->zItem()->zItemType()->getId(), 0 );
+                if( zSurceListe )
+                {
+                    Array<int> toDelete;
+                    int index = 0;
+                    for( auto sourceSlot = zSurceListe->getIterator(); sourceSlot; sourceSlot++, index++ )
+                    {
+                        if( zSourceSlots->getWertIndex( sourceSlot ) < 0 )
+                            continue;
+                        if( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) )
+                            continue;
+                        int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), NO_DIRECTION ), count );
+                        if( number > 0 )
+                        {
+                            ItemStack *stack = sourceSlot->takeItemsOut( number, NO_DIRECTION );
+                            if( stack )
+                            {
+                                if( !sourceSlot->zStack() )
+                                    toDelete.add( index, 0 );
+                                targetSlot->addItems( stack, NO_DIRECTION );
+                                if( stack->getSize() )
+                                {
+                                    cs.Leave();
+                                    throw stack;
+                                }
+                                stack->release();
+                                count -= number;
+                                if( count == 0 )
+                                    break;
+                            }
+                        }
+                    }
+                    for( auto indexToDelete = toDelete.getIterator(); indexToDelete; indexToDelete++ )
+                        zSurceListe->remove( indexToDelete );
+                    if( count == 0 )
+                    {
+                        cs.Leave();
+                        return;
+                    }
+                }
+            }
+            else
+            {
+                while( sourceSlot && ( !sourceSlot->zStack() || ( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) ) ) )
+                    sourceSlot++;
+                if( !sourceSlot )
+                {
+                    cs.Leave();
+                    return;
+                }
+                int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), NO_DIRECTION ), count );
+                if( number > 0 )
+                {
+                    ItemStack *stack = sourceSlot->takeItemsOut( number, NO_DIRECTION );
+                    if( stack )
+                    {
+                        updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
+                        targetSlot->addItems( stack, NO_DIRECTION );
+                        updateCache( targetSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
+                        if( stack->getSize() )
+                        {
+                            cs.Leave();
+                            throw stack;
+                        }
+                        stack->release();
+                        count -= number;
+                        if( count == 0 )
+                        {
+                            cs.Leave();
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+        if( amount == count || targetSlot->isFull() )
+            targetSlot++;
+    }
+    cs.Leave();
+}
+
+InventoryInteraction Inventory::interactWith( Inventory *zInventory, Direction dir )
+{
+    return InventoryInteraction( this, zInventory, dir );
+}

+ 44 - 4
FactoryCraft/Inventory.h

@@ -1,18 +1,58 @@
 #pragma once
 
+#include <Vec3.h>
+#include <ReferenceCounter.h>
+#include <HashMap.h>
+
 #include "ItemSlot.h"
 #include "EventThrower.h"
-#include "ReferenceCounter.h"
+#include "Area.h"
+
+class ItemFilter;
+class Inventory;
+
+class InventoryInteraction
+{
+private:
+    Inventory *current;
+    Inventory *other;
+    Direction dir;
+    void lock();
+    void unlock();
+    void transaction( Inventory *zSource, Inventory *zTarget, ItemFilter *zFilter, Direction sourceView, Direction targetView, int count );
+
+public:
+    InventoryInteraction( Inventory *zCurrent, Inventory *zOther, Direction dir );
+    InventoryInteraction( const InventoryInteraction &interaction );
+    ~InventoryInteraction();
+    InventoryInteraction &operator=( const InventoryInteraction &data );
+    void endInteraction();
+    void pullItems( int count, ItemFilter *zFilter );
+    void pushItems( int count, ItemFilter *zFilter );
+};
 
-class Inventory : public EventThrower
+class Inventory : public virtual Framework::ReferenceCounter
 {
 private:
-    Framework::RCArray<ItemSlot> *slots;
+    Framework::RCArray<ItemSlot> *pullSlotsOrder;
+    Framework::RCArray<ItemSlot> *pushSlotsOrder;
+    Framework::HashMap<int, Framework::Array<ItemSlot *> *> *itemCache;
+    CriticalSection cs;
+    void updateCache( ItemSlot *zSlot, int beforeKey );
 
 protected:
+    Framework::Vec3<float> location;
     void addSlot( ItemSlot *slot );
+    void localTransaction( Framework::Array< ItemSlot * > *zSourceSlots, Framework::Array< ItemSlot * > *zTargetSlots, ItemFilter *zFilter, int count );
+    virtual bool allowPullStack( ItemSlot *zSlot, Direction dir );
+    virtual bool allowPushStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int &count );
+    virtual void afterPullStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int count );
+    virtual void afterPushStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int count );
 
 public:
-    Inventory();
+    Inventory( const Framework::Vec3<float> location );
     virtual ~Inventory();
+    InventoryInteraction interactWith( Inventory *zInventory, Direction dir );
+
+    friend InventoryInteraction;
 };

+ 8 - 1
FactoryCraft/Item.cpp

@@ -1,7 +1,7 @@
 #include "Item.h"
 
 
-Item::Item( ItemType *zType, const char *name )
+Item::Item( const ItemType *zType, const char *name )
     : ReferenceCounter(),
     zType( zType ),
     damage( 0 ),
@@ -11,6 +11,7 @@ Item::Item( ItemType *zType, const char *name )
     eatable( 0 ),
     placeable( 0 ),
     equippable( 0 ),
+    solid( 1 ),
     usable( 0 ),
     maxStackSize( 50 ),
     name( name )
@@ -54,6 +55,11 @@ bool Item::isEquippable() const
     return equippable;
 }
 
+bool Item::isSolid() const
+{
+    return solid;
+}
+
 float Item::getMaxDurability() const
 {
     return maxDurability;
@@ -79,6 +85,7 @@ bool Item::canBeStackedWith( Item *zItem ) const
         eatable == zItem->eatable &&
         placeable == zItem->placeable &&
         equippable == zItem->eatable &&
+        solid == zItem->solid &&
         usable == zItem->usable &&
         maxStackSize == zItem->maxStackSize &&
         name.istGleich( zItem->name );

+ 5 - 5
FactoryCraft/Item.h

@@ -7,8 +7,8 @@ class ItemType;
 
 class Item : public virtual Framework::ReferenceCounter
 {
-private:
-    ItemType *zType;
+protected:
+    const ItemType *zType;
     float damage;
     float maxDamage;
     float durability;
@@ -16,12 +16,11 @@ private:
     bool eatable;
     bool placeable;
     bool equippable;
+    bool solid;
     bool usable;
     int maxStackSize;
     Framework::Text name;
-
-protected:
-    Item( ItemType *zType, const char *name );
+    Item( const ItemType *zType, const char *name );
 
 public:
     virtual void tick();
@@ -33,6 +32,7 @@ public:
     bool isEatable() const;
     bool isPlaceable() const;
     bool isEquippable() const;
+    bool isSolid() const;
     float getMaxDurability() const;
     int getMaxStackSize() const;
     float getMaxDamage() const;

+ 42 - 0
FactoryCraft/ItemFilter.cpp

@@ -0,0 +1,42 @@
+#include "ItemFilter.h"
+#include "ItemType.h"
+#include "Item.h"
+
+
+ItemFilter::ItemFilter()
+    : ReferenceCounter()
+{}
+
+
+CombinedItemFilter::CombinedItemFilter( ItemFilter *filterA, ItemFilter *filterB, std::function<bool( bool, bool )> op )
+    : ItemFilter(),
+    filterA( filterA ),
+    filterB( filterB ),
+    op( op )
+{}
+
+bool CombinedItemFilter::matchItem( const Item *zItem ) const
+{
+    return op( filterA->matchItem( zItem ), filterB->matchItem( zItem ) );
+}
+
+
+AnyItemFilter::AnyItemFilter()
+    : ItemFilter()
+{}
+
+bool AnyItemFilter::matchItem( const Item *zItem ) const
+{
+    return true;
+}
+
+
+TypeItemFilter::TypeItemFilter( const ItemType *zType )
+    : ItemFilter(),
+    zType( zType )
+{}
+
+bool TypeItemFilter::matchItem( const Item *zItem ) const
+{
+    return zItem->zItemType() == zType;
+}

+ 44 - 0
FactoryCraft/ItemFilter.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+#include <functional>
+
+class Item;
+class ItemType;
+
+class ItemFilter : public virtual Framework::ReferenceCounter
+{
+public:
+    ItemFilter();
+    virtual bool matchItem( const Item *zItem ) const = 0;
+};
+
+class CombinedItemFilter : public ItemFilter
+{
+private:
+    ItemFilter *filterA;
+    ItemFilter *filterB;
+    std::function<bool( bool, bool )> op;
+
+public:
+    CombinedItemFilter( ItemFilter *filterA, ItemFilter *filterB, std::function<bool( bool, bool )> op );
+    bool matchItem( const Item *zItem ) const override;
+};
+
+class AnyItemFilter : public ItemFilter
+{
+public:
+    AnyItemFilter();
+    bool matchItem( const Item *zItem ) const override;
+};
+
+class TypeItemFilter : public ItemFilter
+{
+private:
+    const ItemType *zType;
+
+public:
+    TypeItemFilter( const ItemType *zType );
+    bool matchItem( const Item *zItem ) const override;
+};
+

+ 19 - 0
FactoryCraft/ItemSkill.cpp

@@ -0,0 +1,19 @@
+#include "ItemSkill.h"
+
+BasicItemSkill::BasicItemSkill( float maxXP, float durabilityModifier, float speedModifier, float luckModifier, float staminaModifier, float hungerModifier, float xpIncrease )
+    : ReferenceCounter(),
+    level( 1 ),
+    xp( 0 ),
+    maxXP( maxXP ),
+    durabilityModifier( durabilityModifier ),
+    speedModifier( speedModifier ),
+    luckModifier( luckModifier ),
+    staminaModifier( staminaModifier ),
+    hungerModifier( hungerModifier )
+{}
+
+void BasicItemSkill::use( Entity *zActor, Block *zTarget, Dimension *zDimension )
+{}
+
+void BasicItemSkill::use( Entity *zActor, Entity *zTarget, Dimension *zDimension )
+{}

+ 0 - 1
FactoryCraft/ItemSkill.h

@@ -38,7 +38,6 @@ protected:
 
     BasicItemSkill( float maxXp = 100.f, float durabilityModifier = 1.f, float speedModifier = 1.f, float luckModifier = 1.f, float staminaModifier = 1.f, float hungerModifier = 1.f, float xpIncrease = 1.1f );
 
-
 public:
     virtual void use( Entity *zActor, Block *zTarget, Dimension *zDimension ) override;
     virtual void use( Entity *zActor, Entity *zTarget, Dimension *zDimension ) override;

+ 89 - 0
FactoryCraft/ItemSlot.cpp

@@ -0,0 +1,89 @@
+#include "ItemSlot.h"
+
+
+ItemSlot::ItemSlot( int maxSize, int pullPriority, int pushPriority, int allowedPullSide, int allowedPushSides, bool allowHigherStackSize )
+    : ReferenceCounter(),
+    items( 0 ),
+    maxSize( maxSize ),
+    allowedPullSide( allowedPullSide ),
+    allowedPushSides( allowedPushSides ),
+    pullPriority( pullPriority ),
+    pushPriority( pushPriority ),
+    allowHigherStackSize( allowHigherStackSize )
+{}
+
+ItemStack *ItemSlot::takeItemsOut( int count, Direction dir )
+{
+    if( !items )
+        return 0;
+    if( ( dir | allowedPullSide ) == allowedPullSide )
+    {
+        ItemStack *result = items->split( count );
+        if( items->getSize() == 0 )
+        {
+            items->release();
+            items = 0;
+        }
+        return result;
+    }
+    return 0;
+}
+
+void ItemSlot::addItems( ItemStack *zStack, Direction dir )
+{
+    if( ( dir | allowedPushSides ) == allowedPushSides )
+    {
+        if( !items )
+        {
+            if( allowHigherStackSize )
+            {
+                items = zStack->split( maxSize );
+                items->setMaxSize( maxSize );
+            }
+            else
+            {
+                items = zStack->split( MIN( maxSize, items->zItem()->getMaxStackSize() ) );
+                items->setMaxSize( MIN( maxSize, items->zItem()->getMaxStackSize() ) );
+            }
+        }
+        else
+            items->addItemStack( zStack );
+    }
+}
+
+int ItemSlot::numberOfAddableItems( const ItemStack *zStack, Direction dir ) const
+{
+    if( ( dir | allowedPushSides ) == allowedPushSides )
+    {
+        if( !items )
+        {
+            if( allowHigherStackSize )
+                return maxSize;
+            else
+                return MIN( maxSize, zStack->zItem()->getMaxStackSize() );
+        }
+        else
+            return items->getMaxSize() - items->getSize();
+    }
+    return 0;
+}
+
+const ItemStack *ItemSlot::zStack() const
+{
+    return items;
+}
+
+int ItemSlot::getPullPriority() const
+{
+    return pullPriority;
+}
+
+int ItemSlot::getPushPriority() const
+{
+    return pushPriority;
+}
+
+bool ItemSlot::isFull() const
+{
+    return items ? items->getSize() < items->getMaxSize() : 0;
+}

+ 14 - 5
FactoryCraft/ItemSlot.h

@@ -1,19 +1,28 @@
 #pragma once
 
 #include "ItemStack.h"
+#include "Area.h"
 
 class ItemSlot : public virtual Framework::ReferenceCounter
 {
 private:
     ItemStack *items;
     int maxSize;
+    int allowedPullSide;
+    int allowedPushSides;
+    int pullPriority;
+    int pushPriority;
+    bool allowHigherStackSize;
 
 public:
-    ItemSlot( int maxSize );
+    ItemSlot( int maxSize, int pullPriority, int pushPriority, int allowedPullSide, int allowedPushSides, bool allowHigherStackSize );
 
-    ItemStack *takeItemsOut( int count );
-    void addItems( ItemStack *stack );
+    ItemStack *takeItemsOut( int count, Direction dir );
+    void addItems( ItemStack *zStack, Direction dir );
 
-    virtual int numberOfAddableItems( ItemStack *stack ) const;
-    const ItemStack *getContainedItems() const;
+    int numberOfAddableItems( const ItemStack *zStack, Direction dir ) const;
+    const ItemStack *zStack() const;
+    int getPullPriority() const;
+    int getPushPriority() const;
+    bool isFull() const;
 };

+ 76 - 0
FactoryCraft/ItemStack.cpp

@@ -0,0 +1,76 @@
+#include "ItemStack.h"
+#include "Item.h"
+
+
+ItemStack::ItemStack( Item *item, int currentSize, int maxSize )
+    : ReferenceCounter(),
+    item( item ),
+    size( currentSize ),
+    maxSize( maxSize )
+{}
+
+ItemStack::ItemStack( Item *item, int currentSize )
+    : ItemStack( item, currentSize, item->getMaxStackSize() )
+{}
+
+void ItemStack::setMaxSize( int size )
+{
+    maxSize = size;
+}
+
+ItemStack *ItemStack::split( int size )
+{
+    size = MIN( size, this->size );
+    this->size -= size;
+    return new ItemStack( dynamic_cast<Item *>( item->getThis() ), size, item->getMaxStackSize() );
+}
+
+Item *ItemStack::extractFromStack()
+{
+    if( size == 0 )
+        return 0;
+    --size;
+    return item->zItemType()->cloneItem( item );
+}
+
+bool ItemStack::addToStack( Item *item )
+{
+    if( size < maxSize && this->item->canBeStackedWith( item ) )
+    {
+        ++size;
+        item->release();
+        return true;
+    }
+    item->release();
+    return false;
+}
+
+void ItemStack::addItemStack( ItemStack *zItemStack )
+{
+    if( zItemStack->zItem()->canBeStackedWith( item ) )
+    {
+        int numToAdd = MIN( zItemStack->getSize(), maxSize - size );
+        size += numToAdd;
+        zItemStack->size -= numToAdd;
+    }
+}
+
+bool ItemStack::isStackable( Item *zItem ) const
+{
+    return item->canBeStackedWith( zItem );
+}
+
+const Item *ItemStack::zItem() const
+{
+    return item;
+}
+
+int ItemStack::getSize() const
+{
+    return size;
+}
+
+int ItemStack::getMaxSize() const
+{
+    return maxSize;
+}

+ 8 - 2
FactoryCraft/ItemStack.h

@@ -7,14 +7,20 @@ class ItemStack : public virtual Framework::ReferenceCounter
 private:
     Item *item;
     int size;
+    int maxSize;
 
 public:
+    ItemStack( Item *item, int currentSize, int maxSize );
     ItemStack( Item *item, int currentSize );
 
+    void setMaxSize( int size );
     ItemStack *split( int size );
+    Item *extractFromStack();
+    bool addToStack( Item *item );
+    void addItemStack( ItemStack *zItemStack );
 
-    bool isStackable( Item *zItem );
-
+    bool isStackable( Item *zItem ) const;
     const Item *zItem() const;
     int getSize() const;
+    int getMaxSize() const;
 };

+ 20 - 10
FactoryCraft/ItemType.cpp

@@ -1,9 +1,11 @@
 
+#include <InMemoryBuffer.h>
+
 #include "ItemType.h"
 #include "ItemSkill.h"
 #include "ItemStack.h"
 
-ItemType::ItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType )
+ItemType::ItemType( int id, ItemSkillLevelUpRule *levelUpRule, const ItemType *zBrokenType )
     : ReferenceCounter(),
     id( id ),
     levelUpRule( levelUpRule ),
@@ -24,10 +26,13 @@ void ItemType::loadSuperItem( Item *zItem, Framework::Reader *zReader ) const
     zReader->lese( (char *)&zItem->maxDamage, 4 );
     zReader->lese( (char *)&zItem->durability, 4 );
     zReader->lese( (char *)&zItem->maxDurability, 4 );
-    zReader->lese( (char *)&zItem->eatable, 1 );
-    zReader->lese( (char *)&zItem->placeable, 1 );
-    zReader->lese( (char *)&zItem->equippable, 1 );
-    zReader->lese( (char *)&zItem->usable, 1 );
+    unsigned char flags = 0;
+    zReader->lese( (char *)&flags, 1 );
+    zItem->eatable = ( flags | 1 ) == flags;
+    zItem->placeable = ( flags | 2 ) == flags;
+    zItem->equippable = ( flags | 4 ) == flags;
+    zItem->solid = ( flags | 8 ) == flags;
+    zItem->usable = ( flags | 16 ) == flags;
     zReader->lese( (char *)&zItem->maxStackSize, 1 );
     unsigned char len = 0;
     zReader->lese( (char *)&len, 1 );
@@ -41,10 +46,8 @@ void ItemType::saveSuperItem( Item *zItem, Framework::Writer *zWriter ) const
     zWriter->schreibe( (char *)&zItem->maxDamage, 4 );
     zWriter->schreibe( (char *)&zItem->durability, 4 );
     zWriter->schreibe( (char *)&zItem->maxDurability, 4 );
-    zWriter->schreibe( (char *)&zItem->eatable, 1 );
-    zWriter->schreibe( (char *)&zItem->placeable, 1 );
-    zWriter->schreibe( (char *)&zItem->equippable, 1 );
-    zWriter->schreibe( (char *)&zItem->usable, 1 );
+    unsigned char flags = (unsigned char)( ( ( ( ( zItem->usable << 1 ) | zItem->solid << 1 ) | zItem->equippable << 1 ) | zItem->placeable << 1 ) | zItem->eatable );
+    zWriter->schreibe( (char *)&flags, 1 );
     zWriter->schreibe( (char *)&zItem->maxStackSize, 1 );
     unsigned char len = (unsigned char)zItem->name.getLength();
     zWriter->schreibe( (char *)&len, 1 );
@@ -56,7 +59,7 @@ int ItemType::getId() const
     return id;
 }
 
-ItemType *ItemType::zBrokenItemType() const
+const ItemType *ItemType::zBrokenItemType() const
 {
     return zBrokenType;
 }
@@ -91,3 +94,10 @@ void ItemType::saveItem( Item *zItem, Framework::Writer *zWriter ) const
 {
     saveSuperItem( zItem, zWriter );
 }
+
+Item *ItemType::cloneItem( Item *zItem ) const
+{
+    Framework::InMemoryBuffer buffer;
+    saveItem( zItem, &buffer );
+    return loadItem( &buffer );
+}

+ 4 - 3
FactoryCraft/ItemType.h

@@ -18,9 +18,9 @@ class ItemType : public virtual Framework::ReferenceCounter
 protected:
     const int id;
     ItemSkillLevelUpRule *levelUpRule;
-    ItemType *zBrokenType;
+    const ItemType *zBrokenType;
 
-    ItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType );
+    ItemType( int id, ItemSkillLevelUpRule *levelUpRule, const ItemType *zBrokenType );
 
     virtual void loadSuperItem( Item *zItem, Framework::Reader *zReader ) const;
     virtual void saveSuperItem( Item *zItem, Framework::Writer *zWriter ) const;
@@ -29,11 +29,12 @@ public:
     ~ItemType();
 
     int getId() const;
-    ItemType *zBrokenItemType() const;
+    const ItemType *zBrokenItemType() const;
     virtual Item *createItem() const = 0;
     virtual ItemStack *createItemStack( int size ) const;
     virtual ItemSkill *createDefaultItemSkill() const;
     virtual void levelUpItemSkill( ItemSkill *zSkill ) const;
     virtual Item *loadItem( Framework::Reader *zReader ) const;
     virtual void saveItem( Item *zItem, Framework::Writer *zWriter ) const;
+    virtual Item *cloneItem( Item *zItem ) const;
 };