Explorar el Código

improve recipie parsing

Kolja Strohm hace 8 meses
padre
commit
55d793f320
Se han modificado 40 ficheros con 2236 adiciones y 987 borrados
  1. 1 1
      FactoryCraft/BasicBlocks.cpp
  2. 3 2
      FactoryCraft/BasicBlocks.h
  3. 23 5
      FactoryCraft/BasicItems.cpp
  4. 2 1
      FactoryCraft/BasicItems.h
  5. 21 4
      FactoryCraft/BasicTool.cpp
  6. 2 1
      FactoryCraft/BasicTool.h
  7. 23 3
      FactoryCraft/Block.cpp
  8. 2 1
      FactoryCraft/Block.h
  9. 0 15
      FactoryCraft/Chest.cpp
  10. 3 7
      FactoryCraft/Chest.h
  11. 39 44
      FactoryCraft/CraftingStorage.cpp
  12. 11 26
      FactoryCraft/CraftingStorage.h
  13. 24 6
      FactoryCraft/FluidContainer.cpp
  14. 2 1
      FactoryCraft/FluidContainer.h
  15. 6 5
      FactoryCraft/Game.cpp
  16. 4 4
      FactoryCraft/Item.cpp
  17. 2 2
      FactoryCraft/Item.h
  18. 491 22
      FactoryCraft/ItemFilter.cpp
  19. 73 6
      FactoryCraft/ItemFilter.h
  20. 209 22
      FactoryCraft/ItemModifier.cpp
  21. 82 5
      FactoryCraft/ItemModifier.h
  22. 21 2
      FactoryCraft/ItemType.cpp
  23. 5 1
      FactoryCraft/ItemType.h
  24. 2 2
      FactoryCraft/JsonUtils.cpp
  25. 3 1
      FactoryCraft/JsonUtils.h
  26. 17 5
      FactoryCraft/LightSources.cpp
  27. 2 1
      FactoryCraft/LightSources.h
  28. 1 1
      FactoryCraft/PlayerHand.cpp
  29. 501 90
      FactoryCraft/Recipie.cpp
  30. 99 18
      FactoryCraft/Recipie.h
  31. 2 2
      FactoryCraft/RecipieList.cpp
  32. 1 1
      FactoryCraft/RecipieList.h
  33. 37 348
      FactoryCraft/RecipieLoader.cpp
  34. 1 7
      FactoryCraft/RecipieLoader.h
  35. 1 1
      FactoryCraft/TreeSeblingBlock.cpp
  36. 23 4
      FactoryCraft/TypeRegistry.cpp
  37. 12 0
      Windows Version/data/blocks/blockTypes.json
  38. 223 129
      Windows Version/data/recipies/basicItems.json
  39. 103 74
      Windows Version/data/recipies/blocks.json
  40. 159 117
      Windows Version/data/recipies/tools.json

+ 1 - 1
FactoryCraft/BasicBlocks.cpp

@@ -97,7 +97,7 @@ ItemType* BasicBlockType::createItemType() const
         getHardness(),
         speedModifier,
         getItemTypeName(),
-        0, 50);
+        0, 50, getGroupNames());
 }
 
 int BasicBlockType::getItemTypeId() const

+ 3 - 2
FactoryCraft/BasicBlocks.h

@@ -88,8 +88,9 @@ private:
     Framework::Array<SpawnConfig> spawns;
 
 public:
-    AdditionalItemSpawningBlock(
-        int typeId, Framework::Vec3<int> pos, int dimensionId);
+    AdditionalItemSpawningBlock(int typeId,
+        Framework::Vec3<int> pos,
+        int dimensionId);
     void addSpawn(SpawnConfig config);
     virtual void onDestroy() override;
 };

+ 23 - 5
FactoryCraft/BasicItems.cpp

@@ -11,8 +11,9 @@ BasicItemType::BasicItemType(Framework::Text name,
     int maxStack,
     bool solid,
     float hungerRecoveryPerHp,
-    float thirstRecoveryPerHp)
-    : ItemType(name, model, maxStack),
+    float thirstRecoveryPerHp,
+    Framework::RCArray<Framework::Text> groups)
+    : ItemType(name, model, maxStack, groups),
       itemName(itemName),
       hp(hp),
       durability(durability),
@@ -112,6 +113,12 @@ BasicItemTypeFactory::BasicItemTypeFactory()
 BasicItemType* BasicItemTypeFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
+    Framework::RCArray<Framework::Text> groups;
+    for (Framework::JSON::JSONValue* group :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groups.add(new Framework::Text(group->asString()->getString()));
+    }
     return new BasicItemType(zJson->zValue("name")->asString()->getString(),
         Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
             zJson->zValue("model")),
@@ -121,7 +128,7 @@ BasicItemType* BasicItemTypeFactory::fromJson(
         (int)zJson->zValue("maxStack")->asNumber()->getNumber(),
         zJson->zValue("solid")->asBool()->getBool(),
         (float)zJson->zValue("hungerRecoveryPerHp")->asNumber()->getNumber(),
-        (float)zJson->zValue("thirstRecoveryPerHp")->asNumber()->getNumber());
+        (float)zJson->zValue("thirstRecoveryPerHp")->asNumber()->getNumber(), groups);
 }
 
 Framework::JSON::JSONObject* BasicItemTypeFactory::toJson(
@@ -137,14 +144,20 @@ Framework::JSON::JSONObject* BasicItemTypeFactory::toJson(
     result->addValue("hp", new Framework::JSON::JSONNumber(zObject->getHp()));
     result->addValue("durability",
         new Framework::JSON::JSONNumber(zObject->getDurability()));
-    result->addValue(
-        "maxStack", new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
+    result->addValue("maxStack",
+        new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
     result->addValue(
         "solid", new Framework::JSON::JSONBool(zObject->isSolid()));
     result->addValue("hungerRecoveryPerHp",
         new Framework::JSON::JSONNumber(zObject->getHungerRecoveryPerHp()));
     result->addValue("thirstRecoveryPerHp",
         new Framework::JSON::JSONNumber(zObject->getThirstRecoveryPerHp()));
+    Framework::JSON::JSONArray* groups = new Framework::JSON::JSONArray();
+    for (Framework::Text* group : zObject->getGroups())
+    {
+        groups->addValue(new Framework::JSON::JSONString(group->getText()));
+    }
+    result->addValue("groupNames", groups);
     return result;
 }
 
@@ -179,6 +192,11 @@ Framework::JSON::Validator::JSONValidator* BasicItemTypeFactory::getValidator(
         ->whichIsGreaterOrEqual(0.0)
         ->withDefault(0.0)
         ->finishNumber()
+        ->withRequiredArray("groupNames")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->finishArray()
         ->finishObject();
 }
 

+ 2 - 1
FactoryCraft/BasicItems.h

@@ -21,7 +21,8 @@ public:
         int maxStack,
         bool solid,
         float hungerRecoveryPerHp,
-        float thirstRecoveryPerHp);
+        float thirstRecoveryPerHp,
+        Framework::RCArray<Framework::Text> groups);
     Item* createItem() const override;
     Framework::Text getItemName() const;
     float getHp() const;

+ 21 - 4
FactoryCraft/BasicTool.cpp

@@ -198,8 +198,9 @@ BasicToolItemType::BasicToolItemType(Framework::Text name,
     ItemSkillLevelUpRule* levelUpRule,
     Framework::Text brokenItemTypeName,
     Framework::JSON::JSONObject* itemSkillConfigJson,
-    int maxStackSize)
-    : ItemType(name, model, maxStackSize),
+    int maxStackSize,
+    Framework::RCArray<Framework::Text> groups)
+    : ItemType(name, model, maxStackSize, groups),
       headMaterialHardness(headMaterialHardness),
       rodMaterialHardness(rodMaterialHardness),
       handleMaterialHardness(handleMaterialHardness),
@@ -409,6 +410,12 @@ BasicToolItemTypeFactory::BasicToolItemTypeFactory() {}
 BasicToolItemType* BasicToolItemTypeFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
+    Framework::RCArray<Framework::Text> groups;
+    for (Framework::JSON::JSONValue* group :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groups.add(new Framework::Text(group->asString()->getString()));
+    }
     return new BasicToolItemType(zJson->zValue("name")->asString()->getString(),
         Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
             zJson->zValue("model")),
@@ -437,7 +444,7 @@ BasicToolItemType* BasicToolItemTypeFactory::fromJson(
             zJson->zValue("levelUpRule")),
         zJson->zValue("brokenItemTypeName")->asString()->getString(),
         zJson->getValue("itemSkill")->asObject(),
-        (int)zJson->zValue("maxStack")->asNumber()->getNumber());
+        (int)zJson->zValue("maxStack")->asNumber()->getNumber(), groups);
 }
 
 Framework::JSON::JSONObject* BasicToolItemTypeFactory::toJson(
@@ -482,8 +489,13 @@ Framework::JSON::JSONObject* BasicToolItemTypeFactory::toJson(
     json->addValue("itemSkill", zObject->getItemSkillConfigJson());
     json->addValue("maxStack",
         new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
+    Framework::JSON::JSONArray* groups = new Framework::JSON::JSONArray();
+    for (Framework::Text* group : zObject->getGroups())
+    {
+        groups->addValue(new Framework::JSON::JSONString(group->getText()));
+    }
+    json->addValue("groupNames", groups);
     return json;
-    return nullptr;
 }
 
 Framework::JSON::Validator::JSONValidator*
@@ -550,6 +562,11 @@ BasicToolItemTypeFactory::getValidator(
                 ->getValidator<ItemSkillLevelUpRule>())
         ->withRequiredAttribute("itemSkill",
             Game::INSTANCE->zTypeRegistry()->getValidator<ItemSkill>())
+        ->withRequiredArray("groupNames")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->finishArray()
         ->finishObject();
 }
 

+ 2 - 1
FactoryCraft/BasicTool.h

@@ -101,7 +101,8 @@ public:
         ItemSkillLevelUpRule* levelUpRule,
         Framework::Text brokenItemTypeName,
         Framework::JSON::JSONObject* itemSkillConfigJson,
-        int maxStackSize);
+        int maxStackSize,
+        Framework::RCArray<Framework::Text> groups);
     ~BasicToolItemType();
 
 protected:

+ 23 - 3
FactoryCraft/Block.cpp

@@ -424,8 +424,10 @@ BasicBlockItemType::BasicBlockItemType(Framework::Text name,
     float hardness,
     float speedModifier,
     Framework::Text blockTypeName,
-    PlaceableProof* placeableProof, int maxStackSize)
-    : ItemType(name, model, maxStackSize),
+    PlaceableProof* placeableProof,
+    int maxStackSize,
+    Framework::RCArray<Framework::Text> groups)
+    : ItemType(name, model, maxStackSize, groups),
       transparent(transparent),
       passable(passable),
       hardness(hardness),
@@ -533,6 +535,12 @@ BasicBlockItemTypeFactory::BasicBlockItemTypeFactory()
 BasicBlockItemType* BasicBlockItemTypeFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
+    Framework::RCArray<Framework::Text> groups;
+    for (Framework::JSON::JSONValue* group :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groups.add(new Framework::Text(group->asString()->getString()));
+    }
     return new BasicBlockItemType(
         zJson->zValue("name")->asString()->getString(),
         Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
@@ -547,7 +555,8 @@ BasicBlockItemType* BasicBlockItemTypeFactory::fromJson(
             ? Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
                 zJson->zValue("placeableProof"))
             : 0,
-        (int)zJson->zValue("maxStack")->asNumber()->getNumber());
+        (int)zJson->zValue("maxStack")->asNumber()->getNumber(),
+        groups);
 }
 
 Framework::JSON::JSONObject* BasicBlockItemTypeFactory::toJson(
@@ -574,6 +583,12 @@ Framework::JSON::JSONObject* BasicBlockItemTypeFactory::toJson(
                                    : new Framework::JSON::JSONValue());
     zJson->addValue("maxStack",
         new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
+    Framework::JSON::JSONArray* groups = new Framework::JSON::JSONArray();
+    for (Framework::Text* group : zObject->getGroups())
+    {
+        groups->addValue(new Framework::JSON::JSONString(group->getText()));
+    }
+    zJson->addValue("groupNames", groups);
     return zJson;
 }
 
@@ -610,6 +625,11 @@ BasicBlockItemTypeFactory::getValidator(
         ->withDefault(50.0)
         ->whichIsGreaterOrEqual(1.0)
         ->finishNumber()
+        ->withRequiredArray("groupNames")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->finishArray()
         ->finishObject();
 }
 

+ 2 - 1
FactoryCraft/Block.h

@@ -169,7 +169,8 @@ public:
         float speedModifier,
         Framework::Text blockTypeName,
         PlaceableProof* placeableProof,
-        int maxStackSize);
+        int maxStackSize,
+        Framework::RCArray<Framework::Text> groups);
     ~BasicBlockItemType();
     virtual bool initialize(Game* zGame) override;
     int getBlockTypeId() const;

+ 0 - 15
FactoryCraft/Chest.cpp

@@ -169,21 +169,6 @@ Block* ChestBlockType::createBlock(
     return new Chest(getItemTypeId(), position, dimensionId);
 }
 
-ItemType* ChestBlockType::createItemType() const
-{
-    return new BasicBlockItemType(getItemTypeName(),
-        new ModelInfo(zModel()->getModelPath(),
-            zModel()->getTexturePaths(),
-            zModel()->isTransparent(),
-            zModel()->getSize() / 2.f),
-        isTransparent(),
-        isPassable(),
-        getHardness(),
-        getSpeedModifier(),
-        getItemTypeName(),
-        0, 50);
-}
-
 ChestBlockTypeFactory::ChestBlockTypeFactory()
     : SubTypeFactory()
 {}

+ 3 - 7
FactoryCraft/Chest.h

@@ -17,8 +17,7 @@ protected:
         TickQueue* zQueue, int numTicks, bool& blocked) override;
 
 public:
-    Chest(
-        int typeId, Framework::Vec3<int> pos, int dimensionId);
+    Chest(int typeId, Framework::Vec3<int> pos, int dimensionId);
     virtual bool interact(Item* zItem, Entity* zActor) override;
     virtual void sendModelInfo(NetworkMessage* zMessage) override;
 };
@@ -35,16 +34,13 @@ public:
         Framework::RCArray<Framework::Text> groupNames);
     virtual Block* createBlock(
         Framework::Vec3<int> position, int dimensionId) const override;
-    virtual ItemType* createItemType() const override;
 };
 
-class ChestBlockTypeFactory
-    : public SubTypeFactory<BlockType, ChestBlockType>
+class ChestBlockTypeFactory : public SubTypeFactory<BlockType, ChestBlockType>
 {
 public:
     ChestBlockTypeFactory();
-    ChestBlockType* fromJson(
-        Framework::JSON::JSONObject* zJson) const override;
+    ChestBlockType* fromJson(Framework::JSON::JSONObject* zJson) const override;
     Framework::JSON::JSONObject* toJson(ChestBlockType* zObject) const override;
     Framework::JSON::Validator::JSONValidator* getValidator(
         Framework::JSON::Validator::ObjectValidationBuilder<

+ 39 - 44
FactoryCraft/CraftingStorage.cpp

@@ -57,10 +57,10 @@ void BasicShapedCrafter::getOutputPreview(NetworkMessage* zMessage)
 {
     if (currentRecipie)
     {
-        Framework::Array<ItemInfo> output = currentRecipie->getOutput(this);
+        Framework::Array<ItemInfo> output = currentRecipie->getOutput();
         Framework::InMemoryBuffer buffer;
         int count = 0;
-        for (ItemInfo slot : output)
+        for (const ItemInfo& slot : output)
         {
             count++;
             int itemCount = slot.count;
@@ -94,10 +94,8 @@ void BasicShapedCrafter::getOutputPreview(NetworkMessage* zMessage)
     }
 }
 
-bool BasicShapedCrafter::isAllAvailable(Framework::RCArray<ItemFilter>& filters,
-    Framework::Array<int>& inputAmount,
-    int width,
-    int height)
+bool BasicShapedCrafter::isAllAvailable(
+    Framework::RCArray<RecipieInput>& inputs, int width, int height)
 {
     for (int x = 0; x <= this->width - width; x++)
     {
@@ -108,16 +106,16 @@ bool BasicShapedCrafter::isAllAvailable(Framework::RCArray<ItemFilter>& filters,
             {
                 for (int h = 0; h < height; h++)
                 {
-                    ItemFilter* f = filters.z(h * width + w);
+                    RecipieInput* i = inputs.z(h * width + w);
                     ItemSlot* s
                         = craftingInput.get((h + y) * this->width + (x + w));
                     const Item* item = 0;
                     if (s && s->zStack()
-                        && s->zStack()->getSize()
-                               >= inputAmount.get(h * width + w))
+                        && s->zStack()->getSize() >= i->getAmount())
                         item = s->zStack()->zItem();
-                    wrong |= (item && !f) || (!item && f);
-                    wrong |= item && f && !f->matchItem(item);
+                    wrong |= (item && !i->zFilter()) || (!item && i->zFilter());
+                    wrong |= item && i->zFilter()
+                          && !i->zFilter()->matchItem(item);
                     if (wrong) break;
                 }
                 if (wrong) break;
@@ -142,12 +140,11 @@ bool BasicShapedCrafter::isAllAvailable(Framework::RCArray<ItemFilter>& filters,
 }
 
 bool BasicShapedCrafter::isAllAvailable(
-    Framework::RCArray<ItemFilter>& filters, Framework::Array<int>& inputAmount)
+    Framework::RCArray<RecipieInput>& inputs)
 {
     bool* used = new bool[craftingInput.getEintragAnzahl()];
     memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl());
-    int index = 0;
-    for (ItemFilter* filter : filters)
+    for (RecipieInput* input : inputs)
     {
         bool found = 0;
         for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
@@ -155,9 +152,9 @@ bool BasicShapedCrafter::isAllAvailable(
             if (used[i]) continue;
             ItemSlot* slot = craftingInput.get(i);
             if (slot && slot->zStack()
-                && slot->zStack()->getSize() >= inputAmount.get(index)
+                && slot->zStack()->getSize() >= input->getAmount()
                 && slot->zStack()->zItem()
-                && filter->matchItem(slot->zStack()->zItem()))
+                && input->zFilter()->matchItem(slot->zStack()->zItem()))
             {
                 found = 1;
                 used[i] = 1;
@@ -169,7 +166,6 @@ bool BasicShapedCrafter::isAllAvailable(
             delete[] used;
             return 0;
         }
-        index++;
     }
     delete[] used;
     return 1;
@@ -184,11 +180,8 @@ bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount)
     return addable >= amount;
 }
 
-bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
-    Framework::RCArray<ItemModifier>& modifiers,
-    Framework::Array<int>& inputAmount,
-    int width,
-    int height)
+bool BasicShapedCrafter::consume(
+    Framework::RCArray<RecipieInput>& inputs, int width, int height)
 {
     int beginX = this->width;
     int beginY = this->height;
@@ -216,10 +209,11 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                 target, target->getNumberOfItems(), INSIDE);
             if (stack)
             {
-                if (stack->getSize() > inputAmount.get(y * width + x))
+                if (stack->getSize() > inputs.z(y * width + x)->getAmount())
                 {
-                    ItemStack* overflow = stack->split(
-                        stack->getSize() - inputAmount.get(y * width + x));
+                    ItemStack* overflow
+                        = stack->split(stack->getSize()
+                                       - inputs.z(y * width + x)->getAmount());
                     zInventory->unsaveAddItem(
                         overflow, INSIDE, &otherSlotsTarget);
                     if (overflow->getSize() > 0)
@@ -235,7 +229,7 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                 }
                 if (stack->getSize() > 0 && stack->zItem())
                 {
-                    ItemModifier* m = modifiers.z(y * width + x);
+                    ItemModifier* m = inputs.z(y * width + x)->zModifier();
                     if (m) m->applyOn((Item*)stack->zItem());
                 }
                 if (stack->zItem()->getHp() == 0)
@@ -278,17 +272,19 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                     }
                 }
             }
-            ItemFilter* f = filters.z(y * width + x);
+            ItemFilter* f = inputs.z(y * width + x)->zFilter();
             if (f)
             {
                 if (target->isEmpty())
                 {
+                    Framework::RCArray<ItemFilter> filters;
+                    filters.add(dynamic_cast<ItemFilter*>(f->getThis()));
+                    filters.add(
+                        dynamic_cast<ItemFilter*>(otherSlotsSource.getThis()));
                     Framework::Array<ItemSlot*> tmp;
                     tmp.add(target);
                     CombinedItemFilter combinedFilter(
-                        dynamic_cast<ItemFilter*>(f->getThis()),
-                        dynamic_cast<ItemFilter*>(otherSlotsSource.getThis()),
-                        [](bool a, bool b) { return a && b; });
+                        filters, [](bool a, bool b) { return a && b; });
                     zInventory->localTransaction(
                         0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
                 }
@@ -298,9 +294,7 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
     return 1;
 }
 
-bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
-    Framework::RCArray<ItemModifier>& modifiers,
-    Framework::Array<int>& inputAmount)
+bool BasicShapedCrafter::consume(Framework::RCArray<RecipieInput>& inputs)
 {
     SourceSlotBlacklistFilter otherSlotsSource;
     TargetSlotBlacklistFilter otherSlotsTarget;
@@ -311,26 +305,26 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
     }
     bool* used = new bool[craftingInput.getEintragAnzahl()];
     memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl());
-    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    for (int i = 0; i < inputs.getEintragAnzahl(); i++)
     {
         for (int j = 0; j < craftingInput.getEintragAnzahl(); j++)
         {
             if (used[j]) continue;
             ItemSlot* target = craftingInput.get(j);
             if (target && target->zStack()
-                && target->zStack()->getSize() >= inputAmount.get(i)
+                && target->zStack()->getSize() >= inputs.z(i)->getAmount()
                 && target->zStack()->zItem()
-                && filters.z(i)->matchItem(target->zStack()->zItem()))
+                && inputs.z(i)->zFilter()->matchItem(target->zStack()->zItem()))
             {
                 used[i] = 1;
                 ItemStack* stack = zInventory->takeItemsOut(
                     target, target->getNumberOfItems(), INSIDE);
                 if (stack)
                 {
-                    if (stack->getSize() > inputAmount.get(i))
+                    if (stack->getSize() > inputs.z(i)->getAmount())
                     {
                         ItemStack* overflow = stack->split(
-                            stack->getSize() - inputAmount.get(i));
+                            stack->getSize() - inputs.z(i)->getAmount());
                         zInventory->unsaveAddItem(
                             overflow, INSIDE, &otherSlotsTarget);
                         if (overflow->getSize() > 0)
@@ -346,7 +340,7 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                     }
                     if (stack->getSize() > 0 && stack->zItem())
                     {
-                        ItemModifier* m = modifiers.z(i);
+                        ItemModifier* m = inputs.z(i)->zModifier();
                         if (m) m->applyOn((Item*)stack->zItem());
                     }
                     if (stack->zItem()->getHp() == 0)
@@ -390,18 +384,19 @@ bool BasicShapedCrafter::consume(Framework::RCArray<ItemFilter>& filters,
                         }
                     }
                 }
-                ItemFilter* f = filters.z(i);
+                ItemFilter* f = inputs.z(i)->zFilter();
                 if (f)
                 {
                     if (target->isEmpty())
                     {
+                        Framework::RCArray<ItemFilter> filters;
+                        filters.add(dynamic_cast<ItemFilter*>(f->getThis()));
+                        filters.add(dynamic_cast<ItemFilter*>(
+                            otherSlotsSource.getThis()));
                         Framework::Array<ItemSlot*> tmp;
                         tmp.add(target);
                         CombinedItemFilter combinedFilter(
-                            dynamic_cast<ItemFilter*>(f->getThis()),
-                            dynamic_cast<ItemFilter*>(
-                                otherSlotsSource.getThis()),
-                            [](bool a, bool b) { return a && b; });
+                            filters, [](bool a, bool b) { return a && b; });
                         zInventory->localTransaction(
                             0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
                     }

+ 11 - 26
FactoryCraft/CraftingStorage.h

@@ -10,30 +10,20 @@
 class CraftingStorage
 {
 public:
-    virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters,
-        Framework::Array<int>& inputAmount)
-        = 0;
+    virtual bool isAllAvailable(Framework::RCArray<RecipieInput>& inputs) = 0;
     virtual bool hasFreeSpace(const Item* zItem, int amount) = 0;
-    virtual bool consume(Framework::RCArray<ItemFilter>& filters,
-        Framework::RCArray<ItemModifier>& modifiers,
-        Framework::Array<int>& inputAmount)
-        = 0;
+    virtual bool consume(Framework::RCArray<RecipieInput>& inputs) = 0;
     virtual void addCraftingResult(ItemStack* stack) = 0;
 };
 
 class ShapedCraftingStorage : public CraftingStorage
 {
 public:
-    virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters,
-        Framework::Array<int>& inputAmount,
-        int width,
-        int height)
+    virtual bool isAllAvailable(
+        Framework::RCArray<RecipieInput>& inputs, int width, int height)
         = 0;
-    virtual bool consume(Framework::RCArray<ItemFilter>& filters,
-        Framework::RCArray<ItemModifier>& modifiers,
-        Framework::Array<int>& inputAmount,
-        int width,
-        int height)
+    virtual bool consume(
+        Framework::RCArray<RecipieInput>& inputs, int width, int height)
         = 0;
 };
 
@@ -54,21 +44,16 @@ public:
         int height,
         Inventory* zInventory,
         Framework::Text recipieList);
-    virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters,
-        Framework::Array<int>& inputAmount,
+    virtual bool isAllAvailable(Framework::RCArray<RecipieInput>& inputs,
         int width,
         int height) override;
-    virtual bool isAllAvailable(Framework::RCArray<ItemFilter>& filters,
-        Framework::Array<int>& inputAmount) override;
+    virtual bool isAllAvailable(
+        Framework::RCArray<RecipieInput>& inputs) override;
     virtual bool hasFreeSpace(const Item* zItem, int amount) override;
-    virtual bool consume(Framework::RCArray<ItemFilter>& filters,
-        Framework::RCArray<ItemModifier>& modifiers,
-        Framework::Array<int>& inputAmount,
+    virtual bool consume(Framework::RCArray<RecipieInput>& inputs,
         int width,
         int height) override;
-    virtual bool consume(Framework::RCArray<ItemFilter>& filters,
-        Framework::RCArray<ItemModifier>& modifiers,
-        Framework::Array<int>& inputAmount) override;
+    virtual bool consume(Framework::RCArray<RecipieInput>& inputs) override;
     virtual void addCraftingResult(ItemStack* stack) override;
     void applyCurrentRecipie();
     void calculateOutputPreview();

+ 24 - 6
FactoryCraft/FluidContainer.cpp

@@ -462,8 +462,7 @@ FluidContainerItemSkillFactory::getValidator(
     Framework::JSON::Validator::ObjectValidationBuilder<
         Framework::JSON::Validator::JSONValidator>* builder) const
 {
-    return builder
-        ->withRequiredNumber("invalidUseStaminaCost")
+    return builder->withRequiredNumber("invalidUseStaminaCost")
         ->whichIsGreaterOrEqual(0.0)
         ->withDefault(0.5)
         ->finishNumber()
@@ -501,8 +500,9 @@ FluidContainerItemType::FluidContainerItemType(Framework::Text name,
     Framework::JSON::JSONObject* itemSkillConfig,
     ItemSkillLevelUpRule* levelUpRule,
     int maxFluidAmount,
-    int maxStackSize)
-    : ItemType(name, model, maxStackSize),
+    int maxStackSize,
+    Framework::RCArray<Framework::Text> groups)
+    : ItemType(name, model, maxStackSize, groups),
       itemSkillConfig(itemSkillConfig),
       levelUpRule(levelUpRule),
       maxFluidAmount(maxFluidAmount)
@@ -665,6 +665,12 @@ FluidContainerItemTypeFactory::FluidContainerItemTypeFactory()
 FluidContainerItemType* FluidContainerItemTypeFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
+    Framework::RCArray<Framework::Text> groups;
+    for (Framework::JSON::JSONValue* group :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groups.add(new Framework::Text(group->asString()->getString()));
+    }
     return new FluidContainerItemType(
         zJson->zValue("name")->asString()->getString(),
         Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
@@ -673,7 +679,8 @@ FluidContainerItemType* FluidContainerItemTypeFactory::fromJson(
         Game::INSTANCE->zTypeRegistry()->fromJson<ItemSkillLevelUpRule>(
             zJson->zValue("levelUpRule")),
         (int)zJson->zValue("maxFluidAmount")->asNumber()->getNumber(),
-        (int)zJson->zValue("maxStack")->asNumber()->getNumber());
+        (int)zJson->zValue("maxStack")->asNumber()->getNumber(),
+        groups);
 }
 
 Framework::JSON::JSONObject* FluidContainerItemTypeFactory::toJson(
@@ -693,7 +700,13 @@ Framework::JSON::JSONObject* FluidContainerItemTypeFactory::toJson(
         new Framework::JSON::JSONNumber(zObject->getMaxFluidAmount()));
     result->addValue("maxStack",
         new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
-    return nullptr;
+    Framework::JSON::JSONArray* groups = new Framework::JSON::JSONArray();
+    for (Framework::Text* group : zObject->getGroups())
+    {
+        groups->addValue(new Framework::JSON::JSONString(group->getText()));
+    }
+    result->addValue("groupNames", groups);
+    return result;
 }
 
 Framework::JSON::Validator::JSONValidator*
@@ -718,6 +731,11 @@ FluidContainerItemTypeFactory::getValidator(
         ->withDefault(50.0)
         ->whichIsGreaterOrEqual(1.0)
         ->finishNumber()
+        ->withRequiredArray("groupNames")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->finishArray()
         ->finishObject();
 }
 

+ 2 - 1
FactoryCraft/FluidContainer.h

@@ -119,7 +119,8 @@ public:
         Framework::JSON::JSONObject* itemSkillConfig,
         ItemSkillLevelUpRule* levelUpRule,
         int maxFluidAmount,
-        int maxStackSize);
+        int maxStackSize,
+        Framework::RCArray<Framework::Text> groups);
     ~FluidContainerItemType();
 
 protected:

+ 6 - 5
FactoryCraft/Game.cpp

@@ -399,7 +399,8 @@ void Game::initialize()
               ->removeInvalidEntries()
               ->finishArray();
     loadAllJsonsFromDirectory("data/blocks",
-        [this, &blockTypeArray, validator](Framework::JSON::JSONValue* zValue) {
+        [this, &blockTypeArray, validator](
+            Framework::JSON::JSONValue* zValue, Framework::Text path) {
             Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
                 validationResults;
             Framework::JSON::JSONValue* validParts
@@ -447,7 +448,8 @@ void Game::initialize()
               ->removeInvalidEntries()
               ->finishArray();
     loadAllJsonsFromDirectory("data/items",
-        [this, &itemTypeArray, validator](Framework::JSON::JSONValue* zValue) {
+        [this, &itemTypeArray, validator](
+            Framework::JSON::JSONValue* zValue, Framework::Text path) {
             Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
                 validationResults;
             Framework::JSON::JSONValue* validParts
@@ -471,7 +473,6 @@ void Game::initialize()
                 validParts->release();
             }
         });
-    Sleep(10000);
     validator->release();
     std::cout << "Loaded " << itemTypeArray.getEintragAnzahl()
               << " item types from data/items\n";
@@ -504,7 +505,7 @@ void Game::initialize()
               ->finishArray();
     loadAllJsonsFromDirectory("data/entities",
         [this, &entityTypeArray, validator](
-            Framework::JSON::JSONValue* zValue) {
+            Framework::JSON::JSONValue* zValue, Framework::Text path) {
             Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
                 validationResults;
             Framework::JSON::JSONValue* validParts
@@ -869,7 +870,7 @@ void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)
         { // crafting uiml request
             int id;
             zRequest->lese((char*)&id, 4);
-            Text uiml = recipies.getCrafingUIML(zItemType(id));
+            Text uiml = recipies.getCrafingUIML(id);
             Text dialogId = "crafting_";
             dialogId += id;
             uiController->addDialog(new UIDialog(dialogId,

+ 4 - 4
FactoryCraft/Item.cpp

@@ -170,11 +170,11 @@ bool Item::canApplyFoodEffectsFully(Entity* zTarget) const
     return foodEffectDestroysItemTest(this, zTarget);
 }
 
-ItomJsonType::ItomJsonType()
+ItemJsonType::ItemJsonType()
     : TypeFactory()
 {}
 
-Item* ItomJsonType::fromJson(Framework::JSON::JSONValue* zJson) const
+Item* ItemJsonType::fromJson(Framework::JSON::JSONValue* zJson) const
 {
     const ItemType* type = ItemType::zByName(
         zJson->asObject()->zValue("type")->asString()->getString());
@@ -189,7 +189,7 @@ Item* ItomJsonType::fromJson(Framework::JSON::JSONValue* zJson) const
     return result;
 }
 
-Framework::JSON::JSONValue* ItomJsonType::toJson(Item* zObject) const
+Framework::JSON::JSONValue* ItemJsonType::toJson(Item* zObject) const
 {
     Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
     result->addValue("type",
@@ -198,7 +198,7 @@ Framework::JSON::JSONValue* ItomJsonType::toJson(Item* zObject) const
     return result;
 }
 
-Framework::JSON::Validator::JSONValidator* ItomJsonType::getValidator() const
+Framework::JSON::Validator::JSONValidator* ItemJsonType::getValidator() const
 {
     Framework::RCArray<Framework::Text> itemTypes;
     for (int index = 0; index < Game::INSTANCE->getItemTypeCount(); index++)

+ 2 - 2
FactoryCraft/Item.h

@@ -66,10 +66,10 @@ public:
     friend ItemType;
 };
 
-class ItomJsonType : public TypeFactory<Item>
+class ItemJsonType : public TypeFactory<Item>
 {
 public:
-    ItomJsonType();
+    ItemJsonType();
     Item* fromJson(Framework::JSON::JSONValue* zJson) const override;
     Framework::JSON::JSONValue* toJson(Item* zObject) const override;
     Framework::JSON::Validator::JSONValidator*

+ 491 - 22
FactoryCraft/ItemFilter.cpp

@@ -1,5 +1,6 @@
 #include "ItemFilter.h"
 
+#include "Game.h"
 #include "Item.h"
 #include "ItemSlot.h"
 #include "ItemStack.h"
@@ -24,46 +25,339 @@ bool ItemFilter::matchTargetSlot(ItemSlot* zSlot) const
     return 1;
 }
 
-CombinedItemFilter::CombinedItemFilter(ItemFilter* filterA,
-    ItemFilter* filterB,
-    std::function<bool(bool, bool)> op)
+CombinedItemFilter::CombinedItemFilter(
+    Framework::RCArray<ItemFilter> filters, std::function<bool(bool, bool)> op)
     : ItemFilter(),
-      filterA(filterA),
-      filterB(filterB),
+      filters(filters),
       op(op)
 {}
 
-CombinedItemFilter::~CombinedItemFilter()
-{
-    filterA->release();
-    filterB->release();
-}
-
 bool CombinedItemFilter::matchItem(const Item* zItem) const
 {
-    return op(filterA->matchItem(zItem), filterB->matchItem(zItem));
+    bool result = false;
+    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    {
+        if (i == 0)
+            result = filters.z(i)->matchItem(zItem);
+        else
+            result = op(result, filters.z(i)->matchItem(zItem));
+    }
+    return result;
 }
 
 bool CombinedItemFilter::matchSourceSlot(ItemSlot* zSlot) const
 {
-    return op(filterA->matchSourceSlot(zSlot), filterB->matchSourceSlot(zSlot));
+    bool result = false;
+    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    {
+        if (i == 0)
+            result = filters.z(i)->matchSourceSlot(zSlot);
+        else
+            result = op(result, filters.z(i)->matchSourceSlot(zSlot));
+    }
+    return result;
 }
 
 bool CombinedItemFilter::matchTargetSlot(ItemSlot* zSlot) const
 {
-    return op(filterA->matchTargetSlot(zSlot), filterB->matchTargetSlot(zSlot));
+    bool result = false;
+    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    {
+        if (i == 0)
+            result = filters.z(i)->matchTargetSlot(zSlot);
+        else
+            result = op(result, filters.z(i)->matchTargetSlot(zSlot));
+    }
+    return result;
 }
 
 Framework::Text CombinedItemFilter::getLogicUIML() const
 {
-    Framework::Text result = "<operator result_0_0=\"";
-    result.append() << (int)op(0, 0) << "\" result_0_1=\"" << (int)op(0, 1)
+    if (filters.getEintragAnzahl() == 0)
+    {
+        return "";
+    }
+    if (filters.getEintragAnzahl() == 1)
+    {
+        return filters.z(0)->getLogicUIML();
+    }
+    else
+    {
+        Framework::Text result = "<operator result_0_0=\"";
+        result.append() << (int)op(0, 0) << "\" result_0_1=\"" << (int)op(0, 1)
+                        << "\" result_1_0=\"" << (int)op(1, 0)
+                        << "\" result_1_1=\"" << (int)op(1, 1) << "\">";
+        int openCount = 1;
+        for (int i = 0; i < filters.getEintragAnzahl() - 1; i++)
+        {
+            if (i < filters.getEintragAnzahl() - 2)
+            {
+                result.append()
+                    << filters.z(i)->getLogicUIML() << "<operator result_0_0=\""
+                    << (int)op(0, 0) << "\" result_0_1=\"" << (int)op(0, 1)
                     << "\" result_1_0=\"" << (int)op(1, 0) << "\" result_1_1=\""
-                    << (int)op(1, 1) << "\">" << filterA->getLogicUIML()
-                    << filterB->getLogicUIML() << "</operator>";
+                    << (int)op(1, 1) << "\">";
+            }
+            else
+            {
+                filters.z(i)->getLogicUIML();
+                filters.z(i + 1)->getLogicUIML();
+            }
+        }
+        return result;
+    }
+}
+
+const Framework::RCArray<ItemFilter>& CombinedItemFilter::getFilters() const
+{
+    return filters;
+}
+
+std::function<bool(bool, bool)> CombinedItemFilter::getOp() const
+{
+    return op;
+}
+
+CombinedItemFilterFactory::CombinedItemFilterFactory()
+    : SubTypeFactory()
+{}
+
+CombinedItemFilter* CombinedItemFilterFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    std::function<bool(bool, bool)> func;
+    Framework::Text op = zJson->zValue("operator")->asString()->getString();
+    if (op.istGleich("or"))
+    {
+        func = [](bool a, bool b) { return a || b; };
+    }
+    else if (op.istGleich("and"))
+    {
+        func = [](bool a, bool b) { return a && b; };
+    }
+    else if (op.istGleich("xor"))
+    {
+        func = [](bool a, bool b) { return (!a || !b) && (a || b); };
+    }
+    else if (op.istGleich("nor"))
+    {
+        func = [](bool a, bool b) { return !(a || b); };
+    }
+    else if (op.istGleich("nand"))
+    {
+        func = [](bool a, bool b) { return !(a && b); };
+    }
+    else if (op.istGleich("left"))
+    {
+        func = [](bool a, bool b) { return a; };
+    }
+    else if (op.istGleich("right"))
+    {
+        func = [](bool a, bool b) { return b; };
+    }
+    else if (op.istGleich("onlyLeft"))
+    {
+        func = [](bool a, bool b) { return a && !b; };
+    }
+    else if (op.istGleich("onlyRight"))
+    {
+        func = [](bool a, bool b) { return !a && b; };
+    }
+    else if (op.istGleich("notLeft"))
+    {
+        func = [](bool a, bool b) { return !a; };
+    }
+    else if (op.istGleich("notRight"))
+    {
+        func = [](bool a, bool b) { return !b; };
+    }
+    else if (op.istGleich("eq"))
+    {
+        func = [](bool a, bool b) { return a == b; };
+    }
+    else if (op.istGleich("leftOrEq"))
+    {
+        func = [](bool a, bool b) { return a || (a == b); };
+    }
+    else if (op.istGleich("rightOrEq"))
+    {
+        func = [](bool a, bool b) { return b || (a == b); };
+    }
+    else if (op.istGleich("true"))
+    {
+        func = [](bool a, bool b) { return true; };
+    }
+    else
+    {
+        func = [](bool a, bool b) { return false; };
+    }
+    Framework::RCArray<ItemFilter> filters;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("filters")->asArray())
+    {
+        filters.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(value));
+    }
+    return new CombinedItemFilter(filters, func);
+}
+
+Framework::JSON::JSONObject* CombinedItemFilterFactory::toJson(
+    CombinedItemFilter* zObject) const
+{
+    Framework::Text op;
+    std::function<bool(bool, bool)> func = zObject->getOp();
+    if (func(0, 0))
+    {
+        if (func(0, 1))
+        {
+            if (func(1, 0))
+            {
+                if (func(1, 1))
+                {
+                    op = "true";
+                }
+                else
+                {
+                    op = "nand";
+                }
+            }
+            else
+            {
+                if (func(1, 1))
+                {
+                    op = "rightOrEq";
+                }
+                else
+                {
+                    op = "notLeft";
+                }
+            }
+        }
+        else
+        {
+            if (func(1, 0))
+            {
+                if (func(1, 1))
+                {
+                    op = "leftOrEq";
+                }
+                else
+                {
+                    op = "notRight";
+                }
+            }
+            else
+            {
+                if (func(1, 1))
+                {
+                    op = "eq";
+                }
+                else
+                {
+                    op = "nor";
+                }
+            }
+        }
+    }
+    else
+    {
+        if (func(0, 1))
+        {
+            if (func(1, 0))
+            {
+                if (func(1, 1))
+                {
+                    op = "or";
+                }
+                else
+                {
+                    op = "xor";
+                }
+            }
+            else
+            {
+                if (func(1, 1))
+                {
+                    op = "right";
+                }
+                else
+                {
+                    op = "onlyRight";
+                }
+            }
+        }
+        else
+        {
+            if (func(1, 0))
+            {
+                if (func(1, 1))
+                {
+                    op = "left";
+                }
+                else
+                {
+                    op = "onlyLeft";
+                }
+            }
+            else
+            {
+                if (func(1, 1))
+                {
+                    op = "and";
+                }
+                else
+                {
+                    op = "false";
+                }
+            }
+        }
+    }
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("operator", new Framework::JSON::JSONString(op));
+    Framework::JSON::JSONArray* filters = new Framework::JSON::JSONArray();
+    for (ItemFilter* filter : zObject->getFilters())
+    {
+        filters->addValue(Game::INSTANCE->zTypeRegistry()->toJson(filter));
+    }
+    result->addValue("filters", filters);
     return result;
 }
 
+Framework::JSON::Validator::JSONValidator*
+CombinedItemFilterFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("operator")
+        ->whichIsOneOf({"or",
+            "and",
+            "xor",
+            "nor",
+            "nand",
+            "left",
+            "right",
+            "onlyLeft",
+            "onlyRight",
+            "notLeft",
+            "notRight",
+            "eq",
+            "leftOrEq",
+            "rightOrEq",
+            "true",
+            "false"})
+        ->finishString()
+        ->withRequiredArray("filters")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemFilter>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text CombinedItemFilterFactory::getTypeToken() const
+{
+    return "operator";
+}
+
 AnyItemFilter::AnyItemFilter()
     : ItemFilter()
 {}
@@ -78,23 +372,101 @@ Framework::Text AnyItemFilter::getLogicUIML() const
     return "<anyItem/>";
 }
 
+AnyItemFilterFactory::AnyItemFilterFactory()
+    : SubTypeFactory()
+{}
+
+AnyItemFilter* AnyItemFilterFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new AnyItemFilter();
+}
+
+Framework::JSON::JSONObject* AnyItemFilterFactory::toJson(
+    AnyItemFilter* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
+
+Framework::JSON::Validator::JSONValidator* AnyItemFilterFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->finishObject();
+}
+
+Framework::Text AnyItemFilterFactory::getTypeToken() const
+{
+    return "anyItem";
+}
+
 TypeItemFilter::TypeItemFilter(const ItemType* zType)
     : ItemFilter(),
-      zType(zType)
+      type(zType)
 {}
 
 bool TypeItemFilter::matchItem(const Item* zItem) const
 {
-    return zItem->zItemType() == zType;
+    return zItem->zItemType() == type;
 }
 
 Framework::Text TypeItemFilter::getLogicUIML() const
 {
     Framework::Text result = "<attribute name=\"Type\" operator=\"=\" value=\"";
-    result.append() << zType->getId() << "\"/>";
+    result.append() << type->getId() << "\"/>";
     return result;
 }
 
+const ItemType* TypeItemFilter::zType() const
+{
+    return type;
+}
+
+TypeItemFilterFactory::TypeItemFilterFactory()
+    : SubTypeFactory()
+{}
+
+TypeItemFilter* TypeItemFilterFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new TypeItemFilter(
+        Game::INSTANCE->zItemType(Game::INSTANCE->getItemTypeId(
+            zJson->zValue("itemType")->asString()->getString())));
+}
+
+Framework::JSON::JSONObject* TypeItemFilterFactory::toJson(
+    TypeItemFilter* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
+        new Framework::JSON::JSONString(zObject->zType()->getName()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* TypeItemFilterFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    Framework::RCArray<Text> types;
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
+    {
+        if (Game::INSTANCE->zItemType(i))
+        {
+            types.add(
+                new Framework::Text(Game::INSTANCE->zItemType(i)->getName()));
+        }
+    }
+    return builder->withRequiredString("itemType")
+        ->whichIsOneOf(types)
+        ->finishString()
+        ->finishObject();
+}
+
+Framework::Text TypeItemFilterFactory::getTypeToken() const
+{
+    return "type";
+}
+
 SpecificSlotFilter::SpecificSlotFilter(int sourceSlotId, int targetSlotId)
     : ItemFilter(),
       sourceSlotId(sourceSlotId),
@@ -170,4 +542,101 @@ bool TargetSlotBlacklistFilter::matchTargetSlot(ItemSlot* zSlot) const
 Framework::Text TargetSlotBlacklistFilter::getLogicUIML() const
 {
     return "<anyItem/>";
-}
+}
+
+GroupItemFilter::GroupItemFilter(Framework::RCArray<Framework::Text> groups)
+    : ItemFilter(),
+      groups(groups)
+{}
+
+bool GroupItemFilter::matchItem(const Item* zItem) const
+{
+    for (Framework::Text* group : groups)
+    {
+        for (Framework::Text* typeGroup : zItem->zItemType()->getGroups())
+        {
+            if (typeGroup->istGleich(group)) return true;
+        }
+    }
+    return false;
+}
+
+Framework::Text GroupItemFilter::getLogicUIML() const
+{
+    Framework::RCArray<ItemFilter> filters;
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
+    {
+        if (Game::INSTANCE->zItemType(i))
+        {
+            bool found = false;
+            for (Framework::Text* group : groups)
+            {
+                for (Framework::Text* typeGroup :
+                    Game::INSTANCE->zItemType(i)->getGroups())
+                {
+                    if (typeGroup->istGleich(group))
+                    {
+                        found = true;
+                        break;
+                    }
+                }
+                if (found) break;
+            }
+            if (found)
+                filters.add(new TypeItemFilter(Game::INSTANCE->zItemType(i)));
+        }
+    }
+    return CombinedItemFilter(filters, [](bool a, bool b) {
+        return a || b;
+    }).getLogicUIML();
+}
+
+const Framework::RCArray<Framework::Text>& GroupItemFilter::getGroups() const
+{
+    return groups;
+}
+
+GroupItemFilterFactory::GroupItemFilterFactory()
+    : SubTypeFactory()
+{}
+
+GroupItemFilter* GroupItemFilterFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groups;
+    for (Framework::JSON::JSONValue* group :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groups.add(new Framework::Text(group->asString()->getString()));
+    }
+    return new GroupItemFilter(groups);
+}
+
+Framework::JSON::JSONObject* GroupItemFilterFactory::toJson(
+    GroupItemFilter* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* groups = new Framework::JSON::JSONArray();
+    for (Framework::Text* group : zObject->getGroups())
+    {
+        groups->addValue(new Framework::JSON::JSONString(group->getText()));
+    }
+    result->addValue("groupNames", groups);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* GroupItemFilterFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("groupNames")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text GroupItemFilterFactory::getTypeToken() const
+{
+    return "groups";
+}

+ 73 - 6
FactoryCraft/ItemFilter.h

@@ -3,6 +3,7 @@
 #include <Array.h>
 #include <functional>
 #include <ReferenceCounter.h>
+#include <TypeRegistry.h>
 
 class Item;
 class ItemType;
@@ -21,19 +22,33 @@ public:
 class CombinedItemFilter : public ItemFilter
 {
 private:
-    ItemFilter* filterA;
-    ItemFilter* filterB;
+    Framework::RCArray<ItemFilter> filters;
     std::function<bool(bool, bool)> op;
 
 public:
-    CombinedItemFilter(ItemFilter* filterA,
-        ItemFilter* filterB,
+    CombinedItemFilter(Framework::RCArray<ItemFilter> filters,
         std::function<bool(bool, bool)> op);
-    ~CombinedItemFilter();
     bool matchItem(const Item* zItem) const override;
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
     Framework::Text getLogicUIML() const override;
+    const Framework::RCArray<ItemFilter>& getFilters() const;
+    std::function<bool(bool, bool)> getOp() const;
+};
+
+class CombinedItemFilterFactory
+    : public SubTypeFactory<ItemFilter, CombinedItemFilter>
+{
+public:
+    CombinedItemFilterFactory();
+    CombinedItemFilter* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        CombinedItemFilter* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };
 
 class AnyItemFilter : public ItemFilter
@@ -44,15 +59,40 @@ public:
     Framework::Text getLogicUIML() const override;
 };
 
+class AnyItemFilterFactory : public SubTypeFactory<ItemFilter, AnyItemFilter>
+{
+public:
+    AnyItemFilterFactory();
+    AnyItemFilter* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(AnyItemFilter* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
+};
+
 class TypeItemFilter : public ItemFilter
 {
 private:
-    const ItemType* zType;
+    const ItemType* type;
 
 public:
     TypeItemFilter(const ItemType* zType);
     bool matchItem(const Item* zItem) const override;
     Framework::Text getLogicUIML() const override;
+    const ItemType* zType() const;
+};
+
+class TypeItemFilterFactory : public SubTypeFactory<ItemFilter, TypeItemFilter>
+{
+public:
+    TypeItemFilterFactory();
+    TypeItemFilter* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(TypeItemFilter* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };
 
 class SpecificSlotFilter : public ItemFilter
@@ -92,4 +132,31 @@ public:
     bool matchSourceSlot(ItemSlot* zSlot) const override;
     bool matchTargetSlot(ItemSlot* zSlot) const override;
     Framework::Text getLogicUIML() const override;
+};
+
+class GroupItemFilter : public ItemFilter
+{
+private:
+    Framework::RCArray<Framework::Text> groups;
+
+public:
+    GroupItemFilter(Framework::RCArray<Framework::Text> groups);
+    bool matchItem(const Item* zItem) const override;
+    Framework::Text getLogicUIML() const override;
+    const Framework::RCArray<Framework::Text>& getGroups() const;
+};
+
+class GroupItemFilterFactory
+    : public SubTypeFactory<ItemFilter, GroupItemFilter>
+{
+public:
+    GroupItemFilterFactory();
+    GroupItemFilter* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        GroupItemFilter* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 209 - 22
FactoryCraft/ItemModifier.cpp

@@ -1,52 +1,239 @@
 #include "ItemModifier.h"
 
+#include "Game.h"
+
 using namespace Framework;
 
 ItemModifier::ItemModifier()
     : ReferenceCounter()
 {}
 
+ConsumeItemModifier::ConsumeItemModifier()
+    : ItemModifier()
+{}
+
+void ConsumeItemModifier::applyOn(Item* zItem)
+{
+    zItem->setHp(0);
+}
+
+ConsumeItemModifierFactory::ConsumeItemModifierFactory()
+    : SubTypeFactory()
+{}
+
+ConsumeItemModifier* ConsumeItemModifierFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new ConsumeItemModifier();
+}
+
+Framework::JSON::JSONObject* ConsumeItemModifierFactory::toJson(
+    ConsumeItemModifier* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
+
+Framework::JSON::Validator::JSONValidator*
+ConsumeItemModifierFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->finishObject();
+}
+
+Framework::Text ConsumeItemModifierFactory::getTypeToken() const
+{
+    return "consume";
+}
+
+DoNothingModifier::DoNothingModifier()
+    : ItemModifier()
+{}
+
+void DoNothingModifier::applyOn(Item* zItem)
+{
+    // do nothing
+}
+
+DoNothingModifierFactory::DoNothingModifierFactory()
+    : SubTypeFactory()
+{}
+
+DoNothingModifier* DoNothingModifierFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DoNothingModifier();
+}
+
+Framework::JSON::JSONObject* DoNothingModifierFactory::toJson(
+    DoNothingModifier* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
+
+Framework::JSON::Validator::JSONValidator*
+DoNothingModifierFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->finishObject();
+}
+
+Framework::Text DoNothingModifierFactory::getTypeToken() const
+{
+    return "doNothing";
+}
+
 AttributeItemModifier::AttributeItemModifier(
-    Framework::Text attribute, Framework::Text value)
+    Framework::RCArray<Framework::Text> attribute,
+    Framework::RCArray<Framework::JSON::JSONValue> value)
     : ItemModifier(),
-      attribute(attribute),
-      value(value)
+      attributes(attribute),
+      values(value)
 {}
 
 void AttributeItemModifier::applyOn(Item* zItem)
 {
-    if (attribute.istGleich("hp"))
+    auto attribute = attributes.begin();
+    auto value = values.begin();
+    while (attribute && value)
     {
-        float hp = 0;
-        if (value.positionVon("+=") == 0 || value.positionVon("-=") == 0)
-        {
-            hp = zItem->getHp();
-            if (value.positionVon("+=") == 0)
-                hp += TextZuFloat(value.getText() + 2);
-            if (value.positionVon("-=") == 0)
-                hp -= TextZuFloat(value.getText() + 2);
-        }
-        if (value.positionVon("=") == 0)
+        zItem->zItemType()->setItemAttribute(
+            zItem, attribute->getText(), value);
+        attribute++;
+        value++;
+    }
+}
+
+const Framework::RCArray<Framework::Text>&
+AttributeItemModifier::getAttributes() const
+{
+    return attributes;
+}
+
+const Framework::RCArray<Framework::JSON::JSONValue>&
+AttributeItemModifier::getValues() const
+{
+    return values;
+}
+
+AttributeItemModifierFactory::AttributeItemModifierFactory()
+    : SubTypeFactory()
+{}
+
+AttributeItemModifier* AttributeItemModifierFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> attributes;
+    Framework::RCArray<Framework::JSON::JSONValue> values;
+    auto attribute = zJson->getFields();
+    auto value = zJson->getValues();
+    while (attribute, value)
+    {
+        if (!attribute.val().istGleich("type"))
         {
-            hp = TextZuFloat(value.getText() + 1);
+            attributes.add(new Framework::Text(attribute.val()));
+            values.add(
+                dynamic_cast<Framework::JSON::JSONValue*>(value->getThis()));
         }
-        zItem->setHp(hp);
+        attribute++;
+        value++;
     }
+    return new AttributeItemModifier(attributes, values);
 }
 
-CombinedItemModifier::CombinedItemModifier()
-    : ItemModifier()
-{}
+Framework::JSON::JSONObject* AttributeItemModifierFactory::toJson(
+    AttributeItemModifier* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    auto attribute = zObject->getAttributes().begin();
+    auto value = zObject->getValues().begin();
+    while (attribute && value)
+    {
+        result->addValue(attribute->getText(),
+            dynamic_cast<Framework::JSON::JSONObject*>(value->getThis()));
+        attribute++;
+        value++;
+    }
+    return result;
+}
 
-void CombinedItemModifier::addModifier(ItemModifier* modifier)
+Framework::JSON::Validator::JSONValidator*
+AttributeItemModifierFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
 {
-    modifiers.add(modifier);
+    return builder->allowAdditionalAttriutes()->finishObject();
 }
 
+Framework::Text AttributeItemModifierFactory::getTypeToken() const
+{
+    return "attributes";
+}
+
+CombinedItemModifier::CombinedItemModifier(
+    Framework::RCArray<ItemModifier> modifiers)
+    : ItemModifier(),
+      modifiers()
+{}
+
 void CombinedItemModifier::applyOn(Item* zItem)
 {
     for (ItemModifier* modifier : modifiers)
     {
         modifier->applyOn(zItem);
     }
-}
+}
+
+const Framework::RCArray<ItemModifier>&
+CombinedItemModifier::getModifiers() const
+{
+    return modifiers;
+}
+
+CombinedItemModifierFactory::CombinedItemModifierFactory()
+    : SubTypeFactory()
+{}
+
+CombinedItemModifier* CombinedItemModifierFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<ItemModifier> modifiers;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("modifiers")->asArray())
+    {
+        modifiers.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(value));
+    }
+    return new CombinedItemModifier(modifiers);
+}
+
+Framework::JSON::JSONObject* CombinedItemModifierFactory::toJson(
+    CombinedItemModifier* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* modifiers = new Framework::JSON::JSONArray();
+    for (ItemModifier* modifier : zObject->getModifiers())
+    {
+        modifiers->addValue(Game::INSTANCE->zTypeRegistry()->toJson(modifier));
+    }
+    result->addValue("modifiers", modifiers);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+CombinedItemModifierFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("modifiers")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemModifier>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text CombinedItemModifierFactory::getTypeToken() const
+{
+    return "combined";
+}

+ 82 - 5
FactoryCraft/ItemModifier.h

@@ -12,15 +12,77 @@ public:
     virtual void applyOn(Item* zItem) = 0;
 };
 
+class ConsumeItemModifier : public ItemModifier
+{
+public:
+    ConsumeItemModifier();
+    void applyOn(Item* zItem) override;
+};
+
+class ConsumeItemModifierFactory
+    : public SubTypeFactory<ItemModifier, ConsumeItemModifier>
+{
+public:
+    ConsumeItemModifierFactory();
+    ConsumeItemModifier* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        ConsumeItemModifier* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
+};
+
+class DoNothingModifier : public ItemModifier
+{
+public:
+    DoNothingModifier();
+    void applyOn(Item* zItem) override;
+};
+
+class DoNothingModifierFactory
+    : public SubTypeFactory<ItemModifier, DoNothingModifier>
+{
+public:
+    DoNothingModifierFactory();
+    DoNothingModifier* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        DoNothingModifier* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
+};
+
 class AttributeItemModifier : public ItemModifier
 {
 private:
-    Framework::Text attribute;
-    Framework::Text value;
+    Framework::RCArray<Framework::Text> attributes;
+    Framework::RCArray<Framework::JSON::JSONValue> values;
 
 public:
-    AttributeItemModifier(Framework::Text attribute, Framework::Text value);
+    AttributeItemModifier(Framework::RCArray<Framework::Text> attribute,
+        Framework::RCArray<Framework::JSON::JSONValue> value);
     void applyOn(Item* zItem) override;
+    const Framework::RCArray<Framework::Text>& getAttributes() const;
+    const Framework::RCArray<Framework::JSON::JSONValue>& getValues() const;
+};
+
+class AttributeItemModifierFactory
+    : public SubTypeFactory<ItemModifier, AttributeItemModifier>
+{
+public:
+    AttributeItemModifierFactory();
+    AttributeItemModifier* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        AttributeItemModifier* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };
 
 class CombinedItemModifier : public ItemModifier
@@ -28,7 +90,22 @@ class CombinedItemModifier : public ItemModifier
     Framework::RCArray<ItemModifier> modifiers;
 
 public:
-    CombinedItemModifier();
-    void addModifier(ItemModifier* modifier);
+    CombinedItemModifier(Framework::RCArray<ItemModifier> modifiers);
     void applyOn(Item* zItem) override;
+    const Framework::RCArray<ItemModifier>& getModifiers() const;
+};
+
+class CombinedItemModifierFactory
+    : public SubTypeFactory<ItemModifier, CombinedItemModifier>
+{
+public:
+    CombinedItemModifierFactory();
+    CombinedItemModifier* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        CombinedItemModifier* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 21 - 2
FactoryCraft/ItemType.cpp

@@ -7,11 +7,15 @@
 #include "ItemSkill.h"
 #include "ItemStack.h"
 
-ItemType::ItemType(Framework::Text name, ModelInfo* model, int maxStackSize)
+ItemType::ItemType(Framework::Text name,
+    ModelInfo* model,
+    int maxStackSize,
+    Framework::RCArray<Framework::Text> groups)
     : ReferenceCounter(),
       name(name),
       model(model),
-      maxStackSize(maxStackSize)
+      maxStackSize(maxStackSize),
+      groups(groups)
 {
     tooltipUIML = Framework::Text("<tip><text width=\"auto\" height=\"auto\">")
                 + name + "</text></tip>";
@@ -131,6 +135,7 @@ ModelInfo* ItemType::zModel() const
 void ItemType::setItemAttribute(
     Item* zItem, Framework::Text name, Framework::JSON::JSONValue* zValue) const
 {
+    bool ok = true;
     if (zValue->getType() == Framework::JSON::JSONType::NUMBER)
     {
         if (name.istGleich("hp"))
@@ -141,11 +146,20 @@ void ItemType::setItemAttribute(
             zItem->durability = (float)zValue->asNumber()->getNumber();
         else if (name.istGleich("maxDurability"))
             zItem->maxDurability = (float)zValue->asNumber()->getNumber();
+        else
+            ok = false;
     }
     else if (zValue->getType() == Framework::JSON::JSONType::STRING)
     {
         if (name.istGleich("name"))
             zItem->name = zValue->asString()->getString();
+        else
+            ok = false;
+    }
+    if (!ok)
+    {
+        std::cout << "Invalid Item Attribute '" << name << "' for item type '"
+                  << getName() << "'\n";
     }
 }
 
@@ -173,6 +187,11 @@ int ItemType::getMaxStackSize() const
     return maxStackSize;
 }
 
+const Framework::RCArray<Framework::Text>& ItemType::getGroups() const
+{
+    return groups;
+}
+
 Item* ItemType::createBasicItem(int id,
     const char* name,
     float hp,

+ 5 - 1
FactoryCraft/ItemType.h

@@ -28,9 +28,12 @@ protected:
     Framework::Text tooltipUIML;
     ModelInfo *model;
     int maxStackSize;
+    Framework::RCArray<Framework::Text> groups;
 
     ItemType(Framework::Text name,
-        ModelInfo *model, int maxStackSize);
+        ModelInfo* model,
+        int maxStackSize,
+        Framework::RCArray<Framework::Text> groups);
 
     virtual void loadSuperItem(
         Item* zItem, Framework::StreamReader* zReader) const;
@@ -62,6 +65,7 @@ public:
         Item* zItem, Framework::JSON::JSONObject* zItemObjet) const;
     void setTypeId(int id);
     int getMaxStackSize() const;
+    const Framework::RCArray<Framework::Text>& getGroups() const;
 
     static Item* createBasicItem(int id,
         const char* name,

+ 2 - 2
FactoryCraft/JsonUtils.cpp

@@ -3,7 +3,7 @@
 #include <Datei.h>
 
 void loadAllJsonsFromDirectory(Framework::Text path,
-    std::function<void(Framework::JSON::JSONValue* zValue)> action)
+    std::function<void(Framework::JSON::JSONValue* zValue, Framework::Text path)> action)
 {
     if (path.hatAt(path.getLength() - 1, "/")
         || path.hatAt(path.getLength() - 1, "\\"))
@@ -27,7 +27,7 @@ void loadAllJsonsFromDirectory(Framework::Text path,
             = Framework::JSON::loadJSONFromFile(path);
         if (value)
         {
-            action(value);
+            action(value, path);
             value->release();
         }
 	}

+ 3 - 1
FactoryCraft/JsonUtils.h

@@ -2,4 +2,6 @@
 
 #include <JSON.h>
 
-extern void loadAllJsonsFromDirectory(Framework::Text directory, std::function<void(Framework::JSON::JSONValue *zValue)> action);
+extern void loadAllJsonsFromDirectory(Framework::Text directory,
+    std::function<void(
+        Framework::JSON::JSONValue* zValue, Framework::Text path)> action);

+ 17 - 5
FactoryCraft/LightSources.cpp

@@ -2,7 +2,8 @@
 
 #include "Game.h"
 
-LightSourceItem::LightSourceItem(int itemType, int blockType, Framework::Text name)
+LightSourceItem::LightSourceItem(
+    int itemType, int blockType, Framework::Text name)
     : BasicBlockItem(itemType, blockType, name, 0),
       color(0XFFFFFFFF)
 {}
@@ -16,9 +17,18 @@ bool LightSourceItem::canBeStackedWith(const Item* zItem) const
 LightSourceItemType::LightSourceItemType(Framework::Text name,
     ModelInfo* model,
     Framework::Text blockTypeName,
-    int maxStackSize)
-    : BasicBlockItemType(
-        name, model, true, true, 0.f, 1.f, blockTypeName, 0, maxStackSize)
+    int maxStackSize,
+    Framework::RCArray<Framework::Text> groups)
+    : BasicBlockItemType(name,
+        model,
+        true,
+        true,
+        0.f,
+        1.f,
+        blockTypeName,
+        0,
+        maxStackSize,
+        groups)
 {}
 
 void LightSourceItemType::loadSuperItem(
@@ -168,7 +178,9 @@ ItemType* BasicLightSourceBlockType::createItemType() const
                     zModel()->getTexturePaths(),
                     zModel()->isTransparent(),
                     zModel()->getSize() / 2.f),
-                getName(), 50))
+                getName(),
+                50,
+                getGroupNames()))
         ->setColor(0x00F69A54);
 }
 

+ 2 - 1
FactoryCraft/LightSources.h

@@ -29,7 +29,8 @@ public:
     LightSourceItemType(Framework::Text name,
         ModelInfo* model,
         Framework::Text blockTypeName,
-        int maxStackSize);
+        int maxStackSize,
+        Framework::RCArray<Framework::Text> groups);
 
 protected:
     virtual void loadSuperItem(

+ 1 - 1
FactoryCraft/PlayerHand.cpp

@@ -4,7 +4,7 @@
 #include "Entity.h"
 
 PlayerHandItemType::PlayerHandItemType()
-    : ItemType("PlayerHand", 0, 0)
+    : ItemType("PlayerHand", 0, 0, Framework::RCArray<Framework::Text>())
 {}
 
 Item* PlayerHandItemType::createItem() const

+ 501 - 90
FactoryCraft/Recipie.cpp

@@ -1,42 +1,224 @@
 #include "Recipie.h"
 
 #include "CraftingStorage.h"
+#include "Game.h"
 #include "Item.h"
 
-Recipie::Recipie()
-    : ReferenceCounter()
+RecipieInput::RecipieInput(
+    ItemFilter* filter, ItemModifier* modifier, int amount)
+    : ReferenceCounter(),
+      filter(filter),
+      modifier(modifier),
+      amount(amount)
+{}
+
+RecipieInput::~RecipieInput()
+{
+    if (filter) filter->release();
+    if (modifier) modifier->release();
+}
+
+ItemFilter* RecipieInput::zFilter() const
+{
+    return filter;
+}
+
+ItemModifier* RecipieInput::zModifier() const
+{
+    return modifier;
+}
+
+int RecipieInput::getAmount() const
+{
+    return amount;
+}
+
+RecipieInputFactory::RecipieInputFactory()
+    : TypeFactory()
+{}
+
+RecipieInput* RecipieInputFactory::fromJson(
+    Framework::JSON::JSONValue* zJson) const
+{
+    return new RecipieInput(
+        Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
+            zJson->asObject()->zValue("filter")),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
+            zJson->asObject()->zValue("modifier")),
+        (int)zJson->asObject()->zValue("amount")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONValue* RecipieInputFactory::toJson(
+    RecipieInput* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
+    result->addValue("modifier",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModifier()));
+    result->addValue("amount",
+        new Framework::JSON::JSONNumber((double)zObject->getAmount()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+RecipieInputFactory::getValidator() const
+{
+    Framework::JSON::JSONObject* defaultModifier
+        = new Framework::JSON::JSONObject();
+    defaultModifier->addValue(
+        "type", new Framework::JSON::JSONString("consume"));
+    return Framework::JSON::Validator::JSONValidator::buildForObject()
+        ->withRequiredAttribute("filter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemFilter>())
+        ->withRequiredAttribute("modifier",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemModifier>())
+        ->withRequiredObject("modifier")
+        ->withRequiredString("type")
+        ->withExactMatch("consume")
+        ->finishString()
+        ->withDefault(defaultModifier)
+        ->finishObject()
+        ->withRequiredNumber("amount")
+        ->whichIsGreaterOrEqual(1.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->finishObject();
+}
+
+RecipieOutput::RecipieOutput(int itemTypeId, int amount, ItemModifier* modifier)
+    : ReferenceCounter(),
+      itemTypeId(itemTypeId),
+      amount(amount),
+      modifier(modifier)
+{}
+
+RecipieOutput::~RecipieOutput()
+{
+    modifier->release();
+}
+
+int RecipieOutput::getItemTypeId() const
+{
+    return itemTypeId;
+}
+
+int RecipieOutput::getAmount() const
+{
+    return amount;
+}
+
+ItemModifier* RecipieOutput::zModifier() const
+{
+    return modifier;
+}
+
+Item* RecipieOutput::createItem() const
+{
+    Item* result = Game::INSTANCE->zItemType(itemTypeId)->createItem();
+    if (result)
+    {
+        modifier->applyOn(result);
+    }
+    return result;
+}
+
+RecipieOutputFactory::RecipieOutputFactory()
+    : TypeFactory()
 {}
 
-void Recipie::addOutput(Item* item, int amount)
+RecipieOutput* RecipieOutputFactory::fromJson(
+    Framework::JSON::JSONValue* zJson) const
 {
-    outputs.add(item);
-    outputAmount.add(amount);
+    return new RecipieOutput(
+        Game::INSTANCE->getItemTypeId(
+            zJson->asObject()->zValue("itemType")->asString()->getString()),
+        (int)zJson->asObject()->zValue("amount")->asNumber()->getNumber(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
+            zJson->asObject()->zValue("modifier")));
+}
+
+Framework::JSON::JSONValue* RecipieOutputFactory::toJson(
+    RecipieOutput* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
+        new Framework::JSON::JSONString(
+            Game::INSTANCE->zItemType(zObject->getItemTypeId())->getName()));
+    result->addValue("amount",
+        new Framework::JSON::JSONNumber((double)zObject->getAmount()));
+    result->addValue("modifier",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModifier()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+RecipieOutputFactory::getValidator() const
+{
+    Framework::JSON::JSONObject* defaultModifier
+        = new Framework::JSON::JSONObject();
+    defaultModifier->addValue(
+        "type", new Framework::JSON::JSONString("doNothing"));
+    Framework::RCArray<Framework::Text> itemTypes;
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
+    {
+        if (Game::INSTANCE->zItemType(i))
+        {
+            itemTypes.add(
+                new Framework::Text(Game::INSTANCE->zItemType(i)->getName()));
+        }
+    }
+    return Framework::JSON::Validator::JSONValidator::buildForObject()
+        ->withRequiredString("itemType")
+        ->whichIsOneOf(itemTypes)
+        ->finishString()
+        ->withRequiredAttribute("modifier",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemModifier>())
+        ->withRequiredObject("modifier")
+        ->withRequiredString("type")
+        ->withExactMatch("doNothing")
+        ->finishString()
+        ->withDefault(defaultModifier)
+        ->finishObject()
+        ->withRequiredNumber("amount")
+        ->whichIsGreaterOrEqual(1.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->finishObject();
 }
 
-Framework::Array<ItemInfo> Recipie::getOutput(CraftingStorage* zStorage) const
+Recipie::Recipie(
+    Framework::RCArray<RecipieOutput> outputs, Framework::Text groupName)
+    : ReferenceCounter(),
+      groupName(groupName),
+      outputs(outputs)
+{}
+
+Framework::Array<ItemInfo> Recipie::getOutput() const
 {
     Framework::Array<ItemInfo> result;
-    int index = 0;
-    for (const Item* output : outputs)
-    {
-        ItemInfo info;
-        info.count = outputAmount.get(index);
-        info.type = output->zItemType()->getId();
-        info.hp = output->getHp();
-        info.durability = output->getDurability();
-        info.maxHp = output->getMaxHp();
-        info.maxDurability = output->getMaxDurability();
-        result.add(info);
-        index++;
+    for (const RecipieOutput* output : outputs)
+    {
+        Item* item = output->createItem();
+        if (item)
+        {
+            result.add({item->zItemType()->getId(),
+                output->getAmount(),
+                item->getHp(),
+                item->getMaxHp(),
+                item->getDurability(),
+                item->getMaxDurability()});
+            item->release();
+        }
     }
     return result;
 }
 
-bool Recipie::createsOutput(const ItemType* zType)
+bool Recipie::createsOutput(int itemTypeId)
 {
-    for (const Item* output : outputs)
+    for (RecipieOutput* output : outputs)
     {
-        if (output->zItemType() == zType)
+        if (output->getItemTypeId() == itemTypeId)
         {
             return 1;
         }
@@ -44,91 +226,178 @@ bool Recipie::createsOutput(const ItemType* zType)
     return 0;
 }
 
-UnshapedRecipie::UnshapedRecipie()
-    : Recipie()
-{}
+const Framework::RCArray<RecipieOutput>& Recipie::getOutputs() const
+{
+    return outputs;
+}
 
-void UnshapedRecipie::addIngredient(
-    ItemFilter* filter, int amount, ItemModifier* modifier)
+Framework::Text Recipie::getGroupName() const
 {
-    filters.add(filter);
-    modifiers.add(modifier);
-    inputAmount.add(amount);
+    return groupName;
 }
 
+UnshapedRecipie::UnshapedRecipie(Framework::RCArray<RecipieInput> inputs,
+    Framework::RCArray<RecipieOutput> outputs,
+    Framework::Text groupName)
+    : Recipie(outputs, groupName),
+      inputs(inputs)
+{}
+
 bool UnshapedRecipie::testApplicability(CraftingStorage* zStorage)
 {
-    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    for (RecipieOutput* output : outputs)
     {
-        if (!zStorage->hasFreeSpace(outputs.z(i), outputAmount.get(i)))
-            return 0;
+        Item* item = output->createItem();
+        if (item)
+        {
+            if (!zStorage->hasFreeSpace(item, output->getAmount()))
+            {
+                item->release();
+                return 0;
+            }
+            item->release();
+        }
     }
-    return zStorage->isAllAvailable(filters, inputAmount);
+    return zStorage->isAllAvailable(inputs);
 }
 
 void UnshapedRecipie::apply(CraftingStorage* zStorage)
 {
-    zStorage->consume(filters, modifiers, inputAmount);
-    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    zStorage->consume(inputs);
+    for (RecipieOutput* output : outputs)
     {
-        ItemStack* stack
-            = new ItemStack(outputs.z(i)->zItemType()->cloneItem(outputs.z(i)),
-                outputAmount.get(i));
-        zStorage->addCraftingResult(stack);
-        stack->release();
+        Item* item = output->createItem();
+        if (item)
+        {
+            ItemStack* stack = new ItemStack(item, output->getAmount());
+            zStorage->addCraftingResult(stack);
+            stack->release();
+        }
     }
 }
 
 Framework::Text UnshapedRecipie::getRecipieUIML()
 {
     Framework::Text result = "<recipie type=\"unshaped\"><ingredients>";
-    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    for (RecipieInput* input : inputs)
     {
-        result.append() << "<ingredient amount=\"" << inputAmount.get(i)
+        result.append() << "<ingredient amount=\"" << input->getAmount()
                         << "\">";
-        if (filters.z(i))
+        if (input->zFilter())
         {
             result.append()
-                << "<logic>" << filters.z(i)->getLogicUIML() << "</logic>";
+                << "<logic>" << input->zFilter()->getLogicUIML() << "</logic>";
         }
         result += "</ingredient>";
         // TODO: add modifiers
     }
     result += "</ingredients><outputs>";
-    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    for (RecipieOutput* output : outputs)
     {
-        result.append() << "<output amount=\"" << outputAmount.get(i)
-                        << "\" itemType=\""
-                        << outputs.z(i)->zItemType()->getId() << "\" hp=\""
-                        << outputs.z(i)->getHp() << "\" durability=\""
-                        << outputs.z(i)->getDurability() << "\" maxHp=\""
-                        << outputs.z(i)->getMaxHp() << "\" maxDurability=\""
-                        << outputs.z(i)->getMaxDurability() << "\">"
-                        << outputs.z(i)->getTooltipUIML() << "</output>";
+        Item* item = output->createItem();
+        if (item)
+        {
+            result.append()
+                << "<output amount=\"" << output->getAmount()
+                << "\" itemType=\"" << item->zItemType()->getId() << "\" hp=\""
+                << item->getHp() << "\" durability=\"" << item->getDurability()
+                << "\" maxHp=\"" << item->getMaxHp() << "\" maxDurability=\""
+                << item->getMaxDurability() << "\">" << item->getTooltipUIML()
+                << "</output>";
+            item->release();
+        }
     }
     result += "</outputs></recipie>";
     return result;
 }
 
-ShapedRecipie::ShapedRecipie(int width, int height)
-    : ReferenceCounter(),
-      width(width),
-      height(height)
+const Framework::RCArray<RecipieInput>& UnshapedRecipie::getInputs() const
 {
-    for (int i = 0; i < width * height; i++)
+    return inputs;
+}
+
+UnshapedRecipieFactory::UnshapedRecipieFactory()
+    : SubTypeFactory()
+{}
+
+UnshapedRecipie* UnshapedRecipieFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<RecipieInput> inputs;
+    Framework::RCArray<RecipieOutput> outputs;
+    for (Framework::JSON::JSONValue* input :
+        *zJson->zValue("inputs")->asArray())
+    {
+        inputs.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<RecipieInput>(input));
+    }
+    for (Framework::JSON::JSONValue* output :
+        *zJson->zValue("outputs")->asArray())
+    {
+        outputs.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<RecipieOutput>(output));
+    }
+    return new UnshapedRecipie(
+        inputs, outputs, zJson->zValue("group")->asString()->getString());
+}
+
+Framework::JSON::JSONObject* UnshapedRecipieFactory::toJson(
+    UnshapedRecipie* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* inputs = new Framework::JSON::JSONArray();
+    for (RecipieInput* input : zObject->getInputs())
+    {
+        inputs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(input));
+    }
+    result->addValue("inputs", inputs);
+    Framework::JSON::JSONArray* outputs = new Framework::JSON::JSONArray();
+    for (RecipieOutput* output : zObject->getOutputs())
     {
-        filters.add(0);
-        inputAmount.add(0);
-        modifiers.add(0);
+        inputs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(output));
     }
+    result->addValue("outputs", outputs);
+    result->addValue(
+        "group", new Framework::JSON::JSONString(zObject->getGroupName()));
+    return nullptr;
 }
 
-void ShapedRecipie::setIngredient(
-    int x, int y, ItemFilter* filter, ItemModifier* modifier)
+Framework::JSON::Validator::JSONValidator* UnshapedRecipieFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
 {
-    filters.set(filter, width * y + x);
-    inputAmount.set(1, width * y + x); // TODO: make this configurable
-    modifiers.set(modifier, width * y + x);
+    return builder->withRequiredArray("inputs")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<RecipieInput>())
+        ->finishArray()
+        ->withRequiredArray("outputs")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<RecipieOutput>())
+        ->finishArray()
+        ->withRequiredString("group")
+        ->finishString()
+        ->finishObject();
+}
+
+Framework::Text UnshapedRecipieFactory::getTypeToken() const
+{
+    return "unshaped";
+}
+
+ShapedRecipie::ShapedRecipie(int width,
+    int height,
+    Framework::RCArray<RecipieInput> inputs,
+    Framework::RCArray<RecipieOutput> outputs,
+    Framework::Text groupName)
+    : Recipie(outputs, groupName),
+      inputs(inputs),
+      width(width),
+      height(height)
+{
+    while (this->inputs.getEintragAnzahl() < width * height)
+    {
+        this->inputs.add(new RecipieInput(0, 0, 0));
+    }
 }
 
 bool ShapedRecipie::testApplicability(CraftingStorage* zStorage)
@@ -136,26 +405,36 @@ bool ShapedRecipie::testApplicability(CraftingStorage* zStorage)
     ShapedCraftingStorage* zShapedStorage
         = dynamic_cast<ShapedCraftingStorage*>(zStorage);
     if (!zShapedStorage) return 0;
-    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    for (RecipieOutput* output : outputs)
     {
-        if (!zShapedStorage->hasFreeSpace(outputs.z(i), outputAmount.get(i)))
-            return 0;
+        Item* item = output->createItem();
+        if (item)
+        {
+            if (!zShapedStorage->hasFreeSpace(item, output->getAmount()))
+            {
+                item->release();
+                return 0;
+            }
+            item->release();
+        }
     }
-    return zShapedStorage->isAllAvailable(filters, inputAmount, width, height);
+    return zShapedStorage->isAllAvailable(inputs, width, height);
 }
 
 void ShapedRecipie::apply(CraftingStorage* zStorage)
 {
     ShapedCraftingStorage* zShapedStorage
         = dynamic_cast<ShapedCraftingStorage*>(zStorage);
-    zShapedStorage->consume(filters, modifiers, inputAmount, width, height);
-    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    zShapedStorage->consume(inputs, width, height);
+    for (RecipieOutput* output : outputs)
     {
-        ItemStack* stack
-            = new ItemStack(outputs.z(i)->zItemType()->cloneItem(outputs.z(i)),
-                outputAmount.get(i));
-        zStorage->addCraftingResult(stack);
-        stack->release();
+        Item* item = output->createItem();
+        if (item)
+        {
+            ItemStack* stack = new ItemStack(item, output->getAmount());
+            zStorage->addCraftingResult(stack);
+            stack->release();
+        }
     }
 }
 
@@ -163,30 +442,162 @@ Framework::Text ShapedRecipie::getRecipieUIML()
 {
     Framework::Text result = "<recipie type=\"shaped\" width=\"";
     result.append() << width << "\" height=\"" << height << "\"><ingredients>";
-    for (int i = 0; i < filters.getEintragAnzahl(); i++)
+    for (RecipieInput* input : inputs)
     {
-        result.append() << "<ingredient amount=\"" << inputAmount.get(i)
+        result.append() << "<ingredient amount=\"" << input->getAmount()
                         << "\">";
-        if (filters.z(i))
+        if (input->zFilter())
         {
             result.append()
-                << "<logic>" << filters.z(i)->getLogicUIML() << "</logic>";
+                << "<logic>" << input->zFilter()->getLogicUIML() << "</logic>";
         }
         result += "</ingredient>";
         // TODO: add modifiers
     }
     result += "</ingredients><outputs>";
-    for (int i = 0; i < outputs.getEintragAnzahl(); i++)
+    for (RecipieOutput* output : outputs)
     {
-        result.append() << "<output amount=\"" << outputAmount.get(i)
-                        << "\" itemType=\""
-                        << outputs.z(i)->zItemType()->getId() << "\" hp=\""
-                        << outputs.z(i)->getHp() << "\" durability=\""
-                        << outputs.z(i)->getDurability() << "\" maxHp=\""
-                        << outputs.z(i)->getMaxHp() << "\" maxDurability=\""
-                        << outputs.z(i)->getMaxDurability() << "\">"
-                        << outputs.z(i)->getTooltipUIML() << "</output>";
+        Item* item = output->createItem();
+        if (item)
+        {
+            result.append()
+                << "<output amount=\"" << output->getAmount()
+                << "\" itemType=\"" << item->zItemType()->getId() << "\" hp=\""
+                << item->getHp() << "\" durability=\"" << item->getDurability()
+                << "\" maxHp=\"" << item->getMaxHp() << "\" maxDurability=\""
+                << item->getMaxDurability() << "\">" << item->getTooltipUIML()
+                << "</output>";
+            item->release();
+        }
     }
     result += "</outputs></recipie>";
     return result;
+}
+
+int ShapedRecipie::getWidth() const
+{
+    return width;
+}
+
+int ShapedRecipie::getHeight() const
+{
+    return height;
+}
+
+const Framework::RCArray<RecipieInput>& ShapedRecipie::getInputs() const
+{
+    return inputs;
+}
+
+ShapedRecipieFactory::ShapedRecipieFactory()
+    : SubTypeFactory()
+{}
+
+ShapedRecipie* ShapedRecipieFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    int width = (int)zJson->zValue("width")->asNumber()->getNumber();
+    int height = (int)zJson->zValue("height")->asNumber()->getNumber();
+    Framework::RCArray<RecipieInput> inputs;
+    for (int i = 0; i < width * height; i++)
+    {
+        inputs.add(new RecipieInput(0, 0, 0));
+    }
+    for (Framework::JSON::JSONValue* input :
+        *zJson->zValue("inputs")->asArray())
+    {
+        int x = (int)input->asObject()->zValue("x")->asNumber()->getNumber();
+        int y = (int)input->asObject()->zValue("y")->asNumber()->getNumber();
+        if (x >= width || y >= height)
+        {
+            std::cout << "Invalid input position in shaped recipie with width="
+                      << width << ", height=" << height << "\n"
+                      << (x >= width ? x : y) << "\n";
+            return 0;
+        }
+        inputs.set(Game::INSTANCE->zTypeRegistry()->fromJson<RecipieInput>(
+                       input->asObject()->zValue("input")),
+            y * width + x);
+    }
+    Framework::RCArray<RecipieOutput> outputs;
+    for (Framework::JSON::JSONValue* output :
+        *zJson->zValue("outputs")->asArray())
+    {
+        outputs.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<RecipieOutput>(output));
+    }
+    return new ShapedRecipie(
+        (int)zJson->zValue("width")->asNumber()->getNumber(),
+        (int)zJson->zValue("height")->asNumber()->getNumber(),
+        inputs,
+        outputs,
+        zJson->zValue("group")->asString()->getString());
+}
+
+Framework::JSON::JSONObject* ShapedRecipieFactory::toJson(
+    ShapedRecipie* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "width", new Framework::JSON::JSONNumber(zObject->getWidth()));
+    result->addValue(
+        "height", new Framework::JSON::JSONNumber(zObject->getHeight()));
+    Framework::JSON::JSONArray* inputs = new Framework::JSON::JSONArray();
+    for (int i = 0; i < zObject->getWidth() * zObject->getHeight(); i++)
+    {
+        Framework::JSON::JSONObject* input = new Framework::JSON::JSONObject();
+        input->addValue(
+            "x", new Framework::JSON::JSONNumber(i % zObject->getHeight()));
+        input->addValue(
+            "y", new Framework::JSON::JSONNumber(i / zObject->getHeight()));
+        input->addValue("input",
+            Game::INSTANCE->zTypeRegistry()->toJson(zObject->getInputs().z(i)));
+        inputs->addValue(input);
+    }
+    result->addValue("inputs", inputs);
+    Framework::JSON::JSONArray* outputs = new Framework::JSON::JSONArray();
+    for (RecipieOutput* output : zObject->getOutputs())
+    {
+        outputs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(output));
+    }
+    result->addValue("outputs", outputs);
+    result->addValue(
+        "group", new Framework::JSON::JSONString(zObject->getGroupName()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* ShapedRecipieFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("inputs")
+        ->addAcceptedObjectInArray()
+        ->withRequiredNumber("x")
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("y")
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredAttribute("input",
+            Game::INSTANCE->zTypeRegistry()->getValidator<RecipieInput>())
+        ->finishObject()
+        ->finishArray()
+        ->withRequiredArray("outputs")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<RecipieOutput>())
+        ->finishArray()
+        ->withRequiredNumber("width")
+        ->whichIsGreaterOrEqual(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("height")
+        ->whichIsGreaterOrEqual(1.0)
+        ->finishNumber()
+        ->withRequiredString("group")
+        ->finishString()
+        ->finishObject();
+}
+
+Framework::Text ShapedRecipieFactory::getTypeToken() const
+{
+    return "shaped";
 }

+ 99 - 18
FactoryCraft/Recipie.h

@@ -4,6 +4,7 @@
 
 #include "ItemFilter.h"
 #include "ItemModifier.h"
+#include "TypeRegistry.h"
 
 class CraftingStorage;
 class ShapedCraftingStorage;
@@ -18,52 +19,132 @@ struct ItemInfo
     float maxDurability;
 };
 
+class RecipieInput : public Framework::ReferenceCounter
+{
+private:
+    ItemFilter* filter;
+    ItemModifier* modifier;
+    int amount;
+
+public:
+    RecipieInput(ItemFilter* filter, ItemModifier* modifier, int amount);
+    ~RecipieInput();
+    ItemFilter* zFilter() const;
+    ItemModifier* zModifier() const;
+    int getAmount() const;
+};
+
+class RecipieInputFactory : public TypeFactory<RecipieInput>
+{
+public:
+    RecipieInputFactory();
+    RecipieInput* fromJson(Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(RecipieInput* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator() const override;
+};
+
+class RecipieOutput : public Framework::ReferenceCounter
+{
+private:
+    int itemTypeId;
+    int amount;
+    ItemModifier* modifier;
+
+public:
+    RecipieOutput(int itemTypeId, int amount, ItemModifier* modifier);
+    ~RecipieOutput();
+    int getItemTypeId() const;
+    int getAmount() const;
+    ItemModifier* zModifier() const;
+    Item* createItem() const;
+};
+
+class RecipieOutputFactory : public TypeFactory<RecipieOutput>
+{
+public:
+    RecipieOutputFactory();
+    RecipieOutput* fromJson(Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(RecipieOutput* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator() const override;
+};
+
 class Recipie : public virtual Framework::ReferenceCounter
 {
 protected:
-    Framework::RCArray<Item> outputs;
-    Framework::Array<int> outputAmount;
+    Framework::Text groupName;
+    Framework::RCArray<RecipieOutput> outputs;
 
 public:
-    Recipie();
-    virtual void addOutput(Item* item, int amount);
+    Recipie(
+        Framework::RCArray<RecipieOutput> outputs, Framework::Text groupName);
     virtual bool testApplicability(CraftingStorage* zStorage) = 0;
     virtual void apply(CraftingStorage* zStorage) = 0;
     virtual Framework::Text getRecipieUIML() = 0;
-    virtual Framework::Array<ItemInfo> getOutput(
-        CraftingStorage* zStorage) const;
-    virtual bool createsOutput(const ItemType* zType);
+    virtual Framework::Array<ItemInfo> getOutput() const;
+    bool createsOutput(int itemTypeId);
+    const Framework::RCArray<RecipieOutput>& getOutputs() const;
+    Framework::Text getGroupName() const;
 };
 
 class UnshapedRecipie : public Recipie
 {
 private:
-    Framework::RCArray<ItemFilter> filters;
-    Framework::RCArray<ItemModifier> modifiers;
-    Framework::Array<int> inputAmount;
+    Framework::RCArray<RecipieInput> inputs;
 
 public:
-    UnshapedRecipie();
-    void addIngredient(ItemFilter* filter, int amount, ItemModifier* modifier);
+    UnshapedRecipie(Framework::RCArray<RecipieInput> inputs,
+        Framework::RCArray<RecipieOutput> outputs,
+        Framework::Text groupName);
     bool testApplicability(CraftingStorage* zStorage) override;
     void apply(CraftingStorage* zStorage) override;
     Framework::Text getRecipieUIML() override;
+    const Framework::RCArray<RecipieInput>& getInputs() const;
+};
+
+class UnshapedRecipieFactory : public SubTypeFactory<Recipie, UnshapedRecipie>
+{
+public:
+    UnshapedRecipieFactory();
+    UnshapedRecipie* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        UnshapedRecipie* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };
 
 class ShapedRecipie : public Recipie
 {
 private:
-    Framework::RCArray<ItemFilter> filters;
-    Framework::RCArray<ItemModifier> modifiers;
-    Framework::Array<int> inputAmount;
+    Framework::RCArray<RecipieInput> inputs;
     int width;
     int height;
 
 public:
-    ShapedRecipie(int width, int height);
-    void setIngredient(
-        int x, int y, ItemFilter* filter, ItemModifier* modifier);
+    ShapedRecipie(int width,
+        int height,
+        Framework::RCArray<RecipieInput> inputs,
+        Framework::RCArray<RecipieOutput> outputs,
+        Framework::Text groupName);
     bool testApplicability(CraftingStorage* zStorage) override;
     void apply(CraftingStorage* zStorage) override;
     Framework::Text getRecipieUIML() override;
+    int getWidth() const;
+    int getHeight() const;
+    const Framework::RCArray<RecipieInput>& getInputs() const;
+};
+
+class ShapedRecipieFactory : public SubTypeFactory<Recipie, ShapedRecipie>
+{
+public:
+    ShapedRecipieFactory();
+    ShapedRecipie* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(ShapedRecipie* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 2 - 2
FactoryCraft/RecipieList.cpp

@@ -25,11 +25,11 @@ const Framework::Text& RecipieList::getName() const
 }
 
 void RecipieList::findRecipies(
-    const ItemType* zTargetType, Framework::RCArray<Recipie>& recipies)
+    int itemTypeId, Framework::RCArray<Recipie>& recipies)
 {
     for (Recipie* recipie : this->recipies)
     {
-        if (recipie->createsOutput(zTargetType))
+        if (recipie->createsOutput(itemTypeId))
         {
             recipies.add(dynamic_cast<Recipie*>(recipie->getThis()));
         }

+ 1 - 1
FactoryCraft/RecipieList.h

@@ -15,5 +15,5 @@ public:
     void addRecipie(Recipie* recipie);
     Recipie* zFirstRecipie(CraftingStorage* zStorage);
     const Framework::Text& getName() const;
-    void findRecipies(const ItemType *zTargetType, Framework::RCArray<Recipie>& recipies);
+    void findRecipies(int itemTypeId, Framework::RCArray<Recipie>& recipies);
 };

+ 37 - 348
FactoryCraft/RecipieLoader.cpp

@@ -6,6 +6,7 @@
 
 #include "Game.h"
 #include "ItemType.h"
+#include "JsonUtils.h"
 
 using namespace Framework::JSON;
 using namespace Validator;
@@ -22,180 +23,45 @@ RecipieLoader::~RecipieLoader()
 
 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
-    {
-        JSONValue* json = loadJSONFromFile(path);
-        JSONValidator* validator = zRecipieValidator();
-        Framework::RCArray<JSONValidationResult> invalidParts;
-        JSONValue* valid = validator->getValidParts(json, &invalidParts);
-        for (JSONValidationResult* invalidPart : invalidParts)
-        {
-            invalidPart->printInvalidInfo();
-        }
-        json->release();
-        int count = 0;
-        if (valid)
-        {
-            for (JSONValue* recipie : *valid->asArray())
-                loadRecipie(recipie->asObject());
-            count = valid->asArray()->getLength();
-            valid->release();
-        }
-        std::cout << count << " recipies were loaded.\n";
-    }
-}
-
-void RecipieLoader::loadRecipie(JSONObject* zRecipie)
-{
-    Framework::Text group = zRecipie->zValue("group")->asString()->getString();
-    if (zRecipie->zValue("type")->asString()->getString().istGleich("shaped"))
-    {
-        int width = (int)zRecipie->zValue("width")->asNumber()->getNumber();
-        int height = (int)zRecipie->zValue("height")->asNumber()->getNumber();
-        ShapedRecipie* recipie = new ShapedRecipie(width, height);
-        for (JSONValue* input : *zRecipie->zValue("inputs")->asArray())
-        {
-            int x
-                = (int)input->asObject()->zValue("x")->asNumber()->getNumber();
-            int y
-                = (int)input->asObject()->zValue("y")->asNumber()->getNumber();
-            ItemFilter* filter
-                = loadFilter(input->asObject()->zValue("filter")->asObject());
-            CombinedItemModifier* resultingModifier
-                = new CombinedItemModifier();
-            for (JSONValue* modifier :
-                *input->asObject()->zValue("modifiers")->asArray())
-                resultingModifier->addModifier(
-                    loadModifier(modifier->asObject()));
-            recipie->setIngredient(x, y, filter, resultingModifier);
-        }
-        int outputCount = (int)zRecipie->asObject()
-                              ->zValue("outputCount")
-                              ->asNumber()
-                              ->getNumber();
-        Framework::Text outputType = zRecipie->asObject()
-                                         ->zValue("output")
-                                         ->asObject()
-                                         ->zValue("itemType")
-                                         ->asString()
-                                         ->getString();
-        Item* item = 0;
-        for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-        {
-            if (Game::INSTANCE->zItemType(i)
-                && Game::INSTANCE->zItemType(i)->getName().istGleich(
-                    outputType))
+    loadAllJsonsFromDirectory(
+        path, [this](JSONValue* zJson, Framework::Text path) {
+            std::cout << "loading recipies from '" << path << "'" << std::endl;
+            JSONValidator* validator
+                = Framework::JSON::Validator::JSONValidator::buildForArray()
+                      ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                                                   ->getValidator<Recipie>())
+                      ->removeInvalidEntries()
+                      ->finishArray();
+            Framework::RCArray<JSONValidationResult> invalidParts;
+            JSONValue* valid = validator->getValidParts(zJson, &invalidParts);
+            for (JSONValidationResult* invalidPart : invalidParts)
             {
-                item = Game::INSTANCE->zItemType(i)->createItem();
-                break;
+                invalidPart->printInvalidInfo();
             }
-        }
-        recipie->addOutput(item, outputCount);
-        if (!zRecipieList(group)) registerRecipieList(group);
-        zRecipieList(group)->addRecipie(recipie);
-    }
-    else if (zRecipie->zValue("type")->asString()->getString().istGleich(
-                 "unordered"))
-    {
-        UnshapedRecipie* recipie = new UnshapedRecipie();
-        for (JSONValue* input : *zRecipie->zValue("inputs")->asArray())
-        {
-            int count = (int)input->asObject()
-                            ->zValue("count")
-                            ->asNumber()
-                            ->getNumber();
-            ItemFilter* filter
-                = loadFilter(input->asObject()->zValue("filter")->asObject());
-            CombinedItemModifier* resultingModifier
-                = new CombinedItemModifier();
-            for (JSONValue* modifier :
-                *input->asObject()->zValue("modifiers")->asArray())
-                resultingModifier->addModifier(
-                    loadModifier(modifier->asObject()));
-            recipie->addIngredient(filter, count, resultingModifier);
-        }
-        for (JSONValue* output : *zRecipie->zValue("outputs")->asArray())
-        {
-            int count = (int)output->asObject()
-                            ->zValue("count")
-                            ->asNumber()
-                            ->getNumber();
-            Framework::Text outputType = output->asObject()
-                                             ->zValue("item")
-                                             ->asObject()
-                                             ->zValue("itemType")
-                                             ->asString()
-                                             ->getString();
-            Item* item = 0;
-            for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
+            int count = 0;
+            if (valid)
             {
-                if (Game::INSTANCE->zItemType(i)
-                    && Game::INSTANCE->zItemType(i)->getName().istGleich(
-                        outputType))
+                for (JSONValue* value : *valid->asArray())
                 {
-                    item = Game::INSTANCE->zItemType(i)->createItem();
-                    break;
+                    Recipie* recipie
+                        = Game::INSTANCE->zTypeRegistry()->fromJson<Recipie>(
+                            value);
+                    if (recipie)
+                    {
+                        Framework::Text group = recipie->getGroupName();
+                        RecipieList* list = zRecipieList(group);
+                        if (!list)
+                        {
+                            registerRecipieList(group);
+                            list = zRecipieList(group);
+                        }
+                        list->addRecipie(recipie);
+                        count++;
+                    }
                 }
             }
-            recipie->addOutput(item, count);
-        }
-        if (!zRecipieList(group)) registerRecipieList(group);
-        zRecipieList(group)->addRecipie(recipie);
-    }
-}
-
-ItemFilter* RecipieLoader::loadFilter(JSONObject* zFilter)
-{
-    if (zFilter->hasValue("itemType"))
-    {
-        Framework::Text type
-            = zFilter->zValue("itemType")->asString()->getString();
-        return new TypeItemFilter(
-            Game::INSTANCE->zItemType(ItemType::getTypeId(type)));
-    }
-    else if (zFilter->hasValue("operator"))
-    {
-        Framework::Text op
-            = zFilter->zValue("operator")->asString()->getString();
-        ItemFilter* left = loadFilter(zFilter->zValue("left")->asObject());
-        ItemFilter* right = loadFilter(zFilter->zValue("right")->asObject());
-        if (op.istGleich("&&"))
-        {
-            return new CombinedItemFilter(
-                left, right, [](bool a, bool b) { return a && b; });
-        }
-        else if (op.istGleich("||"))
-        {
-            return new CombinedItemFilter(
-                left, right, [](bool a, bool b) { return a || b; });
-        }
-        else if (op.istGleich("=="))
-        {
-            return new CombinedItemFilter(
-                left, right, [](bool a, bool b) { return a == b; });
-        }
-        else if (op.istGleich("!="))
-        {
-            return new CombinedItemFilter(
-                left, right, [](bool a, bool b) { return a != b; });
-        }
-        else
-        {
-            left->release();
-            right->release();
-        }
-    }
-    return 0;
+            std::cout << count << " recipies were loaded.\n";
+        });
 }
 
 RecipieList* RecipieLoader::zRecipieList(const char* name) const
@@ -214,14 +80,14 @@ void RecipieLoader::registerRecipieList(const char* name)
     lists.add(new RecipieList(name));
 }
 
-Framework::Text RecipieLoader::getCrafingUIML(const ItemType* zTargetType)
+Framework::Text RecipieLoader::getCrafingUIML(int itemTypeId)
 {
     Framework::Text result = "<dialog id=\"crafting_";
-    result.append() << zTargetType->getId() << "\"><craftingRecipies>";
+    result.append() << itemTypeId << "\"><craftingRecipies>";
     for (RecipieList* list : lists)
     {
         Framework::RCArray<Recipie> recipies;
-        list->findRecipies(zTargetType, recipies);
+        list->findRecipies(itemTypeId, recipies);
         if (recipies.getEintragAnzahl() > 0)
         {
             result.append()
@@ -242,181 +108,4 @@ Framework::Text RecipieLoader::getCrafingUIML(const ItemType* zTargetType)
     }
     result += "</craftingRecipies></dialog>";
     return result;
-}
-
-ItemModifier* RecipieLoader::loadModifier(
-    Framework::JSON::JSONObject* zModifier)
-{
-    return new AttributeItemModifier(
-        zModifier->zValue("attribute")->asString()->getString(),
-        zModifier->zValue("value")->asString()->getString());
-}
-
-JSONValidator* RecipieLoader::zRecipieValidator()
-{
-    if (validator) return validator;
-    Framework::RCArray<Framework::Text> itemTypes;
-    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zItemType(i))
-        {
-            itemTypes.add(new Framework::Text(
-                Game::INSTANCE->zItemType(i)->getName().getText()));
-        }
-    }
-    JSONValidator* typeFilterValidator
-        = JSONValidator::buildForObject()
-              ->setObjectReferenceId("typeFilter")
-              ->withRequiredString("itemType")
-              ->whichIsOneOf(itemTypes)
-              ->finishString()
-              ->finishObject();
-    Framework::RCArray<Framework::Text> operators;
-    operators.add(new Framework::Text("=="));
-    operators.add(new Framework::Text("!="));
-    operators.add(new Framework::Text("&&"));
-    operators.add(new Framework::Text("||"));
-    JSONValidator* operatorFilterValidator
-        = JSONValidator::buildForObject()
-              ->setObjectReferenceId("operatorFilter")
-              ->withRequiredString("operator")
-              ->whichIsOneOf(operators)
-              ->finishString()
-              ->withRequiredAttribute(
-                  "left", JSONValidator::buildForObjectReference("typeFilter"))
-              ->withRequiredAttribute("left",
-                  JSONValidator::buildForObjectReference("operatorFilter"))
-              ->withRequiredAttribute(
-                  "right", JSONValidator::buildForObjectReference("typeFilter"))
-              ->withRequiredAttribute("right",
-                  JSONValidator::buildForObjectReference("operatorFilter"))
-              ->finishObject();
-    JSONValidator* outputValidator = JSONValidator::buildForObject()
-                                         ->withRequiredString("itemType")
-                                         ->whichIsOneOf(itemTypes)
-                                         ->finishString()
-                                         ->finishObject();
-    validator
-        = JSONValidator::buildForArray()
-              ->typeSpecifiedByAttribute("type")
-              ->removeInvalidEntries()
-              ->addAcceptedTypeInArray(
-                  JSONValidator::buildForObject()
-                      ->withRequiredString("type")
-                      ->withExactMatch("shaped")
-                      ->finishString()
-                      ->withRequiredString("group")
-                      ->finishString()
-                      ->withRequiredNumber("width")
-                      ->whichIsGreaterThen(0)
-                      ->finishNumber()
-                      ->withRequiredNumber("height")
-                      ->whichIsGreaterThen(0)
-                      ->finishNumber()
-                      ->withRequiredAttribute("inputs",
-                          JSONValidator::buildForArray()
-                              ->withDefault(new JSONArray())
-                              ->addAcceptedTypeInArray(
-                                  JSONValidator::buildForObject()
-                                      ->withRequiredNumber("x")
-                                      ->whichIsGreaterOrEqual(0)
-                                      ->finishNumber()
-                                      ->withRequiredNumber("y")
-                                      ->whichIsGreaterOrEqual(0)
-                                      ->finishNumber()
-                                      ->withRequiredAttribute("filter",
-                                          dynamic_cast<JSONValidator*>(
-                                              typeFilterValidator->getThis()))
-                                      ->withRequiredAttribute("filter",
-                                          dynamic_cast<JSONValidator*>(
-                                              operatorFilterValidator
-                                                  ->getThis()))
-                                      ->withRequiredAttribute("modifiers",
-                                          JSONValidator::buildForArray()
-                                              ->withDefault(Parser::getValue(
-                                                  "[{\"attribute\": \"hp\", "
-                                                  "\"value\": \"=0\"}]")
-                                                                ->asArray())
-                                              ->addAcceptedTypeInArray(
-                                                  JSONValidator::
-                                                      buildForObject()
-                                                          ->withRequiredString(
-                                                              "attribute")
-                                                          ->finishString()
-                                                          ->withRequiredString(
-                                                              "value")
-                                                          ->finishString()
-                                                          ->finishObject())
-                                              ->finishArray())
-                                      ->finishObject())
-                              ->finishArray())
-                      ->withRequiredAttribute("output",
-                          dynamic_cast<JSONValidator*>(
-                              outputValidator->getThis()))
-                      ->withRequiredNumber("outputCount")
-                      ->withDefault(1)
-                      ->whichIsGreaterThen(0)
-                      ->finishNumber()
-                      ->finishObject())
-              ->addAcceptedTypeInArray(
-                  JSONValidator::buildForObject()
-                      ->withRequiredString("type")
-                      ->withExactMatch("unordered")
-                      ->finishString()
-                      ->withRequiredString("group")
-                      ->finishString()
-                      ->withRequiredAttribute("inputs",
-                          JSONValidator::buildForArray()
-                              ->withDefault(new JSONArray())
-                              ->addAcceptedTypeInArray(
-                                  JSONValidator::buildForObject()
-                                      ->withRequiredNumber("count")
-                                      ->withDefault(1)
-                                      ->whichIsGreaterThen(0)
-                                      ->finishNumber()
-                                      ->withRequiredAttribute("filter",
-                                          dynamic_cast<JSONValidator*>(
-                                              typeFilterValidator->getThis()))
-                                      ->withRequiredAttribute("filter",
-                                          dynamic_cast<JSONValidator*>(
-                                              operatorFilterValidator
-                                                  ->getThis()))
-                                      ->withRequiredAttribute("modifiers",
-                                          JSONValidator::buildForArray()
-                                              ->withDefault(Parser::getValue(
-                                                  "[{\"attribute\": \"hp\", "
-                                                  "\"value\": \"=0\"}]")
-                                                                ->asArray())
-                                              ->addAcceptedTypeInArray(
-                                                  JSONValidator::
-                                                      buildForObject()
-                                                          ->withRequiredString(
-                                                              "attribute")
-                                                          ->finishString()
-                                                          ->withRequiredString(
-                                                              "value")
-                                                          ->finishString()
-                                                          ->finishObject())
-                                              ->finishArray())
-                                      ->finishObject())
-                              ->finishArray())
-                      ->withRequiredAttribute("output",
-                          JSONValidator::buildForArray()
-                              ->addAcceptedTypeInArray(
-                                  JSONValidator::buildForObject()
-                                      ->withRequiredAttribute("item",
-                                          dynamic_cast<JSONValidator*>(
-                                              outputValidator->getThis()))
-                                      ->withRequiredNumber("count")
-                                      ->withDefault(1)
-                                      ->whichIsGreaterThen(0)
-                                      ->finishNumber()
-                                      ->finishObject())
-                              ->finishArray())
-                      ->finishObject())
-              ->finishArray();
-    typeFilterValidator->release();
-    operatorFilterValidator->release();
-    outputValidator->release();
-    return validator;
 }

+ 1 - 7
FactoryCraft/RecipieLoader.h

@@ -15,11 +15,5 @@ public:
     void loadRecipies(const char* path);
     RecipieList* zRecipieList(const char* name) const;
     void registerRecipieList(const char* name);
-    Framework::Text getCrafingUIML(const ItemType* zTargetType);
-
-private:
-    void loadRecipie(Framework::JSON::JSONObject* zRecipie);
-    ItemFilter* loadFilter(Framework::JSON::JSONObject* zFilter);
-    ItemModifier* loadModifier(Framework::JSON::JSONObject* zModifier);
-    Framework::JSON::Validator::JSONValidator* zRecipieValidator();
+    Framework::Text getCrafingUIML(int itemTypeId);
 };

+ 1 - 1
FactoryCraft/TreeSeblingBlock.cpp

@@ -125,7 +125,7 @@ ItemType* TreeSeblingBlockType::createItemType() const
         getHardness(),
         speedModifier,
         getName(),
-        0, 50);
+        0, 50, getGroupNames());
 }
 
 void TreeSeblingBlockType::createSuperBlock(Block* zBlock, Item* zItem) const

+ 23 - 4
FactoryCraft/TypeRegistry.cpp

@@ -1,6 +1,8 @@
 #include "TypeRegistry.h"
 
 #include "BasicBlocks.h"
+#include "BasicItems.h"
+#include "BasicTool.h"
 #include "BlockFilter.h"
 #include "BlockInstanceGeneratorRule.h"
 #include "BlockTypeGeneratorRule.h"
@@ -8,6 +10,7 @@
 #include "Dimension.h"
 #include "DimensionGenerator.h"
 #include "FluidBlock.h"
+#include "FluidContainer.h"
 #include "GeneratorRule.h"
 #include "Grass.h"
 #include "GrowingPlant.h"
@@ -17,11 +20,9 @@
 #include "OverworldDimensionGenerator.h"
 #include "PlaceableProof.h"
 #include "Quest.h"
+#include "Recipie.h"
 #include "TreeSeblingBlock.h"
 #include "TreeTemplate.h"
-#include "BasicItems.h"
-#include "BasicTool.h"
-#include "FluidContainer.h"
 
 TypeRegistry::TypeRegistry()
     : ReferenceCounter()
@@ -43,7 +44,7 @@ TypeRegistry::TypeRegistry()
     registerType(new QuestType());
     registerType(new QuestCollectionType());
     registerSubType(new QuestRequirementOpenDialogType());
-    registerType(new ItomJsonType());
+    registerType(new ItemJsonType());
     registerType(new ItemStackInfoType());
     registerSubType(new QuestRewardGiveItemsType());
 
@@ -88,6 +89,24 @@ TypeRegistry::TypeRegistry()
     registerSubType(new BlockReplaceItemSkillFactory());
     registerType(new FluidContainerItemSkillConfigFactory());
     registerSubType(new FluidContainerItemSkillFactory());
+
+    // reipies
+    registerType(new RecipieInputFactory());
+    registerType(new RecipieOutputFactory());
+    registerSubType(new ShapedRecipieFactory());
+    registerSubType(new UnshapedRecipieFactory());
+
+    // item modifiers
+    registerSubType(new ConsumeItemModifierFactory());
+    registerSubType(new DoNothingModifierFactory());
+    registerSubType(new AttributeItemModifierFactory());
+    registerSubType(new CombinedItemModifierFactory());
+
+    // item filters
+    registerSubType(new CombinedItemFilterFactory());
+    registerSubType(new AnyItemFilterFactory());
+    registerSubType(new TypeItemFilterFactory());
+    registerSubType(new GroupItemFilterFactory());
 }
 
 void TypeRegistry::registerGeneratorRuleFactory(GeneratorRuleFactory* factory)

+ 12 - 0
Windows Version/data/blocks/blockTypes.json

@@ -97,6 +97,9 @@
         "itemType": "Oak Wood Sapling",
         "chance": 0.015
       }
+    ],
+    "groupNames": [
+      "Leaves"
     ]
   },
   {
@@ -196,6 +199,9 @@
         "itemType": "Birch Wood Sapling",
         "chance": 0.03
       }
+    ],
+    "groupNames": [
+      "Leaves"
     ]
   },
   {
@@ -241,6 +247,9 @@
         "itemType": "Beech Wood Sapling",
         "chance": 0.02
       }
+    ],
+    "groupNames": [
+      "Leaves"
     ]
   },
   {
@@ -304,6 +313,9 @@
         "itemType": "Pine Wood Sapling",
         "chance": 0.025
       }
+    ],
+    "groupNames": [
+      "Leaves"
     ]
   },
   {

+ 223 - 129
Windows Version/data/recipies/basicItems.json

@@ -4,30 +4,41 @@
     "height": 2,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 1,
         "y": 0
       }
     ],
-    "output": {
-      "itemType": "Flint"
-    },
+    "outputs": [
+      {
+        "itemType": "Flint"
+      }
+    ],
     "type": "shaped",
     "width": 2
   },
@@ -36,30 +47,41 @@
     "height": 2,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 1,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 1,
         "y": 0
       }
     ],
-    "output": {
-      "itemType": "Flint"
-    },
+    "outputs": [
+      {
+        "itemType": "Flint"
+      }
+    ],
     "type": "shaped",
     "width": 2
   },
@@ -68,30 +90,41 @@
     "height": 2,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 1,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 1,
         "y": 0
       }
     ],
-    "output": {
-      "itemType": "Flint"
-    },
+    "outputs": [
+      {
+        "itemType": "Flint"
+      }
+    ],
     "type": "shaped",
     "width": 2
   },
@@ -100,30 +133,41 @@
     "height": 2,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 1,
         "y": 1
       }
     ],
-    "output": {
-      "itemType": "Flint"
-    },
+    "outputs": [
+      {
+        "itemType": "Flint"
+      }
+    ],
     "type": "shaped",
     "width": 2
   },
@@ -132,30 +176,41 @@
     "height": 1,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 1,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 2,
         "y": 0
       }
     ],
-    "output": {
-      "itemType": "Flint"
-    },
+    "outputs": [
+      {
+        "itemType": "Flint"
+      }
+    ],
     "type": "shaped",
     "width": 3
   },
@@ -164,30 +219,41 @@
     "height": 3,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Gravel"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Gravel"
+          }
         },
         "x": 0,
         "y": 2
       }
     ],
-    "output": {
-      "itemType": "Flint"
-    },
+    "outputs": [
+      {
+        "itemType": "Flint"
+      }
+    ],
     "type": "shaped",
     "width": 1
   },
@@ -196,35 +262,31 @@
     "height": 2,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Flint"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "left": {
-            "left": {
-              "itemType": "Oak Wood"
-            },
-            "operator": "||",
-            "right": {
-              "itemType": "Birch Wood"
-            }
-          },
-          "operator": "||",
-          "right": {
-            "itemType": "Beech Wood"
+        "input": {
+          "filter": {
+            "type": "groups",
+            "groupNames": [ "Wood" ]
           }
         },
         "x": 0,
         "y": 1
       }
     ],
-    "output": {
-      "itemType": "Wooden Stick"
-    },
+    "outputs": [
+      {
+        "itemType": "Wooden Stick"
+      }
+    ],
     "type": "shaped",
     "width": 1
   },
@@ -233,23 +295,31 @@
     "height": 2,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Flint"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Pine Wood"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Pine Wood"
+          }
         },
         "x": 0,
         "y": 1
       }
     ],
-    "output": {
-      "itemType": "Resin"
-    },
+    "outputs": [
+      {
+        "itemType": "Resin"
+      }
+    ],
     "type": "shaped",
     "width": 1
   },
@@ -258,23 +328,31 @@
     "height": 2,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Resin"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Resin"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 0,
         "y": 1
       }
     ],
-    "output": {
-      "itemType": "Torch"
-    },
+    "outputs": [
+      {
+        "itemType": "Torch"
+      }
+    ],
     "type": "shaped",
     "width": 1
   },
@@ -283,34 +361,21 @@
     "height": 1,
     "inputs": [
       {
-        "filter": {
-          "left": {
-            "left": {
-              "itemType": "Beech Wood Leaves"
-            },
-            "operator": "||",
-            "right": {
-              "itemType": "Birch Wood Leaves"
-            }
-          },
-          "operator": "||",
-          "right": {
-            "left": {
-              "itemType": "Oak Wood Leaves"
-            },
-            "operator": "||",
-            "right": {
-              "itemType": "Pine Wood Leaves"
-            }
+        "input": {
+          "filter": {
+            "type": "groups",
+            "groupNames": [ "Leaves" ]
           }
         },
         "x": 0,
         "y": 0
       }
     ],
-    "output": {
-      "itemType": "Wooden Stick"
-    },
+    "outputs": [
+      {
+        "itemType": "Wooden Stick"
+      }
+    ],
     "type": "shaped",
     "width": 1
   },
@@ -319,72 +384,101 @@
     "height": 3,
     "inputs": [
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 0,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 0,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 0,
         "y": 2
       },
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 1,
         "y": 2
       },
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 2,
         "y": 2
       },
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 2,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Wooden Stick"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
         },
         "x": 2,
         "y": 0
       },
       {
-        "filter": {
-          "itemType": "Flint"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
         },
         "x": 1,
         "y": 1
       },
       {
-        "filter": {
-          "itemType": "Flint"
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
         },
         "x": 1,
         "y": 0
       }
     ],
-    "output": {
-      "itemType": "Wooden Bucket"
-    },
+    "outputs": [
+      {
+        "itemType": "Wooden Bucket"
+      }
+    ],
     "type": "shaped",
     "width": 3
   }

+ 103 - 74
Windows Version/data/recipies/blocks.json

@@ -1,76 +1,105 @@
 [
-	{
-		"type": "shaped",
-		"group": "inventory",
-		"width": 3,
-		"height": 3,
-		"inputs": [
-			{
-				"x": 1,
-				"y": 1,
-				"filter": {
-					"itemType": "Flint"
-				}
-			},
-			{
-				"x": 0,
-				"y": 0,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 0,
-				"y": 1,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 0,
-				"y": 2,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 1,
-				"y": 0,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 1,
-				"y": 2,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 2,
-				"y": 0,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 2,
-				"y": 1,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 2,
-				"y": 2,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			}
-		],
-		"output": {
-			"itemType": "Wooden Chest"
-		}
-	}
+  {
+    "type": "shaped",
+    "group": "inventory",
+    "width": 3,
+    "height": 3,
+    "inputs": [
+      {
+        "x": 1,
+        "y": 1,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
+        }
+      },
+      {
+        "x": 0,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 0,
+        "y": 1,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 0,
+        "y": 2,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 2,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 2,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 2,
+        "y": 1,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 2,
+        "y": 2,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      }
+    ],
+    "outputs": [
+      {
+        "itemType": "Wooden Chest"
+      }
+    ]
+  }
 ]

+ 159 - 117
Windows Version/data/recipies/tools.json

@@ -1,119 +1,161 @@
 [
-	{
-		"type": "shaped",
-		"group": "inventory",
-		"width": 2,
-		"height": 3,
-		"inputs": [
-			{
-				"x": 0,
-				"y": 0,
-				"filter": {
-					"itemType": "Flint"
-				}
-			},
-			{
-				"x": 1,
-				"y": 0,
-				"filter": {
-					"itemType": "Flint"
-				}
-			},
-			{
-				"x": 1,
-				"y": 1,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 1,
-				"y": 2,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			}
-		],
-		"output": {
-			"itemType": "Hoe"
-		}
-	},
-	{
-		"type": "shaped",
-		"group": "inventory",
-		"width": 2,
-		"height": 3,
-		"inputs": [
-			{
-				"x": 0,
-				"y": 0,
-				"filter": {
-					"itemType": "Flint"
-				}
-			},
-			{
-				"x": 1,
-				"y": 0,
-				"filter": {
-					"itemType": "Flint"
-				}
-			},
-			{
-				"x": 0,
-				"y": 1,
-				"filter": {
-					"itemType": "Flint"
-				}
-			},
-			{
-				"x": 1,
-				"y": 1,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 1,
-				"y": 2,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			}
-		],
-		"output": {
-			"itemType": "Axe"
-		}
-	},
-	{
-		"type": "shaped",
-		"group": "inventory",
-		"width": 1,
-		"height": 3,
-		"inputs": [
-			{
-				"x": 0,
-				"y": 0,
-				"filter": {
-					"itemType": "Flint"
-				}
-			},
-			{
-				"x": 0,
-				"y": 1,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			},
-			{
-				"x": 0,
-				"y": 2,
-				"filter": {
-					"itemType": "Wooden Stick"
-				}
-			}
-		],
-		"output": {
-			"itemType": "Shovel"
-		}
-	}
+  {
+    "type": "shaped",
+    "group": "inventory",
+    "width": 2,
+    "height": 3,
+    "inputs": [
+      {
+        "x": 0,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 1,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 2,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      }
+    ],
+    "outputs": [
+      {
+        "itemType": "Hoe"
+      }
+    ]
+  },
+  {
+    "type": "shaped",
+    "group": "inventory",
+    "width": 2,
+    "height": 3,
+    "inputs": [
+      {
+        "x": 0,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
+        }
+      },
+      {
+        "x": 0,
+        "y": 1,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 1,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 1,
+        "y": 2,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      }
+    ],
+    "outputs": [
+      {
+        "itemType": "Axe"
+      }
+    ]
+  },
+  {
+    "type": "shaped",
+    "group": "inventory",
+    "width": 1,
+    "height": 3,
+    "inputs": [
+      {
+        "x": 0,
+        "y": 0,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Flint"
+          }
+        }
+      },
+      {
+        "x": 0,
+        "y": 1,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      },
+      {
+        "x": 0,
+        "y": 2,
+        "input": {
+          "filter": {
+            "type": "type",
+            "itemType": "Wooden Stick"
+          }
+        }
+      }
+    ],
+    "outputs": [
+      {
+        "itemType": "Shovel"
+      }
+    ]
+  }
 ]