Browse Source

add basic crafting architecture

Kolja Strohm 2 years ago
parent
commit
a36c42f642

+ 2 - 1
FactoryCraft/Area.h

@@ -19,7 +19,8 @@ enum Direction
     SOUTH = 4,
     WEST = 8,
     TOP = 16,
-    BOTTOM = 32
+    BOTTOM = 32,
+    INSIDE
 };
 typedef int Directions;
 

+ 80 - 0
FactoryCraft/CraftingStorage.cpp

@@ -0,0 +1,80 @@
+#include "CraftingStorage.h"
+
+BasicShapedCrafter::BasicShapedCrafter( int width, int height, Inventory* zInventory )
+    : zInventory( zInventory ),
+    width( width ),
+    height( height )
+{
+    for( int i = 0; i < width * height; i++ )
+    {
+        ItemSlot* slot = new ItemSlot( 1, std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), INSIDE, INSIDE, 0 );
+        zInventory->addSlot( slot );
+        craftingInput.add( slot );
+    }
+}
+
+bool BasicShapedCrafter::isAllAvailable( Framework::RCArray<ItemFilter>& filters, int width, int height )
+{
+    for( int x = 0; x <= this->width - width; x++ )
+    {
+        for( int y = 0; y <= this->height - height; y++ )
+        {
+            for( int w = 0; w < width; w++ )
+            {
+                for( int h = 0; h < height; h++ )
+                {
+                    ItemFilter* f = filters.z( w * width + h );
+                    ItemSlot* s = craftingInput.get( w * 2 + h );
+                    const Item* item = 0;
+                    if( s && s->zStack() )
+                        item = s->zStack()->zItem();
+                    if( (item && !f) || (!item && f) ) return 0;
+                    if( item && f && !f->matchItem( item ) )
+                        return 0;
+                }
+            }
+        }
+    }
+    return 1;
+}
+
+bool BasicShapedCrafter::hasFreeSpace( const Item* zItem, int amount )
+{
+    ItemStack* stack = new ItemStack( (Item*)zItem, amount );
+    int addable = zInventory->numberOfAddableItems( stack, NO_DIRECTION );
+    stack->release();
+    return addable >= amount;
+}
+
+bool BasicShapedCrafter::consume( Framework::RCArray<ItemFilter>& filters, int width, int height )
+{
+    for( ItemSlot* slot : craftingInput )
+    {
+        if( slot && slot->zStack() )
+        {
+            ItemStack* stack = zInventory->takeItemsOut( slot, 1, INSIDE );
+            if( stack )
+                stack->release();
+        }
+    }
+    for( int x = 0; x < width; x++ )
+    {
+        for( int y = 0; y < height; y++ )
+        {
+            ItemFilter* f = filters.z( x * width + y );
+            if( f )
+            {
+                ItemSlot* target = craftingInput.get( x * this->width + y );
+                Framework::Array< ItemSlot*> tmp;
+                tmp.add( target );
+                zInventory->localTransaction( 0, &tmp, f, 1, NO_DIRECTION, INSIDE );
+            }
+        }
+    }
+    return 1;
+}
+
+void BasicShapedCrafter::addCraftingResult( ItemStack* stack )
+{
+    zInventory->addItems( stack, NO_DIRECTION );
+}

+ 42 - 0
FactoryCraft/CraftingStorage.h

@@ -0,0 +1,42 @@
+#pragma once
+#include <Array.h>
+
+#include "ItemStack.h"
+#include "ItemFilter.h"
+#include "ItemSlot.h"
+#include "Inventory.h"
+
+
+class CraftingStorage
+{
+public:
+    virtual bool isAllAvailable( Framework::RCArray<ItemFilter>& filters, Framework::Array<int>& inputAmount ) = 0;
+    virtual bool hasFreeSpace( const Item* zItem, int amount ) = 0;
+    virtual bool consume( Framework::RCArray<ItemFilter>& filters, Framework::Array<int>& inputAmount ) = 0;
+    virtual void addCraftingResult( ItemStack* stack ) = 0;
+};
+
+class ShapedCraftingStorage
+{
+public:
+    virtual bool isAllAvailable( Framework::RCArray<ItemFilter>& filters, int width, int height ) = 0;
+    virtual bool hasFreeSpace( const Item* zItem, int amount ) = 0;
+    virtual bool consume( Framework::RCArray<ItemFilter>& filters, int width, int height ) = 0;
+    virtual void addCraftingResult( ItemStack* stack ) = 0;
+};
+
+class BasicShapedCrafter : public ShapedCraftingStorage
+{
+private:
+    Framework::Array<ItemSlot*> craftingInput;
+    Inventory* zInventory;
+    int width;
+    int height;
+
+public:
+    BasicShapedCrafter( int width, int height, Inventory* zInventory );
+    virtual bool isAllAvailable( Framework::RCArray<ItemFilter>& filters, int width, int height );
+    virtual bool hasFreeSpace( const Item* zItem, int amount );
+    virtual bool consume( Framework::RCArray<ItemFilter>& filters, int width, int height );
+    virtual void addCraftingResult( ItemStack* stack );
+};

+ 7 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -104,6 +104,7 @@
     <ClInclude Include="BlockType.h" />
     <ClInclude Include="Chunk.h" />
     <ClInclude Include="Constants.h" />
+    <ClInclude Include="CraftingStorage.h" />
     <ClInclude Include="DimensionGenerator.h" />
     <ClInclude Include="Effect.h" />
     <ClInclude Include="EffectFactory.h" />
@@ -134,6 +135,9 @@
     <ClInclude Include="Player.h" />
     <ClInclude Include="PlayerHand.h" />
     <ClInclude Include="RandNoise.h" />
+    <ClInclude Include="Recipie.h" />
+    <ClInclude Include="RecipieList.h" />
+    <ClInclude Include="RecipieLoader.h" />
     <ClInclude Include="Server.h" />
     <ClInclude Include="Dimension.h" />
     <ClInclude Include="StaticRegistry.h" />
@@ -157,6 +161,7 @@
     <ClCompile Include="BlockRemovedUpdate.cpp" />
     <ClCompile Include="BlockType.cpp" />
     <ClCompile Include="Chunk.cpp" />
+    <ClCompile Include="CraftingStorage.cpp" />
     <ClCompile Include="Dimension.cpp" />
     <ClCompile Include="DimensionGenerator.cpp" />
     <ClCompile Include="Entity.cpp" />
@@ -185,6 +190,8 @@
     <ClCompile Include="Player.cpp" />
     <ClCompile Include="PlayerHand.cpp" />
     <ClCompile Include="RandNoise.cpp" />
+    <ClCompile Include="Recipie.cpp" />
+    <ClCompile Include="RecipieLoader.cpp" />
     <ClCompile Include="Server.cpp" />
     <ClCompile Include="Start.cpp" />
     <ClCompile Include="StaticInitializerOrder.cpp" />

+ 24 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -61,6 +61,9 @@
     <Filter Include="world\generator\templates\implementations">
       <UniqueIdentifier>{c2b3a832-eac2-4bf5-bb1f-3e804afd7e71}</UniqueIdentifier>
     </Filter>
+    <Filter Include="inventory\recipies">
+      <UniqueIdentifier>{3289186e-1fb6-40a2-afb6-f9c87adaec62}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -219,6 +222,18 @@
     <ClInclude Include="RandNoise.h">
       <Filter>world\generator\noise</Filter>
     </ClInclude>
+    <ClInclude Include="Recipie.h">
+      <Filter>inventory\recipies</Filter>
+    </ClInclude>
+    <ClInclude Include="CraftingStorage.h">
+      <Filter>inventory\recipies</Filter>
+    </ClInclude>
+    <ClInclude Include="RecipieList.h">
+      <Filter>inventory\recipies</Filter>
+    </ClInclude>
+    <ClInclude Include="RecipieLoader.h">
+      <Filter>inventory\recipies</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -368,5 +383,14 @@
     <ClCompile Include="RandNoise.cpp">
       <Filter>world\generator\noise</Filter>
     </ClCompile>
+    <ClCompile Include="RecipieLoader.cpp">
+      <Filter>inventory\recipies</Filter>
+    </ClCompile>
+    <ClCompile Include="Recipie.cpp">
+      <Filter>inventory\recipies</Filter>
+    </ClCompile>
+    <ClCompile Include="CraftingStorage.cpp">
+      <Filter>inventory\recipies</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 1 - 1
FactoryCraft/Game.cpp

@@ -19,7 +19,7 @@ GameClient::GameClient( Player* zPlayer, FCKlient* client )
     online( 1 ),
     finished( 0 )
 {
-    new AsynchronCall( [this]() {
+    new AsynchronCall( "Game Client", [this]() {
         while( online )
         {
             other.lock();

+ 9 - 9
FactoryCraft/Inventory.cpp

@@ -339,12 +339,12 @@ void Inventory::saveInventory( Framework::StreamWriter* zWriter )
     }
 }
 
-void Inventory::localTransaction( Array< ItemSlot* >* zSourceSlots, Array< ItemSlot* >* zTargetSlots, ItemFilter* zFilter, int count )
+void Inventory::localTransaction( Array< ItemSlot* >* zSourceSlots, Array< ItemSlot* >* zTargetSlots, ItemFilter* zFilter, int count, Direction outDir, Direction inDir )
 {
     if( itemCache )
     {
         cs.lock();
-        auto sourceSlot = zSourceSlots->begin();
+        auto sourceSlot = zSourceSlots ? zSourceSlots->begin() : pullSlotsOrder->begin();
         for( auto targetSlot = zTargetSlots->begin(); targetSlot; )
         {
             int amount = count;
@@ -359,19 +359,19 @@ void Inventory::localTransaction( Array< ItemSlot* >* zSourceSlots, Array< ItemS
                         int index = 0;
                         for( auto sourceSlot = zSurceListe->begin(); sourceSlot; sourceSlot++, index++ )
                         {
-                            if( zSourceSlots->getWertIndex( sourceSlot ) < 0 )
+                            if( zSourceSlots && zSourceSlots->getWertIndex( sourceSlot ) < 0 )
                                 continue;
                             if( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) )
                                 continue;
-                            int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), NO_DIRECTION ), count );
+                            int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), inDir ), count );
                             if( number > 0 )
                             {
-                                ItemStack* stack = sourceSlot->takeItemsOut( number, NO_DIRECTION );
+                                ItemStack* stack = sourceSlot->takeItemsOut( number, outDir );
                                 if( stack )
                                 {
                                     if( !sourceSlot->zStack() )
                                         toDelete.add( index, 0 );
-                                    targetSlot->addItems( stack, NO_DIRECTION );
+                                    targetSlot->addItems( stack, inDir );
                                     updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
                                     if( stack->getSize() )
                                     {
@@ -403,13 +403,13 @@ void Inventory::localTransaction( Array< ItemSlot* >* zSourceSlots, Array< ItemS
                         cs.unlock();
                         return;
                     }
-                    int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), NO_DIRECTION ), count );
+                    int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), inDir ), count );
                     if( number > 0 )
                     {
-                        ItemStack* stack = sourceSlot->takeItemsOut( number, NO_DIRECTION );
+                        ItemStack* stack = sourceSlot->takeItemsOut( number, outDir );
                         if( stack )
                         {
-                            targetSlot->addItems( stack, NO_DIRECTION );
+                            targetSlot->addItems( stack, inDir );
                             updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
                             updateCache( targetSlot, -1 );
                             if( stack->getSize() )

+ 4 - 4
FactoryCraft/Inventory.h

@@ -42,20 +42,20 @@ private:
 
 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 ) const;
     virtual bool allowPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int& count ) const;
     virtual void afterPullStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int count );
     virtual void afterPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int count );
     virtual void loadInventory( Framework::StreamReader* zReader );
     virtual void saveInventory( Framework::StreamWriter* zWriter );
-    virtual void addItems( ItemStack* items, Direction dir );
-    ItemStack* takeItemsOut( ItemSlot* zSlot, int count, Direction dir );
 
 public:
     Inventory( const Framework::Vec3<float> location, bool hasInventory );
     virtual ~Inventory();
+    void addSlot( ItemSlot* slot );
+    void localTransaction( Framework::Array< ItemSlot* >* zSourceSlots, Framework::Array< ItemSlot* >* zTargetSlots, ItemFilter* zFilter, int count, Direction outDir, Direction inDir );
+    ItemStack* takeItemsOut( ItemSlot* zSlot, int count, Direction dir );
+    virtual void addItems( ItemStack* items, Direction dir );
     InventoryInteraction interactWith( Inventory* zInventory, Direction dir );
     void unsaveAddItem( ItemStack* zStack, Direction dir );
     int numberOfAddableItems( const ItemStack* zStack, Direction dir ) const;

+ 5 - 2
FactoryCraft/Player.cpp

@@ -4,7 +4,8 @@
 #include "ItemFilter.h"
 
 Player::Player( Framework::Vec3<float> location, int dimensionId, int entityId )
-    : Entity( PlayerEntityType::INSTANCE, location, dimensionId, entityId )
+    : Entity( PlayerEntityType::INSTANCE, location, dimensionId, entityId ),
+    BasicShapedCrafter( 2, 2, this )
 {
     for( int i = 0; i < 9; i++ )
     {
@@ -89,7 +90,7 @@ void Player::useItemSlot( ItemSlot* zSlot )
                 Array<ItemSlot*> targetSlots;
                 targetSlots.add( zSlot );
                 TypeItemFilter filter( item->zItemType() );
-                localTransaction( &fromSlots, &targetSlots, &filter, zSlot->getFreeSpace() );
+                localTransaction( &fromSlots, &targetSlots, &filter, zSlot->getFreeSpace(), NO_DIRECTION, NO_DIRECTION );
                 // place broken item in inventory
                 const ItemType* brokenType = item->zItemType()->zBrokenItemType();
                 if( brokenType )
@@ -279,6 +280,8 @@ void Player::onFall( float collisionSpeed )
     jumping = 0;
 }
 
+
+
 PlayerEntityType::PlayerEntityType()
     : EntityType( ID )
 {}

+ 2 - 1
FactoryCraft/Player.h

@@ -2,11 +2,12 @@
 
 #include "Entity.h"
 #include "EntityType.h"
+#include "CraftingStorage.h"
 #include <Array.h>
 
 class PlayerEntityType;
 
-class Player : public Entity
+class Player : public Entity, public BasicShapedCrafter
 {
 public:
     class Key

+ 82 - 0
FactoryCraft/Recipie.cpp

@@ -0,0 +1,82 @@
+#include "Recipie.h"
+
+Recipie::Recipie()
+    : ReferenceCounter()
+{}
+
+void Recipie::addIngredient( ItemFilter* filter, int amount )
+{
+    filters.add( filter );
+    inputAmount.add( amount );
+}
+
+void Recipie::addOutput( Item* item, int amount )
+{
+    outputs.add( item );
+    outputAmount.add( amount );
+}
+
+bool Recipie::testApplicability( CraftingStorage* zStorage )
+{
+    for( int i = 0; i < outputs.getEintragAnzahl(); i++ )
+    {
+        if( !zStorage->hasFreeSpace( outputs.z( i ), outputAmount.get( i ) ) )
+            return 0;
+    }
+    return zStorage->isAllAvailable( filters, inputAmount );
+}
+
+void Recipie::apply( CraftingStorage* zStorage )
+{
+    zStorage->consume( filters, inputAmount );
+    for( int i = 0; i < outputs.getEintragAnzahl(); i++ )
+    {
+        ItemStack* stack = new ItemStack( outputs.z( i )->zItemType()->cloneItem( outputs.z( i ) ), outputAmount.get( i ) );
+        zStorage->addCraftingResult( stack );
+        stack->release();
+    }
+}
+
+
+ShapedRecipie::ShapedRecipie( int width, int height )
+    :ReferenceCounter(),
+    width( width ),
+    height( height ),
+    output( 0 ),
+    outputAmount( 0 )
+{
+    for( int i = 0; i < width * height; i++ )
+        filters.add( 0 );
+}
+
+ShapedRecipie::~ShapedRecipie()
+{
+    if( output )
+        output->release();
+}
+
+void ShapedRecipie::setIngredient( int x, int y, ItemFilter* filter )
+{
+    filters.set( filter, width * x + y );
+}
+
+void ShapedRecipie::setOutput( Item* item, int amount )
+{
+    if( output )
+        output->release();
+    output = item;
+    outputAmount = amount;
+}
+
+bool ShapedRecipie::testApplicability( ShapedCraftingStorage* zStorage )
+{
+    return zStorage->isAllAvailable( filters, width, height ) && zStorage->hasFreeSpace( output, outputAmount );
+}
+
+void ShapedRecipie::apply( ShapedCraftingStorage* zStorage )
+{
+    zStorage->consume( filters, width, height );
+    ItemStack* stack = new ItemStack( output->zItemType()->cloneItem( output ), outputAmount );
+    zStorage->addCraftingResult( stack );
+    stack->release();
+}

+ 40 - 0
FactoryCraft/Recipie.h

@@ -0,0 +1,40 @@
+#pragma once
+#include <Array.h>
+#include <JSON.h>
+
+#include "ItemFilter.h"
+#include "CraftingStorage.h"
+
+class Recipie : public virtual Framework::ReferenceCounter
+{
+private:
+    Framework::RCArray<ItemFilter> filters;
+    Framework::Array<int> inputAmount;
+    Framework::RCArray<Item> outputs;
+    Framework::Array<int> outputAmount;
+
+public:
+    Recipie();
+    void addIngredient( ItemFilter* filter, int amount );
+    void addOutput( Item* item, int amount );
+    bool testApplicability( CraftingStorage* zStorage );
+    void apply( CraftingStorage* zStorage );
+};
+
+class ShapedRecipie : public virtual Framework::ReferenceCounter
+{
+private:
+    Framework::RCArray<ItemFilter> filters;
+    int width;
+    int height;
+    Item* output;
+    int outputAmount;
+
+public:
+    ShapedRecipie( int width, int height );
+    ~ShapedRecipie();
+    void setIngredient( int x, int y, ItemFilter* filter );
+    void setOutput( Item* item, int amount );
+    bool testApplicability( ShapedCraftingStorage* zStorage );
+    void apply( ShapedCraftingStorage* zStorage );
+};

+ 39 - 0
FactoryCraft/RecipieList.h

@@ -0,0 +1,39 @@
+#pragma once
+#include <Text.h>
+#include "Recipie.h"
+
+template <typename T, typename S>
+class RecipieListType : public virtual Framework::ReferenceCounter
+{
+private:
+    Framework::RCArray<T> recipies;
+    Framework::Text name;
+
+public:
+    RecipieListType( const char* name )
+        : ReferenceCounter(),
+        name( name )
+    {}
+
+    void addRecipie( T* recipie )
+    {
+        recipies.add( recipie );
+    }
+
+    T* zFirstRecipie( S* zStorage )
+    {
+        for( T* recipie : recipies )
+        {
+            if( recipie->testApplicability( zStorage ) )
+                return recipie;
+        }
+    }
+
+    const Framework::Text& getName() const
+    {
+        return name;
+    }
+};
+
+typedef RecipieListType<Recipie, CraftingStorage> RecipieList;
+typedef RecipieListType<ShapedRecipie, ShapedCraftingStorage> ShapedRecipieList;

+ 68 - 0
FactoryCraft/RecipieLoader.cpp

@@ -0,0 +1,68 @@
+#include <stdexcept>
+#include <Datei.h>
+#include <iostream>
+#include "RecipieLoader.h"
+
+
+RecipieLoader::RecipieLoader()
+    : Framework::ReferenceCounter()
+{}
+
+void RecipieLoader::loadRecipies( const char* path )
+{
+    std::cout << "loading recipies from '" << path << "'" << std::endl;
+    Framework::Datei d;
+    d.setDatei( path );
+    if( d.istOrdner() )
+    {
+        Framework::RCArray<Framework::Text>* files = d.getDateiListe();
+        for( Framework::Text* f : *files )
+            loadRecipies( Framework::Text( path ) + "/" + *f );
+        files->release();
+    }
+    else
+    {
+        Framework::JSON::JSONValue* json = Framework::JSON::loadJSONFromFile( path );
+        if( json->getType() == Framework::JSON::JSONType::ARRAY )
+        {
+            // TODO: parse the json recipies
+        }
+        else
+            std::cout << "could not load recipie file '" << path << "' because it does not contain a valid json array of recipies" << std::endl;
+        json->release();
+    }
+}
+
+RecipieList* RecipieLoader::zRecipieList( const char* name )
+{
+    for( RecipieList* l : lists )
+    {
+        if( l->getName().istGleich( name ) )
+            return l;
+    }
+    return 0;
+}
+
+ShapedRecipieList* RecipieLoader::zShapedRecipieList( const char* name )
+{
+    for( ShapedRecipieList* l : shapedLists )
+    {
+        if( l->getName().istGleich( name ) )
+            return l;
+    }
+    return 0;
+}
+
+void RecipieLoader::registerRecipieList( const char* name )
+{
+    if( zRecipieList( name ) )
+        throw new std::invalid_argument( "the recipie list already exists" );
+    lists.add( new RecipieList( name ) );
+}
+
+void RecipieLoader::registerShapedRecipieList( const char* name )
+{
+    if( zShapedRecipieList( name ) )
+        throw new std::invalid_argument( "the recipie list already exists" );
+    shapedLists.add( new ShapedRecipieList( name ) );
+}

+ 18 - 0
FactoryCraft/RecipieLoader.h

@@ -0,0 +1,18 @@
+#pragma once
+#include <Array.h>
+#include "RecipieList.h"
+
+class RecipieLoader : public virtual Framework::ReferenceCounter
+{
+private:
+    Framework::RCArray<RecipieList> lists;
+    Framework::RCArray<ShapedRecipieList> shapedLists;
+
+public:
+    RecipieLoader();
+    void loadRecipies( const char* path );
+    RecipieList* zRecipieList( const char* name );
+    ShapedRecipieList* zShapedRecipieList( const char* name );
+    void registerRecipieList( const char* name );
+    void registerShapedRecipieList( const char* name );
+};