Explorar o código

add json config for block and item types

Kolja Strohm hai 8 meses
pai
achega
9e77b69498
Modificáronse 100 ficheiros con 7813 adicións e 2706 borrados
  1. 1 0
      .gitignore
  2. 1 2
      FactoryCraft/AddEntityUpdate.cpp
  3. 11 0
      FactoryCraft/ArrayUtils.cpp
  4. 5 0
      FactoryCraft/ArrayUtils.h
  5. 0 93
      FactoryCraft/Axe.cpp
  6. 0 42
      FactoryCraft/Axe.h
  7. 0 148
      FactoryCraft/BasicBlock.cpp
  8. 452 0
      FactoryCraft/BasicBlocks.cpp
  9. 80 34
      FactoryCraft/BasicBlocks.h
  10. 180 10
      FactoryCraft/BasicItems.cpp
  11. 34 8
      FactoryCraft/BasicItems.h
  12. 1582 30
      FactoryCraft/BasicTool.cpp
  13. 332 16
      FactoryCraft/BasicTool.h
  14. 176 78
      FactoryCraft/Block.cpp
  15. 50 32
      FactoryCraft/Block.h
  16. 492 0
      FactoryCraft/BlockFilter.cpp
  17. 213 0
      FactoryCraft/BlockFilter.h
  18. 1 3
      FactoryCraft/BlockInfoCommand.cpp
  19. 8 5
      FactoryCraft/BlockInstanceGeneratorRule.cpp
  20. 51 37
      FactoryCraft/BlockType.cpp
  21. 25 43
      FactoryCraft/BlockType.h
  22. 6 4
      FactoryCraft/BlockTypeGeneratorRule.cpp
  23. 126 8
      FactoryCraft/Chest.cpp
  24. 30 1
      FactoryCraft/Chest.h
  25. 32 44
      FactoryCraft/Chunk.cpp
  26. 2 1
      FactoryCraft/ChunkMap.cpp
  27. 6 10
      FactoryCraft/Dimension.cpp
  28. 18 17
      FactoryCraft/Entity.cpp
  29. 1 1
      FactoryCraft/Entity.h
  30. 31 11
      FactoryCraft/EntityType.cpp
  31. 10 5
      FactoryCraft/EntityType.h
  32. 9 9
      FactoryCraft/FactoryCraft.vcxproj
  33. 28 25
      FactoryCraft/FactoryCraft.vcxproj.filters
  34. 170 15
      FactoryCraft/FluidBlock.cpp
  35. 34 15
      FactoryCraft/FluidBlock.h
  36. 455 95
      FactoryCraft/FluidContainer.cpp
  37. 91 18
      FactoryCraft/FluidContainer.h
  38. 368 33
      FactoryCraft/Game.cpp
  39. 20 1
      FactoryCraft/Game.h
  40. 2 2
      FactoryCraft/GeneratedStructure.cpp
  41. 129 74
      FactoryCraft/Grass.cpp
  42. 24 20
      FactoryCraft/Grass.h
  43. 193 60
      FactoryCraft/GrowingPlant.cpp
  44. 48 25
      FactoryCraft/GrowingPlant.h
  45. 0 102
      FactoryCraft/Hoe.cpp
  46. 0 43
      FactoryCraft/Hoe.h
  47. 1 2
      FactoryCraft/Inventory.cpp
  48. 29 21
      FactoryCraft/Item.cpp
  49. 2 2
      FactoryCraft/Item.h
  50. 3 3
      FactoryCraft/ItemEntity.cpp
  51. 1 1
      FactoryCraft/ItemEntity.h
  52. 42 33
      FactoryCraft/ItemSkill.cpp
  53. 15 36
      FactoryCraft/ItemSkill.h
  54. 38 66
      FactoryCraft/ItemType.cpp
  55. 15 35
      FactoryCraft/ItemType.h
  56. 3 4
      FactoryCraft/JsonExpression.cpp
  57. 34 0
      FactoryCraft/JsonUtils.cpp
  58. 5 0
      FactoryCraft/JsonUtils.h
  59. 136 30
      FactoryCraft/LightSources.cpp
  60. 42 11
      FactoryCraft/LightSources.h
  61. 84 38
      FactoryCraft/ModelInfo.cpp
  62. 26 7
      FactoryCraft/ModelInfo.h
  63. 1 3
      FactoryCraft/MultiblockStructure.cpp
  64. 0 1
      FactoryCraft/MultiblockTree.h
  65. 17 4
      FactoryCraft/NoBlock.cpp
  66. 2 1
      FactoryCraft/NoBlock.h
  67. 0 1
      FactoryCraft/OverworldDimensionGenerator.h
  68. 352 0
      FactoryCraft/PlaceableProof.cpp
  69. 136 0
      FactoryCraft/PlaceableProof.h
  70. 4 2
      FactoryCraft/Player.cpp
  71. 3 26
      FactoryCraft/PlayerHand.cpp
  72. 1 13
      FactoryCraft/PlayerHand.h
  73. 4 2
      FactoryCraft/QuestRequirement.cpp
  74. 1 1
      FactoryCraft/QuestReward.cpp
  75. 1 1
      FactoryCraft/RecipieList.cpp
  76. 1 1
      FactoryCraft/RecipieList.h
  77. 18 23
      FactoryCraft/RecipieLoader.cpp
  78. 0 91
      FactoryCraft/Shovel.cpp
  79. 0 41
      FactoryCraft/Shovel.h
  80. 12 18
      FactoryCraft/Start.cpp
  81. 0 699
      FactoryCraft/StaticInitializerOrder.cpp
  82. 0 76
      FactoryCraft/StaticRegistry.h
  83. 150 29
      FactoryCraft/TreeSeblingBlock.cpp
  84. 39 15
      FactoryCraft/TreeSeblingBlock.h
  85. 13 12
      FactoryCraft/TreeTemplate.cpp
  86. 55 0
      FactoryCraft/TypeRegistry.cpp
  87. 53 15
      FactoryCraft/TypeRegistry.h
  88. 6 5
      FactoryCraft/WorldLoader.cpp
  89. 0 2
      FactoryCraft/WorldUpdate.h
  90. 14 3
      NoiseTest/NoiseTest.cpp
  91. 46 43
      NoiseTest/NoiseTest.vcxproj.filters
  92. 9 9
      Windows Version/Windows Version.vcxproj
  93. 28 25
      Windows Version/Windows Version.vcxproj.filters
  94. 566 0
      Windows Version/data/blocks/blockTypes.json
  95. 244 0
      Windows Version/data/items/itemTypes.json
  96. 1 1
      Windows Version/data/quests/quests.json
  97. 18 18
      Windows Version/data/recipies/basicItems.json
  98. 9 9
      Windows Version/data/recipies/blocks.json
  99. 6 6
      Windows Version/data/recipies/tools.json
  100. 0 1
      Windows Version/data/syntax/generatorValidation.xml

+ 1 - 0
.gitignore

@@ -366,3 +366,4 @@ FodyWeavers.xsd
 /Windows Version/cert.key
 *.dll
 /enc_temp_folder
+/Windows Version/data/syntax/

+ 1 - 2
FactoryCraft/AddEntityUpdate.cpp

@@ -3,7 +3,6 @@
 #include "Dimension.h"
 #include "Entity.h"
 #include "EntityType.h"
-#include "StaticRegistry.h"
 
 AddEntityUpdate::AddEntityUpdate(Entity* entity, int dimension)
     : WorldUpdate(WorldUpdateTypeEnum::ADD_ENTITY, dimension, entity->getLocation()),
@@ -34,5 +33,5 @@ void AddEntityUpdate::write(Framework::StreamWriter* zWriter)
     zWriter->schreibe((char*)&maxSpeed, 4);
     bool special = !entity->hasDefaultModel();
     zWriter->schreibe((char*)&special, 1);
-    if (special) entity->getSpecialModel().writeTo(zWriter);
+    if (special) entity->zSpecialModel()->writeTo(zWriter);
 }

+ 11 - 0
FactoryCraft/ArrayUtils.cpp

@@ -0,0 +1,11 @@
+#include "ArrayUtils.h"
+
+Framework::RCArray<Framework::Text> toArray(Framework::Text text, int count)
+{
+    Framework::RCArray<Framework::Text> result;
+    for (int i = 0; i < count; i++)
+    {
+        result.add(new Framework::Text(text));
+    }
+    return result;
+}

+ 5 - 0
FactoryCraft/ArrayUtils.h

@@ -0,0 +1,5 @@
+#pragma once
+
+#include <Array.h>
+
+Framework::RCArray<Framework::Text> toArray(Framework::Text text, int count);

+ 0 - 93
FactoryCraft/Axe.cpp

@@ -1,93 +0,0 @@
-#include "Axe.h"
-
-#include "Game.h"
-
-AxeToolItemType::AxeToolItemType() // TODO: add broken Axe
-    : BasicToolItemType(ItemTypeEnum::AXE,
-        "Axe",
-        new AxeToolLevelUpRule(),
-        ItemTypeEnum::AXE_BROKEN,
-        ModelInfo("tools.m3/axe", "tools.ltdb/stoneaxe.png", 1))
-{}
-
-Item* AxeToolItemType::createItem() const
-{
-    return new BasicToolItem(ItemTypeEnum::AXE, "Axe");
-}
-
-ItemSkill* AxeToolItemType::createDefaultItemSkill() const
-{
-    return new AxeToolSkill();
-}
-
-void AxeToolItemType::loadSuperItemSkill(
-    ItemSkill* zSkill, Framework::StreamReader* zReader) const
-{
-    AxeToolSkill* skill = dynamic_cast<AxeToolSkill*>(zSkill);
-    zReader->lese((char*)&skill->level, 4);
-    zReader->lese((char*)&skill->xp, 4);
-    zReader->lese((char*)&skill->maxXP, 4);
-}
-
-void AxeToolItemType::saveSuperItemSkill(
-    const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const
-{
-    const AxeToolSkill* skill = dynamic_cast<const AxeToolSkill*>(zSkill);
-    zWriter->schreibe((char*)&skill->level, 4);
-    zWriter->schreibe((char*)&skill->xp, 4);
-    zWriter->schreibe((char*)&skill->maxXP, 4);
-}
-
-AxeToolLevelUpRule::AxeToolLevelUpRule()
-    : ItemSkillLevelUpRule()
-{}
-
-void AxeToolLevelUpRule::applyOn(ItemSkill* zSkill)
-{
-    AxeToolSkill* skill = dynamic_cast<AxeToolSkill*>(zSkill);
-    if (skill->xp >= skill->maxXP)
-    {
-        skill->level++;
-        skill->xp = 0;
-        skill->maxXP = skill->maxXP * 2;
-    }
-}
-
-AxeToolSkill::AxeToolSkill()
-    : ItemSkill(ItemTypeEnum::AXE),
-      level(1),
-      xp(0.f),
-      maxXP(10.f)
-{}
-
-bool AxeToolSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
-{
-    if (zActor->getStamina() > 0.0001f)
-    {
-        if (zTarget->zBlockType()->getId() == BlockTypeEnum::WOOD_BEECH
-            || zTarget->zBlockType()->getId() == BlockTypeEnum::WOOD_BIRCH
-            || zTarget->zBlockType()->getId() == BlockTypeEnum::WOOD_OAK
-            || zTarget->zBlockType()->getId() == BlockTypeEnum::WOOD_PINE)
-        {
-            float damage
-                = (1 + ((float)level / 10.f)) / (zTarget->getHardness() + 1);
-            zTarget->setHP(zTarget->getHP() - damage);
-            xp += damage / 20;
-            zActor->setStamina(zActor->getStamina() - 0.0001f);
-            zUsedItem->setDurability(zUsedItem->getDurability() - damage / 50);
-        }
-        else
-        {
-            zActor->setStamina(zActor->getStamina() - 0.0001f);
-            zUsedItem->setDurability(zUsedItem->getDurability() - 0.001f);
-        }
-        return 1;
-    }
-    return 0;
-}
-
-bool AxeToolSkill::use(Entity* zActor, Item* zUsedItem, Entity* zTarget)
-{
-    // an Axe can not be used on an entity
-    return 0;
-}

+ 0 - 42
FactoryCraft/Axe.h

@@ -1,42 +0,0 @@
-#pragma once
-
-#include "BasicTool.h"
-#include "ItemSkill.h"
-#include "ItemType.h"
-
-class AxeToolItemType : public BasicToolItemType
-{
-protected:
-    void loadSuperItemSkill(
-        ItemSkill* zSkill, Framework::StreamReader* zReader) const override;
-    void saveSuperItemSkill(const ItemSkill* zSkill,
-        Framework::StreamWriter* zWriter) const override;
-
-public:
-    AxeToolItemType();
-    Item* createItem() const override;
-    ItemSkill* createDefaultItemSkill() const override;
-};
-
-class AxeToolLevelUpRule : public ItemSkillLevelUpRule
-{
-public:
-    AxeToolLevelUpRule();
-    void applyOn(ItemSkill* zSkill) override;
-};
-
-class AxeToolSkill : public ItemSkill
-{
-private:
-    int level;
-    float xp;
-    float maxXP;
-
-public:
-    AxeToolSkill();
-    bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) override;
-    bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
-
-    friend AxeToolItemType;
-    friend AxeToolLevelUpRule;
-};

+ 0 - 148
FactoryCraft/BasicBlock.cpp

@@ -1,148 +0,0 @@
-#include "AddEntityUpdate.h"
-#include "BasicBlocks.h"
-#include "Game.h"
-#include "ItemEntity.h"
-#include "TreeSeblingBlock.h"
-
-BasicBlock::BasicBlock(
-    int typeId, ItemType* zTool, Framework::Vec3<int> pos, int dimensionId)
-    : BasicBlock(typeId, zTool, pos, dimensionId, false)
-{}
-
-BasicBlock::BasicBlock(int typeId,
-    ItemType* zTool,
-    Framework::Vec3<int> pos,
-    int dimensionId,
-    bool hasInventory)
-    : Block(typeId, zTool, pos, dimensionId, hasInventory)
-{}
-
-bool BasicBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
-{
-    return 0;
-}
-
-void BasicBlock::onPostTick() {}
-
-AdditionalItemSpawningBlock::AdditionalItemSpawningBlock(
-    int typeId, ItemType* zTool, Framework::Vec3<int> pos, int dimensionId)
-    : BasicBlock(typeId, zTool, pos, dimensionId)
-{}
-
-void AdditionalItemSpawningBlock::addSpawn(SpawnConfig config)
-{
-    spawns.add(config);
-}
-
-void AdditionalItemSpawningBlock::onDestroy()
-{
-    for (const SpawnConfig& config : spawns)
-    {
-        if ((double)rand() / RAND_MAX < config.chance)
-        {
-            int amount = config.min
-                       + (int)((config.max - config.min)
-                               * ((double)rand() / RAND_MAX));
-            if (amount > 0)
-            {
-                ItemStack* spawnedItems = StaticRegistry<ItemType>::INSTANCE
-                                              .zElement(config.itemType)
-                                              ->createItemStack(amount);
-                if (spawnedItems)
-                {
-                    ItemEntity* itemEntity
-                        = (ItemEntity*)StaticRegistry<EntityType>::INSTANCE
-                              .zElement(EntityTypeEnum::ITEM)
-                              ->createEntity(location
-                                                 + Framework::Vec3<float>(
-                                                     0.5f, 0.5f, 0.5f),
-                                  getDimensionId(),
-                                  Game::INSTANCE->getNextEntityId());
-                    itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION, 0);
-                    spawnedItems->release();
-                    Game::INSTANCE->requestWorldUpdate(
-                        new AddEntityUpdate(itemEntity, getDimensionId()));
-                }
-            }
-        }
-    }
-    BasicBlock::onDestroy();
-}
-
-BasicBlockType::BasicBlockType(
-    int typeId, int itemTypeId, ModelInfo model, const char* name, int mapColor)
-    : BasicBlockType(
-        typeId,
-        itemTypeId,
-        model,
-        [typeId](Framework::Vec3<int> pos, int dimensionId) {
-            return new BasicBlock(typeId, 0, pos, dimensionId);
-        },
-        name,
-        mapColor)
-{}
-
-BasicBlockType::BasicBlockType(int typeId,
-    int itemTypeId,
-    ModelInfo model,
-    std::function<Block*(Framework::Vec3<int>, int)> creatBlockCustom,
-    const char* name,
-    int mapColor)
-    : BasicBlockType(
-        typeId, itemTypeId, model, creatBlockCustom, name, mapColor, 0)
-{}
-
-BasicBlockType::BasicBlockType(int typeId,
-    int itemTypeId,
-    ModelInfo model,
-    std::function<Block* (Framework::Vec3<int>, int)> creatBlockCustom,
-    const char* name,
-    int mapColor,
-    bool modelSubscription)
-    : BlockType(typeId, 0, model, 1, 100, 0, name, modelSubscription, mapColor),
-      itemType(itemTypeId),
-      transparent(0),
-      passable(0),
-      hardness(1.f),
-      zTool(0),
-      speedModifier(1.f),
-      interactable(1),
-      creatBlockCustom(creatBlockCustom)
-{}
-
-void BasicBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
-{
-    BasicBlock* block = dynamic_cast<BasicBlock*>(zBlock);
-    block->transparent = transparent;
-    block->passable = passable;
-    block->hp = (float)getInitialMaxHP();
-    block->maxHP = (float)getInitialMaxHP();
-    block->hardness = hardness;
-    block->zTool = zTool;
-    block->speedModifier = speedModifier;
-    block->interactable = interactable;
-    BlockType::createSuperBlock(zBlock, zItem);
-}
-
-Block* BasicBlockType::createBlock(
-    Framework::Vec3<int> position, int dimensionId) const
-{
-    return creatBlockCustom(position, dimensionId);
-}
-
-Item* BasicBlockType::createItem() const
-{
-    return StaticRegistry<ItemType>::INSTANCE.zElement(itemType)->createItem();
-}
-
-BasicBlockType* BasicBlockType::setHardness(float hardness)
-{
-    this->hardness = hardness;
-    return this;
-}
-
-BasicBlockType* BasicBlockType::setTransparent(bool transparent)
-{
-    this->transparent = transparent;
-    return this;
-}

+ 452 - 0
FactoryCraft/BasicBlocks.cpp

@@ -0,0 +1,452 @@
+#include "BasicBlocks.h"
+
+#include "AddEntityUpdate.h"
+#include "Game.h"
+#include "ItemEntity.h"
+#include "ModelInfo.h"
+#include "TreeSeblingBlock.h"
+
+BasicBlock::BasicBlock(int typeId, Framework::Vec3<int> pos, int dimensionId)
+    : BasicBlock(typeId, pos, dimensionId, false)
+{}
+
+BasicBlock::BasicBlock(
+    int typeId, Framework::Vec3<int> pos, int dimensionId, bool hasInventory)
+    : Block(typeId, pos, dimensionId, hasInventory)
+{}
+
+bool BasicBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
+{
+    return 0;
+}
+
+void BasicBlock::onPostTick() {}
+
+BasicBlockType::BasicBlockType(Framework::Text itemTypeName,
+    ModelInfo* model,
+    Framework::Text name,
+    int mapColor,
+    bool modelSubscription,
+    float hardness,
+    Framework::RCArray<Framework::Text> groupNames)
+    : BlockType(0,
+        model,
+        1,
+        100,
+        0,
+        name,
+        modelSubscription,
+        mapColor,
+        groupNames,
+        hardness),
+      itemTypeName(itemTypeName),
+      transparent(0),
+      passable(0),
+      speedModifier(1.f),
+      interactable(1)
+{}
+
+bool BasicBlockType::initialize(Game* zGame)
+{
+    if (itemTypeName.getLength())
+    {
+        itemTypeId = zGame->getItemTypeId(itemTypeName);
+    }
+    else
+    {
+        itemTypeId = 0;
+    }
+    return itemTypeId >= 0 && BlockType::initialize(zGame);
+}
+
+void BasicBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
+{
+    BasicBlock* block = dynamic_cast<BasicBlock*>(zBlock);
+    block->transparent = transparent;
+    block->passable = passable;
+    block->hp = (float)getInitialMaxHP();
+    block->maxHP = (float)getInitialMaxHP();
+    block->hardness = getHardness();
+    block->speedModifier = speedModifier;
+    block->interactable = interactable;
+    BlockType::createSuperBlock(zBlock, zItem);
+}
+
+Block* BasicBlockType::createBlock(
+    Framework::Vec3<int> position, int dimensionId) const
+{
+    return new BasicBlock(getId(), position, dimensionId);
+}
+
+Item* BasicBlockType::createItem() const
+{
+    return Game::INSTANCE->zItemType(itemTypeId)->createItem();
+}
+
+Framework::Text BasicBlockType::getItemTypeName() const
+{
+    return itemTypeName;
+}
+
+ItemType* BasicBlockType::createItemType() const
+{
+    return new BasicBlockItemType(getItemTypeName(),
+        new ModelInfo(zModel()->getModelPath(), zModel()->getTexturePaths(), zModel()->isTransparent(), zModel()->getSize() / 2.f),
+        transparent,
+        passable,
+        getHardness(),
+        speedModifier,
+        getItemTypeName(),
+        0, 50);
+}
+
+int BasicBlockType::getItemTypeId() const
+{
+    return itemTypeId;
+}
+
+void BasicBlockType::setTransparent(bool transparent) {
+	this->transparent = transparent;
+}
+
+bool BasicBlockType::isTransparent() const
+{
+    return transparent;
+}
+
+void BasicBlockType::setPassable(bool passable) {
+	this->passable = passable;
+}
+
+bool BasicBlockType::isPassable() const
+{
+    return passable;
+}
+
+void BasicBlockType::setSpeedModifier(float speedModifier) {
+	this->speedModifier = speedModifier;
+}
+
+float BasicBlockType::getSpeedModifier() const
+{
+    return speedModifier;
+}
+
+void BasicBlockType::setInteractable(bool interactable) {
+	this->interactable = interactable;
+}
+
+BasicBlockTypeFactory::BasicBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+BasicBlockType* BasicBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    return new BasicBlockType(
+        zJson->zValue("itemType")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("name")->asString()->getString(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        zJson->zValue("modelSubscription")->asBool()->getBool(),
+        (float)zJson->zValue("hardness")->asNumber()->getNumber(),
+        groupNames);
+}
+
+Framework::JSON::JSONObject* BasicBlockTypeFactory::toJson(
+    BasicBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
+        new Framework::JSON::JSONString(zObject->getItemTypeName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    result->addValue("modelSubscription",
+        new Framework::JSON::JSONBool(zObject->doesNeedModelSubscription()));
+    result->addValue(
+        "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* BasicBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("itemType")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredBool("modelSubscription")
+        ->withDefault(false)
+        ->finishBool()
+        ->withRequiredNumber("hardness")
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text BasicBlockTypeFactory::getTypeToken() const
+{
+    return "basicBlock";
+}
+
+AdditionalItemSpawningBlock::AdditionalItemSpawningBlock(
+    int typeId, Framework::Vec3<int> pos, int dimensionId)
+    : BasicBlock(typeId, pos, dimensionId)
+{}
+
+void AdditionalItemSpawningBlock::addSpawn(SpawnConfig config)
+{
+    spawns.add(config);
+}
+
+void AdditionalItemSpawningBlock::onDestroy()
+{
+    for (const SpawnConfig& config : spawns)
+    {
+        if ((double)rand() / RAND_MAX < config.chance)
+        {
+            int amount = config.min
+                       + (int)((config.max - config.min)
+                               * ((double)rand() / RAND_MAX));
+            if (amount > 0)
+            {
+                ItemStack* spawnedItems
+                    = Game::INSTANCE->zItemType(config.typeId)
+                          ->createItemStack(amount);
+                if (spawnedItems)
+                {
+                    ItemEntity* itemEntity
+                        = (ItemEntity*)Game::INSTANCE
+                              ->zEntityType(EntityTypeEnum::ITEM)
+                              ->createEntity(location
+                                                 + Framework::Vec3<float>(
+                                                     0.5f, 0.5f, 0.5f),
+                                  getDimensionId(),
+                                  Game::INSTANCE->getNextEntityId());
+                    itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION, 0);
+                    spawnedItems->release();
+                    Game::INSTANCE->requestWorldUpdate(
+                        new AddEntityUpdate(itemEntity, getDimensionId()));
+                }
+            }
+        }
+    }
+    BasicBlock::onDestroy();
+}
+
+void AdditionalItemSpawningBlockType::createSuperBlock(
+    Block* zBlock, Item* zItem) const
+{
+    AdditionalItemSpawningBlock* block
+		= dynamic_cast<AdditionalItemSpawningBlock*>(zBlock);
+    if (block)
+    {
+        for (const SpawnConfig& config : spawns)
+        {
+            block->addSpawn(config);
+        }
+    }
+    BasicBlockType::createSuperBlock(zBlock, zItem);
+}
+
+AdditionalItemSpawningBlockType::AdditionalItemSpawningBlockType(
+    Framework::Text itemTypeName,
+    ModelInfo* model,
+    Framework::Text name,
+    int mapColor,
+    bool modelSubscription,
+    float hardness,
+    Framework::Array<SpawnConfig> spawns,
+    Framework::RCArray<Framework::Text> groupNames)
+    : BasicBlockType(itemTypeName,
+        model,
+        name,
+        mapColor,
+        modelSubscription,
+        hardness,
+        groupNames),
+      spawns(spawns)
+{}
+
+bool AdditionalItemSpawningBlockType::initialize(Game* zGame)
+{
+    for (auto iterator = spawns.begin(); iterator; iterator++)
+    {
+        int itemTypeId
+            = Game::INSTANCE->getItemTypeId(iterator.val().itemTypeName);
+        if (itemTypeId < 0)
+        {
+            return false;
+        }
+        iterator.set({iterator.val().min,
+            iterator.val().max,
+            iterator.val().chance,
+            iterator.val().itemTypeName,
+            itemTypeId});
+    }
+    return BasicBlockType::initialize(zGame);
+}
+
+Block* AdditionalItemSpawningBlockType::createBlock(
+    Framework::Vec3<int> position, int dimensionId) const
+{
+    AdditionalItemSpawningBlock* block
+        = new AdditionalItemSpawningBlock(getId(), position, dimensionId);
+    return block;
+}
+
+const Framework::Array<SpawnConfig>&
+AdditionalItemSpawningBlockType::getSpawns() const
+{
+    return spawns;
+}
+
+AdditionalItemSpawningBlockTypeFactory::AdditionalItemSpawningBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+AdditionalItemSpawningBlockType*
+AdditionalItemSpawningBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    Framework::Array<SpawnConfig> spawns;
+    Framework::JSON::JSONArray* spawnsJson = zJson->zValue("spawns")->asArray();
+    for (int i = 0; i < spawnsJson->getLength(); i++)
+    {
+        Framework::JSON::JSONObject* spawnJson
+            = spawnsJson->zValue(i)->asObject();
+        spawns.add(SpawnConfig{
+            (int)spawnJson->zValue("min")->asNumber()->getNumber(),
+            (int)spawnJson->zValue("max")->asNumber()->getNumber(),
+            (float)spawnJson->zValue("chance")->asNumber()->getNumber(),
+            spawnJson->zValue("itemType")->asString()->getString(),
+            0,
+        });
+    }
+    return new AdditionalItemSpawningBlockType(
+        zJson->zValue("itemType")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("name")->asString()->getString(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        zJson->zValue("modelSubscription")->asBool()->getBool(),
+        (float)zJson->zValue("hardness")->asNumber()->getNumber(),
+        spawns,
+        groupNames);
+}
+
+Framework::JSON::JSONObject* AdditionalItemSpawningBlockTypeFactory::toJson(
+    AdditionalItemSpawningBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
+        new Framework::JSON::JSONString(zObject->getItemTypeName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    result->addValue("modelSubscription",
+        new Framework::JSON::JSONBool(zObject->doesNeedModelSubscription()));
+    result->addValue(
+        "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
+    Framework::JSON::JSONArray* spawns = new Framework::JSON::JSONArray();
+    for (const SpawnConfig& config : zObject->getSpawns())
+    {
+        Framework::JSON::JSONObject* spawn = new Framework::JSON::JSONObject();
+        spawn->addValue(
+            "itemType", new Framework::JSON::JSONString(config.itemTypeName));
+        spawn->addValue(
+            "chance", new Framework::JSON::JSONNumber(config.chance));
+        spawn->addValue("min", new Framework::JSON::JSONNumber(config.min));
+        spawn->addValue("max", new Framework::JSON::JSONNumber(config.max));
+        spawns->addValue(spawn);
+    }
+    result->addValue("spawns", spawns);
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+AdditionalItemSpawningBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("itemType")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredBool("modelSubscription")
+        ->withDefault(false)
+        ->finishBool()
+        ->withRequiredNumber("hardness")
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredAttribute("spawns",
+            JSON::Validator::JSONValidator::buildForArray()
+                ->addAcceptedObjectInArray()
+                ->withRequiredString("itemType")
+                ->finishString()
+                ->withRequiredNumber("chance")
+                ->finishNumber()
+                ->withRequiredNumber("min")
+                ->finishNumber()
+                ->withRequiredNumber("max")
+                ->finishNumber()
+                ->finishObject()
+                ->finishArray())
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text AdditionalItemSpawningBlockTypeFactory::getTypeToken() const
+{
+    return "additionalItemsBlockType";
+}

+ 80 - 34
FactoryCraft/BasicBlocks.h

@@ -3,6 +3,7 @@
 #include "Block.h"
 #include "BlockType.h"
 #include "Item.h"
+#include "TypeRegistry.h"
 
 class BlockType;
 class ItemType;
@@ -11,10 +12,8 @@ class BasicBlockType;
 class BasicBlock : public Block
 {
 public:
-    BasicBlock(
-        int typeId, ItemType* zTool, Framework::Vec3<int> pos, int dimensionId);
+    BasicBlock(int typeId, Framework::Vec3<int> pos, int dimensionId);
     BasicBlock(int typeId,
-        ItemType* zTool,
         Framework::Vec3<int> pos,
         int dimensionId,
         bool hasInventory);
@@ -30,7 +29,57 @@ struct SpawnConfig
     int min;
     int max;
     double chance;
-    int itemType;
+    Framework::Text itemTypeName;
+    int typeId;
+};
+
+class BasicBlockType : public BlockType
+{
+private:
+    Framework::Text itemTypeName;
+    int itemTypeId;
+    bool transparent;
+    bool passable;
+    float speedModifier;
+    bool interactable;
+
+protected:
+    virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
+
+public:
+    BasicBlockType(Framework::Text itemTypeName,
+        ModelInfo* model,
+        Framework::Text name,
+        int mapColor,
+        bool modelSubscription,
+        float hardness,
+        Framework::RCArray<Framework::Text> groupNames);
+    virtual bool initialize(Game* zGame) override;
+    virtual Block* createBlock(
+        Framework::Vec3<int> position, int dimensionId) const override;
+    virtual Item* createItem() const override;
+    Framework::Text getItemTypeName() const;
+    virtual ItemType* createItemType() const override;
+    int getItemTypeId() const;
+    void setTransparent(bool transparent);
+    bool isTransparent() const;
+    void setPassable(bool passable);
+    bool isPassable() const;
+    void setSpeedModifier(float speedModifier);
+    float getSpeedModifier() const;
+    void setInteractable(bool interactable);
+};
+
+class BasicBlockTypeFactory : public SubTypeFactory<BlockType, BasicBlockType>
+{
+public:
+    BasicBlockTypeFactory();
+    BasicBlockType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(BasicBlockType* 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 AdditionalItemSpawningBlock : public BasicBlock
@@ -40,48 +89,45 @@ private:
 
 public:
     AdditionalItemSpawningBlock(
-        int typeId, ItemType* zTool, Framework::Vec3<int> pos, int dimensionId);
+        int typeId, Framework::Vec3<int> pos, int dimensionId);
     void addSpawn(SpawnConfig config);
     virtual void onDestroy() override;
 };
 
-class BasicBlockType : public BlockType
+class AdditionalItemSpawningBlockType : public BasicBlockType
 {
 private:
-    int itemType;
-    bool transparent;
-    bool passable;
-    float hardness;
-    ItemType* zTool;
-    float speedModifier;
-    bool interactable;
-    std::function<Block*(Framework::Vec3<int>, int)> creatBlockCustom;
+    Framework::Array<SpawnConfig> spawns;
 
 protected:
     virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
 
 public:
-    BasicBlockType(int typeId,
-        int itemTypeId,
-        ModelInfo model,
-        const char* name,
-        int mapColor);
-    BasicBlockType(int typeId,
-        int itemTypeId,
-        ModelInfo model,
-        std::function<Block*(Framework::Vec3<int>, int)> creatBlockCustom,
-        const char* name,
-        int mapColor);
-    BasicBlockType(int typeId,
-        int itemTypeId,
-        ModelInfo model,
-        std::function<Block*(Framework::Vec3<int>, int)> creatBlockCustom,
-        const char* name,
+    AdditionalItemSpawningBlockType(Framework::Text itemTypeName,
+        ModelInfo* model,
+        Framework::Text name,
         int mapColor,
-        bool modelSubscription);
+        bool modelSubscription,
+        float hardness,
+        Framework::Array<SpawnConfig> spawns,
+        Framework::RCArray<Framework::Text> groupNames);
+    virtual bool initialize(Game* zGame) override;
     virtual Block* createBlock(
         Framework::Vec3<int> position, int dimensionId) const override;
-    virtual Item* createItem() const override;
-    BasicBlockType* setHardness(float hardness);
-    BasicBlockType* setTransparent(bool transparent);
+    const Framework::Array<SpawnConfig>& getSpawns() const;
+};
+
+class AdditionalItemSpawningBlockTypeFactory
+    : public SubTypeFactory<BlockType, AdditionalItemSpawningBlockType>
+{
+public:
+    AdditionalItemSpawningBlockTypeFactory();
+    AdditionalItemSpawningBlockType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        AdditionalItemSpawningBlockType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 180 - 10
FactoryCraft/BasicItems.cpp

@@ -1,18 +1,188 @@
 #include "BasicItems.h"
 
+#include "Game.h"
 #include "ModelInfo.h"
 
-NoBlockItemType::NoBlockItemType(int id,
-    const char* name,
-    ItemSkillLevelUpRule* levelUp,
-    int brokenTypeId,
-    ModelInfo model,
-    std::function<Item*()> createItemImp)
-    : ItemType(id, name, levelUp, brokenTypeId, model),
-      createItemImp(createItemImp)
+BasicItemType::BasicItemType(Framework::Text name,
+    ModelInfo* model,
+    Framework::Text itemName,
+    float hp,
+    float durability,
+    int maxStack,
+    bool solid,
+    float hungerRecoveryPerHp,
+    float thirstRecoveryPerHp)
+    : ItemType(name, model, maxStack),
+      itemName(itemName),
+      hp(hp),
+      durability(durability),
+      solid(solid),
+      hungerRecoveryPerHp(hungerRecoveryPerHp),
+      thirstRecoveryPerHp(thirstRecoveryPerHp)
 {}
 
-Item* NoBlockItemType::createItem() const
+Item* BasicItemType::createItem() const
 {
-    return createItemImp();
+    Item* result = createBasicItem(getId(),
+        itemName,
+        hp,
+        hp,
+        durability,
+        durability,
+        hungerRecoveryPerHp > 0 || thirstRecoveryPerHp > 0,
+        0,
+        0,
+        solid,
+        0);
+    if (hungerRecoveryPerHp > 0 || thirstRecoveryPerHp > 0)
+    {
+        result->setFoodEffect(
+            [this](Item* zItem, Entity* zEntity) {
+                float added = zItem->getHp();
+                if (zEntity->getHunger() + added * hungerRecoveryPerHp
+                        > zEntity->getMaxHunger()
+                    && zEntity->getThirst() + added * thirstRecoveryPerHp
+                           > zEntity->getMaxThirst())
+                {
+                    added = MAX((zEntity->getMaxHunger() - zEntity->getHunger())
+                                    / hungerRecoveryPerHp,
+                        (zEntity->getMaxThirst() - zEntity->getThirst())
+                            / thirstRecoveryPerHp);
+                }
+                zEntity->setHunger(
+                    zEntity->getHunger() + added * hungerRecoveryPerHp);
+                zEntity->setThirst(
+                    zEntity->getThirst() + added * thirstRecoveryPerHp);
+                zItem->setHp(zItem->getHp() - added);
+                return added != 0.f;
+            },
+            [this](const Item* zItem, Entity* zEntity) {
+                float addable = zItem->getHp();
+                if (zEntity->getHunger() + addable * hungerRecoveryPerHp
+                        > zEntity->getMaxHunger()
+                    && zEntity->getThirst() + addable * thirstRecoveryPerHp
+                           > zEntity->getMaxThirst())
+                {
+                    addable
+                        = MAX((zEntity->getMaxHunger() - zEntity->getHunger())
+                                  / hungerRecoveryPerHp,
+                            (zEntity->getMaxThirst() - zEntity->getThirst())
+                                / thirstRecoveryPerHp);
+                }
+                return addable >= zItem->getHp();
+            });
+    }
+    return result;
+}
+
+Framework::Text BasicItemType::getItemName() const
+{
+    return itemName;
+}
+
+float BasicItemType::getHp() const
+{
+    return hp;
+}
+
+float BasicItemType::getDurability() const
+{
+    return durability;
+}
+
+bool BasicItemType::isSolid() const
+{
+    return solid;
+}
+
+float BasicItemType::getHungerRecoveryPerHp() const
+{
+    return hungerRecoveryPerHp;
+}
+
+float BasicItemType::getThirstRecoveryPerHp() const
+{
+    return thirstRecoveryPerHp;
+}
+
+BasicItemTypeFactory::BasicItemTypeFactory()
+    : SubTypeFactory()
+{}
+
+BasicItemType* BasicItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BasicItemType(zJson->zValue("name")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("itemName")->asString()->getString(),
+        (float)zJson->zValue("hp")->asNumber()->getNumber(),
+        (float)zJson->zValue("durability")->asNumber()->getNumber(),
+        (int)zJson->zValue("maxStack")->asNumber()->getNumber(),
+        zJson->zValue("solid")->asBool()->getBool(),
+        (float)zJson->zValue("hungerRecoveryPerHp")->asNumber()->getNumber(),
+        (float)zJson->zValue("thirstRecoveryPerHp")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* BasicItemTypeFactory::toJson(
+    BasicItemType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "itemName", new Framework::JSON::JSONString(zObject->getItemName()));
+    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(
+        "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()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* BasicItemTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("name")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("itemName")
+        ->finishString()
+        ->withRequiredNumber("hp")
+        ->whichIsGreaterThen(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("durability")
+        ->whichIsGreaterThen(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("maxStack")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(50.0)
+        ->finishNumber()
+        ->withRequiredBool("solid")
+        ->withDefault(true)
+        ->finishBool()
+        ->withRequiredNumber("hungerRecoveryPerHp")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("thirstRecoveryPerHp")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber()
+        ->finishObject();
+}
+
+Framework::Text BasicItemTypeFactory::getTypeToken() const
+{
+    return "basic";
 }

+ 34 - 8
FactoryCraft/BasicItems.h

@@ -2,17 +2,43 @@
 
 #include "ItemType.h"
 
-class NoBlockItemType : public ItemType
+class BasicItemType : public ItemType
 {
 private:
-    std::function<Item*()> createItemImp;
+    Framework::Text itemName;
+    float hp;
+    float durability;
+    bool solid;
+    float hungerRecoveryPerHp;
+    float thirstRecoveryPerHp;
 
 public:
-    NoBlockItemType(int id,
-        const char* name,
-        ItemSkillLevelUpRule* levelUp,
-        int brokenTypeId,
-        ModelInfo model,
-        std::function<Item*()> createItemImp);
+    BasicItemType(Framework::Text name,
+        ModelInfo* model,
+        Framework::Text itemName,
+        float hp,
+        float durability,
+        int maxStack,
+        bool solid,
+        float hungerRecoveryPerHp,
+        float thirstRecoveryPerHp);
     Item* createItem() const override;
+    Framework::Text getItemName() const;
+    float getHp() const;
+    float getDurability() const;
+    bool isSolid() const;
+    float getHungerRecoveryPerHp() const;
+    float getThirstRecoveryPerHp() const;
+};
+
+class BasicItemTypeFactory : public SubTypeFactory<ItemType, BasicItemType>
+{
+public:
+    BasicItemTypeFactory();
+    BasicItemType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(BasicItemType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 1582 - 30
FactoryCraft/BasicTool.cpp

@@ -1,60 +1,1612 @@
 #include "BasicTool.h"
 
+#include "Game.h"
 
-BasicToolItem::BasicToolItem(int itemTypeId, const char *name)
-    : Item(itemTypeId, name)
+XPBasedLevelUpRule::XPBasedLevelUpRule(float xpIncrease,
+    float xpMultiplier,
+    float levelIncrease,
+    float levelMultiplier,
+    float maxLevel)
+    : ItemSkillLevelUpRule(),
+      xpIncrease(xpIncrease),
+      xpMultiplier(xpMultiplier),
+      levelIncrease(levelIncrease),
+      levelMultiplier(levelMultiplier),
+      maxLevel(maxLevel)
+{}
+
+void XPBasedLevelUpRule::applyOn(ItemSkill* zSkill)
+{
+    if (zSkill->getXp() >= zSkill->getMaxXp())
+    {
+        zSkill->setXp(zSkill->getXp() - zSkill->getMaxXp());
+        zSkill->setLevel(MIN(
+            (zSkill->getLevel() + levelIncrease) * levelMultiplier, maxLevel));
+        zSkill->setMaxXp((zSkill->getMaxXp() + xpIncrease) * xpMultiplier);
+    }
+}
+
+float XPBasedLevelUpRule::getXpIncrease() const
+{
+    return xpIncrease;
+}
+
+float XPBasedLevelUpRule::getXpMultiplier() const
+{
+    return xpMultiplier;
+}
+
+float XPBasedLevelUpRule::getLevelIncrease() const
+{
+    return levelIncrease;
+}
+
+float XPBasedLevelUpRule::getLevelMultiplier() const
+{
+    return levelMultiplier;
+}
+
+float XPBasedLevelUpRule::getMaxLevel() const
 {
-    hp = 10.f;
-    maxHp = 10.f;
-    durability = 10.f;
-    maxDurability = 10.f;
+    return maxLevel;
+}
+
+XPBasedLevelUpRuleFactory::XPBasedLevelUpRuleFactory()
+    : SubTypeFactory()
+{}
+
+XPBasedLevelUpRule* XPBasedLevelUpRuleFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    float maxLevel;
+    if (zJson->zValue("maxLevel")->getType()
+        == Framework::JSON::JSONType::NULL_)
+    {
+        maxLevel = -1;
+    }
+    else
+    {
+        maxLevel = (float)zJson->zValue("maxLevel")->asNumber()->getNumber();
+    }
+    return new XPBasedLevelUpRule(
+        (float)zJson->zValue("xpIncrease")->asNumber()->getNumber(),
+        (float)zJson->zValue("xpMultiplier")->asNumber()->getNumber(),
+        (float)zJson->zValue("levelIncrease")->asNumber()->getNumber(),
+        (float)zJson->zValue("levelMultiplier")->asNumber()->getNumber(),
+        maxLevel);
+}
+
+Framework::JSON::JSONObject* XPBasedLevelUpRuleFactory::toJson(
+    XPBasedLevelUpRule* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("xpIncrease",
+        new Framework::JSON::JSONNumber(zObject->getXpIncrease()));
+    result->addValue("xpMultiplier",
+        new Framework::JSON::JSONNumber(zObject->getXpMultiplier()));
+    result->addValue("levelIncrease",
+        new Framework::JSON::JSONNumber(zObject->getLevelIncrease()));
+    result->addValue("levelMultiplier",
+        new Framework::JSON::JSONNumber(zObject->getLevelMultiplier()));
+    if (zObject->getMaxLevel() < 0)
+    {
+        result->addValue("maxLevel",
+            new Framework::JSON::JSONNumber(zObject->getMaxLevel()));
+    }
+    else
+    {
+        result->addValue("maxLevel", new Framework::JSON::JSONValue());
+    }
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+XPBasedLevelUpRuleFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredNumber("xpIncrease")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("xpMultiplier")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(2.0)
+        ->finishNumber()
+        ->withRequiredNumber("levelIncrease")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("levelMultiplier")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("maxLevel")
+        ->withDefaultNull()
+        ->whichCanBeNull()
+        ->finishNumber()
+        ->finishObject();
+}
+
+Framework::Text XPBasedLevelUpRuleFactory::getTypeToken() const
+{
+    return "xpBased";
+}
+
+BasicToolItem::BasicToolItem(int itemTypeId, Framework::Text name,
+    float maxHp,
+    float maxDurability)
+    : Item(itemTypeId, name),
+      headMaterialHardness(0.0),
+      rodMaterialHardness(0.0),
+      handleMaterialHardness(0.0)
+{
+    hp = maxHp;
+    this->maxHp = maxHp;
+    durability = maxDurability;
+    this->maxDurability = maxDurability;
+    eatable = 0;
+    placeable = 0;
+    equippable = 0;
+    solid = 1;
     usable = 1;
 }
 
-void BasicToolItem::updateBasedOnUsedMaterial() {
-    float basicDurability = 10.f;
-    float headDurabilityModifier = 1.f;
-    float rodDurabilityModifier = 1.f;
-    // TODO: adjust durability modifier based on material
-    float currentDurability = durability / maxDurability;
-    maxDurability
-        = basicDurability * headDurabilityModifier * rodDurabilityModifier;
-    durability = currentDurability * maxDurability;
+void BasicToolItem::setHeadMaterialHardness(float hardness)
+{
+    headMaterialHardness = hardness;
+}
+
+void BasicToolItem::setRodMaterialHardness(float hardness)
+{
+    rodMaterialHardness = hardness;
+}
+
+void BasicToolItem::setHandleMaterialHardness(float hardness)
+{
+    handleMaterialHardness = hardness;
 }
 
-void BasicToolItem::setHeadMaterial(int headMaterial)
+float BasicToolItem::getHeadMaterialHardness() const
 {
-    this->headMaterial = headMaterial;
+    return headMaterialHardness;
 }
 
-void BasicToolItem::setRodMaterial(int rodMaterial)
+float BasicToolItem::getRodMaterialHardness() const
 {
-    this->rodMaterial = rodMaterial;
+    return rodMaterialHardness;
 }
 
+float BasicToolItem::getHandleMaterialHardness() const
+{
+    return handleMaterialHardness;
+}
 
-BasicToolItemType::BasicToolItemType(int id,
-    const char* name,
+BasicToolItemType::BasicToolItemType(Framework::Text name,
+    ModelInfo* model,
+    float headMaterialHardness,
+    float rodMaterialHardness,
+    float handleMaterialHardness,
+    float baseDurability,
+    float baseDurabilityMultiplier,
+    float headMaterialDurability,
+    float headMaterialDurabilityMultiplier,
+    float rodMaterialDurability,
+    float rodMaterialDurabilityMultiplier,
+    float handleMaterialDurability,
+    float handleMaterialDurabilityMultiplier,
     ItemSkillLevelUpRule* levelUpRule,
-    int brokenTypeId,
-    ModelInfo model)
-    : ItemType(id, name, levelUpRule, brokenTypeId, model)
+    Framework::Text brokenItemTypeName,
+    Framework::JSON::JSONObject* itemSkillConfigJson,
+    int maxStackSize)
+    : ItemType(name, model, maxStackSize),
+      headMaterialHardness(headMaterialHardness),
+      rodMaterialHardness(rodMaterialHardness),
+      handleMaterialHardness(handleMaterialHardness),
+      baseDurability(baseDurability),
+      baseDurabilityMultiplier(baseDurabilityMultiplier),
+      headMaterialDurability(headMaterialDurability),
+      headMaterialDurabilityMultiplier(headMaterialDurabilityMultiplier),
+      rodMaterialDurability(rodMaterialDurability),
+      rodMaterialDurabilityMultiplier(rodMaterialDurabilityMultiplier),
+      handleMaterialDurability(handleMaterialDurability),
+      handleMaterialDurabilityMultiplier(handleMaterialDurabilityMultiplier),
+      levelUpRule(levelUpRule),
+      brokenItemTypeName(brokenItemTypeName),
+      itemSkillConfigJson(itemSkillConfigJson),
+      brokenItemTypeId(-1)
 {}
 
+BasicToolItemType::~BasicToolItemType()
+{
+    levelUpRule->release();
+    itemSkillConfigJson->release();
+}
+
 void BasicToolItemType::loadSuperItem(
     Item* zItem, Framework::StreamReader* zReader) const
 {
-    ItemType::loadSuperItem(zItem, zReader);
     BasicToolItem* item = dynamic_cast<BasicToolItem*>(zItem);
-    zReader->lese((char*)&item->headMaterial, 4);
-    zReader->lese((char*)&item->rodMaterial, 4);
+    float data;
+    zReader->lese((char*)&data, 4);
+    item->setHeadMaterialHardness(data);
+    zReader->lese((char*)&data, 4);
+    item->setRodMaterialHardness(data);
+    zReader->lese((char*)&data, 4);
+    item->setHandleMaterialHardness(data);
+    ItemType::loadSuperItem(item, zReader);
 }
 
 void BasicToolItemType::saveSuperItem(
     const Item* zItem, Framework::StreamWriter* zWriter) const
 {
-    ItemType::saveSuperItem(zItem, zWriter);
     const BasicToolItem* item = dynamic_cast<const BasicToolItem*>(zItem);
-    zWriter->schreibe((char*)&item->headMaterial, 4);
-    zWriter->schreibe((char*)&item->rodMaterial, 4);
+    float data = item->getHeadMaterialHardness();
+    zWriter->schreibe((char*)&data, 4);
+    data = item->getRodMaterialHardness();
+    zWriter->schreibe((char*)&data, 4);
+    data = item->getHandleMaterialHardness();
+    zWriter->schreibe((char*)&data, 4);
+    ItemType::saveSuperItem(item, zWriter);
+}
+
+bool BasicToolItemType::initialize(Game* zGame)
+{
+    brokenItemTypeId = zGame->getItemTypeId(brokenItemTypeName);
+    return brokenItemTypeId >= 0 && ItemType::initialize(zGame);
+}
+
+const ItemType* BasicToolItemType::zBrokenItemType() const
+{
+    return Game::INSTANCE->zItemType(brokenItemTypeId);
+}
+
+Item* BasicToolItemType::createItem() const
+{
+    BasicToolItem* item = new BasicToolItem(getId(),
+        getName(),
+        1.f,
+        (baseDurability + headMaterialDurability * headMaterialHardness
+            + rodMaterialDurability * rodMaterialHardness
+            + handleMaterialDurability * handleMaterialHardness)
+            * (baseDurabilityMultiplier
+                + headMaterialDurabilityMultiplier * headMaterialHardness
+                + rodMaterialDurabilityMultiplier * rodMaterialHardness
+                + handleMaterialDurabilityMultiplier * handleMaterialHardness));
+    item->setHandleMaterialHardness(headMaterialHardness);
+    item->setRodMaterialHardness(rodMaterialHardness);
+    item->setHandleMaterialHardness(handleMaterialHardness);
+    return item;
+}
+
+void BasicToolItemType::levelUpItemSkill(ItemSkill* zSkill) const
+{
+    levelUpRule->applyOn(zSkill);
+}
+
+void BasicToolItemType::setItemAttribute(
+    Item* zItem, Framework::Text name, Framework::JSON::JSONValue* zValue) const
+{
+    BasicToolItem* item = dynamic_cast<BasicToolItem*>(zItem);
+    if (name.istGleich("headMaterialHardness")
+        && zValue->getType() == Framework::JSON::JSONType::NUMBER)
+    {
+        item->setHeadMaterialHardness((float)zValue->asNumber()->getNumber());
+    }
+    else if (name.istGleich("rodMaterialHardness")
+             && zValue->getType() == Framework::JSON::JSONType::NUMBER)
+    {
+        item->setRodMaterialHardness((float)zValue->asNumber()->getNumber());
+    }
+    else if (name.istGleich("handleMaterialHardness")
+             && zValue->getType() == Framework::JSON::JSONType::NUMBER)
+    {
+        item->setHandleMaterialHardness((float)zValue->asNumber()->getNumber());
+    }
+    else
+    {
+        ItemType::setItemAttribute(item, name, zValue);
+    }
+    item->setMaxDurability(
+        (baseDurability
+            + headMaterialDurability * item->getHandleMaterialHardness()
+            + rodMaterialDurability * item->getRodMaterialHardness()
+            + handleMaterialDurability * item->getHandleMaterialHardness())
+        * (baseDurabilityMultiplier
+            + headMaterialDurabilityMultiplier * item->getHeadMaterialHardness()
+            + rodMaterialDurabilityMultiplier * item->getRodMaterialHardness()
+            + handleMaterialDurabilityMultiplier
+                  * item->getHandleMaterialHardness()));
+}
+
+void BasicToolItemType::addItemAttributes(
+    Item* zItem, Framework::JSON::JSONObject* zItemObjet) const
+{
+    BasicToolItem* item = dynamic_cast<BasicToolItem*>(zItem);
+    zItemObjet->addValue("headMaterialHardness",
+        new Framework::JSON::JSONNumber(item->getHeadMaterialHardness()));
+    zItemObjet->addValue("rodMaterialHardness",
+        new Framework::JSON::JSONNumber(item->getRodMaterialHardness()));
+    zItemObjet->addValue("handleMaterialHardness",
+        new Framework::JSON::JSONNumber(item->getHandleMaterialHardness()));
+    ItemType::addItemAttributes(item, zItemObjet);
+}
+
+float BasicToolItemType::getHeadMaterialHardness() const
+{
+    return headMaterialHardness;
+}
+
+float BasicToolItemType::getRodMaterialHardness() const
+{
+    return rodMaterialHardness;
+}
+
+float BasicToolItemType::getHandleMaterialHardness() const
+{
+    return handleMaterialHardness;
+}
+
+float BasicToolItemType::getBaseDurablility() const
+{
+    return baseDurability;
+}
+
+float BasicToolItemType::getBaseDurabilityMultiplier() const
+{
+    return baseDurabilityMultiplier;
+}
+
+float BasicToolItemType::getHeadMaterialDurability() const
+{
+    return headMaterialDurability;
+}
+
+float BasicToolItemType::getHeadMaterialDurabilityMultiplier() const
+{
+    return headMaterialDurabilityMultiplier;
+}
+
+float BasicToolItemType::getRodMaterialDurability() const
+{
+    return rodMaterialDurability;
+}
+
+float BasicToolItemType::getRodMaterialDurabilityMultiplier() const
+{
+    return rodMaterialDurabilityMultiplier;
+}
+
+float BasicToolItemType::getHandleMaterialDurability() const
+{
+    return handleMaterialDurability;
+}
+
+float BasicToolItemType::getHandleMaterialDurabilityMultiplier() const
+{
+    return handleMaterialDurabilityMultiplier;
+}
+
+ItemSkillLevelUpRule* BasicToolItemType::zLevelUpRule() const
+{
+    return levelUpRule;
+}
+
+Framework::JSON::JSONObject* BasicToolItemType::getItemSkillConfigJson() const
+{
+    return dynamic_cast<Framework::JSON::JSONObject*>(
+        itemSkillConfigJson->getThis());
+}
+
+ItemSkill* BasicToolItemType::createDefaultItemSkill() const
+{
+    return Game::INSTANCE->zTypeRegistry()->fromJson<ItemSkill>(
+        itemSkillConfigJson);
+}
+
+BasicToolItemTypeFactory::BasicToolItemTypeFactory() {}
+
+BasicToolItemType* BasicToolItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BasicToolItemType(zJson->zValue("name")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        (float)zJson->zValue("headMaterialHardness")->asNumber()->getNumber(),
+        (float)zJson->zValue("rodMaterialHardness")->asNumber()->getNumber(),
+        (float)zJson->zValue("handleMaterialHardness")->asNumber()->getNumber(),
+        (float)zJson->zValue("baseDurability")->asNumber()->getNumber(),
+        (float)zJson->zValue("baseDurabilityMultiplier")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->zValue("headMaterialDurability")->asNumber()->getNumber(),
+        (float)zJson->zValue("headMaterialDurabilityMultiplier")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->zValue("rodMaterialDurability")->asNumber()->getNumber(),
+        (float)zJson->zValue("rodMaterialDurabilityMultiplier")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->zValue("handleMaterialDurability")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->zValue("handleMaterialDurabilityMultiplier")
+            ->asNumber()
+            ->getNumber(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ItemSkillLevelUpRule>(
+            zJson->zValue("levelUpRule")),
+        zJson->zValue("brokenItemTypeName")->asString()->getString(),
+        zJson->getValue("itemSkill")->asObject(),
+        (int)zJson->zValue("maxStack")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* BasicToolItemTypeFactory::toJson(
+    BasicToolItemType* zObject) const
+{
+    Framework::JSON::JSONObject* json = new Framework::JSON::JSONObject();
+    json->addValue("name", new Framework::JSON::JSONString(zObject->getName()));
+    json->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    json->addValue("headMaterialHardness",
+        new Framework::JSON::JSONNumber(zObject->getHeadMaterialHardness()));
+    json->addValue("rodMaterialHardness",
+        new Framework::JSON::JSONNumber(zObject->getRodMaterialHardness()));
+    json->addValue("handleMaterialHardness",
+        new Framework::JSON::JSONNumber(zObject->getHandleMaterialHardness()));
+    json->addValue("baseDurability",
+        new Framework::JSON::JSONNumber(zObject->getBaseDurablility()));
+    json->addValue("baseDurabilityMultiplier",
+        new Framework::JSON::JSONNumber(
+            zObject->getBaseDurabilityMultiplier()));
+    json->addValue("headMaterialDurability",
+        new Framework::JSON::JSONNumber(zObject->getHeadMaterialDurability()));
+
+    json->addValue("headMaterialDurabilityMultiplier",
+        new Framework::JSON::JSONNumber(
+            zObject->getHeadMaterialDurabilityMultiplier()));
+    json->addValue("rodMaterialDurability",
+        new Framework::JSON::JSONNumber(zObject->getRodMaterialDurability()));
+    json->addValue("rodMaterialDurabilityMultiplier",
+        new Framework::JSON::JSONNumber(
+            zObject->getRodMaterialDurabilityMultiplier()));
+    json->addValue("handleMaterialDurability",
+        new Framework::JSON::JSONNumber(
+            zObject->getHandleMaterialDurability()));
+    json->addValue("handleMaterialDurabilityMultiplier",
+        new Framework::JSON::JSONNumber(
+            zObject->getHandleMaterialDurabilityMultiplier()));
+    json->addValue("levelUpRule",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zLevelUpRule()));
+    json->addValue("brokenItemTypeName",
+        new Framework::JSON::JSONString(zObject->zBrokenItemType()->getName()));
+    json->addValue("itemSkill", zObject->getItemSkillConfigJson());
+    json->addValue("maxStack",
+        new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
+    return json;
+    return nullptr;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BasicToolItemTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("name")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredNumber("headMaterialHardness")
+        ->withDefault(1.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("rodMaterialHardness")
+        ->withDefault(1.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("handleMaterialHardness")
+        ->withDefault(1.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("baseDurability")
+        ->withDefault(10.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("baseDurabilityMultiplier")
+        ->withDefault(1.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("headMaterialDurability")
+        ->withDefault(10.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("headMaterialDurabilityMultiplier")
+        ->withDefault(0.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("rodMaterialDurability")
+        ->withDefault(10.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("rodMaterialDurabilityMultiplier")
+        ->withDefault(0.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("handleMaterialDurability")
+        ->withDefault(10.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("handleMaterialDurabilityMultiplier")
+        ->withDefault(0.0)
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("maxStack")
+        ->withDefault(10)
+        ->whichIsGreaterOrEqual(1)
+        ->finishNumber()
+        ->withRequiredString("brokenItemTypeName")
+        ->finishString()
+        ->withRequiredAttribute("levelUpRule",
+            Game::INSTANCE->zTypeRegistry()
+                ->getValidator<ItemSkillLevelUpRule>())
+        ->withRequiredAttribute("itemSkill",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemSkill>())
+        ->finishObject();
+}
+
+Framework::Text BasicToolItemTypeFactory::getTypeToken() const
+{
+    return "tool";
+}
+
+BlockReplaceItemSkillConfig::BlockReplaceItemSkillConfig(
+    BlockFilter* targetBlockFilter,
+    int replacementBlockTypeId,
+    int cooldownTicks,
+    float staminaCost,
+    float staminaCostDevider,
+    float additionalStaminaCostDeviderPerLevel,
+    float durabilityCost,
+    float durabilityCostDevider,
+    float additionalDurabilityCostDeviderPerLevel,
+    float xpGain)
+    : ReferenceCounter(),
+      targetBlockFilter(targetBlockFilter),
+      replacementBlockTypeId(replacementBlockTypeId),
+      cooldownTicks(cooldownTicks),
+      staminaCost(staminaCost),
+      staminaCostDevider(staminaCostDevider),
+      additionalStaminaCostDeviderPerLevel(
+          additionalStaminaCostDeviderPerLevel),
+      durabilityCost(durabilityCost),
+      durabilityCostDevider(durabilityCostDevider),
+      additionalDurabilityCostDeviderPerLevel(
+          additionalDurabilityCostDeviderPerLevel),
+      xpGain(xpGain)
+{}
+
+BlockReplaceItemSkillConfig::~BlockReplaceItemSkillConfig()
+{
+    if (targetBlockFilter) targetBlockFilter->release();
+}
+
+BlockFilter* BlockReplaceItemSkillConfig::zTargetBlockFilter() const
+{
+    return targetBlockFilter;
+}
+
+int BlockReplaceItemSkillConfig::getReplacementBlockTypeId() const
+{
+    return replacementBlockTypeId;
+}
+
+int BlockReplaceItemSkillConfig::getCooldownTicks() const
+{
+    return cooldownTicks;
+}
+
+float BlockReplaceItemSkillConfig::getStaminaCost() const
+{
+    return staminaCost;
+}
+
+float BlockReplaceItemSkillConfig::getStaminaCostDevider() const
+{
+    return staminaCostDevider;
+}
+
+float BlockReplaceItemSkillConfig::getAdditionalStaminaCostDeviderPerLevel()
+    const
+{
+    return additionalStaminaCostDeviderPerLevel;
+}
+
+float BlockReplaceItemSkillConfig::getDurabilityCost() const
+{
+    return durabilityCost;
+}
+
+float BlockReplaceItemSkillConfig::getDurabilityCostDevider() const
+{
+    return durabilityCostDevider;
+}
+
+float BlockReplaceItemSkillConfig::getAdditionalDurabilityCostDeviderPerLevel()
+    const
+{
+    return additionalDurabilityCostDeviderPerLevel;
+}
+
+float BlockReplaceItemSkillConfig::getXpGain() const
+{
+    return xpGain;
+}
+
+BlockReplaceItemSkillConfigFactory::BlockReplaceItemSkillConfigFactory()
+    : TypeFactory()
+{}
+
+BlockReplaceItemSkillConfig* BlockReplaceItemSkillConfigFactory::fromJson(
+    Framework::JSON::JSONValue* zJson) const
+{
+    return new BlockReplaceItemSkillConfig(
+        Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
+            zJson->asObject()->zValue("targetFilter")),
+        Game::INSTANCE->getBlockTypeId(zJson->asObject()
+                                           ->zValue("replacementBlockType")
+                                           ->asString()
+                                           ->getString()),
+        (int)zJson->asObject()
+            ->zValue("cooldownTicks")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCost")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCostDevider")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("additionalStaminaCostDeviderPerLevel")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("durabilityCost")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("durabilityCostDevider")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("additionalDurabilityCostDeviderPerLevel")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()->zValue("xpGain")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONValue* BlockReplaceItemSkillConfigFactory::toJson(
+    BlockReplaceItemSkillConfig* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("targetFilter",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetBlockFilter()));
+    result->addValue("replacementBlockType",
+        new Framework::JSON::JSONString(
+            Game::INSTANCE->zBlockType(zObject->getReplacementBlockTypeId())
+                ->getName()));
+    result->addValue("cooldownTicks",
+        new Framework::JSON::JSONNumber(zObject->getCooldownTicks()));
+    result->addValue("staminaCost",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCost()));
+    result->addValue("staminaCostDevider",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider()));
+    result->addValue("additionalStaminaCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->getAdditionalStaminaCostDeviderPerLevel()));
+    result->addValue("durabilityCost",
+        new Framework::JSON::JSONNumber(zObject->getDurabilityCost()));
+    result->addValue("durabilityCostDevider",
+        new Framework::JSON::JSONNumber(zObject->getDurabilityCostDevider()));
+    result->addValue("additionalDurabilityCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->getAdditionalDurabilityCostDeviderPerLevel()));
+    result->addValue(
+        "xpGain", new Framework::JSON::JSONNumber(zObject->getXpGain()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BlockReplaceItemSkillConfigFactory::getValidator() const
+{
+    return Framework::JSON::Validator::JSONValidator::buildForObject()
+        ->withRequiredAttribute("targetFilter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
+        ->withRequiredString("replacementBlockType")
+        ->finishString()
+        ->withRequiredNumber("cooldownTicks")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(20)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCost")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCostDevider")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(0.8)
+        ->finishNumber()
+        ->withRequiredNumber("additionalStaminaCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(0.2)
+        ->finishNumber()
+        ->withRequiredNumber("durabilityCost")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("durabilityCostDevider")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(0.98)
+        ->finishNumber()
+        ->withRequiredNumber("additionalDurabilityCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(0.02)
+        ->finishNumber()
+        ->withRequiredNumber("xpGain")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->finishObject();
+}
+
+BlockReplaceItemSkill::BlockReplaceItemSkill(float xp,
+    float maxXp,
+    float level,
+    BlockReplaceItemSkillConfig* invalidUseConfig,
+    Framework::RCArray<BlockReplaceItemSkillConfig> configs,
+    int cooldownTicks)
+    : ItemSkill(xp, maxXp, level),
+      invalidUseConfig(invalidUseConfig),
+      configs(configs),
+      cooldownTicks(cooldownTicks)
+{}
+
+void BlockReplaceItemSkill::load(Framework::StreamReader* zReader)
+{
+    zReader->lese((char*)&cooldownTicks, 4);
+    ItemSkill::load(zReader);
+}
+
+void BlockReplaceItemSkill::save(Framework::StreamWriter* zWriter)
+{
+    zWriter->schreibe((char*)&cooldownTicks, 4);
+    ItemSkill::save(zWriter);
+}
+
+bool BlockReplaceItemSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
+{
+    if (cooldownTicks > 0)
+    {
+        cooldownTicks--;
+        return false;
+    }
+    BlockReplaceItemSkillConfig* usedConfig = 0;
+    for (BlockReplaceItemSkillConfig* config : configs)
+    {
+        if (config->zTargetBlockFilter()->test(zTarget))
+        {
+            usedConfig = config;
+            break;
+        }
+    }
+    bool invalid = 0;
+    if (usedConfig == 0)
+    {
+        usedConfig = invalidUseConfig;
+        invalid = 1;
+    }
+    float staminaDevider
+        = usedConfig->getStaminaCostDevider()
+        + usedConfig->getAdditionalStaminaCostDeviderPerLevel() * getLevel();
+    float staminaCost = usedConfig->getStaminaCost();
+    if (staminaDevider != 0)
+    {
+        staminaCost /= staminaDevider;
+    }
+    if (zActor->getStamina() < staminaCost)
+    {
+        return false;
+    }
+    float durabilityDevider
+        = usedConfig->getDurabilityCostDevider()
+        + usedConfig->getAdditionalDurabilityCostDeviderPerLevel() * getLevel();
+    float durabilityCost = usedConfig->getDurabilityCost();
+    if (durabilityDevider != 0)
+    {
+        durabilityCost /= durabilityDevider;
+    }
+    zUsedItem->setDurability(zUsedItem->getDurability() - durabilityCost);
+    zActor->setStamina(zActor->getStamina() - staminaCost);
+    cooldownTicks = usedConfig->getCooldownTicks();
+    setXp(getXp() + usedConfig->getXpGain());
+    if (!invalid)
+    {
+        Vec3<int> pos = zTarget->getPos();
+        int dimension = zTarget->getDimensionId();
+        Game::INSTANCE->doLater([pos, dimension, usedConfig]() {
+            Game::INSTANCE->zDimension(dimension)->placeBlock(
+                pos, usedConfig->getReplacementBlockTypeId());
+        });
+    }
+    return true;
+}
+
+bool BlockReplaceItemSkill::use(
+    Entity* zActor, Item* zUsedItem, Entity* zTarget)
+{
+    return false;
+}
+
+BlockReplaceItemSkillConfig* BlockReplaceItemSkill::zInvalidUseConfig() const
+{
+    return invalidUseConfig;
+}
+
+const Framework::RCArray<BlockReplaceItemSkillConfig>&
+BlockReplaceItemSkill::getConfigs() const
+{
+    return configs;
+}
+
+int BlockReplaceItemSkill::getCooldownTicks() const
+{
+    return cooldownTicks;
+}
+
+BlockReplaceItemSkillFactory::BlockReplaceItemSkillFactory()
+    : SubTypeFactory()
+{}
+
+BlockReplaceItemSkill* BlockReplaceItemSkillFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<BlockReplaceItemSkillConfig> configs;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("configs")->asArray())
+    {
+        configs.add(Game::INSTANCE->zTypeRegistry()
+                        ->fromJson<BlockReplaceItemSkillConfig>(value));
+    }
+    return new BlockReplaceItemSkill(0,
+        (float)zJson->zValue("maxXp")->asNumber()->getNumber(),
+        1,
+        new BlockReplaceItemSkillConfig(0,
+            0,
+            0,
+            (float)zJson->zValue("invalidStaminaCost")->asNumber()->getNumber(),
+            (float)zJson->zValue("invalidStaminaCostDevider")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidAdditionalStaminaCostDeviderPerLevel")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidDurabilityCost")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidDurabilityCostDevider")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson
+                ->zValue("invalidAdditionalDurabilityCostDeviderPerLevel")
+                ->asNumber()
+                ->getNumber(),
+            0.f),
+        configs,
+        (int)zJson->zValue("cooldownTicks")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* BlockReplaceItemSkillFactory::toJson(
+    BlockReplaceItemSkill* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "maxXp", new Framework::JSON::JSONNumber(zObject->getMaxXp()));
+    result->addValue("invalidStaminaCost",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCost()));
+    result->addValue("invalidStaminaCostDevider",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCostDevider()));
+    result->addValue("invalidAdditionalStaminaCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()
+                ->getAdditionalStaminaCostDeviderPerLevel()));
+    result->addValue("invalidDurabilityCost",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getDurabilityCost()));
+    result->addValue("invalidDurabilityCostDevider",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getDurabilityCostDevider()));
+    result->addValue("invalidAdditionalDurabilityCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()
+                ->getAdditionalDurabilityCostDeviderPerLevel()));
+    result->addValue("invalidXpGain",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getXpGain()));
+    result->addValue("invalidCooldownTicks",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getCooldownTicks()));
+    Framework::JSON::JSONArray* configs = new Framework::JSON::JSONArray();
+    for (BlockReplaceItemSkillConfig* config : zObject->getConfigs())
+    {
+        configs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(config));
+    }
+    result->addValue("configs", configs);
+    result->addValue("cooldownTicks",
+        new Framework::JSON::JSONNumber(zObject->getCooldownTicks()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BlockReplaceItemSkillFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredNumber("maxXp")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(10.0)
+        ->finishNumber()
+        ->withRequiredNumber("invalidStaminaCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("invalidStaminaCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.8)
+        ->finishNumber()
+        ->withRequiredNumber("invalidAdditionalStaminaCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.2)
+        ->finishNumber()
+        ->withRequiredNumber("invalidDurabilityCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("invalidDurabilityCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.98)
+        ->finishNumber()
+        ->withRequiredNumber("invalidAdditionalDurabilityCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.02)
+        ->finishNumber()
+        ->withRequiredArray("configs")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()
+                ->getValidator<BlockReplaceItemSkillConfig>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text BlockReplaceItemSkillFactory::getTypeToken() const
+{
+    return "replaceBlock";
+}
+
+DamagingItemSkillConfig::DamagingItemSkillConfig(BlockFilter* targetBlockFilter,
+    float damage,
+    float damagePerHeadHardness,
+    float baseDamageMultiplier,
+    float damageMupliplierPerHeadHardness,
+    float damagePerLevel,
+    float damageMultiplierPerLevel,
+    float damageDevider,
+    float damageDeviderPerHardness,
+    float staminaCost,
+    float staminaCostPerDamage,
+    float staminaCostPerHardness,
+    float staminaCostDevider,
+    float staminaCostDeviderPerLevel,
+    float durabilityCost,
+    float durabilityCostPerDamage,
+    float durabilityCostPerHardness,
+    float durabilityCostDevider,
+    float additionalDurabilityCostDeviderPerLevel,
+    float xpGainPerDamage)
+    : ReferenceCounter(),
+      targetBlockFilter(targetBlockFilter),
+      damage(damage),
+      damagePerHeadHardness(damagePerHeadHardness),
+      baseDamageMultiplier(baseDamageMultiplier),
+      damageMupliplierPerHeadHardness(damageMupliplierPerHeadHardness),
+      damagePerLevel(damagePerLevel),
+      damageMultiplierPerLevel(damageMultiplierPerLevel),
+      damageDevider(damageDevider),
+      damageDeviderPerHardness(damageDeviderPerHardness),
+      staminaCost(staminaCost),
+      staminaCostPerDamage(staminaCostPerDamage),
+      staminaCostPerHardness(staminaCostPerHardness),
+      staminaCostDevider(staminaCostDevider),
+      staminaCostDeviderPerLevel(staminaCostDeviderPerLevel),
+      durabilityCost(durabilityCost),
+      durabilityCostPerDamage(durabilityCostPerDamage),
+      durabilityCostPerHardness(durabilityCostPerHardness),
+      durabilityCostDevider(durabilityCostDevider),
+      additionalDurabilityCostDeviderPerLevel(
+          additionalDurabilityCostDeviderPerLevel),
+      xpGainPerDamage(xpGainPerDamage)
+{}
+
+DamagingItemSkillConfig::~DamagingItemSkillConfig()
+{
+    if (targetBlockFilter) targetBlockFilter->release();
+}
+
+BlockFilter* DamagingItemSkillConfig::zTargetBlockFilter() const
+{
+    return targetBlockFilter;
+}
+
+float DamagingItemSkillConfig::getDamage() const
+{
+    return damage;
+}
+
+float DamagingItemSkillConfig::getDamagePerHeadHardness() const
+{
+    return damageDeviderPerHardness;
+}
+
+float DamagingItemSkillConfig::getBaseDamageMultiplier() const
+{
+    return baseDamageMultiplier;
+}
+
+float DamagingItemSkillConfig::getDamageMupliplierPerHeadHardness() const
+{
+    return damageMupliplierPerHeadHardness;
+}
+
+float DamagingItemSkillConfig::getDamagePerLevel() const
+{
+    return damagePerLevel;
+}
+
+float DamagingItemSkillConfig::getDamageMultiplierPerLevel() const
+{
+    return damageMultiplierPerLevel;
+}
+
+float DamagingItemSkillConfig::getDamageDevider() const
+{
+    return damageDevider;
+}
+
+float DamagingItemSkillConfig::getDamageDeviderPerHardness() const
+{
+    return damageDeviderPerHardness;
+}
+
+float DamagingItemSkillConfig::getStaminaCost() const
+{
+    return staminaCost;
+}
+
+float DamagingItemSkillConfig::getStaminaCostPerDamage() const
+{
+    return staminaCostPerDamage;
+}
+
+float DamagingItemSkillConfig::getStaminaCostPerHardness() const
+{
+    return staminaCostPerHardness;
+}
+
+float DamagingItemSkillConfig::getStaminaCostDevider() const
+{
+    return staminaCostDevider;
+}
+
+float DamagingItemSkillConfig::getStaminaCostDeviderPerLevel() const
+{
+    return staminaCostDeviderPerLevel;
+}
+
+float DamagingItemSkillConfig::getDurabilityCost() const
+{
+    return durabilityCost;
+}
+
+float DamagingItemSkillConfig::getDurabilityCostPerDamage() const
+{
+    return durabilityCostPerDamage;
+}
+
+float DamagingItemSkillConfig::getDurabilityCostPerHardness() const
+{
+    return durabilityCostPerHardness;
+}
+
+float DamagingItemSkillConfig::getDurabilityCostDevider() const
+{
+    return durabilityCostDevider;
+}
+
+float DamagingItemSkillConfig::getAdditionalDurabilityCostDeviderPerLevel()
+    const
+{
+    return additionalDurabilityCostDeviderPerLevel;
+}
+
+float DamagingItemSkillConfig::getXpGainPerDamage() const
+{
+    return xpGainPerDamage;
+}
+
+DamagingItemSkillConfigFactory::DamagingItemSkillConfigFactory()
+    : TypeFactory()
+{}
+
+DamagingItemSkillConfig* DamagingItemSkillConfigFactory::fromJson(
+    Framework::JSON::JSONValue* zJson) const
+{
+    return new DamagingItemSkillConfig(
+        Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
+            zJson->asObject()->zValue("targetFilter")),
+        (float)zJson->asObject()->zValue("damage")->asNumber()->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("damagePerHeadHardness")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("baseDamageMultiplier")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("damageMupliplierPerHeadHardness")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("damagePerLevel")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("damageMultiplierPerLevel")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("damageDevider")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("damageDeviderPerHardness")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCost")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCostPerDamage")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCostPerHardness")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCostDevider")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCostDeviderPerLevel")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("durabilityCost")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("durabilityCostPerDamage")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("durabilityCostPerHardness")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("durabilityCostDevider")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("additionalDurabilityCostDeviderPerLevel")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("xpGainPerDamage")
+            ->asNumber()
+            ->getNumber());
+}
+
+Framework::JSON::JSONValue* DamagingItemSkillConfigFactory::toJson(
+    DamagingItemSkillConfig* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("targetFilter",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetBlockFilter()));
+    result->addValue(
+        "damage", new Framework::JSON::JSONNumber(zObject->getDamage()));
+    result->addValue("damagePerHeadHardness",
+        new Framework::JSON::JSONNumber(zObject->getDamagePerHeadHardness()));
+    result->addValue("baseDamageMultiplier",
+        new Framework::JSON::JSONNumber(zObject->getBaseDamageMultiplier()));
+    result->addValue("damageMupliplierPerHeadHardness",
+        new Framework::JSON::JSONNumber(
+            zObject->getDamageMupliplierPerHeadHardness()));
+    result->addValue("damagePerLevel",
+        new Framework::JSON::JSONNumber(zObject->getDamagePerLevel()));
+    result->addValue("damageMultiplierPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->getDamageMultiplierPerLevel()));
+    result->addValue("damageDevider",
+        new Framework::JSON::JSONNumber(zObject->getDamageDevider()));
+    result->addValue("damageDeviderPerHardness",
+        new Framework::JSON::JSONNumber(
+            zObject->getDamageDeviderPerHardness()));
+    result->addValue("staminaCost",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCost()));
+    result->addValue("staminaCostPerDamage",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCostPerDamage()));
+    result->addValue("staminaCostPerHardness",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCostPerHardness()));
+    result->addValue("staminaCostDevider",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider()));
+    result->addValue("staminaCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->getStaminaCostDeviderPerLevel()));
+    result->addValue("durabilityCost",
+        new Framework::JSON::JSONNumber(zObject->getDurabilityCost()));
+    result->addValue("durabilityCostPerDamage",
+        new Framework::JSON::JSONNumber(zObject->getDurabilityCostPerDamage()));
+    result->addValue("durabilityCostPerHardness",
+        new Framework::JSON::JSONNumber(
+            zObject->getDurabilityCostPerHardness()));
+    result->addValue("durabilityCostDevider",
+        new Framework::JSON::JSONNumber(zObject->getDurabilityCostDevider()));
+    result->addValue("additionalDurabilityCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->getAdditionalDurabilityCostDeviderPerLevel()));
+    result->addValue("xpGainPerDamage",
+        new Framework::JSON::JSONNumber(zObject->getXpGainPerDamage()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+DamagingItemSkillConfigFactory::getValidator() const
+{
+    return Framework::JSON::Validator::JSONValidator::buildForObject()
+        ->withRequiredAttribute("targetFilter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
+        ->withRequiredNumber("damage")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(2.0)
+        ->finishNumber()
+        ->withRequiredNumber("damagePerHeadHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("baseDamageMultiplier")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("damageMupliplierPerHeadHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("damagePerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.3)
+        ->finishNumber()
+        ->withRequiredNumber("damageMultiplierPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("damageDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("damageDeviderPerHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0001)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCostPerDamage")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.00001)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCostPerHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.001)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.9)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.1)
+        ->finishNumber()
+        ->withRequiredNumber("durabilityCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.1)
+        ->finishNumber()
+        ->withRequiredNumber("durabilityCostPerDamage")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.01)
+        ->finishNumber()
+        ->withRequiredNumber("durabilityCostPerHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.01)
+        ->finishNumber()
+        ->withRequiredNumber("durabilityCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.8)
+        ->finishNumber()
+        ->withRequiredNumber("additionalDurabilityCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.2)
+        ->finishNumber()
+        ->withRequiredNumber("xpGainPerDamage")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.05)
+        ->finishNumber()
+        ->finishObject();
+}
+
+DamagingItemSkill::DamagingItemSkill(float xp,
+    float maxXp,
+    float level,
+    DamagingItemSkillConfig* invalidUseConfig,
+    Framework::RCArray<DamagingItemSkillConfig> configs)
+    : ItemSkill(xp, maxXp, level)
+{}
+
+bool DamagingItemSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
+{
+    BasicToolItem* tool = dynamic_cast<BasicToolItem*>(zUsedItem);
+    DamagingItemSkillConfig* usedConfig = 0;
+    for (DamagingItemSkillConfig* config : configs)
+    {
+        if (config->zTargetBlockFilter()->test(zTarget))
+        {
+            usedConfig = config;
+            break;
+        }
+    }
+    bool invalid = 0;
+    if (usedConfig == 0)
+    {
+        usedConfig = invalidUseConfig;
+        invalid = 1;
+    }
+    float damage = usedConfig->getDamage()
+                 + usedConfig->getDamagePerHeadHardness()
+                       * (tool ? tool->getHeadMaterialHardness() : 0)
+                 + usedConfig->getDamagePerLevel() * getLevel();
+    float damageMultiplier
+        = usedConfig->getBaseDamageMultiplier()
+        + usedConfig->getDamageMultiplierPerLevel() * getLevel()
+        + usedConfig->getDamageMupliplierPerHeadHardness()
+              * (tool ? tool->getHeadMaterialHardness() : 0);
+    if (damageMultiplier != 0)
+    {
+        damage *= damageMultiplier;
+    }
+    float damageDevider
+        = usedConfig->getDamageDevider()
+        + usedConfig->getDamageDeviderPerHardness() * zTarget->getHardness();
+    if (damageDevider != 0)
+    {
+        damage /= damageDevider;
+    }
+    float staminaCost
+        = usedConfig->getStaminaCost()
+        + usedConfig->getStaminaCostPerDamage() * damage
+        + usedConfig->getStaminaCostPerHardness() * zTarget->getHardness();
+    float staminaDevider
+        = usedConfig->getStaminaCostDevider()
+        + usedConfig->getStaminaCostDeviderPerLevel() * getLevel();
+    if (staminaDevider != 0)
+    {
+        staminaCost /= staminaDevider;
+    }
+    if (zActor->getStamina() < staminaCost)
+    {
+        return false;
+    }
+    float durabilityCost
+        = usedConfig->getDurabilityCost()
+        + usedConfig->getDurabilityCostPerDamage() * damage
+        + usedConfig->getDurabilityCostPerHardness() * zTarget->getHardness();
+    float durabilityDevider
+        = usedConfig->getDurabilityCostDevider()
+        + usedConfig->getAdditionalDurabilityCostDeviderPerLevel() * getLevel();
+    if (durabilityDevider != 0)
+    {
+        durabilityCost /= durabilityDevider;
+    }
+    zUsedItem->setDurability(zUsedItem->getDurability() - durabilityCost);
+    zActor->setStamina(zActor->getStamina() - staminaCost);
+    setXp(getXp() + usedConfig->getXpGainPerDamage() * damage);
+    zTarget->setHP(zTarget->getHP() - damage);
+    return true;
+}
+
+bool DamagingItemSkill::use(Entity* zActor, Item* zUsedItem, Entity* zTarget)
+{
+    return false;
+}
+
+DamagingItemSkillConfig* DamagingItemSkill::zInvalidUseConfig() const
+{
+    return invalidUseConfig;
+}
+
+const Framework::RCArray<DamagingItemSkillConfig>&
+DamagingItemSkill::getConfigs() const
+{
+    return configs;
+}
+
+DamagingItemSkillFactory::DamagingItemSkillFactory()
+    : SubTypeFactory()
+{}
+
+DamagingItemSkill* DamagingItemSkillFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<DamagingItemSkillConfig> configs;
+    for (Framework::JSON::JSONValue* configValue :
+        *zJson->zValue("configs")->asArray())
+    {
+        configs.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<DamagingItemSkillConfig>(
+                configValue));
+    }
+    return new DamagingItemSkill(0.f,
+        (float)zJson->zValue("maxXp")->asNumber()->getNumber(),
+        1.f,
+        new DamagingItemSkillConfig(0,
+            0.f,
+            0.f,
+            0.f,
+            0.f,
+            0.f,
+            0.f,
+            1.f,
+            0.f,
+            (float)zJson->zValue("invalidStaminaCost")->asNumber()->getNumber(),
+            0.f,
+            (float)zJson->zValue("invalidStaminaCostPerHardness")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidStaminaCostDevider")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidStaminaCostDeviderPerLevel")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidDurabilityCost")
+                ->asNumber()
+                ->getNumber(),
+            0.f,
+            (float)zJson->zValue("invalidDurabilityCostPerHardness")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidDurabilityCostDevider")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidDurabilityCostDeviderPerLevel")
+                ->asNumber()
+                ->getNumber(),
+            0.f),
+        configs);
+}
+
+Framework::JSON::JSONObject* DamagingItemSkillFactory::toJson(
+    DamagingItemSkill* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "maxXp", new Framework::JSON::JSONNumber(zObject->getMaxXp()));
+    result->addValue("invalidStaminaCost",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCost()));
+    result->addValue("invalidStaminaCostPerHardness",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCostPerHardness()));
+    result->addValue("invalidStaminaCostDevider",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCostDevider()));
+    result->addValue("invalidStaminaCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCostDeviderPerLevel()));
+    result->addValue("invalidDurabilityCost",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getDurabilityCost()));
+    result->addValue("invalidDurabilityCostPerHardness",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getDurabilityCostPerHardness()));
+    result->addValue("invalidDurabilityCostDevider",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getDurabilityCostDevider()));
+    result->addValue("invalidDurabilityCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()
+                ->getAdditionalDurabilityCostDeviderPerLevel()));
+    Framework::JSON::JSONArray* configs = new Framework::JSON::JSONArray();
+    for (DamagingItemSkillConfig* config : zObject->getConfigs())
+    {
+        configs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(config));
+    }
+    result->addValue("configs", configs);
+    return nullptr;
+}
+
+Framework::JSON::Validator::JSONValidator*
+DamagingItemSkillFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredNumber("maxXp")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(10.0)
+        ->finishNumber()
+        ->withRequiredNumber("invalidStaminaCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("invalidStaminaCostPerHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.001)
+        ->finishNumber()
+        ->withRequiredNumber("invalidStaminaCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.8)
+        ->finishNumber()
+        ->withRequiredNumber("invalidAdditionalStaminaCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.2)
+        ->finishNumber()
+        ->withRequiredNumber("invalidDurabilityCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("invalidDurabilityCostPerHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.01)
+        ->finishNumber()
+        ->withRequiredNumber("invalidDurabilityCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.98)
+        ->finishNumber()
+        ->withRequiredNumber("invalidAdditionalDurabilityCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.02)
+        ->finishNumber()
+        ->withRequiredArray("configs")
+        ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                                     ->getValidator<DamagingItemSkillConfig>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text DamagingItemSkillFactory::getTypeToken() const
+{
+    return "damaging";
 }

+ 332 - 16
FactoryCraft/BasicTool.h

@@ -1,37 +1,353 @@
 #pragma once
 
 #include "BasicItems.h"
+#include "BlockFilter.h"
 #include "Item.h"
+#include "ItemSkill.h"
 
 class BasicToolItemType;
 
-class BasicToolItem : public Item
+class XPBasedLevelUpRule : public ItemSkillLevelUpRule
 {
 private:
-    int headMaterial;
-    int rodMaterial;
+    float xpIncrease;
+    float xpMultiplier;
+    float levelIncrease;
+    float levelMultiplier;
+    float maxLevel;
 
-protected:
-    virtual void updateBasedOnUsedMaterial();
+public:
+    XPBasedLevelUpRule(float xpIncrease,
+        float xpMultiplier,
+        float levelIncrease,
+        float levelMultiplier,
+        float maxLevel);
+    virtual void applyOn(ItemSkill* zSkill) override;
+    float getXpIncrease() const;
+    float getXpMultiplier() const;
+    float getLevelIncrease() const;
+    float getLevelMultiplier() const;
+    float getMaxLevel() const;
+};
 
+class XPBasedLevelUpRuleFactory
+    : public SubTypeFactory<ItemSkillLevelUpRule, XPBasedLevelUpRule>
+{
 public:
-    BasicToolItem(int itemTypeId, const char* name);
-    void setHeadMaterial(int headMaterial);
-    void setRodMaterial(int rodMaterial);
+    XPBasedLevelUpRuleFactory();
+    XPBasedLevelUpRule* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        XPBasedLevelUpRule* 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 BasicToolItem : public Item
+{
+private:
+    float headMaterialHardness;
+    float rodMaterialHardness;
+    float handleMaterialHardness;
 
-    friend BasicToolItemType;
+public:
+    BasicToolItem(int itemTypeId,
+        Framework::Text name,
+        float maxHp,
+        float maxDurability);
+    void setHeadMaterialHardness(float hardness);
+    void setRodMaterialHardness(float hardness);
+    void setHandleMaterialHardness(float hardness);
+    float getHeadMaterialHardness() const;
+    float getRodMaterialHardness() const;
+    float getHandleMaterialHardness() const;
 };
 
 class BasicToolItemType : public ItemType
 {
-protected:
-    BasicToolItemType(int id,
-        const char* name,
+private:
+    float headMaterialHardness;
+    float rodMaterialHardness;
+    float handleMaterialHardness;
+    float baseDurability;
+    float baseDurabilityMultiplier;
+    float headMaterialDurability;
+    float headMaterialDurabilityMultiplier;
+    float rodMaterialDurability;
+    float rodMaterialDurabilityMultiplier;
+    float handleMaterialDurability;
+    float handleMaterialDurabilityMultiplier;
+    ItemSkillLevelUpRule* levelUpRule;
+    int brokenItemTypeId;
+    Framework::Text brokenItemTypeName;
+    Framework::JSON::JSONObject* itemSkillConfigJson;
+
+public:
+    BasicToolItemType(Framework::Text name,
+        ModelInfo* model,
+        float headMaterialHardness,
+        float rodMaterialHardness,
+        float handleMaterialHardness,
+        float baseDurability,
+        float baseDurabilityMultiplier,
+        float headMaterialDurability,
+        float headMaterialDurabilityMultiplier,
+        float rodMaterialDurability,
+        float rodMaterialDurabilityMultiplier,
+        float handleMaterialDurability,
+        float handleMaterialDurabilityMultiplier,
         ItemSkillLevelUpRule* levelUpRule,
-        int brokenTypeId,
-        ModelInfo model);
+        Framework::Text brokenItemTypeName,
+        Framework::JSON::JSONObject* itemSkillConfigJson,
+        int maxStackSize);
+    ~BasicToolItemType();
+
+protected:
     virtual void loadSuperItem(
-        Item* zItem, Framework::StreamReader* zReader) const;
+        Item* zItem, Framework::StreamReader* zReader) const override;
     virtual void saveSuperItem(
-        const Item* zItem, Framework::StreamWriter* zWriter) const;
+        const Item* zItem, Framework::StreamWriter* zWriter) const override;
+
+public:
+    virtual bool initialize(Game* zGame) override;
+    virtual const ItemType* zBrokenItemType() const override;
+    virtual Item* createItem() const override;
+    virtual void levelUpItemSkill(ItemSkill* zSkill) const override;
+    virtual void setItemAttribute(Item* zItem,
+        Framework::Text name,
+        Framework::JSON::JSONValue* zValue) const override;
+    virtual void addItemAttributes(
+        Item* zItem, Framework::JSON::JSONObject* zItemObjet) const override;
+    float getHeadMaterialHardness() const;
+    float getRodMaterialHardness() const;
+    float getHandleMaterialHardness() const;
+    float getBaseDurablility() const;
+    float getBaseDurabilityMultiplier() const;
+    float getHeadMaterialDurability() const;
+    float getHeadMaterialDurabilityMultiplier() const;
+    float getRodMaterialDurability() const;
+    float getRodMaterialDurabilityMultiplier() const;
+    float getHandleMaterialDurability() const;
+    float getHandleMaterialDurabilityMultiplier() const;
+    ItemSkillLevelUpRule* zLevelUpRule() const;
+    Framework::JSON::JSONObject* getItemSkillConfigJson() const;
+    virtual ItemSkill* createDefaultItemSkill() const override;
+};
+
+class BasicToolItemTypeFactory
+    : public SubTypeFactory<ItemType, BasicToolItemType>
+{
+public:
+    BasicToolItemTypeFactory();
+    BasicToolItemType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BasicToolItemType* 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 BlockReplaceItemSkillConfig : public Framework::ReferenceCounter
+{
+private:
+    BlockFilter* targetBlockFilter;
+    int replacementBlockTypeId;
+    int cooldownTicks;
+    float staminaCost;
+    float staminaCostDevider;
+    float additionalStaminaCostDeviderPerLevel;
+    float durabilityCost;
+    float durabilityCostDevider;
+    float additionalDurabilityCostDeviderPerLevel;
+    float xpGain;
+
+public:
+    BlockReplaceItemSkillConfig(BlockFilter* targetBlockFilter,
+        int replacementBlockTypeId,
+        int cooldownTicks,
+        float staminaCost,
+        float staminaCostDevider,
+        float additionalStaminaCostDeviderPerLevel,
+        float durabilityCost,
+        float durabilityCostDevider,
+        float additionalDurabilityCostDeviderPerLevel,
+        float xpGain);
+    ~BlockReplaceItemSkillConfig();
+    BlockFilter* zTargetBlockFilter() const;
+    int getReplacementBlockTypeId() const;
+    int getCooldownTicks() const;
+    float getStaminaCost() const;
+    float getStaminaCostDevider() const;
+    float getAdditionalStaminaCostDeviderPerLevel() const;
+    float getDurabilityCost() const;
+    float getDurabilityCostDevider() const;
+    float getAdditionalDurabilityCostDeviderPerLevel() const;
+    float getXpGain() const;
+};
+
+class BlockReplaceItemSkillConfigFactory
+    : public TypeFactory<BlockReplaceItemSkillConfig>
+{
+public:
+    BlockReplaceItemSkillConfigFactory();
+    BlockReplaceItemSkillConfig* fromJson(
+        Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(
+        BlockReplaceItemSkillConfig* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator() const override;
+};
+
+class BlockReplaceItemSkill : public ItemSkill
+{
+private:
+    BlockReplaceItemSkillConfig* invalidUseConfig;
+    Framework::RCArray<BlockReplaceItemSkillConfig> configs;
+    int cooldownTicks;
+
+public:
+    BlockReplaceItemSkill(float xp,
+        float maxXp,
+        float level,
+        BlockReplaceItemSkillConfig* invalidUseConfig,
+        Framework::RCArray<BlockReplaceItemSkillConfig> configs,
+        int cooldownTicks);
+    virtual void load(Framework::StreamReader* zReader) override;
+    virtual void save(Framework::StreamWriter* zWriter) override;
+    virtual bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) override;
+    virtual bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
+    BlockReplaceItemSkillConfig* zInvalidUseConfig() const;
+    const Framework::RCArray<BlockReplaceItemSkillConfig>& getConfigs() const;
+    int getCooldownTicks() const;
+};
+
+class BlockReplaceItemSkillFactory
+    : public SubTypeFactory<ItemSkill, BlockReplaceItemSkill>
+{
+public:
+    BlockReplaceItemSkillFactory();
+    BlockReplaceItemSkill* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BlockReplaceItemSkill* 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 DamagingItemSkillConfig : public Framework::ReferenceCounter
+{
+private:
+    BlockFilter* targetBlockFilter;
+    float damage;
+    float damagePerHeadHardness;
+    float baseDamageMultiplier;
+    float damageMupliplierPerHeadHardness;
+    float damagePerLevel;
+    float damageMultiplierPerLevel;
+    float damageDevider;
+    float damageDeviderPerHardness;
+    float staminaCost;
+    float staminaCostPerDamage;
+    float staminaCostPerHardness;
+    float staminaCostDevider;
+    float staminaCostDeviderPerLevel;
+    float durabilityCost;
+    float durabilityCostPerDamage;
+    float durabilityCostPerHardness;
+    float durabilityCostDevider;
+    float additionalDurabilityCostDeviderPerLevel;
+    float xpGainPerDamage;
+
+public:
+    DamagingItemSkillConfig(BlockFilter* targetBlockFilter,
+        float damage,
+        float damagePerHeadHardness,
+        float baseDamageMultiplier,
+        float damageMupliplierPerHeadHardness,
+        float damagePerLevel,
+        float damageMultiplierPerLevel,
+        float damageDevider,
+        float damageDeviderPerHardness,
+        float staminaCost,
+        float staminaCostPerDamage,
+        float staminaCostPerHardness,
+        float staminaCostDevider,
+        float staminaCostDeviderPerLevel,
+        float durabilityCost,
+        float durabilityCostPerDamage,
+        float durabilityCostPerHardness,
+        float durabilityCostDevider,
+        float additionalDurabilityCostDeviderPerLevel,
+        float xpGainPerDamage);
+    ~DamagingItemSkillConfig();
+    BlockFilter* zTargetBlockFilter() const;
+    float getDamage() const;
+    float getDamagePerHeadHardness() const;
+    float getBaseDamageMultiplier() const;
+    float getDamageMupliplierPerHeadHardness() const;
+    float getDamagePerLevel() const;
+    float getDamageMultiplierPerLevel() const;
+    float getDamageDevider() const;
+    float getDamageDeviderPerHardness() const;
+    float getStaminaCost() const;
+    float getStaminaCostPerDamage() const;
+    float getStaminaCostPerHardness() const;
+    float getStaminaCostDevider() const;
+    float getStaminaCostDeviderPerLevel() const;
+    float getDurabilityCost() const;
+    float getDurabilityCostPerDamage() const;
+    float getDurabilityCostPerHardness() const;
+    float getDurabilityCostDevider() const;
+    float getAdditionalDurabilityCostDeviderPerLevel() const;
+    float getXpGainPerDamage() const;
+};
+
+class DamagingItemSkillConfigFactory
+    : public TypeFactory<DamagingItemSkillConfig>
+{
+public:
+    DamagingItemSkillConfigFactory();
+    DamagingItemSkillConfig* fromJson(
+        Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(
+        DamagingItemSkillConfig* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator() const override;
+};
+
+class DamagingItemSkill : public ItemSkill
+{
+private:
+    DamagingItemSkillConfig* invalidUseConfig;
+    Framework::RCArray<DamagingItemSkillConfig> configs;
+
+public:
+    DamagingItemSkill(float xp,
+        float maxXp,
+        float level,
+        DamagingItemSkillConfig* invalidUseConfig,
+        Framework::RCArray<DamagingItemSkillConfig> configs);
+    virtual bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) override;
+    virtual bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
+    DamagingItemSkillConfig* zInvalidUseConfig() const;
+    const Framework::RCArray<DamagingItemSkillConfig>& getConfigs() const;
+};
+
+class DamagingItemSkillFactory
+    : public SubTypeFactory<ItemSkill, DamagingItemSkill>
+{
+public:
+    DamagingItemSkillFactory();
+    DamagingItemSkill* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        DamagingItemSkill* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 176 - 78
FactoryCraft/Block.cpp

@@ -6,12 +6,10 @@
 #include "ItemEntity.h"
 #include "MultiblockStructure.h"
 #include "NoBlock.h"
+#include "PlaceableProof.h"
 
-Block::Block(int typeId,
-    const ItemType* zTool,
-    Framework::Vec3<int> pos,
-    int dimensionId,
-    bool hasInventory)
+Block::Block(
+    int typeId, Framework::Vec3<int> pos, int dimensionId, bool hasInventory)
     : Inventory(pos, dimensionId, hasInventory)
 {
     transparent = false;
@@ -20,7 +18,6 @@ Block::Block(int typeId,
     maxHP = 1;
     hardness = 1;
     this->typeId = typeId;
-    this->zTool = zTool;
     speedModifier = 1;
     ticksLeftCounter = 0;
     wasTicked = 0;
@@ -214,8 +211,7 @@ void Block::onUnloaded()
 
 Framework::Text Block::getTargetUIML()
 {
-    return StaticRegistry<BlockType>::INSTANCE.zElement(typeId)
-        ->getTargetUIML();
+    return Game::INSTANCE->zBlockType(typeId)->getTargetUIML();
 }
 
 void Block::sendModelInfo(NetworkMessage* zMessage)
@@ -257,7 +253,7 @@ bool Block::isTickSource() const
 
 const BlockType* Block::zBlockType() const
 {
-    return StaticRegistry<BlockType>::INSTANCE.zElement(typeId);
+    return Game::INSTANCE->zBlockType(typeId);
 }
 
 bool Block::isTransparent() const
@@ -290,11 +286,6 @@ float Block::getHardness() const
     return hardness;
 }
 
-const ItemType* Block::zEffectiveTool() const
-{
-    return zTool;
-}
-
 float Block::getSpeedModifier() const
 {
     return speedModifier;
@@ -357,7 +348,7 @@ Block* Block::zNeighbor(Direction dir) const
     return zNeighbours[getDirectionIndex(dir)];
 }
 
-void Block::updateModel(ModelInfo info) const
+void Block::updateModel(ModelInfo* zInfo) const
 {
     Dimension* dim = Game::INSTANCE->zDimension(getDimensionId());
     if (dim)
@@ -369,7 +360,7 @@ void Block::updateModel(ModelInfo info) const
             NetworkMessage* changeMsg = new NetworkMessage();
             changeMsg->addressBlock(this);
             InMemoryBuffer buffer;
-            info.writeTo(&buffer);
+            zInfo->writeTo(&buffer);
             char* msg = new char[(int)buffer.getSize() + 1];
             msg[0] = 1; // hmodel change
             buffer.lese(msg + 1, (int)buffer.getSize());
@@ -384,42 +375,25 @@ int Block::getMapColor() const
     return mapColor;
 }
 
-BasicBlockItem::BasicBlockItem(
-    int itemTypeId, int blockTypeId, const char* name)
+BasicBlockItem::BasicBlockItem(int itemTypeId,
+    int blockTypeId,
+    Framework::Text name,
+    PlaceableProof* placeableProof)
     : Item(itemTypeId, name),
       transparent(0),
       passable(0),
       hardness(1.f),
-      toolId(0),
       speedModifier(1.f),
-      interactable(1)
+      interactable(1),
+      placeableProof(placeableProof)
 {
     this->blockTypeId = blockTypeId;
     placeable = 1;
-    placableProof = [this](const Item* self,
-                        int dimensionId,
-                        Framework::Vec3<int> worldPos) {
-        return Item::canBePlacedAt(dimensionId, worldPos);
-    };
 }
 
-void BasicBlockItem::setPlacableProof(
-    std::function<bool(const Item*, int, Framework::Vec3<int>)> condition,
-    bool andDefault)
+BasicBlockItem::~BasicBlockItem()
 {
-    if (andDefault)
-    {
-        placableProof = [this, condition](const Item* self,
-                            int dimensionId,
-                            Framework::Vec3<int> worldPos) {
-            return Item::canBePlacedAt(dimensionId, worldPos)
-                && condition(self, dimensionId, worldPos);
-        };
-    }
-    else
-    {
-        placableProof = condition;
-    }
+    if (placeableProof) placeableProof->release();
 }
 
 bool BasicBlockItem::canBeStackedWith(const Item* zItem) const
@@ -429,7 +403,7 @@ bool BasicBlockItem::canBeStackedWith(const Item* zItem) const
     {
         return Item::canBeStackedWith(zItem) && transparent == item->transparent
             && passable == item->passable && hardness == item->hardness
-            && toolId == item->toolId && speedModifier == item->speedModifier
+            && speedModifier == item->speedModifier
             && interactable == item->interactable;
     }
     return 0;
@@ -438,24 +412,73 @@ bool BasicBlockItem::canBeStackedWith(const Item* zItem) const
 bool BasicBlockItem::canBePlacedAt(
     int dimensionId, Framework::Vec3<int> worldPos) const
 {
-    return placableProof(this, dimensionId, worldPos);
+    return Item::canBePlacedAt(dimensionId, worldPos)
+        && (!placeableProof
+            || placeableProof->isPlacable(this, worldPos, dimensionId));
+}
+
+BasicBlockItemType::BasicBlockItemType(Framework::Text name,
+    ModelInfo* model,
+    bool transparent,
+    bool passable,
+    float hardness,
+    float speedModifier,
+    Framework::Text blockTypeName,
+    PlaceableProof* placeableProof, int maxStackSize)
+    : ItemType(name, model, maxStackSize),
+      transparent(transparent),
+      passable(passable),
+      hardness(hardness),
+      speedModifier(speedModifier),
+      blockTypeName(blockTypeName),
+      placeableProof(placeableProof)
+{}
+
+BasicBlockItemType::~BasicBlockItemType()
+{
+    if (placeableProof) placeableProof->release();
 }
 
-BasicBlockItemType::BasicBlockItemType(int id,
-    const char* name,
-    ItemSkillLevelUpRule* levelUpRule,
-    int brokenTypeId,
-    ModelInfo model,
-    int blockTypeId)
-    : ItemType(id, name, levelUpRule, brokenTypeId, model),
-      transparent(0),
-      passable(0),
-      hardness(1.f),
-      toolId(0),
-      speedModifier(1.f),
-      blockTypeId(blockTypeId),
-      placableProofState(0)
-{}
+bool BasicBlockItemType::initialize(Game* zGame)
+{
+    blockTypeId = zGame->getBlockTypeId(blockTypeName);
+    return blockTypeId >= 0 && ItemType::initialize(zGame);
+}
+
+int BasicBlockItemType::getBlockTypeId() const
+{
+    return blockTypeId;
+}
+
+bool BasicBlockItemType::isTransparent() const
+{
+    return transparent;
+}
+
+bool BasicBlockItemType::isPassable() const
+{
+    return passable;
+}
+
+float BasicBlockItemType::getHardness() const
+{
+    return hardness;
+}
+
+float BasicBlockItemType::getSpeedModifier() const
+{
+    return speedModifier;
+}
+
+Framework::Text BasicBlockItemType::getBlockTypeName() const
+{
+    return blockTypeName;
+}
+
+PlaceableProof* BasicBlockItemType::zPlaceableProof() const
+{
+    return placeableProof;
+}
 
 void BasicBlockItemType::loadSuperItem(
     Item* zItem, Framework::StreamReader* zReader) const
@@ -468,7 +491,6 @@ void BasicBlockItemType::loadSuperItem(
     zReader->lese((char*)&item->transparent, 1);
     zReader->lese((char*)&item->passable, 1);
     zReader->lese((char*)&item->hardness, 4);
-    zReader->lese((char*)&item->toolId, 4);
     zReader->lese((char*)&item->speedModifier, 4);
     zReader->lese((char*)&item->interactable, 1);
 }
@@ -484,38 +506,114 @@ void BasicBlockItemType::saveSuperItem(
     zWriter->schreibe((char*)&item->transparent, 1);
     zWriter->schreibe((char*)&item->passable, 1);
     zWriter->schreibe((char*)&item->hardness, 4);
-    zWriter->schreibe((char*)&item->toolId, 4);
     zWriter->schreibe((char*)&item->speedModifier, 4);
     zWriter->schreibe((char*)&item->interactable, 1);
 }
 
 Item* BasicBlockItemType::createItem() const
 {
-    BasicBlockItem* item = new BasicBlockItem(id, blockTypeId, name);
+    BasicBlockItem* item = new BasicBlockItem(id,
+        blockTypeId,
+        name,
+        placeableProof
+            ? dynamic_cast<PlaceableProof*>(placeableProof->getThis())
+            : 0);
     item->transparent = transparent;
     item->passable = passable;
     item->hardness = hardness;
-    item->toolId = toolId;
     item->speedModifier = speedModifier;
     item->interactable = 1;
-    if (placableProofState)
-    {
-        item->setPlacableProof(placableProof, placableProofState > 1);
-    }
     return item;
 }
 
-BasicBlockItemType* BasicBlockItemType::setHardness(float hardness)
-{
-    this->hardness = hardness;
-    return this;
-}
+BasicBlockItemTypeFactory::BasicBlockItemTypeFactory()
+    : SubTypeFactory()
+{}
 
-BasicBlockItemType* BasicBlockItemType::setPlacableProof(
-    std::function<bool(const Item*, int, Framework::Vec3<int>)> condition,
-    bool andDefault)
-{
-    placableProofState = 1 + (andDefault ? 1 : 0);
-    placableProof = condition;
-    return this;
+BasicBlockItemType* BasicBlockItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BasicBlockItemType(
+        zJson->zValue("name")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("transparent")->asBool()->getBool(),
+        zJson->zValue("passable")->asBool()->getBool(),
+        (float)zJson->zValue("hardness")->asNumber()->getNumber(),
+        (float)zJson->zValue("speedModifier")->asNumber()->getNumber(),
+        zJson->zValue("blockType")->asString()->getString(),
+        zJson->zValue("placeableProof")->getType()
+                == Framework::JSON::JSONType::OBJECT
+            ? Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
+                zJson->zValue("placeableProof"))
+            : 0,
+        (int)zJson->zValue("maxStack")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* BasicBlockItemTypeFactory::toJson(
+    BasicBlockItemType* zObject) const
+{
+    Framework::JSON::JSONObject* zJson = new Framework::JSON::JSONObject();
+    zJson->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    zJson->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    zJson->addValue(
+        "transparent", new Framework::JSON::JSONBool(zObject->isTransparent()));
+    zJson->addValue(
+        "passable", new Framework::JSON::JSONBool(zObject->isPassable()));
+    zJson->addValue(
+        "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
+    zJson->addValue("speedModifier",
+        new Framework::JSON::JSONNumber(zObject->getSpeedModifier()));
+    zJson->addValue("blockType",
+        new Framework::JSON::JSONString(zObject->getBlockTypeName()));
+    zJson->addValue("placeableProof",
+        zObject->zPlaceableProof() ? Game::INSTANCE->zTypeRegistry()->toJson(
+            zObject->zPlaceableProof())
+                                   : new Framework::JSON::JSONValue());
+    zJson->addValue("maxStack",
+        new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
+    return zJson;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BasicBlockItemTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("name")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredBool("transparent")
+        ->withDefault(false)
+        ->finishBool()
+        ->withRequiredBool("passable")
+        ->withDefault(false)
+        ->finishBool()
+        ->withRequiredNumber("hardness")
+        ->withDefault(1.f)
+        ->finishNumber()
+        ->withRequiredNumber("speedModifier")
+        ->withDefault(1.f)
+        ->finishNumber()
+        ->withRequiredString("blockType")
+        ->finishString()
+        ->withRequiredAttribute("placeableProof",
+            Game::INSTANCE->zTypeRegistry()->getValidator<PlaceableProof>())
+        ->withRequiredObject("placeableProof")
+        ->withDefaultNull()
+        ->whichCanBeNull()
+        ->finishObject()
+        ->withRequiredNumber("maxStack")
+        ->withDefault(50.0)
+        ->whichIsGreaterOrEqual(1.0)
+        ->finishNumber()
+        ->finishObject();
+}
+
+Framework::Text BasicBlockItemTypeFactory::getTypeToken() const
+{
+    return "placeable";
 }

+ 50 - 32
FactoryCraft/Block.h

@@ -7,19 +7,19 @@
 
 #include "Inventory.h"
 #include "Item.h"
+#include "MultiblockStructure.h"
 #include "NetworkMessage.h"
 #include "ReferenceCounter.h"
 #include "Tickable.h"
 
-#define CONST_BLOCK(maybeBlock, type)                                     \
-    (maybeBlock ? maybeBlock                                              \
-                : StaticRegistry<BlockType>::INSTANCE.zElement((int)type) \
-                      ->zDefault())
+#define CONST_BLOCK(maybeBlock, type) \
+    (maybeBlock ? maybeBlock          \
+                : Game::INSTANCE->zBlockType((int)type)->zDefault())
 
 class ItemType;
 class Chunk;
 class BasicBlockItemType;
-class MultiblockStructure;
+class PlaceableProof;
 
 class TickQueue;
 
@@ -39,7 +39,6 @@ protected:
     float maxHP;
     float hardness;
     int typeId;
-    const ItemType* zTool;
     float speedModifier;
     Block* zNeighbours[6];
     int neighbourTypes[6];
@@ -74,11 +73,10 @@ protected:
 
     virtual void onDialogClosed(Framework::Text dialogId);
     void broadcastModelInfoChange();
-    void broadcastMessage(NetworkMessage *message);
+    void broadcastMessage(NetworkMessage* message);
 
 public:
     Block(int typeId,
-        const ItemType* zTool,
         Framework::Vec3<int> pos,
         int dimensionId,
         bool hasInventory);
@@ -102,11 +100,10 @@ public:
     const BlockType* zBlockType() const;
     bool isTransparent() const;
     bool isPassable() const;
-    virtual bool isInteractable(const Item *zItem) const;
+    virtual bool isInteractable(const Item* zItem) const;
     float getHP() const;
     float getMaxHP() const;
     float getHardness() const;
-    const ItemType* zEffectiveTool() const;
     float getSpeedModifier() const;
     const Framework::Vec3<int> getPos() const;
     bool isVisible() const;
@@ -115,7 +112,7 @@ public:
     const unsigned char* getLightEmisionColor() const;
     virtual void filterPassingLight(unsigned char rgb[3]) const;
     Block* zNeighbor(Direction dir) const;
-    void updateModel(ModelInfo info) const;
+    void updateModel(ModelInfo* zInfo) const;
     int getMapColor() const;
 
     friend BlockType;
@@ -127,16 +124,16 @@ protected:
     bool transparent;
     bool passable;
     float hardness;
-    int toolId;
     float speedModifier;
     bool interactable;
-    std::function<bool(const Item*, int, Framework::Vec3<int>)> placableProof;
+    PlaceableProof* placeableProof;
 
 public:
-    BasicBlockItem(int itemTypeId, int blockTypeId, const char* name);
-    void setPlacableProof(
-        std::function<bool(const Item*, int, Framework::Vec3<int>)> condition,
-        bool andDefault);
+    BasicBlockItem(int itemTypeId,
+        int blockTypeId,
+        Framework::Text name,
+        PlaceableProof* placeableProof);
+    ~BasicBlockItem();
     virtual bool canBeStackedWith(const Item* zItem) const override;
     virtual bool canBePlacedAt(
         int dimensionId, Framework::Vec3<int> worldPos) const override;
@@ -147,16 +144,16 @@ public:
 
 class BasicBlockItemType : public ItemType
 {
-protected:
+private:
     bool transparent;
     bool passable;
     float hardness;
-    int toolId;
     float speedModifier;
+    Framework::Text blockTypeName;
     int blockTypeId;
-    char placableProofState;
-    std::function<bool(const Item*, int, Framework::Vec3<int>)> placableProof;
+    PlaceableProof* placeableProof;
 
+protected:
     virtual void loadSuperItem(
         Item* zItem, Framework::StreamReader* zReader) const override;
     virtual void saveSuperItem(
@@ -164,16 +161,37 @@ protected:
     virtual Item* createItem() const override;
 
 public:
-    BasicBlockItemType(int id,
-        const char* name,
-        ItemSkillLevelUpRule* levelUpRule,
-        int brokenTypeId,
-        ModelInfo model,
-        int blockTypeId);
-    BasicBlockItemType* setHardness(float hardness);
-    BasicBlockItemType* setPlacableProof(
-        std::function<bool(const Item*, int, Framework::Vec3<int>)> condition,
-        bool andDefault);
+    BasicBlockItemType(Framework::Text name,
+        ModelInfo* model,
+        bool transparent,
+        bool passable,
+        float hardness,
+        float speedModifier,
+        Framework::Text blockTypeName,
+        PlaceableProof* placeableProof,
+        int maxStackSize);
+    ~BasicBlockItemType();
+    virtual bool initialize(Game* zGame) override;
+    int getBlockTypeId() const;
+    bool isTransparent() const;
+    bool isPassable() const;
+    float getHardness() const;
+    float getSpeedModifier() const;
+    Framework::Text getBlockTypeName() const;
+    PlaceableProof* zPlaceableProof() const;
 };
 
-#include "MultiblockStructure.h"
+class BasicBlockItemTypeFactory
+    : public SubTypeFactory<ItemType, BasicBlockItemType>
+{
+public:
+    BasicBlockItemTypeFactory();
+    BasicBlockItemType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BasicBlockItemType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
+};

+ 492 - 0
FactoryCraft/BlockFilter.cpp

@@ -0,0 +1,492 @@
+#include "BlockFilter.h"
+
+#include "Block.h"
+#include "FluidBlock.h"
+#include "Game.h"
+
+BlockFilter::BlockFilter()
+    : ReferenceCounter()
+{}
+
+BlockFilterAnd::BlockFilterAnd(Framework::RCArray<BlockFilter> filters)
+    : BlockFilter(),
+      filters(filters)
+{}
+
+bool BlockFilterAnd::test(const Block* zBlock)
+{
+    for (BlockFilter* filter : filters)
+    {
+        if (!filter->test(zBlock))
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+Framework::RCArray<BlockFilter> BlockFilterAnd::getFilters() const
+{
+    return filters;
+}
+
+BlockFilterAndFactory::BlockFilterAndFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterAnd* BlockFilterAndFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<BlockFilter> filters;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("filters")->asArray())
+    {
+        filters.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(value));
+    }
+    return new BlockFilterAnd(filters);
+}
+
+Framework::JSON::JSONObject* BlockFilterAndFactory::toJson(
+    BlockFilterAnd* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* filters = new Framework::JSON::JSONArray();
+    for (BlockFilter* filter : zObject->getFilters())
+    {
+        filters->addValue(Game::INSTANCE->zTypeRegistry()->toJson(filter));
+    }
+    result->addValue("filters", filters);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* BlockFilterAndFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("filters")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text BlockFilterAndFactory::getTypeToken() const
+{
+    return "and";
+}
+
+BlockFilterOr::BlockFilterOr(Framework::RCArray<BlockFilter> filters)
+    : BlockFilter(),
+      filters(filters)
+{}
+
+bool BlockFilterOr::test(const Block* zBlock)
+{
+    for (BlockFilter* filter : filters)
+    {
+        if (filter->test(zBlock))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+Framework::RCArray<BlockFilter> BlockFilterOr::getFilters() const
+{
+    return filters;
+}
+
+BlockFilterOrFactory::BlockFilterOrFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterOr* BlockFilterOrFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<BlockFilter> filters;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("filters")->asArray())
+    {
+        filters.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(value));
+    }
+    return new BlockFilterOr(filters);
+}
+
+Framework::JSON::JSONObject* BlockFilterOrFactory::toJson(
+    BlockFilterOr* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* filters = new Framework::JSON::JSONArray();
+    for (BlockFilter* filter : zObject->getFilters())
+    {
+        filters->addValue(Game::INSTANCE->zTypeRegistry()->toJson(filter));
+    }
+    result->addValue("filters", filters);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* BlockFilterOrFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("filters")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text BlockFilterOrFactory::getTypeToken() const
+{
+    return "or";
+}
+
+BlockFilterNot::BlockFilterNot(BlockFilter* filter)
+    : BlockFilter(),
+      filter(filter)
+{}
+
+bool BlockFilterNot::test(const Block* zBlock)
+{
+    return !filter->test(zBlock);
+}
+
+BlockFilter* BlockFilterNot::zFilter() const
+{
+    return filter;
+}
+
+BlockFilterNotFactory::BlockFilterNotFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterNot* BlockFilterNotFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BlockFilterNot(
+        Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
+            zJson->zValue("filter")));
+}
+
+Framework::JSON::JSONObject* BlockFilterNotFactory::toJson(
+    BlockFilterNot* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* BlockFilterNotFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder
+        ->withRequiredAttribute("filter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
+        ->finishObject();
+}
+
+Framework::Text BlockFilterNotFactory::getTypeToken() const
+{
+    return "not";
+}
+
+BlockFilterBlockType::BlockFilterBlockType(Framework::Array<int> blockTypeIds)
+    : BlockFilter(),
+      blockTypeIds(blockTypeIds)
+{}
+
+bool BlockFilterBlockType::test(const Block* zBlock)
+{
+    for (int blockTypeId : blockTypeIds)
+    {
+        if (zBlock->zBlockType()->getId() == blockTypeId)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+const Framework::Array<int>& BlockFilterBlockType::getBlockTypeIds() const
+{
+    return blockTypeIds;
+}
+
+BlockFilterBlockTypeFactory::BlockFilterBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterBlockType* BlockFilterBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::Array<int> blockTypeIds;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("typeNames")->asArray())
+    {
+        blockTypeIds.add(
+            Game::INSTANCE->getBlockTypeId(value->asString()->getString()));
+    }
+    return new BlockFilterBlockType(blockTypeIds);
+}
+
+Framework::JSON::JSONObject* BlockFilterBlockTypeFactory::toJson(
+    BlockFilterBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* typeNames = new Framework::JSON::JSONArray();
+    for (int typeId : zObject->getBlockTypeIds())
+    {
+        typeNames->addValue(new Framework::JSON::JSONString(
+            Game::INSTANCE->zBlockType(typeId)->getName()));
+    }
+    result->addValue("typeNames", typeNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BlockFilterBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("typeNames")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text BlockFilterBlockTypeFactory::getTypeToken() const
+{
+    return "types";
+}
+
+BlockFilterTypeGroup::BlockFilterTypeGroup(
+    Framework::RCArray<Framework::Text> groupNames)
+    : BlockFilter(),
+      groupNames(groupNames)
+{}
+
+bool BlockFilterTypeGroup::test(const Block* zBlock)
+{
+    for (Framework::Text* groupName : groupNames)
+    {
+        for (Framework::Text* otherGroupName :
+            zBlock->zBlockType()->getGroupNames())
+        {
+            if (groupName->istGleich(*otherGroupName))
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+const Framework::RCArray<Framework::Text>&
+BlockFilterTypeGroup::getGroupNames() const
+{
+    return groupNames;
+}
+
+BlockFilterTypeGroupFactory::BlockFilterTypeGroupFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterTypeGroup* BlockFilterTypeGroupFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    return new BlockFilterTypeGroup(groupNames);
+}
+
+Framework::JSON::JSONObject* BlockFilterTypeGroupFactory::toJson(
+    BlockFilterTypeGroup* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BlockFilterTypeGroupFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("groupNames")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text BlockFilterTypeGroupFactory::getTypeToken() const
+{
+    return "groups";
+}
+
+BlockFilterMaxHardness::BlockFilterMaxHardness(float maxHardness)
+    : BlockFilter(),
+      maxHardness(maxHardness)
+{}
+
+bool BlockFilterMaxHardness::test(const Block* zBlock)
+{
+    return zBlock->zBlockType()->getHardness() <= maxHardness;
+}
+
+float BlockFilterMaxHardness::getMaxHardness() const
+{
+    return maxHardness;
+}
+
+BlockFilterMaxHardnessFactory::BlockFilterMaxHardnessFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterMaxHardness* BlockFilterMaxHardnessFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BlockFilterMaxHardness(
+        (float)zJson->zValue("maxHardness")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* BlockFilterMaxHardnessFactory::toJson(
+    BlockFilterMaxHardness* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("maxHardness",
+        new Framework::JSON::JSONNumber(zObject->getMaxHardness()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BlockFilterMaxHardnessFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredNumber("maxHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->finishObject();
+}
+
+Framework::Text BlockFilterMaxHardnessFactory::getTypeToken() const
+{
+    return "maxHardness";
+}
+
+BlockFilterMinHardness::BlockFilterMinHardness(float minHardness)
+    : BlockFilter(),
+      minHardness(minHardness)
+{}
+
+bool BlockFilterMinHardness::test(const Block* zBlock)
+{
+    return zBlock->zBlockType()->getHardness() >= minHardness;
+}
+
+float BlockFilterMinHardness::getMinHardness() const
+{
+    return minHardness;
+}
+
+BlockFilterMinHardnessFactory::BlockFilterMinHardnessFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterMinHardness* BlockFilterMinHardnessFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BlockFilterMinHardness(
+        (float)zJson->zValue("minHardness")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* BlockFilterMinHardnessFactory::toJson(
+    BlockFilterMinHardness* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("minHardness",
+        new Framework::JSON::JSONNumber(zObject->getMinHardness()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BlockFilterMinHardnessFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredNumber("minHardness")
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->finishObject();
+}
+
+Framework::Text BlockFilterMinHardnessFactory::getTypeToken() const
+{
+    return "minHardness";
+}
+
+BlockFilterMaxHeat::BlockFilterMaxHeat(float maxHeat)
+    : BlockFilter(),
+      maxHeat(maxHeat)
+{}
+
+bool BlockFilterMaxHeat::test(const Block* zBlock)
+{
+    const FluidBlockType* type
+        = dynamic_cast<const FluidBlockType*>(zBlock->zBlockType());
+    return type && type->getHeat() <= maxHeat;
+}
+
+float BlockFilterMaxHeat::getMaxHeat() const
+{
+    return maxHeat;
+}
+
+BlockFilterMaxHeatFactory::BlockFilterMaxHeatFactory()
+    : SubTypeFactory()
+{}
+
+BlockFilterMaxHeat* BlockFilterMaxHeatFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BlockFilterMaxHeat(
+        (float)zJson->zValue("heat")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* BlockFilterMaxHeatFactory::toJson(
+    BlockFilterMaxHeat* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "heat", new Framework::JSON::JSONNumber(zObject->getMaxHeat()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BlockFilterMaxHeatFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredNumber("heat")->finishNumber()->finishObject();
+}
+
+Framework::Text BlockFilterMaxHeatFactory::getTypeToken() const
+{
+    return "maxHeat";
+}

+ 213 - 0
FactoryCraft/BlockFilter.h

@@ -0,0 +1,213 @@
+#pragma once
+
+#include <Array.h>
+
+#include "TypeRegistry.h"
+
+class Block;
+
+class BlockFilter : public Framework::ReferenceCounter
+{
+public:
+    BlockFilter();
+    virtual bool test(const Block* zBlock) = 0;
+};
+
+class BlockFilterAnd : public BlockFilter
+{
+private:
+    Framework::RCArray<BlockFilter> filters;
+
+public:
+    BlockFilterAnd(Framework::RCArray<BlockFilter> filters);
+    bool test(const Block* zBlock) override;
+    Framework::RCArray<BlockFilter> getFilters() const;
+};
+
+class BlockFilterAndFactory : public SubTypeFactory<BlockFilter, BlockFilterAnd>
+{
+public:
+    BlockFilterAndFactory();
+    BlockFilterAnd* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(BlockFilterAnd* 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 BlockFilterOr : public BlockFilter
+{
+private:
+    Framework::RCArray<BlockFilter> filters;
+
+public:
+    BlockFilterOr(Framework::RCArray<BlockFilter> filters);
+    bool test(const Block* zBlock) override;
+    Framework::RCArray<BlockFilter> getFilters() const;
+};
+
+class BlockFilterOrFactory : public SubTypeFactory<BlockFilter, BlockFilterOr>
+{
+public:
+    BlockFilterOrFactory();
+    BlockFilterOr* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(BlockFilterOr* 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 BlockFilterNot : public BlockFilter
+{
+private:
+    BlockFilter* filter;
+
+public:
+    BlockFilterNot(BlockFilter* filter);
+    bool test(const Block* zBlock) override;
+    BlockFilter* zFilter() const;
+};
+
+class BlockFilterNotFactory : public SubTypeFactory<BlockFilter, BlockFilterNot>
+{
+public:
+    BlockFilterNotFactory();
+    BlockFilterNot* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(BlockFilterNot* 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 BlockFilterBlockType : public BlockFilter
+{
+private:
+    Framework::Array<int> blockTypeIds;
+
+public:
+    BlockFilterBlockType(Framework::Array<int> blockTypeIds);
+    bool test(const Block* zBlock) override;
+    const Framework::Array<int>& getBlockTypeIds() const;
+};
+
+class BlockFilterBlockTypeFactory
+    : public SubTypeFactory<BlockFilter, BlockFilterBlockType>
+{
+public:
+    BlockFilterBlockTypeFactory();
+    BlockFilterBlockType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BlockFilterBlockType* 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 BlockFilterTypeGroup : public BlockFilter
+{
+private:
+    Framework::RCArray<Framework::Text> groupNames;
+
+public:
+    BlockFilterTypeGroup(Framework::RCArray<Framework::Text> groupNames);
+    bool test(const Block* zBlock) override;
+    const Framework::RCArray<Framework::Text>& getGroupNames() const;
+};
+
+class BlockFilterTypeGroupFactory
+    : public SubTypeFactory<BlockFilter, BlockFilterTypeGroup>
+{
+public:
+    BlockFilterTypeGroupFactory();
+    BlockFilterTypeGroup* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BlockFilterTypeGroup* 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 BlockFilterMaxHardness : public BlockFilter
+{
+private:
+    float maxHardness;
+
+public:
+    BlockFilterMaxHardness(float maxHardness);
+    bool test(const Block* zBlock) override;
+    float getMaxHardness() const;
+};
+
+class BlockFilterMaxHardnessFactory
+    : public SubTypeFactory<BlockFilter, BlockFilterMaxHardness>
+{
+public:
+    BlockFilterMaxHardnessFactory();
+    BlockFilterMaxHardness* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BlockFilterMaxHardness* 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 BlockFilterMinHardness : public BlockFilter
+{
+private:
+    float minHardness;
+
+public:
+    BlockFilterMinHardness(float minHardness);
+    bool test(const Block* zBlock) override;
+    float getMinHardness() const;
+};
+
+class BlockFilterMinHardnessFactory
+    : public SubTypeFactory<BlockFilter, BlockFilterMinHardness>
+{
+public:
+    BlockFilterMinHardnessFactory();
+    BlockFilterMinHardness* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BlockFilterMinHardness* 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 BlockFilterMaxHeat : public BlockFilter
+{
+private:
+    float maxHeat;
+
+public:
+    BlockFilterMaxHeat(float maxHeat);
+    bool test(const Block* zBlock) override;
+    float getMaxHeat() const;
+};
+
+class BlockFilterMaxHeatFactory
+    : public SubTypeFactory<BlockFilter, BlockFilterMaxHeat>
+{
+public:
+    BlockFilterMaxHeatFactory();
+    BlockFilterMaxHeat* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BlockFilterMaxHeat* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
+};

+ 1 - 3
FactoryCraft/BlockInfoCommand.cpp

@@ -41,9 +41,7 @@ void BlockInfoCommand::execute(
             }
             else
             {
-                result += StaticRegistry<BlockType>::INSTANCE
-                              .zElement(block.getB())
-                              ->getName();
+                result += Game::INSTANCE->zBlockType(block.getB())->getName();
             }
             result += " (";
             result += block.getB();

+ 8 - 5
FactoryCraft/BlockInstanceGeneratorRule.cpp

@@ -1,5 +1,7 @@
 #include "BlockInstanceGeneratorRule.h"
 
+#include "Game.h"
+
 BlockInstanceGeneratorRule::BlockInstanceGeneratorRule(
     Framework::JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
     : GeneratorRule(zConfig, zMemory)
@@ -11,7 +13,8 @@ BlockInstanceGeneratorRule::BlockInstanceGeneratorRule(
 Framework::Either<Block*, int> BlockInstanceGeneratorRule::createBlock(
     int x, int y, int z, int dimensionId)
 {
-    return StaticRegistry<BlockType>::INSTANCE.zElement(blockType)->createBlockAt(Framework::Vec3<int>(x, y, z), dimensionId, 0);
+    return Game::INSTANCE->zBlockType(blockType)->createBlockAt(
+        Framework::Vec3<int>(x, y, z), dimensionId, 0);
 }
 
 BlockInstanceGeneratorRuleFactory::BlockInstanceGeneratorRuleFactory()
@@ -28,12 +31,12 @@ Framework::JSON::Validator::JSONValidator*
 BlockInstanceGeneratorRuleFactory::getValidator()
 {
     Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < StaticRegistry<BlockType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
     {
-        if (StaticRegistry<BlockType>::INSTANCE.zElement(i))
+        if (Game::INSTANCE->zBlockType(i))
         {
-            blockTypeNames.add(new Framework::Text(
-                StaticRegistry<BlockType>::INSTANCE.zElement(i)->getName()));
+            blockTypeNames.add(
+                new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
         }
     }
     return GeneratorRule::addToValidator(

+ 51 - 37
FactoryCraft/BlockType.cpp

@@ -8,15 +8,16 @@
 
 using namespace Framework;
 
-BlockType::BlockType(int id,
-    Block* defaultBlock,
-    ModelInfo model,
+BlockType::BlockType(Block* defaultBlock,
+    ModelInfo* model,
     bool needsClientInstance,
     int initialMaxHP,
     bool lightSource,
-    const char* name,
+    Framework::Text name,
     bool needModelSubscription,
-    int initialMapColor)
+    int initialMapColor,
+    Framework::RCArray<Framework::Text> groupNames,
+    float hardness)
     : ReferenceCounter(),
       id(id),
       model(model),
@@ -26,10 +27,10 @@ BlockType::BlockType(int id,
       name(name),
       needModelSubscription(needModelSubscription),
       initialMapColor(initialMapColor),
-      defaultBlock(defaultBlock)
-{
-    StaticRegistry<BlockType>::INSTANCE.registerT(this, id);
-}
+      defaultBlock(defaultBlock),
+      groupNames(groupNames),
+      hardness(hardness)
+{}
 
 BlockType::~BlockType()
 {
@@ -47,13 +48,6 @@ void BlockType::loadSuperBlock(
     zReader->lese((char*)&zBlock->hardness, 4);
     zReader->lese((char*)&zBlock->speedModifier, 4);
     zReader->lese((char*)&zBlock->mapColor, 4);
-    int effectiveToolId;
-    zReader->lese((char*)&effectiveToolId, 4);
-    if (effectiveToolId >= 0)
-        zBlock->zTool
-            = StaticRegistry<ItemType>::INSTANCE.zElement(effectiveToolId);
-    else
-        zBlock->zTool = 0;
     zReader->lese((char*)&zBlock->interactable, 1);
     int strCount;
     zReader->lese((char*)&strCount, 4);
@@ -82,8 +76,6 @@ void BlockType::saveSuperBlock(
     zWriter->schreibe((char*)&zBlock->hardness, 4);
     zWriter->schreibe((char*)&zBlock->speedModifier, 4);
     zWriter->schreibe((char*)&zBlock->mapColor, 4);
-    int effectiveToolId = zBlock->zTool ? zBlock->zTool->getId() : -1;
-    zWriter->schreibe((char*)&effectiveToolId, 4);
     zWriter->schreibe((char*)&zBlock->interactable, 1);
     int strCount = zBlock->structures.getEintragAnzahl();
     zWriter->schreibe((char*)&strCount, 4);
@@ -105,10 +97,6 @@ void BlockType::createSuperBlock(Block* zBlock, Item* zItem) const
             zBlock->passable = item->passable;
             zBlock->hardness = item->hardness;
             zBlock->speedModifier = item->speedModifier;
-            zBlock->zTool
-                = item->toolId >= 0
-                    ? StaticRegistry<ItemType>::INSTANCE.zElement(item->toolId)
-                    : 0;
             zBlock->interactable = item->interactable;
         }
     }
@@ -124,11 +112,15 @@ void BlockType::createSuperItem(Block* zBlock, Item* zItem) const
         item->passable = zBlock->passable;
         item->hardness = zBlock->hardness;
         item->speedModifier = zBlock->speedModifier;
-        item->toolId = zBlock->zTool ? zBlock->zTool->getId() : -1;
         item->interactable = zBlock->interactable;
     }
 }
 
+bool BlockType::initialize(Game* zGame)
+{
+    return true;
+}
+
 Framework::Text BlockType::getTargetUIML() const
 {
     return Text("<targetInfo><text width=\"auto\" height=\"auto\">") + name
@@ -172,11 +164,26 @@ bool BlockType::doesNeedClientInstance() const
     return needsClientInstance;
 }
 
-const ModelInfo& BlockType::getModel() const
+ModelInfo* BlockType::zModel() const
 {
     return model;
 }
 
+int BlockType::getMapColor() const
+{
+    return initialMapColor;
+}
+
+const Framework::RCArray<Framework::Text>& BlockType::getGroupNames() const
+{
+    return groupNames;
+}
+
+float BlockType::getHardness() const
+{
+    return hardness;
+}
+
 int BlockType::getId() const
 {
     return id;
@@ -202,12 +209,15 @@ const Block* getDefaultBlock(Either<Block*, int> b)
     if (b.isA())
         return b;
     else
-        return StaticRegistry<BlockType>::INSTANCE.zElement(b)->zDefault();
+        return Game::INSTANCE->zBlockType(b)->zDefault();
 }
 
 BlockType* BlockType::initializeDefault()
 {
-    defaultBlock = createBlockAt({0, 0, 0}, 0, 0);
+    if (!defaultBlock)
+    {
+        defaultBlock = createBlockAt({0, 0, 0}, 0, 0);
+    }
     return this;
 }
 
@@ -238,7 +248,7 @@ void BlockType::writeTypeInfo(StreamWriter* zWriter) const
     }
     int maxHp = getInitialMaxHP();
     zWriter->schreibe((char*)&maxHp, 4);
-    getModel().writeTo(zWriter);
+    zModel()->writeTo(zWriter);
 }
 
 bool BlockType::isFluid() const
@@ -249,28 +259,32 @@ bool BlockType::isFluid() const
 int BlockType::getTypeId(const char* name)
 {
     Text n = name;
-    for (int i = 0; i < StaticRegistry<BlockType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
     {
-        if (StaticRegistry<BlockType>::INSTANCE.zElement(i)
-            && n.istGleich(
-                StaticRegistry<BlockType>::INSTANCE.zElement(i)->getName()))
-            return StaticRegistry<BlockType>::INSTANCE.zElement(i)->getId();
+        if (Game::INSTANCE->zBlockType(i)
+            && n.istGleich(Game::INSTANCE->zBlockType(i)->getName()))
+            return Game::INSTANCE->zBlockType(i)->getId();
     }
     return 0;
 }
 
 Framework::Text BlockType::getTypeName(int id)
 {
-    for (int i = 0; i < StaticRegistry<BlockType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
     {
-        if (StaticRegistry<BlockType>::INSTANCE.zElement(i)
-            && StaticRegistry<BlockType>::INSTANCE.zElement(i)->getId() == id)
-            return StaticRegistry<BlockType>::INSTANCE.zElement(i)->getName();
+        if (Game::INSTANCE->zBlockType(i)
+            && Game::INSTANCE->zBlockType(i)->getId() == id)
+            return Game::INSTANCE->zBlockType(i)->getName();
     }
     return 0;
 }
 
-char BlockType::getFlowDistance() const
+unsigned char BlockType::getFlowDistance() const
 {
     return 0;
 }
+
+void BlockType::setTypeId(int id)
+{
+    this->id = id;
+}

+ 25 - 43
FactoryCraft/BlockType.h

@@ -6,71 +6,45 @@
 #include <Writer.h>
 
 #include "ModelInfo.h"
-#include "StaticRegistry.h"
 
 class Item;
 class Block;
+class Game;
+class ItemType;
 
 class BlockTypeEnum
 {
 public:
     static const int NO_BLOCK = 0;
     static const int AIR = 1;
-    static const int DIRT = 2;
-    static const int SAND = 3;
-    static const int GRAVEL = 4;
-    static const int STONE = 5;
-    static const int STONE_GRANITE = 6;
-    static const int STONE_COBBLE = 7;
-    static const int STONE_BASALT = 8;
-    static const int WOOD_OAK = 9;
-    static const int WOOD_BIRCH = 10;
-    static const int WOOD_BEECH = 11;
-    static const int WOOD_PINE = 12;
-    static const int LEAVES_WOOD_OAK = 13;
-    static const int LEAVES_WOOD_BIRCH = 14;
-    static const int LEAVES_WOOD_BEECH = 15;
-    static const int LEAVES_WOOD_PINE = 16;
-    static const int SEBLING_WOOD_OAK = 17;
-    static const int SEBLING_WOOD_BIRCH = 18;
-    static const int SEBLING_WOOD_BEECH = 19;
-    static const int SEBLING_WOOD_PINE = 20;
-    static const int TORCH = 21;
-    static const int GRASS = 22;
-    static const int FARMLAND = 23;
-    static const int WHEAT_SEED = 24;
-    static const int WHEAT = 25;
-    static const int WATER = 26;
-    static const int CRAFTING_TABLE = 27;
-    static const int CHEST = 28;
-
-    static const int MAX_VALUE = 100000; // leve enough space for other blocks
 };
 
 class BlockType : public virtual Framework::ReferenceCounter
 {
 private:
-    const int id;
-    const ModelInfo model;
+    int id;
+    ModelInfo* model;
     int initialMaxHP;
     const bool needsClientInstance;
     bool lightSource;
-    const char* name;
+    Framework::Text name;
     const bool needModelSubscription;
-
-protected:
     int initialMapColor;
     Block* defaultBlock;
+    Framework::RCArray<Framework::Text> groupNames;
+    float hardness;
 
-    BlockType(int id,
-        Block* defaultBlock,
-        ModelInfo model,
+protected:
+    BlockType(Block* defaultBlock,
+        ModelInfo* model,
         bool needsClientInstance,
         int initialMaxHP,
         bool lightSource,
-        const char* name,
+        Framework::Text name,
         bool needModelSubscription,
-        int initialMapColor);
+        int initialMapColor,
+        Framework::RCArray<Framework::Text> groupNames,
+        float hardness);
     virtual ~BlockType();
 
     virtual void loadSuperBlock(
@@ -79,10 +53,13 @@ protected:
         Block* zBlock, Framework::StreamWriter* zWriter) const;
     virtual void createSuperBlock(Block* zBlock, Item* zItem) const;
     virtual void createSuperItem(Block* zBlock, Item* zItem) const;
-    virtual Block* createBlock(Framework::Vec3<int> position, int dimensionId) const = 0;
+    virtual Block* createBlock(
+        Framework::Vec3<int> position, int dimensionId) const
+        = 0;
     virtual Item* createItem() const = 0;
 
 public:
+    virtual bool initialize(Game* zGame);
     virtual Framework::Text getTargetUIML() const;
     virtual Block* loadBlock(Framework::Vec3<int> position,
         Framework::StreamReader* zReader,
@@ -94,7 +71,6 @@ public:
         Framework::Vec3<int> position, int dimensionId, Item* zUsedItem) const;
     virtual const Block* zDefault() const;
     bool doesNeedClientInstance() const;
-    const ModelInfo& getModel() const;
     int getId() const;
     int getInitialMaxHP() const;
     bool isLightSource() const;
@@ -103,10 +79,16 @@ public:
     const bool doesNeedModelSubscription() const;
     void writeTypeInfo(Framework::StreamWriter* zWriter) const;
     virtual bool isFluid() const;
+    virtual unsigned char getFlowDistance() const;
+    void setTypeId(int id);
+    ModelInfo* zModel() const;
+    int getMapColor() const;
+    virtual ItemType* createItemType() const = 0;
+    const Framework::RCArray<Framework::Text>& getGroupNames() const;
+    float getHardness() const;
 
     static int getTypeId(const char* name);
     static Framework::Text getTypeName(int id);
-    virtual char getFlowDistance() const;
 };
 
 const Block* getDefaultBlock(Framework::Either<Block*, int> b);

+ 6 - 4
FactoryCraft/BlockTypeGeneratorRule.cpp

@@ -1,5 +1,7 @@
 #include "BlockTypeGeneratorRule.h"
 
+#include "Game.h"
+
 BlockTypeGeneratorRule::BlockTypeGeneratorRule(
     Framework::JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
     : GeneratorRule(zConfig, zMemory)
@@ -28,12 +30,12 @@ Framework::JSON::Validator::JSONValidator*
 BlockTypeGeneratorRuleFactory::getValidator()
 {
     Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < StaticRegistry<BlockType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
     {
-        if (StaticRegistry<BlockType>::INSTANCE.zElement(i))
+        if (Game::INSTANCE->zBlockType(i))
         {
-            blockTypeNames.add(new Framework::Text(
-                StaticRegistry<BlockType>::INSTANCE.zElement(i)->getName()));
+            blockTypeNames.add(
+                new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
         }
     }
     return GeneratorRule::addToValidator(

+ 126 - 8
FactoryCraft/Chest.cpp

@@ -4,9 +4,8 @@
 
 #include "Game.h"
 
-Chest::Chest(
-    int typeId, ItemType* zTool, Framework::Vec3<int> pos, int dimensionId)
-    : BasicBlock(typeId, zTool, pos, dimensionId, 1),
+Chest::Chest(int typeId, Framework::Vec3<int> pos, int dimensionId)
+    : BasicBlock(typeId, pos, dimensionId, 1),
       open(0),
       userEntityId(0)
 {
@@ -97,11 +96,13 @@ bool Chest::interact(Item* zItem, Entity* zActor)
                "numSlots=\"30\" slotNameFilter=\"\" target=\""
             << getDimensionId() << "," << getPos().x << "," << getPos().y << ","
             << getPos().z << "\"/>"
-            << "<text id=\"player_label\" width=\"100%\" height=\"auto\" style=\""
+            << "<text id=\"player_label\" width=\"100%\" height=\"auto\" "
+               "style=\""
             << std::uppercase << std::hex
             << (TextFeld::Style::Text | TextFeld::Style::Center) << std::dec
             << std::nouppercase
-            << "\" margin-bottom=\"9\" align-bottom=\"player_inventory\">Player "
+            << "\" margin-bottom=\"9\" "
+               "align-bottom=\"player_inventory\">Player "
                "Inventory</text>"
             << "<inventory id=\"player_inventory\" margin-bottom=\"18\" "
                "align-bottom=\"item_bar\" align-left=\"start\" "
@@ -114,9 +115,9 @@ bool Chest::interact(Item* zItem, Entity* zActor)
                "slotNameFilter=\"ItemBar\" target=\""
             << zActor->getId() << "\"/>"
             << "</dialog>";
-        Game::INSTANCE->zUIController()->addDialog(
-            new UIDialog(getDialogId(), zActor->getId(), new Framework::XML::Element(uiml)));
-        NetworkMessage *msg = new NetworkMessage();
+        Game::INSTANCE->zUIController()->addDialog(new UIDialog(
+            getDialogId(), zActor->getId(), new Framework::XML::Element(uiml)));
+        NetworkMessage* msg = new NetworkMessage();
         msg->animateBlockBone(getDimensionId(),
             Game::getChunkCenter(getPos().x, getPos().y),
             Chunk::index(Dimension::chunkCoordinates(getPos())),
@@ -144,4 +145,121 @@ void Chest::sendModelInfo(NetworkMessage* zMessage)
             Vec3<float>(
                 0.0f, (float)(PI / 2.0), 0.f)); // open the chest instantly
     }
+}
+
+ChestBlockType::ChestBlockType(Framework::Text itemTypeName,
+    ModelInfo* model,
+    Framework::Text name,
+    int mapColor,
+    bool modelSubscription,
+    float hardness,
+    Framework::RCArray<Framework::Text> groupNames)
+    : BasicBlockType(itemTypeName,
+        model,
+        name,
+        mapColor,
+        modelSubscription,
+        hardness,
+        groupNames)
+{}
+
+Block* ChestBlockType::createBlock(
+    Framework::Vec3<int> position, int dimensionId) const
+{
+    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()
+{}
+
+ChestBlockType* ChestBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    return new ChestBlockType(
+        zJson->zValue("itemType")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("name")->asString()->getString(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        zJson->zValue("modelSubscription")->asBool()->getBool(),
+        (float)zJson->zValue("hardness")->asNumber()->getNumber(),
+        groupNames);
+}
+
+Framework::JSON::JSONObject* ChestBlockTypeFactory::toJson(
+    ChestBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
+        new Framework::JSON::JSONString(zObject->getItemTypeName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    result->addValue("modelSubscription",
+        new Framework::JSON::JSONBool(zObject->doesNeedModelSubscription()));
+    result->addValue(
+        "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* ChestBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("itemType")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredBool("modelSubscription")
+        ->withDefault(false)
+        ->finishBool()
+        ->withRequiredNumber("hardness")
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text ChestBlockTypeFactory::getTypeToken() const
+{
+    return "chest";
 }

+ 30 - 1
FactoryCraft/Chest.h

@@ -18,7 +18,36 @@ protected:
 
 public:
     Chest(
-        int typeId, ItemType* zTool, Framework::Vec3<int> pos, int dimensionId);
+        int typeId, Framework::Vec3<int> pos, int dimensionId);
     virtual bool interact(Item* zItem, Entity* zActor) override;
     virtual void sendModelInfo(NetworkMessage* zMessage) override;
+};
+
+class ChestBlockType : public BasicBlockType
+{
+public:
+    ChestBlockType(Framework::Text itemTypeName,
+        ModelInfo* model,
+        Framework::Text name,
+        int mapColor,
+        bool modelSubscription,
+        float hardness,
+        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>
+{
+public:
+    ChestBlockTypeFactory();
+    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<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 32 - 44
FactoryCraft/Chunk.cpp

@@ -113,8 +113,7 @@ void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
                                    + pos.z;
                             int type = blockIds[bi];
                             needSend |= type != BlockTypeEnum::NO_BLOCK
-                                     && StaticRegistry<BlockType>::INSTANCE
-                                            .zElement(type)
+                                     && Game::INSTANCE->zBlockType(type)
                                             ->doesNeedClientInstance();
                         }
                         else
@@ -133,10 +132,8 @@ void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
                                                * WORLD_HEIGHT
                                            + (pos.z - offset.z);
                                     int type = zNeighbours[i]->blockIds[bi];
-                                    needSend
-                                        |= StaticRegistry<BlockType>::INSTANCE
-                                               .zElement(type)
-                                               ->doesNeedClientInstance();
+                                    needSend |= Game::INSTANCE->zBlockType(type)
+                                                    ->doesNeedClientInstance();
                                 }
                                 cs.unlock();
                             }
@@ -446,10 +443,10 @@ void Chunk::initializeLightning()
                                                 * 0.85f));
                     }
                     const Block* current
-                        = blocks[index] ? blocks[index]
-                                        : StaticRegistry<BlockType>::INSTANCE
-                                              .zElement(blockIds[index])
-                                              ->zDefault();
+                        = blocks[index]
+                            ? blocks[index]
+                            : Game::INSTANCE->zBlockType(blockIds[index])
+                                  ->zDefault();
                     // add own light emission
                     for (int j = 3; j < 6; j++)
                         newLight[j] = (unsigned char)MAX(newLight[j],
@@ -487,7 +484,7 @@ const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
 {
     auto b = zBlockAt(location);
     if (b.isA()) return b;
-    return StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())->zDefault();
+    return Game::INSTANCE->zBlockType(b.getB())->zDefault();
 }
 
 const Block* Chunk::zBlockConst(int index) const
@@ -495,8 +492,7 @@ const Block* Chunk::zBlockConst(int index) const
     if (blocks[index])
         return blocks[index];
     else
-        return StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])
-            ->zDefault();
+        return Game::INSTANCE->zBlockType(blockIds[index])->zDefault();
 }
 
 void Chunk::instantiateBlock(Framework::Vec3<int> location)
@@ -507,13 +503,12 @@ void Chunk::instantiateBlock(Framework::Vec3<int> location)
     b = zBlockAt(location);
     if (b.isB())
         putBlockAt(location,
-            StaticRegistry<BlockType>::INSTANCE.zElement(b.getB())
-                ->createBlockAt(
-                    {location.x + this->location.x - CHUNK_SIZE / 2,
-                        location.y + this->location.y - CHUNK_SIZE / 2,
-                        location.z},
-                    dimensionId,
-                    0));
+            Game::INSTANCE->zBlockType(b.getB())->createBlockAt(
+                {location.x + this->location.x - CHUNK_SIZE / 2,
+                    location.y + this->location.y - CHUNK_SIZE / 2,
+                    location.z},
+                dimensionId,
+                0));
 }
 
 void Chunk::generateBlock(Framework::Vec3<int> location)
@@ -550,8 +545,7 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
     bool change = 0;
     bool wasLightSource
         = old ? old->zBlockType()->isLightSource()
-              : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])
-                    ->isLightSource();
+              : Game::INSTANCE->zBlockType(blockIds[index])->isLightSource();
     bool isLightSource = 0;
     if (block)
     {
@@ -629,10 +623,8 @@ void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
     int index = Chunk::index(location);
     assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
     bool wasLightSource
-        = StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])
-              ->isLightSource();
-    bool isLightSource
-        = StaticRegistry<BlockType>::INSTANCE.zElement(type)->isLightSource();
+        = Game::INSTANCE->zBlockType(blockIds[index])->isLightSource();
+    bool isLightSource = Game::INSTANCE->zBlockType(type)->isLightSource();
     if (blockIds[index] != (unsigned short)type)
     {
         blockIds[index] = (unsigned short)type;
@@ -820,13 +812,13 @@ void Chunk::load(Framework::StreamReader* zReader)
             if (d)
             {
                 putBlockAt(pos,
-                    StaticRegistry<BlockType>::INSTANCE.zElement(blockType)
-                        ->loadBlock(Framework::Vec3<int>(
-                                        pos.x + location.x - CHUNK_SIZE / 2,
-                                        pos.y + location.y - CHUNK_SIZE / 2,
-                                        pos.z),
-                            zReader,
-                            dimensionId));
+                    Game::INSTANCE->zBlockType(blockType)->loadBlock(
+                        Framework::Vec3<int>(
+                            pos.x + location.x - CHUNK_SIZE / 2,
+                            pos.y + location.y - CHUNK_SIZE / 2,
+                            pos.z),
+                        zReader,
+                        dimensionId));
             }
             else
             {
@@ -852,8 +844,8 @@ void Chunk::save(Framework::StreamWriter* zWriter)
             {
                 bool d = 1;
                 zWriter->schreibe((char*)&d, 1);
-                StaticRegistry<BlockType>::INSTANCE.zElement(blockType)
-                    ->saveBlock(blocks[index], zWriter);
+                Game::INSTANCE->zBlockType(blockType)->saveBlock(
+                    blocks[index], zWriter);
             }
             else
             {
@@ -874,8 +866,7 @@ void Chunk::sendToClient(Framework::StreamWriter* zWriter)
             {
                 int index = Chunk::index({x, y, z});
                 if (isVisible(index)
-                    && StaticRegistry<BlockType>::INSTANCE
-                           .zElement(blockIds[index])
+                    && Game::INSTANCE->zBlockType(blockIds[index])
                            ->doesNeedClientInstance())
                 {
                     unsigned short blockType = blocks[index]
@@ -885,9 +876,7 @@ void Chunk::sendToClient(Framework::StreamWriter* zWriter)
                                                  : blockIds[index];
                     zWriter->schreibe((char*)&blockType, 2);
                     zWriter->schreibe((char*)&index, 4);
-                    if (StaticRegistry<BlockType>::INSTANCE
-                            .zElement(blockIds[index])
-                            ->isFluid())
+                    if (Game::INSTANCE->zBlockType(blockIds[index])->isFluid())
                     {
                         FluidBlock* fluidBlock
                             = dynamic_cast<FluidBlock*>(blocks[index]);
@@ -944,8 +933,7 @@ void Chunk::removeUnusedBlocks()
     int count = 0;
     for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
     {
-        if (StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[i])
-                ->doesNeedClientInstance())
+        if (Game::INSTANCE->zBlockType(blockIds[i])->doesNeedClientInstance())
             count++;
     }
     std::cout << "chunk " << location.x << ", " << location.y
@@ -1040,7 +1028,7 @@ void Chunk::setLightData(
             {
                 int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
                 int type = blockIds[bi];
-                needSend |= StaticRegistry<BlockType>::INSTANCE.zElement(type)
+                needSend |= Game::INSTANCE->zBlockType(type)
                                 ->doesNeedClientInstance();
                 if (needSend) break;
             }
@@ -1052,7 +1040,7 @@ void Chunk::setLightData(
                             this->location.y - CHUNK_SIZE / 2,
                             0),
                     dimensionId);
-                needSend |= StaticRegistry<BlockType>::INSTANCE.zElement(type)
+                needSend |= Game::INSTANCE->zBlockType(type)
                                 ->doesNeedClientInstance();
                 if (needSend) break;
             }

+ 2 - 1
FactoryCraft/ChunkMap.cpp

@@ -2,6 +2,7 @@
 
 #include "Chunk.h"
 #include "Constants.h"
+#include "Game.h"
 
 ChunkMap::ChunkMap(Framework::Punkt chunkCenter)
     : ReferenceCounter(),
@@ -44,7 +45,7 @@ ChunkMap::ChunkMap(Chunk* zChunk)
                     MapBlock tmp = {(unsigned char)height,
                         ((color1 >> 24) & 0xFF) > ((color2 >> 24) & 0xFF)
                             ? color1
-                                                                 : color2};
+                            : color2};
                     blocksBuffer[256 - ++count] = tmp;
                 }
             }

+ 6 - 10
FactoryCraft/Dimension.cpp

@@ -322,8 +322,7 @@ void Dimension::saveStructure(MultiblockStructure* zStructure) const
     d.schreibe((char*)&typeId, 4);
     __int64 strId = zStructure->getStructureId();
     d.schreibe((char*)&strId, 8);
-    StaticRegistry<MultiblockStructureType>::INSTANCE
-        .zElement(zStructure->getStructureTypeId())
+    Game::INSTANCE->zMultiblockStructureType(zStructure->getStructureTypeId())
         ->saveStructure(zStructure, &d);
     d.close();
 }
@@ -557,8 +556,7 @@ void Dimension::save(Text worldDir) const
                 {
                     int type = entity->zType()->getId();
                     file->schreibe((char*)&type, 4);
-                    StaticRegistry<EntityType>::INSTANCE.zElement(type)
-                        ->saveEntity(entity, file);
+                    Game::INSTANCE->zEntityType(type)->saveEntity(entity, file);
                 }
             }
             else
@@ -568,8 +566,7 @@ void Dimension::save(Text worldDir) const
                                + Game::INSTANCE->getPlayerId(
                                    ((Player*)entity)->getName()));
                 if (pFile.open(Datei::Style::schreiben))
-                    StaticRegistry<EntityType>::INSTANCE
-                        .zElement(EntityTypeEnum::PLAYER)
+                    Game::INSTANCE->zEntityType(EntityTypeEnum::PLAYER)
                         ->saveEntity(entity, &pFile);
             }
         }
@@ -812,8 +809,7 @@ MultiblockStructure* Dimension::zStructureByPosition(
                     __int64 strId;
                     d.lese((char*)&strId, 8);
                     MultiblockStructure* str
-                        = StaticRegistry<MultiblockStructureType>::INSTANCE
-                              .zElement(type)
+                        = Game::INSTANCE->zMultiblockStructureType(type)
                               ->loadStructure(
                                   dimensionId, strId, uniquePosition, &d);
                     d.close();
@@ -859,8 +855,8 @@ MultiblockStructure* Dimension::zStructureById(__int64 id)
         __int64 strId;
         d.lese((char*)&strId, 8);
         MultiblockStructure* str
-            = StaticRegistry<MultiblockStructureType>::INSTANCE.zElement(type)
-                  ->loadStructure(dimensionId, strId, uPos, &d);
+            = Game::INSTANCE->zMultiblockStructureType(type)->loadStructure(
+                dimensionId, strId, uPos, &d);
         d.close();
         structures.add(str);
         structurCs.unlock();

+ 18 - 17
FactoryCraft/Entity.cpp

@@ -138,9 +138,8 @@ void ActionTarget::toMessage(
             }
             else if (block.isB())
             {
-                targetUIML = StaticRegistry<BlockType>::INSTANCE
-                                 .zElement(block.getB())
-                                 ->getTargetUIML();
+                targetUIML
+                    = Game::INSTANCE->zBlockType(block.getB())->getTargetUIML();
             }
             char* message = new char[18 + targetUIML.getLength() + 2];
             message[0] = 3;
@@ -250,14 +249,15 @@ bool Entity::useItem(int typeId, ItemStack* zStack, bool left)
                 ItemSkill* selected = zSkill(typeId);
                 if (!selected)
                 {
-                    selected
-                        = StaticRegistry<ItemType>::INSTANCE.zElement(typeId)
-                              ->createDefaultItemSkill();
+                    selected = Game::INSTANCE->zItemType(typeId)
+                                   ->createDefaultItemSkill();
+                    selected->setItemTypeId(typeId);
                     if (selected) skills.add(selected);
                 }
                 if (!selected)
                 {
                     selected = zSkill(ItemTypeEnum::PLAYER_HAND);
+                    selected->setItemTypeId(ItemTypeEnum::PLAYER_HAND);
                 }
                 bool result = target->useItemSkillOnTarget(this,
                     selected,
@@ -294,8 +294,8 @@ bool Entity::useItem(int typeId, ItemStack* zStack, bool left)
                             addItems(newStack, NO_DIRECTION, 0);
                             if (newStack->getSize())
                             {
-                                Game::INSTANCE->spawnItem(location,
-                                    dimensionId, newStack);
+                                Game::INSTANCE->spawnItem(
+                                    location, dimensionId, newStack);
                             }
                         }
                         else
@@ -316,8 +316,8 @@ bool Entity::useItem(int typeId, ItemStack* zStack, bool left)
                 }
                 else
                 {
-                	cs.unlock();
-					return 0;
+                    cs.unlock();
+                    return 0;
                 }
             }
             cs.unlock();
@@ -348,14 +348,15 @@ bool Entity::useItem(int typeId, ItemStack* zStack, bool left)
                 ItemSkill* selected = zSkill(typeId);
                 if (!selected)
                 {
-                    selected
-                        = StaticRegistry<ItemType>::INSTANCE.zElement(typeId)
-                              ->createDefaultItemSkill();
+                    selected = Game::INSTANCE->zItemType(typeId)
+                                   ->createDefaultItemSkill();
+                    selected->setItemTypeId(typeId);
                     if (selected) skills.add(selected);
                 }
                 if (!selected)
                 {
                     selected = zSkill(ItemTypeEnum::PLAYER_HAND);
+                    selected->setItemTypeId(ItemTypeEnum::PLAYER_HAND);
                 }
                 bool result = target->interactItemSkillOnTarget(this,
                     selected,
@@ -581,7 +582,7 @@ ItemSkill* Entity::zSkill(int itemType)
 {
     for (ItemSkill* skill : skills)
     {
-        if (skill->getTypeId() == typeId)
+        if (skill->getItemTypeId() == typeId)
         {
             return skill;
         }
@@ -833,7 +834,7 @@ bool Entity::isRemoved() const
 
 const EntityType* Entity::zType() const
 {
-    return StaticRegistry<EntityType>::INSTANCE.zElement(typeId);
+    return Game::INSTANCE->zEntityType(typeId);
 }
 
 const ActionTarget* Entity::zTarget() const
@@ -851,9 +852,9 @@ bool Entity::hasDefaultModel() const
     return 1;
 }
 
-ModelInfo Entity::getSpecialModel() const
+ModelInfo* Entity::zSpecialModel() const
 {
-    return ModelInfo("", "", 0);
+    return 0;
 }
 
 float Entity::getMaxSpeed() const

+ 1 - 1
FactoryCraft/Entity.h

@@ -130,7 +130,7 @@ public:
     const ActionTarget* zTarget() const;
     int getId() const;
     virtual bool hasDefaultModel() const;
-    virtual ModelInfo getSpecialModel() const;
+    virtual ModelInfo* zSpecialModel() const;
     float getMaxSpeed() const;
     bool isMoving() const;
     int getChatSecurityLevel() const;

+ 31 - 11
FactoryCraft/EntityType.cpp

@@ -3,12 +3,16 @@
 #include "Entity.h"
 #include "Game.h"
 
-EntityType::EntityType(int id, ModelInfo model)
+EntityType::EntityType(Framework::Text name, ModelInfo* model)
     : ReferenceCounter(),
-      id(id),
-      model(model)
+      name(name),
+      model(model),
+      id(-1)
+{}
+
+EntityType::~EntityType()
 {
-    StaticRegistry<EntityType>::INSTANCE.registerT(this, id);
+    if (model) model->release();
 }
 
 void EntityType::loadSuperEntity(
@@ -44,9 +48,10 @@ void EntityType::loadSuperEntity(
     {
         int type;
         zReader->lese((char*)&type, 4);
-        zEntity->skills.add(
-            StaticRegistry<ItemType>::INSTANCE.zElement(type)->loadItemSkill(
-                zReader));
+        ItemSkill* skill
+            = Game::INSTANCE->zItemType(type)->createDefaultItemSkill();
+        skill->load(zReader);
+        zEntity->skills.add(skill);
     }
 }
 
@@ -79,14 +84,19 @@ void EntityType::saveSuperEntity(
     zWriter->schreibe((char*)&skillCount, 4);
     for (ItemSkill* skill : zEntity->skills)
     {
-        int type = skill->zSkillType()->getId();
+        int type = skill->getItemTypeId();
         zWriter->schreibe((char*)&type, 4);
-        skill->zSkillType()->saveItemSkill(skill, zWriter);
+        skill->save(zWriter);
     }
 }
 
 void EntityType::createSuperEntity(Entity* zEntity) const {}
 
+bool EntityType::initialize(Game* zGame)
+{
+    return true;
+}
+
 Entity* EntityType::loadEntity(Framework::StreamReader* zReader) const
 {
     Entity* entity = createEntity(Framework::Vec3<float>(0, 0, 0), 0, 0);
@@ -114,7 +124,17 @@ int EntityType::getId() const
     return id;
 }
 
-const ModelInfo& EntityType::getModel() const
+ModelInfo* EntityType::zModel() const
 {
     return model;
-}
+}
+
+void EntityType::setTypeId(int id)
+{
+    this->id = id;
+}
+
+Framework::Text EntityType::getName() const
+{
+    return name;
+}

+ 10 - 5
FactoryCraft/EntityType.h

@@ -6,9 +6,9 @@
 #include <Writer.h>
 
 #include "ModelInfo.h"
-#include "StaticRegistry.h"
 
 class Entity;
+class Game;
 
 class EntityTypeEnum
 {
@@ -20,11 +20,13 @@ public:
 class EntityType : public virtual Framework::ReferenceCounter
 {
 private:
-    const int id;
-    const ModelInfo model;
+    Framework::Text name;
+    int id;
+    ModelInfo *model;
 
 protected:
-    EntityType(int id, ModelInfo model);
+    EntityType(Framework::Text name, ModelInfo* model);
+    ~EntityType();
 
     virtual void loadSuperEntity(
         Entity* zEntity, Framework::StreamReader* zReader) const;
@@ -33,6 +35,7 @@ protected:
     virtual void createSuperEntity(Entity* zEntity) const;
 
 public:
+    virtual bool initialize(Game *zGame);
     virtual Entity* loadEntity(Framework::StreamReader* zReader) const;
     virtual void saveEntity(
         Entity* zEntity, Framework::StreamWriter* zWriter) const;
@@ -43,5 +46,7 @@ public:
         int entityId) const = 0;
 
     int getId() const;
-    const ModelInfo& getModel() const;
+    ModelInfo* zModel() const;
+    void setTypeId(int id);
+    Framework::Text getName() const;
 };

+ 9 - 9
FactoryCraft/FactoryCraft.vcxproj

@@ -96,6 +96,8 @@
     <RemoteTargetPath>$(RemoteProjectDir)/$(TargetName)$(TargetExt)</RemoteTargetPath>
   </PropertyGroup>
   <ItemGroup>
+    <ClInclude Include="ArrayUtils.h" />
+    <ClInclude Include="BlockFilter.h" />
     <ClInclude Include="BlockInfoCommand.h" />
     <ClInclude Include="BlockInstanceGeneratorRule.h" />
     <ClInclude Include="FactorizeNoise.h" />
@@ -107,7 +109,6 @@
     <ClInclude Include="ChunkMap.h" />
     <ClInclude Include="AddEntityUpdate.h" />
     <ClInclude Include="Area.h" />
-    <ClInclude Include="Axe.h" />
     <ClInclude Include="BasicBlocks.h" />
     <ClInclude Include="BasicItems.h" />
     <ClInclude Include="BasicTool.h" />
@@ -138,7 +139,6 @@
     <ClInclude Include="GrantCommand.h" />
     <ClInclude Include="Grass.h" />
     <ClInclude Include="Chat.h" />
-    <ClInclude Include="Hoe.h" />
     <ClInclude Include="InformationObserver.h" />
     <ClInclude Include="Inventory.h" />
     <ClInclude Include="Item.h" />
@@ -151,6 +151,7 @@
     <ClInclude Include="ItemType.h" />
     <ClInclude Include="JNoise.h" />
     <ClInclude Include="JsonExpression.h" />
+    <ClInclude Include="JsonUtils.h" />
     <ClInclude Include="LightSources.h" />
     <ClInclude Include="DimensionMap.h" />
     <ClInclude Include="ModelInfo.h" />
@@ -164,6 +165,7 @@
     <ClInclude Include="OverworldDimension.h" />
     <ClInclude Include="NoiseInterpolator.h" />
     <ClInclude Include="OverworldDimensionGenerator.h" />
+    <ClInclude Include="PlaceableProof.h" />
     <ClInclude Include="Player.h" />
     <ClInclude Include="PlayerHand.h" />
     <ClInclude Include="PlayerRegister.h" />
@@ -181,8 +183,6 @@
     <ClInclude Include="Server.h" />
     <ClInclude Include="Dimension.h" />
     <ClInclude Include="ShapedNoise.h" />
-    <ClInclude Include="Shovel.h" />
-    <ClInclude Include="StaticRegistry.h" />
     <ClInclude Include="StructureCollection.h" />
     <ClInclude Include="Tickable.h" />
     <ClInclude Include="TickOrganizer.h" />
@@ -202,12 +202,13 @@
   <ItemGroup>
     <ClCompile Include="AddEntityUpdate.cpp" />
     <ClCompile Include="Area.cpp" />
-    <ClCompile Include="Axe.cpp" />
-    <ClCompile Include="BasicBlock.cpp" />
+    <ClCompile Include="ArrayUtils.cpp" />
+    <ClCompile Include="BasicBlocks.cpp" />
     <ClCompile Include="BasicItems.cpp" />
     <ClCompile Include="BasicTool.cpp" />
     <ClCompile Include="BiomGenerator.cpp" />
     <ClCompile Include="Block.cpp" />
+    <ClCompile Include="BlockFilter.cpp" />
     <ClCompile Include="BlockInfoCommand.cpp" />
     <ClCompile Include="BlockInstanceGeneratorRule.cpp" />
     <ClCompile Include="BlockType.cpp" />
@@ -240,7 +241,6 @@
     <ClCompile Include="GeneratorRule.cpp" />
     <ClCompile Include="GrantCommand.cpp" />
     <ClCompile Include="Grass.cpp" />
-    <ClCompile Include="Hoe.cpp" />
     <ClCompile Include="InformationObserver.cpp" />
     <ClCompile Include="Inventory.cpp" />
     <ClCompile Include="Item.cpp" />
@@ -253,6 +253,7 @@
     <ClCompile Include="ItemType.cpp" />
     <ClCompile Include="JNoise.cpp" />
     <ClCompile Include="JsonExpression.cpp" />
+    <ClCompile Include="JsonUtils.cpp" />
     <ClCompile Include="LightSources.cpp" />
     <ClCompile Include="ModelInfo.cpp" />
     <ClCompile Include="MultiblockStructure.cpp" />
@@ -265,6 +266,7 @@
     <ClCompile Include="OverworldDimension.cpp" />
     <ClCompile Include="NoiseInterpolator.cpp" />
     <ClCompile Include="OverworldDimensionGenerator.cpp" />
+    <ClCompile Include="PlaceableProof.cpp" />
     <ClCompile Include="Player.cpp" />
     <ClCompile Include="PlayerHand.cpp" />
     <ClCompile Include="PlayerRegister.cpp" />
@@ -281,9 +283,7 @@
     <ClCompile Include="ScaleNoise.cpp" />
     <ClCompile Include="Server.cpp" />
     <ClCompile Include="ShapedNoise.cpp" />
-    <ClCompile Include="Shovel.cpp" />
     <ClCompile Include="Start.cpp" />
-    <ClCompile Include="StaticInitializerOrder.cpp" />
     <ClCompile Include="StructureCollection.cpp" />
     <ClCompile Include="TickOrganizer.cpp" />
     <ClCompile Include="TickQueue.cpp" />

+ 28 - 25
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -106,6 +106,9 @@
     <Filter Include="inventory\items\fluidContainer">
       <UniqueIdentifier>{59a5d9f2-a3fb-45a5-92c8-c641f2891b01}</UniqueIdentifier>
     </Filter>
+    <Filter Include="server\utils">
+      <UniqueIdentifier>{843e5bdf-f68d-4178-93be-426e72b12699}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -156,9 +159,6 @@
     <ClInclude Include="BasicBlocks.h">
       <Filter>world\blocks</Filter>
     </ClInclude>
-    <ClInclude Include="StaticRegistry.h">
-      <Filter>static</Filter>
-    </ClInclude>
     <ClInclude Include="WorldGenerator.h">
       <Filter>world\generator</Filter>
     </ClInclude>
@@ -291,9 +291,6 @@
     <ClInclude Include="Grass.h">
       <Filter>world\blocks</Filter>
     </ClInclude>
-    <ClInclude Include="Hoe.h">
-      <Filter>inventory\items\tools</Filter>
-    </ClInclude>
     <ClInclude Include="BasicTool.h">
       <Filter>inventory\items\tools</Filter>
     </ClInclude>
@@ -303,9 +300,6 @@
     <ClInclude Include="FluidBlock.h">
       <Filter>world\blocks\fluids</Filter>
     </ClInclude>
-    <ClInclude Include="Axe.h">
-      <Filter>inventory\items\tools</Filter>
-    </ClInclude>
     <ClInclude Include="ChatCommand.h">
       <Filter>chat</Filter>
     </ClInclude>
@@ -339,9 +333,6 @@
     <ClInclude Include="Chest.h">
       <Filter>world\blocks\storage</Filter>
     </ClInclude>
-    <ClInclude Include="Shovel.h">
-      <Filter>inventory\items\tools</Filter>
-    </ClInclude>
     <ClInclude Include="JsonExpression.h">
       <Filter>server\config</Filter>
     </ClInclude>
@@ -414,6 +405,18 @@
     <ClInclude Include="FluidContainer.h">
       <Filter>inventory\items\fluidContainer</Filter>
     </ClInclude>
+    <ClInclude Include="JsonUtils.h">
+      <Filter>server\config</Filter>
+    </ClInclude>
+    <ClInclude Include="BlockFilter.h">
+      <Filter>world</Filter>
+    </ClInclude>
+    <ClInclude Include="ArrayUtils.h">
+      <Filter>server\utils</Filter>
+    </ClInclude>
+    <ClInclude Include="PlaceableProof.h">
+      <Filter>world</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -425,15 +428,12 @@
     <ClCompile Include="Block.cpp">
       <Filter>world</Filter>
     </ClCompile>
-    <ClCompile Include="BasicBlock.cpp">
+    <ClCompile Include="BasicBlocks.cpp">
       <Filter>world\blocks</Filter>
     </ClCompile>
     <ClCompile Include="Start.cpp">
       <Filter>server</Filter>
     </ClCompile>
-    <ClCompile Include="StaticInitializerOrder.cpp">
-      <Filter>static</Filter>
-    </ClCompile>
     <ClCompile Include="ItemType.cpp">
       <Filter>inventory</Filter>
     </ClCompile>
@@ -584,9 +584,6 @@
     <ClCompile Include="Grass.cpp">
       <Filter>world\blocks</Filter>
     </ClCompile>
-    <ClCompile Include="Hoe.cpp">
-      <Filter>inventory\items\tools</Filter>
-    </ClCompile>
     <ClCompile Include="BasicTool.cpp">
       <Filter>inventory\items\tools</Filter>
     </ClCompile>
@@ -599,9 +596,6 @@
     <ClCompile Include="RecipieList.cpp">
       <Filter>inventory\recipies</Filter>
     </ClCompile>
-    <ClCompile Include="Axe.cpp">
-      <Filter>inventory\items\tools</Filter>
-    </ClCompile>
     <ClCompile Include="SaveCommand.cpp">
       <Filter>chat\commands</Filter>
     </ClCompile>
@@ -635,9 +629,6 @@
     <ClCompile Include="Chest.cpp">
       <Filter>world\blocks\storage</Filter>
     </ClCompile>
-    <ClCompile Include="Shovel.cpp">
-      <Filter>inventory\items\tools</Filter>
-    </ClCompile>
     <ClCompile Include="JsonExpression.cpp">
       <Filter>server\config</Filter>
     </ClCompile>
@@ -710,5 +701,17 @@
     <ClCompile Include="FluidContainer.cpp">
       <Filter>inventory\items\fluidContainer</Filter>
     </ClCompile>
+    <ClCompile Include="JsonUtils.cpp">
+      <Filter>server\config</Filter>
+    </ClCompile>
+    <ClCompile Include="BlockFilter.cpp">
+      <Filter>world</Filter>
+    </ClCompile>
+    <ClCompile Include="ArrayUtils.cpp">
+      <Filter>server\utils</Filter>
+    </ClCompile>
+    <ClCompile Include="PlaceableProof.cpp">
+      <Filter>world</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 170 - 15
FactoryCraft/FluidBlock.cpp

@@ -7,7 +7,7 @@ FluidBlock::FluidBlock(int typeId,
     Framework::Vec3<int> pos,
     int dimensionId,
     Vec3<float> lightWeights)
-    : Block(typeId, 0, pos, dimensionId, 0),
+    : Block(typeId, pos, dimensionId, 0),
       lightWeights(lightWeights),
       neighborChanged(1),
       nextFlow(0),
@@ -218,17 +218,23 @@ char FluidBlock::getFlowOptions() const
     return flowOptions;
 }
 
-FluidBlockType::FluidBlockType(int id,
-    ModelInfo model,
-    const char* name,
+FluidBlockType::FluidBlockType(ModelInfo* model,
+    Framework::Text name,
     int mapColor,
     Vec3<float> lightWeights,
     int ticktsToFlow,
-    char flowDistance)
-    : BlockType(id, 0, model, 1, 10, 0, name, true, mapColor),
+    unsigned char flowDistance,
+    float hpRecoveryPerL,
+    float thirstRecoveryPerL,
+    float heat,
+    Framework::RCArray<Framework::Text> groupNames)
+    : BlockType(0, model, 1, 10, 0, name, true, mapColor, groupNames, 0.f),
       lightWeights(lightWeights),
       ticktsToFlow(ticktsToFlow),
-      flowDistance(flowDistance)
+      flowDistance(flowDistance),
+      hungerRecoveryPerL(hungerRecoveryPerL),
+      thirstRecoveryPerL(thirstRecoveryPerL),
+    heat(heat)
 {}
 
 void FluidBlockType::loadSuperBlock(
@@ -276,20 +282,169 @@ int FluidBlockType::getTicktsToFlow() const
     return ticktsToFlow;
 }
 
-char FluidBlockType::getFlowDistance() const
+unsigned char FluidBlockType::getFlowDistance() const
 {
     return flowDistance;
 }
 
-std::function<bool(FluidContainerItem*, Entity*)>
-FluidBlockType::getFoodEffect() const
+Framework::Vec3<float> FluidBlockType::getLightWeights() const
 {
-    return foodEffect;
+    return lightWeights;
 }
 
-FluidBlockType* FluidBlockType::setFoodEffect(
-    std::function<bool(FluidContainerItem*, Entity*)> foodEffect)
+float FluidBlockType::getHungerRecoveryPerL() const
 {
-    this->foodEffect = foodEffect;
-    return this;
+    return hungerRecoveryPerL;
+}
+
+float FluidBlockType::getThirstRecoveryPerL() const
+{
+    return thirstRecoveryPerL;
+}
+
+ItemType* FluidBlockType::createItemType() const
+{
+    return 0;
+}
+
+float FluidBlockType::getHeat() const
+{
+    return heat;
+}
+
+FluidBlockTypeFactory::FluidBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+FluidBlockType* FluidBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    return new FluidBlockType(
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("name")->asString()->getString(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        Framework::Vec3<float>((float)zJson->zValue("lightWeight")
+                                   ->asObject()
+                                   ->zValue("red")
+                                   ->asNumber()
+                                   ->getNumber(),
+            (float)zJson->zValue("lightWeight")
+                ->asObject()
+                ->zValue("green")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("lightWeight")
+                ->asObject()
+                ->zValue("blue")
+                ->asNumber()
+                ->getNumber()),
+        (int)zJson->zValue("ticksToFlow")->asNumber()->getNumber(),
+        (char)zJson->zValue("flowDistance")->asNumber()->getNumber(),
+        (float)zJson->zValue("hungerRecoveryPerL")->asNumber()->getNumber(),
+        (float)zJson->zValue("thirstRecoveryPerL")->asNumber()->getNumber(),
+        (float)zJson->zValue("heat")->asNumber()->getNumber(),
+        groupNames);
+}
+
+Framework::JSON::JSONObject* FluidBlockTypeFactory::toJson(
+    FluidBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    Framework::JSON::JSONObject* lightWeight
+        = new Framework::JSON::JSONObject();
+    lightWeight->addValue(
+        "red", new Framework::JSON::JSONNumber(zObject->getLightWeights().x));
+    lightWeight->addValue(
+        "green", new Framework::JSON::JSONNumber(zObject->getLightWeights().y));
+    lightWeight->addValue(
+        "blue", new Framework::JSON::JSONNumber(zObject->getLightWeights().z));
+    result->addValue("lightWeight", lightWeight);
+    result->addValue("ticksToFlow",
+        new Framework::JSON::JSONNumber((double)zObject->getTicktsToFlow()));
+    result->addValue("flowDistance",
+        new Framework::JSON::JSONNumber((double)zObject->getFlowDistance()));
+    result->addValue("hungerRecoveryPerL",
+        new Framework::JSON::JSONNumber(
+            (double)zObject->getHungerRecoveryPerL()));
+    result->addValue("thirstRecoveryPerL",
+        new Framework::JSON::JSONNumber(
+            (double)zObject->getThirstRecoveryPerL()));
+    result->addValue("heat",
+        new Framework::JSON::JSONNumber(
+            (double)zObject->getHeat()));
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* FluidBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredObject("lightWeight")
+        ->withRequiredNumber("red")
+        ->whichIsGreaterOrEqual(0.0)
+        ->whichIsLessOrEqual(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("green")
+        ->whichIsGreaterOrEqual(0.0)
+        ->whichIsLessOrEqual(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("blue")
+        ->whichIsGreaterOrEqual(0.0)
+        ->whichIsLessOrEqual(1.0)
+        ->finishNumber()
+        ->finishObject()
+        ->withRequiredNumber("ticksToFlow")
+        ->whichIsGreaterOrEqual(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("flowDistance")
+        ->whichIsGreaterOrEqual(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("hungerRecoveryPerL")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("thirstRecoveryPerL")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber()
+        ->withRequiredNumber("heat")
+        ->withDefault(10.0)
+        ->finishNumber()
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text FluidBlockTypeFactory::getTypeToken() const
+{
+    return "fluid";
 }

+ 34 - 15
FactoryCraft/FluidBlock.h

@@ -14,7 +14,7 @@ private:
     int nextFlow;
     Framework::Vec3<float> lightWeights;
     bool neighborChanged;
-    char maxFlowDistance;
+    unsigned char maxFlowDistance;
 
 protected:
     virtual bool onTick(
@@ -46,8 +46,22 @@ class FluidBlockType : public BlockType
 private:
     Framework::Vec3<float> lightWeights;
     int ticktsToFlow;
-    char flowDistance;
-    std::function<bool(FluidContainerItem*, Entity*)> foodEffect;
+    unsigned char flowDistance;
+    float hungerRecoveryPerL;
+    float thirstRecoveryPerL;
+    float heat;
+
+public:
+    FluidBlockType(ModelInfo* model,
+        Framework::Text name,
+        int mapColor,
+        Framework::Vec3<float> lightWeights,
+        int ticktsToFlow,
+        unsigned char flowDistance,
+        float hungerRecoveryPerL,
+        float thirstRecoveryPerL,
+        float heat,
+        Framework::RCArray<Framework::Text> groupNames);
 
 protected:
     virtual void loadSuperBlock(Block* zBlock,
@@ -60,19 +74,24 @@ protected:
         Framework::Vec3<int> position, int dimesionId) const override;
 
 public:
-    FluidBlockType(int id,
-        ModelInfo model,
-        const char* name,
-        int mapColor,
-        Framework::Vec3<float> lightWeights,
-        int ticktsToFlow,
-        char flowDistance);
-
     bool isFluid() const override;
     int getTicktsToFlow() const;
-    char getFlowDistance() const override;
-    std::function<bool(FluidContainerItem*, Entity*)> getFoodEffect() const;
+    unsigned char getFlowDistance() const override;
+    Framework::Vec3<float> getLightWeights() const;
+    float getHungerRecoveryPerL() const;
+    float getThirstRecoveryPerL() const;
+    virtual ItemType* createItemType() const override;
+    float getHeat() const;
+};
 
-    FluidBlockType* setFoodEffect(
-        std::function<bool(FluidContainerItem*, Entity*)> foodEffect);
+class FluidBlockTypeFactory : public SubTypeFactory<BlockType, FluidBlockType>
+{
+public:
+    FluidBlockTypeFactory();
+    FluidBlockType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(FluidBlockType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 455 - 95
FactoryCraft/FluidContainer.cpp

@@ -5,7 +5,7 @@
 #include "FluidBlock.h"
 #include "Game.h"
 
-FluidContainerItem::FluidContainerItem(int itemTypeId, const char* name)
+FluidContainerItem::FluidContainerItem(int itemTypeId, Framework::Text name)
     : Item(itemTypeId, name),
       fluidTypeId(0),
       fluidAmount(0)
@@ -17,7 +17,9 @@ FluidContainerItem::FluidContainerItem(int itemTypeId, const char* name)
 
 const BlockType* FluidContainerItem::zPlacedBlockType() const
 {
-    return fluidTypeId && fluidAmount >= 1000 ? StaticRegistry<BlockType>::INSTANCE.zElement(fluidTypeId) : 0;
+    return fluidTypeId && fluidAmount >= 1000
+             ? Game::INSTANCE->zBlockType(fluidTypeId)
+             : 0;
 }
 
 bool FluidContainerItem::canBeStackedWith(const Item* zItem) const
@@ -66,9 +68,7 @@ Framework::Text FluidContainerItem::getTooltipUIML() const
     if (fluidTypeId != 0)
     {
         uiml.append() << "\nFluid: "
-                      << StaticRegistry<BlockType>::INSTANCE
-                             .zElement(fluidTypeId)
-                             ->getName()
+                      << Game::INSTANCE->zBlockType(fluidTypeId)->getName()
                       << "\nAmount: " << fluidAmount << " L";
     }
     else
@@ -84,10 +84,35 @@ bool FluidContainerItem::applyFoodEffects(Entity* zTarget)
     if (fluidTypeId)
     {
         const FluidBlockType* fluidType = dynamic_cast<const FluidBlockType*>(
-            StaticRegistry<BlockType>::INSTANCE.zElement(fluidTypeId));
-        if (fluidType && fluidType->getFoodEffect())
+            Game::INSTANCE->zBlockType(fluidTypeId));
+        if (fluidType
+            && (fluidType->getHungerRecoveryPerL()
+                || fluidType->getThirstRecoveryPerL()))
         {
-            return fluidType->getFoodEffect()(this, zTarget);
+            int drinkable
+                = fluidType->getThirstRecoveryPerL() > 0
+                    ? (int)((zTarget->getMaxThirst() - zTarget->getThirst())
+                            / fluidType->getThirstRecoveryPerL())
+                    : (int)((zTarget->getMaxHunger() - zTarget->getHunger())
+                            / fluidType->getHungerRecoveryPerL());
+            if (fluidType->getHungerRecoveryPerL() > 0
+                && fluidType->getThirstRecoveryPerL() > 0)
+            {
+                int drinkable2
+                    = (int)((zTarget->getMaxHunger() - zTarget->getHunger())
+                            / fluidType->getHungerRecoveryPerL());
+                if (drinkable2 < drinkable) drinkable = drinkable2;
+            }
+            if (getAmount() < drinkable) drinkable = getAmount();
+            if (!drinkable) return false;
+            setAmount(getAmount() - drinkable);
+            zTarget->setThirst(
+                zTarget->getThirst()
+                + drinkable * fluidType->getThirstRecoveryPerL());
+            zTarget->setHunger(
+                zTarget->getHunger()
+                + drinkable * fluidType->getHungerRecoveryPerL());
+            return true;
         }
     }
     return false;
@@ -126,47 +151,230 @@ void FluidContainerItem::setFluidTypeId(int fluidTypeId)
     }
 }
 
-FluidContainerItemSkill::FluidContainerItemSkill(int itemTypeId)
-    : ItemSkill(itemTypeId),
-      level(1),
-      xp(0.f),
-      maxXP(10.f)
+FluidContainerItemSkillConfig::FluidContainerItemSkillConfig(
+    BlockFilter* targetFilter,
+    float staminaCost,
+    float staminaCostDevider,
+    float staminaCostDeviderPerLevel,
+    int cooldownTicks,
+    float xpGain)
+    : targetFilter(targetFilter),
+      staminaCost(staminaCost),
+      staminaCostDevider(staminaCostDevider),
+      staminaCostDeviderPerLevel(staminaCostDeviderPerLevel),
+      cooldownTicks(cooldownTicks),
+      xpGain(xpGain)
+{}
+
+FluidContainerItemSkillConfig::~FluidContainerItemSkillConfig()
+{
+    if (targetFilter) targetFilter->release();
+}
+
+BlockFilter* FluidContainerItemSkillConfig::zTargetFilter() const
+{
+    return targetFilter;
+}
+
+float FluidContainerItemSkillConfig::getStaminaCost() const
+{
+    return staminaCost;
+}
+
+float FluidContainerItemSkillConfig::getStaminaCostDevider() const
+{
+    return staminaCostDevider;
+}
+
+float FluidContainerItemSkillConfig::getStaminaCostDeviderPerLevel() const
+{
+    return staminaCostDeviderPerLevel;
+}
+
+int FluidContainerItemSkillConfig::getCooldownTicks() const
+{
+    return cooldownTicks;
+}
+
+float FluidContainerItemSkillConfig::getXpGain() const
+{
+    return xpGain;
+}
+
+FluidContainerItemSkillConfigFactory::FluidContainerItemSkillConfigFactory()
+    : TypeFactory()
+{}
+
+FluidContainerItemSkillConfig* FluidContainerItemSkillConfigFactory::fromJson(
+    Framework::JSON::JSONValue* zJson) const
+{
+    return new FluidContainerItemSkillConfig(
+        Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
+            zJson->asObject()->zValue("targetFilter")),
+        (float)zJson->asObject()
+            ->zValue("staminaCost")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCostDevider")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()
+            ->zValue("staminaCostDeviderPerLevel")
+            ->asNumber()
+            ->getNumber(),
+        (int)zJson->asObject()
+            ->zValue("cooldownTicks")
+            ->asNumber()
+            ->getNumber(),
+        (float)zJson->asObject()->zValue("xpGain")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONValue* FluidContainerItemSkillConfigFactory::toJson(
+    FluidContainerItemSkillConfig* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("targetFilter",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetFilter()));
+    result->addValue("staminaCost",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCost()));
+    result->addValue("staminaCostDevider",
+        new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider()));
+    result->addValue("staminaCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->getStaminaCostDeviderPerLevel()));
+    result->addValue("cooldownTicks",
+        new Framework::JSON::JSONNumber(zObject->getCooldownTicks()));
+    result->addValue(
+        "xpGain", new Framework::JSON::JSONNumber(zObject->getXpGain()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+FluidContainerItemSkillConfigFactory::getValidator() const
+{
+    return Framework::JSON::Validator::JSONValidator::buildForObject()
+        ->withRequiredAttribute("targetFilter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
+        ->withRequiredNumber("staminaCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.9)
+        ->finishNumber()
+        ->withRequiredNumber("staminaCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.1)
+        ->finishNumber()
+        ->withRequiredNumber("cooldownTicks")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(10)
+        ->finishNumber()
+        ->withRequiredNumber("xpGain")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->finishObject();
+}
+
+FluidContainerItemSkill::FluidContainerItemSkill(float xp,
+    float maxXp,
+    float level,
+    int cooldownTicks,
+    FluidContainerItemSkillConfig* invalidUseConfig,
+    Framework::RCArray<FluidContainerItemSkillConfig> configs)
+    : ItemSkill(xp, maxXp, level),
+      cooldownTicks(cooldownTicks),
+      invalidUseConfig(invalidUseConfig),
+      configs(configs)
 {}
 
 bool FluidContainerItemSkill::use(
     Entity* zActor, Item* zUsedItem, Block* zTarget)
 {
+    if (cooldownTicks)
+    {
+        cooldownTicks--;
+        return false;
+    }
     FluidContainerItem* usedItem = dynamic_cast<FluidContainerItem*>(zUsedItem);
-    if (usedItem)
+    FluidBlock* fluidBlock = dynamic_cast<FluidBlock*>(zTarget);
+    const FluidContainerItemType* usedItemType
+        = dynamic_cast<const FluidContainerItemType*>(usedItem->zItemType());
+    FluidContainerItemSkillConfig* usedConfig = 0;
+    bool invalid = false;
+    if (!zTarget->zBlockType()->isFluid() || zTarget->getHP() <= 0)
+    {
+        usedConfig = invalidUseConfig;
+        invalid = true;
+    }
+    else if (!usedItem)
+    {
+        usedConfig = invalidUseConfig;
+        invalid = true;
+    }
+    else if (!fluidBlock || fluidBlock->getDistanceToSource())
+    {
+        usedConfig = invalidUseConfig;
+        invalid = true;
+    }
+    else if (!usedItemType)
+    {
+        usedConfig = invalidUseConfig;
+        invalid = true;
+    }
+    else if (usedItem->getAmount() + 1000 <= usedItemType->getMaxFluidAmount())
+    {
+        usedConfig = invalidUseConfig;
+        invalid = true;
+    }
+    else if (usedItem->getFluidTypeId()
+             && usedItem->getFluidTypeId() != fluidBlock->zBlockType()->getId())
+    {
+        usedConfig = invalidUseConfig;
+        invalid = true;
+    }
+    if (!usedConfig)
     {
-        if (zTarget->zBlockType()->isFluid() && zTarget->getHP() > 0)
+        for (FluidContainerItemSkillConfig* config : configs)
         {
-            FluidBlock* fluidBlock = dynamic_cast<FluidBlock*>(zTarget);
-            if (fluidBlock)
+            if (config->zTargetFilter()->test(zTarget))
             {
-                if (!usedItem->getFluidTypeId()
-                    || usedItem->getFluidTypeId()
-                           == fluidBlock->zBlockType()->getId())
-                {
-                    const FluidContainerItemType* usedItemType
-                        = dynamic_cast<const FluidContainerItemType*>(
-                            usedItem->zItemType());
-                    if (usedItemType)
-                    {
-                        if (usedItem->getAmount() + 1000
-                            <= usedItemType->getMaxFluidAmount())
-                        {
-                            usedItem->setFluidTypeId(
-                                fluidBlock->zBlockType()->getId());
-                            usedItem->setAmount(usedItem->getAmount() + 1000);
-                            zTarget->setHP(0);
-                        }
-                    }
-                }
+                usedConfig = config;
+                break;
             }
         }
     }
-    return false;
+    if (!usedConfig)
+    {
+        usedConfig = invalidUseConfig;
+        invalid = true;
+    }
+    float staminaCost = usedConfig->getStaminaCost();
+    float staminaCostDevider
+        = usedConfig->getStaminaCostDevider()
+        + usedConfig->getStaminaCostDeviderPerLevel() * getLevel();
+    if (staminaCostDevider)
+    {
+        staminaCost /= staminaCostDevider;
+    }
+    if (zActor->getStamina() < staminaCost)
+    {
+        return false;
+    }
+    zActor->setStamina(zActor->getStamina() - staminaCost);
+    if (!invalid
+        && usedItem->getAmount() + 1000 <= usedItemType->getMaxFluidAmount())
+    {
+        usedItem->setFluidTypeId(fluidBlock->zBlockType()->getId());
+        usedItem->setAmount(usedItem->getAmount() + 1000);
+        zTarget->setHP(0);
+    }
+    this->cooldownTicks = usedConfig->getCooldownTicks();
+    setXp(getXp() + usedConfig->getXpGain());
+    return true;
 }
 
 bool FluidContainerItemSkill::use(
@@ -176,20 +384,134 @@ bool FluidContainerItemSkill::use(
     return false;
 }
 
-FluidContainerItemSkillLevelUpRule::FluidContainerItemSkillLevelUpRule()
-    : ItemSkillLevelUpRule()
-{}
+FluidContainerItemSkillConfig*
+FluidContainerItemSkill::zInvalidUseConfig() const
+{
+    return invalidUseConfig;
+}
+
+const Framework::RCArray<FluidContainerItemSkillConfig>&
+FluidContainerItemSkill::zConfigs() const
+{
+    return configs;
+}
+
+FluidContainerItemSkillFactory::FluidContainerItemSkillFactory() {}
+
+FluidContainerItemSkill* FluidContainerItemSkillFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<FluidContainerItemSkillConfig> configs;
+    for (Framework::JSON::JSONValue* configValue :
+        *zJson->zValue("configs")->asArray())
+    {
+        configs.add(Game::INSTANCE->zTypeRegistry()
+                        ->fromJson<FluidContainerItemSkillConfig>(
+                            configValue->asObject()));
+    }
+    return new FluidContainerItemSkill(0,
+        (float)zJson->zValue("maxXp")->asNumber()->getNumber(),
+        1,
+        0,
+        new FluidContainerItemSkillConfig(0,
+            (float)zJson->zValue("invalidUseStaminaCost")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidUseStaminaCostDevider")
+                ->asNumber()
+                ->getNumber(),
+            (float)zJson->zValue("invalidUseStaminaCostDeviderPerLevel")
+                ->asNumber()
+                ->getNumber(),
+            (int)zJson->zValue("invalidUseCooldownTicks")
+                ->asNumber()
+                ->getNumber(),
+            0),
+        configs);
+}
 
-void FluidContainerItemSkillLevelUpRule::applyOn(ItemSkill* zSkill)
+Framework::JSON::JSONObject* FluidContainerItemSkillFactory::toJson(
+    FluidContainerItemSkill* zObject) const
 {
-    FluidContainerItemSkill* skill
-        = dynamic_cast<FluidContainerItemSkill*>(zSkill);
-    if (skill->xp >= skill->maxXP)
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "maxXp", new Framework::JSON::JSONNumber(zObject->getMaxXp()));
+    result->addValue("invalidUseStaminaCost",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCost()));
+    result->addValue("invalidUseStaminaCostDevider",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCostDevider()));
+    result->addValue("invalidUseStaminaCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getStaminaCostDeviderPerLevel()));
+    result->addValue("invalidUseCooldownTicks",
+        new Framework::JSON::JSONNumber(
+            zObject->zInvalidUseConfig()->getCooldownTicks()));
+    Framework::JSON::JSONArray* configs = new Framework::JSON::JSONArray();
+    for (FluidContainerItemSkillConfig* config : zObject->zConfigs())
     {
-        skill->level++;
-        skill->xp = 0;
-        skill->maxXP = skill->maxXP * 2;
+        configs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(config));
     }
+    result->addValue("configs", configs);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+FluidContainerItemSkillFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder
+        ->withRequiredNumber("invalidUseStaminaCost")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredNumber("invalidUseStaminaCostDevider")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.9)
+        ->finishNumber()
+        ->withRequiredNumber("sinvalidUseStaminaCostDeviderPerLevel")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.1)
+        ->finishNumber()
+        ->withRequiredNumber("invalidUseCooldownTicks")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(10)
+        ->finishNumber()
+        ->withRequiredNumber("maxXp")
+        ->whichIsGreaterOrEqual(0)
+        ->withDefault(10)
+        ->finishNumber()
+        ->withRequiredArray("configs")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()
+                ->getValidator<FluidContainerItemSkillConfig>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text FluidContainerItemSkillFactory::getTypeToken() const
+{
+    return "fluidGathering";
+}
+
+FluidContainerItemType::FluidContainerItemType(Framework::Text name,
+    ModelInfo* model,
+    Framework::JSON::JSONObject* itemSkillConfig,
+    ItemSkillLevelUpRule* levelUpRule,
+    int maxFluidAmount,
+    int maxStackSize)
+    : ItemType(name, model, maxStackSize),
+      itemSkillConfig(itemSkillConfig),
+      levelUpRule(levelUpRule),
+      maxFluidAmount(maxFluidAmount)
+{}
+
+FluidContainerItemType::~FluidContainerItemType()
+{
+    itemSkillConfig->release();
+    levelUpRule->release();
 }
 
 void FluidContainerItemType::loadSuperItem(
@@ -227,51 +549,6 @@ void FluidContainerItemType::saveSuperItem(
     }
 }
 
-void FluidContainerItemType::loadSuperItemSkill(
-    ItemSkill* zSkill, Framework::StreamReader* zReader) const
-{
-    ItemType::loadSuperItemSkill(zSkill, zReader);
-    FluidContainerItemSkill* skill
-        = dynamic_cast<FluidContainerItemSkill*>(zSkill);
-    if (skill)
-    {
-        zReader->lese((char*)&skill->level, 4);
-        zReader->lese((char*)&skill->xp, 4);
-        zReader->lese((char*)&skill->maxXP, 4);
-    }
-    else
-    {
-        std::cout << "ERROR: FluidContainerItemType::loadSuperItemSkill: "
-                     "zSkill is not a FluidContainerItemSkill\n";
-    }
-}
-
-void FluidContainerItemType::saveSuperItemSkill(
-    const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const
-{
-    ItemType::saveSuperItemSkill(zSkill, zWriter);
-    const FluidContainerItemSkill* skill
-        = dynamic_cast<const FluidContainerItemSkill*>(zSkill);
-    if (skill)
-    {
-        zWriter->schreibe((char*)&skill->level, 4);
-        zWriter->schreibe((char*)&skill->xp, 4);
-        zWriter->schreibe((char*)&skill->maxXP, 4);
-    }
-    else
-    {
-        std::cout << "ERROR: FluidContainerItemType::saveSuperItemSkill: "
-                     "zSkill is not a FluidContainerItemSkill\n";
-    }
-}
-
-FluidContainerItemType::FluidContainerItemType(
-    int typeId, const char* name, ModelInfo model)
-    : ItemType(
-        typeId, name, new FluidContainerItemSkillLevelUpRule(), 0, model),
-      maxFluidAmount(1000)
-{}
-
 Item* FluidContainerItemType::createItem() const
 {
     Item* result = new FluidContainerItem(getId(), getName());
@@ -280,7 +557,13 @@ Item* FluidContainerItemType::createItem() const
 
 ItemSkill* FluidContainerItemType::createDefaultItemSkill() const
 {
-    return new FluidContainerItemSkill(getId());
+    return Game::INSTANCE->zTypeRegistry()->fromJson<ItemSkill>(
+        itemSkillConfig);
+}
+
+void FluidContainerItemType::levelUpItemSkill(ItemSkill* zSkill) const
+{
+    levelUpRule->applyOn(zSkill);
 }
 
 void FluidContainerItemType::setItemAttribute(
@@ -347,13 +630,22 @@ void FluidContainerItemType::addItemAttributes(
     {
         zItemObjet->addValue("fluidType",
             new Framework::JSON::JSONString(
-                StaticRegistry<ItemType>::INSTANCE.zElement(item->fluidTypeId)
-                    ->getName()));
+                Game::INSTANCE->zItemType(item->fluidTypeId)->getName()));
         zItemObjet->addValue(
             "fluidAmount", new Framework::JSON::JSONNumber(item->fluidAmount));
     }
 }
 
+Framework::JSON::JSONObject* FluidContainerItemType::zItemSkillConfig() const
+{
+    return itemSkillConfig;
+}
+
+ItemSkillLevelUpRule* FluidContainerItemType::zLevelUpRule() const
+{
+    return levelUpRule;
+}
+
 int FluidContainerItemType::getMaxFluidAmount() const
 {
     return maxFluidAmount;
@@ -365,3 +657,71 @@ FluidContainerItemType* FluidContainerItemType::setMaxFluidAmount(
     this->maxFluidAmount = maxFluidAmount;
     return this;
 }
+
+FluidContainerItemTypeFactory::FluidContainerItemTypeFactory()
+    : SubTypeFactory()
+{}
+
+FluidContainerItemType* FluidContainerItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new FluidContainerItemType(
+        zJson->zValue("name")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->getValue("itemSkill")->asObject(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ItemSkillLevelUpRule>(
+            zJson->zValue("levelUpRule")),
+        (int)zJson->zValue("maxFluidAmount")->asNumber()->getNumber(),
+        (int)zJson->zValue("maxStack")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* FluidContainerItemTypeFactory::toJson(
+    FluidContainerItemType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue("levelUpRule",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zLevelUpRule()));
+    result->addValue("itemSkill",
+        dynamic_cast<Framework::JSON::JSONObject*>(
+            zObject->zItemSkillConfig()->getThis()));
+    result->addValue("maxFluidAmount",
+        new Framework::JSON::JSONNumber(zObject->getMaxFluidAmount()));
+    result->addValue("maxStack",
+        new Framework::JSON::JSONNumber(zObject->getMaxStackSize()));
+    return nullptr;
+}
+
+Framework::JSON::Validator::JSONValidator*
+FluidContainerItemTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("name")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredAttribute("levelUpRule",
+            Game::INSTANCE->zTypeRegistry()
+                ->getValidator<ItemSkillLevelUpRule>())
+        ->withRequiredAttribute("itemSkill",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemSkill>())
+        ->withRequiredNumber("maxFluidAmount")
+        ->whichIsGreaterThen(0)
+        ->withDefault(1000.0)
+        ->finishNumber()
+        ->withRequiredNumber("maxStack")
+        ->withDefault(50.0)
+        ->whichIsGreaterOrEqual(1.0)
+        ->finishNumber()
+        ->finishObject();
+}
+
+Framework::Text FluidContainerItemTypeFactory::getTypeToken() const
+{
+    return "fluidContainer";
+}

+ 91 - 18
FactoryCraft/FluidContainer.h

@@ -2,6 +2,7 @@
 
 #include <Vec3.h>
 
+#include "BlockFilter.h"
 #include "Item.h"
 #include "ItemSkill.h"
 
@@ -14,7 +15,7 @@ private:
     int fluidAmount;
 
 public:
-    FluidContainerItem(int itemTypeId, const char* name);
+    FluidContainerItem(int itemTypeId, Framework::Text name);
     virtual const BlockType* zPlacedBlockType() const override;
     virtual bool canBeStackedWith(const Item* zItem) const override;
     virtual bool canBePlacedAt(
@@ -32,56 +33,128 @@ public:
     friend FluidContainerItemType;
 };
 
-class FluidContainerItemSkillLevelUpRule;
+class FluidContainerItemSkillConfig : public Framework::ReferenceCounter
+{
+private:
+    BlockFilter* targetFilter;
+    float staminaCost;
+    float staminaCostDevider;
+    float staminaCostDeviderPerLevel;
+    int cooldownTicks;
+    float xpGain;
+
+public:
+    FluidContainerItemSkillConfig(BlockFilter* targetFilter,
+        float staminaCost,
+        float staminaCostDevider,
+        float staminaCostDeviderPerLevel,
+        int cooldownTicks,
+        float xpGain);
+    ~FluidContainerItemSkillConfig();
+    BlockFilter* zTargetFilter() const;
+    float getStaminaCost() const;
+    float getStaminaCostDevider() const;
+    float getStaminaCostDeviderPerLevel() const;
+    int getCooldownTicks() const;
+    float getXpGain() const;
+};
+
+class FluidContainerItemSkillConfigFactory
+    : public TypeFactory<FluidContainerItemSkillConfig>
+{
+public:
+    FluidContainerItemSkillConfigFactory();
+    FluidContainerItemSkillConfig* fromJson(
+        Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(
+        FluidContainerItemSkillConfig* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator() const override;
+};
 
 class FluidContainerItemSkill : public ItemSkill
 {
-    int level;
-    float xp;
-    float maxXP;
+private:
+    int cooldownTicks;
+    FluidContainerItemSkillConfig* invalidUseConfig;
+    Framework::RCArray<FluidContainerItemSkillConfig> configs;
 
 public:
-    FluidContainerItemSkill(int itemTypeId);
+    FluidContainerItemSkill(float xp,
+        float maxXp,
+        float level,
+        int cooldownTicks,
+        FluidContainerItemSkillConfig* invalidUseConfig,
+        Framework::RCArray<FluidContainerItemSkillConfig> configs);
     virtual bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) override;
     virtual bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
-
-    friend FluidContainerItemType;
-    friend FluidContainerItemSkillLevelUpRule;
+    FluidContainerItemSkillConfig* zInvalidUseConfig() const;
+    const Framework::RCArray<FluidContainerItemSkillConfig>& zConfigs() const;
 };
 
-class FluidContainerItemSkillLevelUpRule : public ItemSkillLevelUpRule
+class FluidContainerItemSkillFactory
+    : public SubTypeFactory<ItemSkill, FluidContainerItemSkill>
 {
 public:
-    FluidContainerItemSkillLevelUpRule();
-    void applyOn(ItemSkill* zSkill) override;
+    FluidContainerItemSkillFactory();
+    FluidContainerItemSkill* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        FluidContainerItemSkill* 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 FluidContainerItemType : public ItemType
 {
 private:
     int maxFluidAmount;
+    Framework::JSON::JSONObject* itemSkillConfig;
+    ItemSkillLevelUpRule* levelUpRule;
+
+public:
+    FluidContainerItemType(Framework::Text name,
+        ModelInfo* model,
+        Framework::JSON::JSONObject* itemSkillConfig,
+        ItemSkillLevelUpRule* levelUpRule,
+        int maxFluidAmount,
+        int maxStackSize);
+    ~FluidContainerItemType();
 
 protected:
     virtual void loadSuperItem(
         Item* zItem, Framework::StreamReader* zReader) const override;
     virtual void saveSuperItem(
         const Item* zItem, Framework::StreamWriter* zWriter) const override;
-    virtual void loadSuperItemSkill(
-        ItemSkill* zSkill, Framework::StreamReader* zReader) const override;
-    virtual void saveSuperItemSkill(const ItemSkill* zSkill,
-        Framework::StreamWriter* zWriter) const override;
 
 public:
-    FluidContainerItemType(int typeId, const char* name, ModelInfo model);
-
     virtual Item* createItem() const override;
     virtual ItemSkill* createDefaultItemSkill() const override;
+    virtual void levelUpItemSkill(ItemSkill* zSkill) const override;
     virtual void setItemAttribute(Item* zItem,
         Framework::Text name,
         Framework::JSON::JSONValue* zValue) const override;
     virtual void addItemAttributes(
         Item* zItem, Framework::JSON::JSONObject* zItemObjet) const override;
+    Framework::JSON::JSONObject* zItemSkillConfig() const;
+    ItemSkillLevelUpRule* zLevelUpRule() const;
     int getMaxFluidAmount() const;
 
     FluidContainerItemType* setMaxFluidAmount(int maxFluidAmount);
+};
+
+class FluidContainerItemTypeFactory
+    : public SubTypeFactory<ItemType, FluidContainerItemType>
+{
+public:
+    FluidContainerItemTypeFactory();
+    FluidContainerItemType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        FluidContainerItemType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 368 - 33
FactoryCraft/Game.cpp

@@ -5,10 +5,13 @@
 #include "Entity.h"
 #include "EntityRemovedUpdate.h"
 #include "ItemEntity.h"
+#include "JsonUtils.h"
+#include "MultiblockTree.h"
 #include "NetworkMessage.h"
 #include "NoBlock.h"
 #include "OverworldDimension.h"
 #include "Player.h"
+#include "PlayerHand.h"
 #include "Zeit.h"
 
 using namespace Framework;
@@ -238,24 +241,31 @@ Player* GameClient::zEntity() const
 void GameClient::sendTypes()
 {
     foreground.lock();
-    int count = StaticRegistry<BlockType>::INSTANCE.getCount();
+    int count = 0;
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
+    {
+        if (Game::INSTANCE->zBlockType(i)) count++;
+    }
     client->zForegroundWriter()->schreibe((char*)&count, 4);
-    for (int i = 0; i < count; i++)
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
     {
-        const BlockType* t = StaticRegistry<BlockType>::INSTANCE.zElement(i);
-        t->writeTypeInfo(client->zForegroundWriter());
+        const BlockType* t = Game::INSTANCE->zBlockType(i);
+        if (t)
+        {
+            t->writeTypeInfo(client->zForegroundWriter());
+        }
     }
     count = 0;
-    for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
     {
-        if (StaticRegistry<ItemType>::INSTANCE.zElement(i)) count++;
+        if (Game::INSTANCE->zItemType(i)) count++;
     }
     client->zForegroundWriter()->schreibe((char*)&count, 4);
-    for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
     {
-        if (StaticRegistry<ItemType>::INSTANCE.zElement(i))
+        const ItemType* t = Game::INSTANCE->zItemType(i);
+        if (t)
         {
-            const ItemType* t = StaticRegistry<ItemType>::INSTANCE.zElement(i);
             int id = t->getId();
             client->zForegroundWriter()->schreibe((char*)&id, 4);
             char len = (char)t->getName().getLength();
@@ -265,17 +275,37 @@ void GameClient::sendTypes()
             client->zForegroundWriter()->schreibe((char*)&tlen, 2);
             client->zForegroundWriter()->schreibe(
                 t->getTooltipUIML().getText(), tlen);
-            t->getModel().writeTo(client->zForegroundWriter());
+            if (t->zModel())
+            {
+                t->zModel()->writeTo(client->zForegroundWriter());
+            }
+            else
+            {
+                ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
+                    .writeTo(client->zForegroundWriter());
+            }
         }
     }
-    count = StaticRegistry<EntityType>::INSTANCE.getCount();
+    count = 0;
+    for (int i = 0; i < Game::INSTANCE->getEntityTypeCount(); i++)
+    {
+        if (Game::INSTANCE->zEntityType(i)) count++;
+    }
     client->zForegroundWriter()->schreibe((char*)&count, 4);
     for (int i = 0; i < count; i++)
     {
-        const EntityType* t = StaticRegistry<EntityType>::INSTANCE.zElement(i);
+        const EntityType* t = Game::INSTANCE->zEntityType(i);
         int id = t->getId();
         client->zForegroundWriter()->schreibe((char*)&id, 4);
-        t->getModel().writeTo(client->zForegroundWriter());
+        if (t->zModel())
+        {
+            t->zModel()->writeTo(client->zForegroundWriter());
+        }
+        else
+        {
+            ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
+                .writeTo(client->zForegroundWriter());
+        }
     }
     foreground.unlock();
 }
@@ -302,7 +332,15 @@ Game::Game(Framework::Text name, Framework::Text worldsDir)
       tickCounter(0),
       averageTickTime(0),
       ticksPerSecond(0),
-      totalTime(0)
+      totalTime(0),
+      blockTypes(0),
+      blockTypeCount(0),
+      itemTypes(0),
+      itemTypeCount(0),
+      entityTypes(0),
+      entityTypeCount(0),
+      multiblockStructureTypes(0),
+      multiblockStructureTypeCount(0)
 {
     if (!DateiExistiert(path)) DateiPfadErstellen(path + "/");
     Datei d;
@@ -327,18 +365,255 @@ Game::~Game()
     playerRegister->release();
     typeRegistry->release();
     uiController->release();
+    for (int i = 0; i < blockTypeCount; i++)
+    {
+        if (blockTypes[i]) blockTypes[i]->release();
+    }
+    delete[] blockTypes;
+    for (int i = 0; i < itemTypeCount; i++)
+    {
+        if (itemTypes[i]) itemTypes[i]->release();
+    }
+    delete[] itemTypes;
+    for (int i = 0; i < entityTypeCount; i++)
+    {
+        if (entityTypes[i]) entityTypes[i]->release();
+    }
+    delete[] entityTypes;
+    for (int i = 0; i < multiblockStructureTypeCount; i++)
+    {
+        if (multiblockStructureTypes[i]) multiblockStructureTypes[i]->release();
+    }
+    delete[] multiblockStructureTypes;
 }
 
 void Game::initialize()
 {
+    // TODO load mods libraries
+    // load block types
+    std::cout << "Loading block types\n";
+    Framework::Array<BlockType*> blockTypeArray;
+    Framework::JSON::Validator::JSONValidator* validator
+        = Framework::JSON::Validator::JSONValidator::buildForArray()
+              ->addAcceptedTypeInArray(typeRegistry->getValidator<BlockType>())
+              ->removeInvalidEntries()
+              ->finishArray();
+    loadAllJsonsFromDirectory("data/blocks",
+        [this, &blockTypeArray, validator](Framework::JSON::JSONValue* zValue) {
+            Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+                validationResults;
+            Framework::JSON::JSONValue* validParts
+                = validator->getValidParts(zValue, &validationResults);
+            for (Framework::JSON::Validator::JSONValidationResult* result :
+                validationResults)
+            {
+                result->printInvalidInfo();
+            }
+            if (validParts)
+            {
+                for (Framework::JSON::JSONValue* value : *validParts->asArray())
+                {
+                    BlockType* blockType
+                        = typeRegistry->fromJson<BlockType>(value);
+                    if (blockType)
+                    {
+                        blockTypeArray.add(blockType);
+                    }
+                }
+                validParts->release();
+            }
+        });
+    validator->release();
+    std::cout << "Loaded " << blockTypeArray.getEintragAnzahl()
+              << " block types from data/blocks\n";
+    blockTypes = new BlockType*[2 + blockTypeArray.getEintragAnzahl()];
+    blockTypes[0]
+        = new NoBlockBlockType(&NoBlock::INSTANCE, "__not_yet_generated");
+    blockTypes[1] = new NoBlockBlockType(&AirBlock::INSTANCE, "Air");
+    blockTypeCount = 2;
+    for (BlockType* blockType : blockTypeArray)
+    {
+        blockTypes[blockTypeCount++] = blockType;
+    }
+    for (int i = 0; i < blockTypeCount; i++)
+    {
+        blockTypes[i]->setTypeId(i);
+    }
+    std::cout << "Loading item types\n";
+    Framework::Array<ItemType*> itemTypeArray;
+    validator
+        = Framework::JSON::Validator::JSONValidator::buildForArray()
+              ->addAcceptedTypeInArray(typeRegistry->getValidator<ItemType>())
+              ->removeInvalidEntries()
+              ->finishArray();
+    loadAllJsonsFromDirectory("data/items",
+        [this, &itemTypeArray, validator](Framework::JSON::JSONValue* zValue) {
+            Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+                validationResults;
+            Framework::JSON::JSONValue* validParts
+                = validator->getValidParts(zValue, &validationResults);
+            for (Framework::JSON::Validator::JSONValidationResult* result :
+                validationResults)
+            {
+                result->printInvalidInfo();
+            }
+            if (validParts)
+            {
+                for (Framework::JSON::JSONValue* value : *validParts->asArray())
+                {
+                    ItemType* itemType
+                        = typeRegistry->fromJson<ItemType>(value);
+                    if (itemType)
+                    {
+                        itemTypeArray.add(itemType);
+                    }
+                }
+                validParts->release();
+            }
+        });
+    Sleep(10000);
+    validator->release();
+    std::cout << "Loaded " << itemTypeArray.getEintragAnzahl()
+              << " item types from data/items\n";
+    itemTypes
+        = new ItemType*[blockTypeCount + itemTypeArray.getEintragAnzahl()];
+    itemTypes[0] = new PlayerHandItemType();
+    itemTypeCount = 1;
+    for (int i = 0; i < blockTypeCount; i++)
+    {
+        ItemType* itemType = blockTypes[i]->createItemType();
+        if (itemType)
+        {
+            itemTypes[itemTypeCount++] = itemType;
+        }
+    }
+    for (ItemType* itemType : itemTypeArray)
+    {
+        itemTypes[itemTypeCount++] = itemType;
+    }
+    for (int i = 0; i < itemTypeCount; i++)
+    {
+        itemTypes[i]->setTypeId(i);
+    }
+    std::cout << "Loading entity types\n";
+    Framework::Array<EntityType*> entityTypeArray;
+    /* validator
+        = Framework::JSON::Validator::JSONValidator::buildForArray()
+              ->addAcceptedTypeInArray(typeRegistry->getValidator<EntityType>())
+              ->removeInvalidEntries()
+              ->finishArray();
+    loadAllJsonsFromDirectory("data/entities",
+        [this, &entityTypeArray, validator](
+            Framework::JSON::JSONValue* zValue) {
+            Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+                validationResults;
+            Framework::JSON::JSONValue* validParts
+                = validator->getValidParts(zValue, &validationResults);
+            for (Framework::JSON::Validator::JSONValidationResult* result :
+                validationResults)
+            {
+                result->printInvalidInfo();
+            }
+            if (validParts)
+            {
+                for (Framework::JSON::JSONValue* value : *validParts->asArray())
+                {
+                    EntityType* entityType
+                        = typeRegistry->fromJson<EntityType>(value);
+                    if (entityType)
+                    {
+                        entityTypeArray.add(entityType);
+                    }
+                }
+                validParts->release();
+            }
+        });
+    validator->release();*/
+    std::cout << "Loaded " << entityTypeArray.getEintragAnzahl()
+              << " entity types from data/entities\n";
+    entityTypes = new EntityType*[2 + entityTypeArray.getEintragAnzahl()];
+    entityTypes[0] = new PlayerEntityType();
+    entityTypes[1] = new ItemEntityType();
+    entityTypeCount = 2;
+    for (EntityType* entityType : entityTypeArray)
+    {
+        entityTypes[entityTypeCount++] = entityType;
+    }
+    for (int i = 0; i < entityTypeCount; i++)
+    {
+        entityTypes[i]->setTypeId(i);
+    }
+    // initialize loaded types
+    bool allInitialized = false;
+    while (!allInitialized)
+    {
+        allInitialized = true;
+        for (int i = 0; i < blockTypeCount; i++)
+        {
+            if (blockTypes[i] && !blockTypes[i]->initialize(this))
+            {
+                std::cout << "ERROR: Could not initialize Block Type '"
+                          << blockTypes[i]->getName() << "'.\n";
+                blockTypes[i]->release();
+                blockTypes[i] = 0;
+                allInitialized = false;
+            }
+        }
+    }
+    allInitialized = false;
+    while (!allInitialized)
+    {
+        allInitialized = true;
+        for (int i = 0; i < itemTypeCount; i++)
+        {
+            if (itemTypes[i] && !itemTypes[i]->initialize(this))
+            {
+                std::cout << "ERROR: Could not initialize Item Type '"
+                          << itemTypes[i]->getName() << "'.\n";
+                itemTypes[i]->release();
+                itemTypes[i] = 0;
+                allInitialized = false;
+            }
+        }
+    }
+    allInitialized = false;
+    while (!allInitialized)
+    {
+        allInitialized = true;
+        for (int i = 0; i < entityTypeCount; i++)
+        {
+            if (entityTypes[i] && !entityTypes[i]->initialize(this))
+            {
+                std::cout << "ERROR: Could not initialize Entity Type '"
+                          << entityTypes[i]->getName() << "'.\n";
+                entityTypes[i]->release();
+                entityTypes[i] = 0;
+                allInitialized = false;
+            }
+        }
+    }
+    for (int i = 0; i < blockTypeCount; i++)
+    {
+        if (blockTypes[i])
+        {
+            blockTypes[i]->initializeDefault();
+        }
+    }
+    multiblockStructureTypes = new MultiblockStructureType*[1];
+    multiblockStructureTypes[0] = new MultiblockTreeStructureType();
+    multiblockStructureTypeCount = 1;
+    // initialize world generator and world loader
     int seed = 0;
     int index = 0;
     for (const char* n = name; *n; n++)
         seed += (int)pow((float)*n * 31, (float)++index);
     generator = new WorldGenerator(seed);
     loader = new WorldLoader();
+    // load recipies
     recipies.loadRecipies("data/recipies");
+    // initialize chat
     chat = new Chat();
+    // load quests
     questManager->loadQuests();
 }
 
@@ -391,8 +666,7 @@ void Game::thread()
                                + getPlayerId(player->zEntity()->getName()));
                 pFile.erstellen();
                 if (pFile.open(Datei::Style::schreiben))
-                    StaticRegistry<EntityType>::INSTANCE
-                        .zElement(EntityTypeEnum::PLAYER)
+                    zEntityType(EntityTypeEnum::PLAYER)
                         ->saveEntity(player->zEntity(), &pFile);
                 pFile.close();
                 removed.add(index, 0);
@@ -595,13 +869,12 @@ void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)
         { // crafting uiml request
             int id;
             zRequest->lese((char*)&id, 4);
-            Text uiml = recipies.getCrafingUIML(
-                StaticRegistry<ItemType>::INSTANCE.zElement(id));
+            Text uiml = recipies.getCrafingUIML(zItemType(id));
             Text dialogId = "crafting_";
             dialogId += id;
-            uiController
-                ->addDialog(new UIDialog(
-                    dialogId, zOrigin->zEntity()->getId(), new Framework::XML::Element(uiml)));
+            uiController->addDialog(new UIDialog(dialogId,
+                zOrigin->zEntity()->getId(),
+                new Framework::XML::Element(uiml)));
             break;
         }
     case 6:
@@ -715,8 +988,7 @@ GameClient* Game::addPlayer(FCKlient* client, Framework::Text name)
     bool isNew = 0;
     if (!pFile.existiert() || !pFile.open(Datei::Style::lesen))
     {
-        player = (Player*)StaticRegistry<EntityType>::INSTANCE
-                     .zElement(EntityTypeEnum::PLAYER)
+        player = (Player*)zEntityType(EntityTypeEnum::PLAYER)
                      ->createEntityAt(
                          Vec3<float>(0.5, 0.5, 0), DimensionEnum::OVERWORLD);
         player->setName(name);
@@ -724,9 +996,8 @@ GameClient* Game::addPlayer(FCKlient* client, Framework::Text name)
     }
     else
     {
-        player = (Player*)StaticRegistry<EntityType>::INSTANCE
-                     .zElement(EntityTypeEnum::PLAYER)
-                     ->loadEntity(&pFile);
+        player
+            = (Player*)zEntityType(EntityTypeEnum::PLAYER)->loadEntity(&pFile);
         pFile.close();
     }
     if (player->getId() >= nextEntityId)
@@ -779,10 +1050,7 @@ GameClient* Game::addPlayer(FCKlient* client, Framework::Text name)
         Either<Block*, int> b = BlockTypeEnum::AIR;
         int h = WORLD_HEIGHT;
         while (((b.isA() && (!(Block*)b || ((Block*)b)->isPassable()))
-                   || (b.isB()
-                       && StaticRegistry<BlockType>::INSTANCE.zElement(b)
-                              ->zDefault()
-                              ->isPassable()))
+                   || (b.isB() && zBlockType(b)->zDefault()->isPassable()))
                && h > 0)
             b = zBlockAt({(int)player->getPosition().x,
                              (int)player->getPosition().y,
@@ -848,8 +1116,7 @@ void Game::spawnItem(
     Framework::Vec3<float> location, int dimensionId, ItemStack* stack)
 {
     ItemEntity* itemEntity
-        = (ItemEntity*)StaticRegistry<EntityType>::INSTANCE
-              .zElement(EntityTypeEnum::ITEM)
+        = (ItemEntity*)zEntityType(EntityTypeEnum::ITEM)
               ->createEntity(
                   location, dimensionId, Game::INSTANCE->getNextEntityId());
     itemEntity->unsaveAddItem(stack, NO_DIRECTION, 0);
@@ -1077,4 +1344,72 @@ int Game::getChunkCount() const
         result += dim->getChunkCount();
     }
     return result;
-}
+}
+
+const BlockType* Game::zBlockType(int id) const
+{
+    return blockTypes[id];
+}
+
+const ItemType* Game::zItemType(int id) const
+{
+    return itemTypes[id];
+}
+
+const EntityType* Game::zEntityType(int id) const
+{
+    return entityTypes[id];
+}
+
+int Game::getBlockTypeId(const char* name) const
+{
+    for (int i = 0; i < blockTypeCount; i++)
+    {
+        if (blockTypes[i]
+            && Framework::Text(blockTypes[i]->getName()).istGleich(name))
+        {
+            return i;
+        }
+    }
+    std::cout << "WARNING: no block type with name '" << name << "' found.\n";
+    return -1;
+}
+
+int Game::getItemTypeId(const char* name) const
+{
+    for (int i = 0; i < itemTypeCount; i++)
+    {
+        if (itemTypes[i]
+            && Framework::Text(itemTypes[i]->getName()).istGleich(name))
+        {
+            return i;
+        }
+    }
+    std::cout << "WARNING: no item type with name '" << name << "' found.\n";
+    return -1;
+}
+
+int Game::getBlockTypeCount() const
+{
+    return blockTypeCount;
+}
+
+int Game::getItemTypeCount() const
+{
+    return itemTypeCount;
+}
+
+int Game::getEntityTypeCount() const
+{
+    return entityTypeCount;
+}
+
+const MultiblockStructureType* Game::zMultiblockStructureType(int id) const
+{
+    return multiblockStructureTypes[id];
+}
+
+int Game::getMultiblockStructureTypeCount() const
+{
+    return multiblockStructureTypeCount;
+}

+ 20 - 1
FactoryCraft/Game.h

@@ -17,10 +17,10 @@
 #include "Server.h"
 #include "TickOrganizer.h"
 #include "TypeRegistry.h"
+#include "UIController.h"
 #include "WorldGenerator.h"
 #include "WorldLoader.h"
 #include "WorldUpdate.h"
-#include "UIController.h"
 
 class FCKlient;
 
@@ -101,6 +101,14 @@ private:
     double averageTickTime;
     int ticksPerSecond;
     double totalTime;
+    BlockType** blockTypes;
+    int blockTypeCount;
+    ItemType** itemTypes;
+    int itemTypeCount;
+    EntityType** entityTypes;
+    int entityTypeCount;
+    MultiblockStructureType **multiblockStructureTypes;
+    int multiblockStructureTypeCount;
 
     void thread() override;
 
@@ -161,6 +169,17 @@ public:
     int getPlayerCount() const;
     int getChunkCount() const;
 
+    const BlockType* zBlockType(int id) const;
+    const ItemType* zItemType(int id) const;
+    const EntityType* zEntityType(int id) const;
+    int getBlockTypeId(const char* name) const;
+    int getItemTypeId(const char* name) const;
+    int getBlockTypeCount() const;
+    int getItemTypeCount() const;
+    int getEntityTypeCount() const;
+    const MultiblockStructureType* zMultiblockStructureType(int id) const;
+    int getMultiblockStructureTypeCount() const;
+
     static Game* INSTANCE;
     static Critical INSTANCE_CS;
     static void initialize(Framework::Text name, Framework::Text worldsDir);

+ 2 - 2
FactoryCraft/GeneratedStructure.cpp

@@ -3,6 +3,7 @@
 #include "GeneratorTemplate.h"
 #include "MultiblockStructure.h"
 #include "NoBlock.h"
+#include "Game.h"
 
 using namespace Framework;
 
@@ -80,8 +81,7 @@ Framework::Either<Block*, int> GeneratedStructure::generateBlockAt(
             if (blockIds[index] && blockIds[index] != BlockTypeEnum::AIR)
             {
                 Block* result
-                    = StaticRegistry<BlockType>::INSTANCE
-                          .zElement(blockIds[index])
+                    = Game::INSTANCE->zBlockType(blockIds[index])
                           ->createBlockAt(
                               minAffectedPos + localPos, dimensionId, 0);
                 if (result)

+ 129 - 74
FactoryCraft/Grass.cpp

@@ -4,11 +4,8 @@
 #include "Game.h"
 #include "ItemEntity.h"
 
-GrassBlock::GrassBlock(int typeId,
-    const ItemType* zTool,
-    Framework::Vec3<int> pos,
-    int dimensionId)
-    : Block(typeId, zTool, pos, dimensionId, 0)
+GrassBlock::GrassBlock(int typeId, Framework::Vec3<int> pos, int dimensionId)
+    : AdditionalItemSpawningBlock(typeId, pos, dimensionId)
 {
     tickSource = 1;
     transparent = 1;
@@ -22,51 +19,6 @@ bool GrassBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
 
 void GrassBlock::onPostTick() {}
 
-void GrassBlock::onDestroy()
-{
-    if (!deadAndRemoved)
-    {
-        for (int i = 0; i < 6; i++)
-        {
-            if (neighbourTypes[i] == BlockTypeEnum::NO_BLOCK)
-            {
-                Framework::Vec3<int> pos
-                    = getPos() + getDirection(getDirectionFromIndex(i));
-                Game::INSTANCE->zDimension(getDimensionId())
-                    ->placeBlock(pos,
-                        Game::INSTANCE->zGenerator()->generateSingleBlock(
-                            pos, getDimensionId()));
-            }
-        }
-        if ((double)rand() / RAND_MAX < 0.1)
-        {
-            ItemStack* spawnedItems = StaticRegistry<ItemType>::INSTANCE
-                                          .zElement(ItemTypeEnum::WHEAT_SEED)
-                                          ->createItemStack(1);
-            if (spawnedItems)
-            {
-                ItemEntity* itemEntity
-                    = (ItemEntity*)StaticRegistry<EntityType>::INSTANCE
-                          .zElement(EntityTypeEnum::ITEM)
-                          ->createEntity(
-                              location
-                                  + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
-                              getDimensionId(),
-                              Game::INSTANCE->getNextEntityId());
-                itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION, 0);
-                spawnedItems->release();
-                Game::INSTANCE->requestWorldUpdate(
-                    new AddEntityUpdate(itemEntity, getDimensionId()));
-            }
-        }
-        for (MultiblockStructure* structure : structures)
-            structure->onBlockRemoved(this);
-        Game::INSTANCE->zDimension(getDimensionId())
-            ->placeBlock(
-                getPos(), BlockTypeEnum::AIR); // this will be deleted here
-    }
-}
-
 void GrassBlock::filterPassingLight(unsigned char rgb[3]) const
 {
     rgb[0] = (unsigned char)(rgb[0] * 0.7);
@@ -74,42 +26,40 @@ void GrassBlock::filterPassingLight(unsigned char rgb[3]) const
     rgb[2] = (unsigned char)(rgb[2] * 0.7);
 }
 
-GrassBlockType::GrassBlockType(
-    int typeId, int itemTypeId, ModelInfo model, const char* name, int mapColor)
-    : BlockType(typeId, 0, model, 1, 10, 0, name, false, mapColor),
-      itemType(itemTypeId),
-      transparent(true),
-      passable(true),
-      hardness(0.1f),
-      zTool(0),
-      speedModifier(0.5f),
-      interactable(1)
-{}
+GrassBlockType::GrassBlockType(ModelInfo* model,
+    Framework::Text name,
+    int mapColor,
+    Framework::Array<SpawnConfig> spawns,
+    Framework::RCArray<Framework::Text> groupNames)
+    : AdditionalItemSpawningBlockType(
+        "", model, name, mapColor, false, 0.1f, spawns, groupNames)
+{
+    setTransparent(true);
+    setPassable(true);
+    setSpeedModifier(0.5f);
+}
+
+ItemType* GrassBlockType::createItemType() const
+{
+    return 0;
+}
 
 void GrassBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
 {
-    GrassBlock* block = dynamic_cast<GrassBlock*>(zBlock);
-    block->transparent = transparent;
-    block->passable = passable;
-    block->hp = (float)getInitialMaxHP();
-    block->maxHP = (float)getInitialMaxHP();
-    block->hardness = hardness;
-    block->zTool = zTool;
-    block->speedModifier = speedModifier;
-    block->interactable = interactable;
-    BlockType::createSuperBlock(zBlock, zItem);
+    AdditionalItemSpawningBlockType::createSuperBlock(zBlock, zItem);
 }
 
 void GrassBlockType::loadSuperBlock(
     Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
 {
-    BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
+    AdditionalItemSpawningBlockType::loadSuperBlock(
+        zBlock, zReader, dimensionId);
 }
 
 void GrassBlockType::saveSuperBlock(
     Block* zBlock, Framework::StreamWriter* zWriter) const
 {
-    BlockType::saveSuperBlock(zBlock, zWriter);
+    AdditionalItemSpawningBlockType::saveSuperBlock(zBlock, zWriter);
 }
 
 Item* GrassBlockType::createItem() const
@@ -120,5 +70,110 @@ Item* GrassBlockType::createItem() const
 Block* GrassBlockType::createBlock(
     Framework::Vec3<int> position, int dimensionId) const
 {
-    return new GrassBlock(getId(), zTool, position, dimensionId);
+    return new GrassBlock(getId(), position, dimensionId);
+}
+
+GrassBlockTypeFactory::GrassBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+GrassBlockType* GrassBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    Framework::Array<SpawnConfig> spawns;
+    Framework::JSON::JSONArray* spawnsJson = zJson->zValue("spawns")->asArray();
+    for (int i = 0; i < spawnsJson->getLength(); i++)
+    {
+        Framework::JSON::JSONObject* spawnJson
+            = spawnsJson->zValue(i)->asObject();
+        spawns.add(SpawnConfig{
+            (int)spawnJson->zValue("min")->asNumber()->getNumber(),
+            (int)spawnJson->zValue("max")->asNumber()->getNumber(),
+            (float)spawnJson->zValue("chance")->asNumber()->getNumber(),
+            spawnJson->zValue("itemType")->asString()->getString(),
+            0,
+        });
+    }
+    return new GrassBlockType(
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("name")->asString()->getString(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        spawns,
+        groupNames);
+}
+
+Framework::JSON::JSONObject* GrassBlockTypeFactory::toJson(
+    GrassBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    Framework::JSON::JSONArray* spawns = new Framework::JSON::JSONArray();
+    for (const SpawnConfig& config : zObject->getSpawns())
+    {
+        Framework::JSON::JSONObject* spawn = new Framework::JSON::JSONObject();
+        spawn->addValue(
+            "itemType", new Framework::JSON::JSONString(config.itemTypeName));
+        spawn->addValue(
+            "chance", new Framework::JSON::JSONNumber(config.chance));
+        spawn->addValue("min", new Framework::JSON::JSONNumber(config.min));
+        spawn->addValue("max", new Framework::JSON::JSONNumber(config.max));
+        spawns->addValue(spawn);
+    }
+    result->addValue("spawns", spawns);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator* GrassBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredAttribute("spawns",
+            JSON::Validator::JSONValidator::buildForArray()
+                ->addAcceptedObjectInArray()
+                ->withRequiredString("itemType")
+                ->finishString()
+                ->withRequiredNumber("chance")
+                ->finishNumber()
+                ->withRequiredNumber("min")
+                ->finishNumber()
+                ->withRequiredNumber("max")
+                ->finishNumber()
+                ->finishObject()
+                ->finishArray())
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text GrassBlockTypeFactory::getTypeToken() const
+{
+    return "grass";
 }

+ 24 - 20
FactoryCraft/Grass.h

@@ -1,35 +1,30 @@
 #pragma once
 
+#include "BasicBlocks.h"
 #include "Block.h"
 
 class GrassBlockType;
 
-class GrassBlock : public Block
+class GrassBlock : public AdditionalItemSpawningBlock
 {
 public:
-    GrassBlock(int typeId,
-        const ItemType* zTool,
-        Framework::Vec3<int> pos,
-        int dimensionId);
+    GrassBlock(int typeId, Framework::Vec3<int> pos, int dimensionId);
     virtual bool onTick(
         TickQueue* zQueue, int numTicks, bool& blocked) override;
     virtual void onPostTick() override;
-    virtual void onDestroy() override;
     void filterPassingLight(unsigned char rgb[3]) const override;
 
     friend GrassBlockType;
 };
 
-class GrassBlockType : public BlockType
+class GrassBlockType : public AdditionalItemSpawningBlockType
 {
-private:
-    int itemType;
-    bool transparent;
-    bool passable;
-    float hardness;
-    const ItemType* zTool;
-    float speedModifier;
-    bool interactable;
+public:
+    GrassBlockType(ModelInfo* model,
+        Framework::Text name,
+        int mapColor,
+        Framework::Array<SpawnConfig> spawns,
+        Framework::RCArray<Framework::Text> groupNames);
 
 protected:
     virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
@@ -43,9 +38,18 @@ protected:
         Framework::Vec3<int> position, int dimensionId) const override;
 
 public:
-    GrassBlockType(int typeId,
-        int itemTypeId,
-        ModelInfo model,
-        const char* name,
-        int mapColor);
+    Framework::Text getItemTypeName() const;
+    virtual ItemType* createItemType() const override;
+};
+
+class GrassBlockTypeFactory : public SubTypeFactory<BlockType, GrassBlockType>
+{
+public:
+    GrassBlockTypeFactory();
+    GrassBlockType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(GrassBlockType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 193 - 60
FactoryCraft/GrowingPlant.cpp

@@ -2,36 +2,34 @@
 
 #include "Game.h"
 
-GrowthState::GrowthState()
-    : percentage(1),
-      model("", "", 0)
-{}
-
-GrowthState::GrowthState(float percentage, ModelInfo model)
-    : percentage(percentage),
+GrowthState::GrowthState(float percentage, ModelInfo* model)
+    : ReferenceCounter(),
+      percentage(percentage),
       model(model)
 {}
 
-GrowthState::GrowthState(const GrowthState& right)
-    : percentage(right.percentage),
-      model(right.model)
-{}
+GrowthState::~GrowthState()
+{
+    model->release();
+}
+
+float GrowthState::getPercentage() const
+{
+    return percentage;
+}
 
-GrowthState& GrowthState::operator=(const GrowthState& right)
+ModelInfo* GrowthState::zModel() const
 {
-    percentage = right.percentage;
-    model = ModelInfo(right.model);
-    return *this;
+    return model;
 }
 
 GrowingPlantBlock::GrowingPlantBlock(int typeId,
-    const ItemType* zTool,
     Framework::Vec3<int> pos,
     int dimensionId,
     int maxTicks,
-    const char* name,
+    Framework::Text name,
     int blockTypeAfterGrowth)
-    : Block(typeId, zTool, pos, dimensionId, 0),
+    : Block(typeId, pos, dimensionId, 0),
       seblingTicks(0),
       seblingTicksMax(maxTicks),
       name(name),
@@ -54,9 +52,9 @@ bool GrowingPlantBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
     }
     int index = 0;
     int currentIndex = 0;
-    for (const GrowthState& state : states)
+    for (GrowthState* state : states)
     {
-        if (state.percentage <= seblingTicks / (float)seblingTicksMax)
+        if (state->getPercentage() <= seblingTicks / (float)seblingTicksMax)
         {
             currentIndex = index;
         }
@@ -68,7 +66,7 @@ bool GrowingPlantBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
     }
     if (lastSendState != currentIndex)
     {
-        updateModel(states.get(currentIndex).model);
+        updateModel(states.z(currentIndex)->zModel());
         lastSendState = currentIndex;
     }
     return 1;
@@ -88,21 +86,19 @@ void GrowingPlantBlock::onPostTick()
 
 void GrowingPlantBlock::sendModelInfo(NetworkMessage* zMessage)
 {
-    GrowthState current;
-    bool found = 0;
-    for (const GrowthState& state : states)
+    GrowthState* current = 0;
+    for (GrowthState* state : states)
     {
-        if (state.percentage <= seblingTicks / (float)seblingTicksMax)
+        if (state->getPercentage() <= seblingTicks / (float)seblingTicksMax)
         {
-            found = 1;
             current = state;
         }
     }
-    if (found)
+    if (current)
     {
         zMessage->addressBlock(this);
         InMemoryBuffer buffer;
-        current.model.writeTo(&buffer);
+        current->zModel()->writeTo(&buffer);
         char* msg = new char[(int)buffer.getSize() + 1];
         msg[0] = 1; // hmodel change
         buffer.lese(msg + 1, (int)buffer.getSize());
@@ -118,12 +114,12 @@ Framework::Text GrowingPlantBlock::getTargetUIML()
          + "%</text></targetInfo>";
 }
 
-GrowingPlantBlock* GrowingPlantBlock::addGrowthState(GrowthState state)
+GrowingPlantBlock* GrowingPlantBlock::addGrowthState(GrowthState* state)
 {
     int index = 0;
-    for (const GrowthState& s : states)
+    for (GrowthState* s : states)
     {
-        if (s.percentage > state.percentage)
+        if (s->getPercentage() > state->getPercentage())
         {
             states.add(state, index);
             return this;
@@ -134,46 +130,32 @@ GrowingPlantBlock* GrowingPlantBlock::addGrowthState(GrowthState state)
     return this;
 }
 
-GrowingPlantBlockType::GrowingPlantBlockType(int typeId,
-    ModelInfo model,
-    const char* name,
-    int blockTypeAfterGrowth,
+GrowingPlantBlockType::GrowingPlantBlockType(ModelInfo* model,
+    Framework::Text name,
+    Framework::Text blockTypeNameAfterGrowth,
     const char* readableName,
     int ticksNeeded,
-    int mapColor)
-    : BlockType(typeId, 0, model, 1, 10, 0, name, true, mapColor),
+    int mapColor,
+    float hardness,
+    Framework::RCArray<Framework::Text> groupNames)
+    : BlockType(
+        0, model, true, 10, false, name, true, mapColor, groupNames, hardness),
       transparent(1),
       passable(1),
-      hardness(0.1f),
-      zTool(0),
       speedModifier(0.3f),
       interactable(1),
       states(),
-      blockTypeAfterGrowth(blockTypeAfterGrowth),
+      blockTypeNameAfterGrowth(blockTypeNameAfterGrowth),
       readableName(readableName),
       ticksNeeded(ticksNeeded)
 {}
 
-GrowingPlantBlockType* GrowingPlantBlockType::setHardness(float hardness)
-{
-    this->hardness = hardness;
-    return this;
-}
-
-GrowingPlantBlockType* GrowingPlantBlockType::addGrowthState(
-    float growthPercentage, ModelInfo model)
-{
-    states.add(GrowthState(growthPercentage, model));
-    return this;
-}
-
 void GrowingPlantBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
 {
     GrowingPlantBlock* block = dynamic_cast<GrowingPlantBlock*>(zBlock);
     block->transparent = transparent;
     block->passable = passable;
-    block->hardness = hardness;
-    block->zTool = zTool;
+    block->hardness = getHardness();
     block->speedModifier = speedModifier;
     block->interactable = interactable;
     BlockType::createSuperBlock(zBlock, zItem);
@@ -204,15 +186,166 @@ Block* GrowingPlantBlockType::createBlock(
     Framework::Vec3<int> position, int dimensionId) const
 {
     GrowingPlantBlock* block = new GrowingPlantBlock(getId(),
-        zTool,
         position,
         dimensionId,
         ticksNeeded,
         readableName,
-        blockTypeAfterGrowth);
-    for (const GrowthState& state : states)
+        blockTypeIdAfterGrowth);
+    for (GrowthState* state : states)
     {
-        block->addGrowthState(state);
+        block->addGrowthState(dynamic_cast<GrowthState*>(state->getThis()));
     }
     return block;
-}
+}
+
+GrowingPlantBlockType* GrowingPlantBlockType::addGrowthState(
+    float growthPercentage, ModelInfo* model)
+{
+    states.add(new GrowthState(growthPercentage, model));
+    return this;
+}
+
+Framework::Text GrowingPlantBlockType::getBlockTypeNameAfterGrowth() const
+{
+    return blockTypeNameAfterGrowth;
+}
+
+const char* GrowingPlantBlockType::getReadableName() const
+{
+    return readableName;
+}
+
+int GrowingPlantBlockType::getTicksNeeded() const
+{
+    return ticksNeeded;
+}
+
+const Framework::RCArray<GrowthState>& GrowingPlantBlockType::getStates() const
+{
+    return states;
+}
+
+ItemType* GrowingPlantBlockType::createItemType() const
+{
+    return 0;
+}
+
+GrowingPlantBlockTypeFactory::GrowingPlantBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+GrowingPlantBlockType* GrowingPlantBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    GrowingPlantBlockType* result = new GrowingPlantBlockType(
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("name")->asString()->getString(),
+        zJson->zValue("blockTypeAfterGrowth")->asString()->getString(),
+        zJson->zValue("readableName")->asString()->getString(),
+        (int)zJson->zValue("ticksNeeded")->asNumber()->getNumber(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        (float)zJson->zValue("hardness")->asNumber()->getNumber(),
+        groupNames);
+    for (Framework::JSON::JSONValue* state :
+        *zJson->zValue("states")->asArray())
+    {
+        result->addGrowthState((float)state->asObject()
+                                   ->zValue("percentage")
+                                   ->asNumber()
+                                   ->getNumber(),
+            Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+                state->asObject()->zValue("model")));
+    }
+    return result;
+}
+
+Framework::JSON::JSONObject* GrowingPlantBlockTypeFactory::toJson(
+    GrowingPlantBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("readableName",
+        new Framework::JSON::JSONString(zObject->getReadableName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    result->addValue("blockTypeAfterGrowth",
+        new Framework::JSON::JSONString(
+            zObject->getBlockTypeNameAfterGrowth()));
+    result->addValue("ticksNeeded",
+        new Framework::JSON::JSONNumber((double)zObject->getTicksNeeded()));
+    Framework::JSON::JSONArray* states = new Framework::JSON::JSONArray();
+    for (GrowthState* state : zObject->getStates())
+    {
+        Framework::JSON::JSONObject* stateObj
+            = new Framework::JSON::JSONObject();
+        stateObj->addValue(
+            "model", Game::INSTANCE->zTypeRegistry()->toJson(state->zModel()));
+        stateObj->addValue("percentage",
+            new Framework::JSON::JSONNumber(state->getPercentage()));
+        states->addValue(stateObj);
+    }
+    result->addValue("states", states);
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+GrowingPlantBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredNumber("hardness")
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredString("readableName")
+        ->finishString()
+        ->withRequiredNumber("ticksNeeded")
+        ->finishNumber()
+        ->withRequiredString("blockTypeAfterGrowth")
+        ->finishString()
+        ->withRequiredArray("states")
+        ->addAcceptedObjectInArray()
+        ->withRequiredNumber("percentage")
+        ->whichIsGreaterOrEqual(0.0)
+        ->whichIsLessOrEqual(1.0)
+        ->finishNumber()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->finishObject()
+        ->finishArray()
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text GrowingPlantBlockTypeFactory::getTypeToken() const
+{
+    return "growingPlant";
+}

+ 48 - 25
FactoryCraft/GrowingPlant.h

@@ -4,16 +4,18 @@
 
 class GrowingPlantBlockType;
 
-struct GrowthState
+struct GrowthState : public Framework::ReferenceCounter
 {
-    GrowthState();
-    GrowthState(float percentage, ModelInfo model);
-    GrowthState(const GrowthState& right);
+private:
+    float percentage;
+    ModelInfo* model;
 
-    GrowthState& operator=(const GrowthState& right);
+public:
+    GrowthState(float percentage, ModelInfo* model);
+    ~GrowthState();
 
-    float percentage;
-    ModelInfo model;
+    float getPercentage() const;
+    ModelInfo* zModel() const;
 };
 
 class GrowingPlantBlock : public Block
@@ -21,26 +23,25 @@ class GrowingPlantBlock : public Block
 private:
     float seblingTicks;
     int seblingTicksMax;
-    const char* name;
-    Framework::Array<GrowthState> states;
+    Framework::Text name;
+    Framework::RCArray<GrowthState> states;
     int blockTypeAfterGrowth;
     bool plantSpawned;
     int lastSendState;
 
 public:
     GrowingPlantBlock(int typeId,
-        const ItemType* zTool,
         Framework::Vec3<int> pos,
         int dimensionId,
         int maxTicks,
-        const char* name,
+        Framework::Text name,
         int blockTypeAfterGrowth);
     virtual bool onTick(
         TickQueue* zQueue, int numTicks, bool& blocked) override;
     virtual void onPostTick() override;
     virtual void sendModelInfo(NetworkMessage* zMessage) override;
     virtual Framework::Text getTargetUIML();
-    GrowingPlantBlock* addGrowthState(GrowthState state);
+    GrowingPlantBlock* addGrowthState(GrowthState* state);
 
     friend GrowingPlantBlockType;
 };
@@ -50,15 +51,24 @@ class GrowingPlantBlockType : public BlockType
 private:
     bool transparent;
     bool passable;
-    float hardness;
-    const ItemType* zTool;
     float speedModifier;
     bool interactable;
-    Framework::Array<GrowthState> states;
-    int blockTypeAfterGrowth;
+    Framework::RCArray<GrowthState> states;
+    int blockTypeIdAfterGrowth;
+    Framework::Text blockTypeNameAfterGrowth;
     const char* readableName;
     int ticksNeeded;
 
+public:
+    GrowingPlantBlockType(ModelInfo* model,
+        Framework::Text name,
+        Framework::Text blockTypeNameAfterGrowth,
+        const char* readableName,
+        int ticksNeeded,
+        int mapColor,
+        float hardness,
+        Framework::RCArray<Framework::Text> groupNames);
+
 protected:
     virtual void loadSuperBlock(Block* zBlock,
         Framework::StreamReader* zReader,
@@ -71,14 +81,27 @@ protected:
         Framework::Vec3<int> position, int dimensionId) const override;
 
 public:
-    GrowingPlantBlockType(int typeId,
-        ModelInfo model,
-        const char* name,
-        int blockTypeAfterGrowth,
-        const char* readableName,
-        int ticksNeeded,
-        int mapColor);
-    GrowingPlantBlockType* setHardness(float hardness);
     GrowingPlantBlockType* addGrowthState(
-        float growthPercentage, ModelInfo model);
+        float growthPercentage, ModelInfo* model);
+
+    Framework::Text getBlockTypeNameAfterGrowth() const;
+    const char* getReadableName() const;
+    int getTicksNeeded() const;
+    const Framework::RCArray<GrowthState>& getStates() const;
+    virtual ItemType* createItemType() const override;
+};
+
+class GrowingPlantBlockTypeFactory
+    : public SubTypeFactory<BlockType, GrowingPlantBlockType>
+{
+public:
+    GrowingPlantBlockTypeFactory();
+    GrowingPlantBlockType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        GrowingPlantBlockType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 0 - 102
FactoryCraft/Hoe.cpp

@@ -1,102 +0,0 @@
-#include "Hoe.h"
-
-#include "Game.h"
-
-HoeToolItemType::HoeToolItemType() // TODO: add broken hoe
-    : BasicToolItemType(ItemTypeEnum::HOE,
-        "Hoe",
-        new HoeToolLevelUpRule(),
-        ItemTypeEnum::BROKEN_HOE,
-        ModelInfo("tools.m3/hoe", "tools.ltdb/stonehoe.png", 1))
-{}
-
-Item* HoeToolItemType::createItem() const
-{
-    return new BasicToolItem(ItemTypeEnum::HOE, "Hoe");
-}
-
-ItemSkill* HoeToolItemType::createDefaultItemSkill() const
-{
-    return new HoeToolSkill();
-}
-
-void HoeToolItemType::loadSuperItemSkill(
-    ItemSkill* zSkill, Framework::StreamReader* zReader) const
-{
-    HoeToolSkill* skill = dynamic_cast<HoeToolSkill*>(zSkill);
-    zReader->lese((char*)&skill->level, 4);
-    zReader->lese((char*)&skill->xp, 4);
-    zReader->lese((char*)&skill->maxXP, 4);
-}
-
-void HoeToolItemType::saveSuperItemSkill(
-    const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const
-{
-    const HoeToolSkill* skill = dynamic_cast<const HoeToolSkill*>(zSkill);
-    zWriter->schreibe((char*)&skill->level, 4);
-    zWriter->schreibe((char*)&skill->xp, 4);
-    zWriter->schreibe((char*)&skill->maxXP, 4);
-}
-
-HoeToolLevelUpRule::HoeToolLevelUpRule()
-    : ItemSkillLevelUpRule()
-{}
-
-void HoeToolLevelUpRule::applyOn(ItemSkill* zSkill)
-{
-    HoeToolSkill* skill = dynamic_cast<HoeToolSkill*>(zSkill);
-    if (skill->xp >= skill->maxXP)
-    {
-        skill->level++;
-        skill->xp = 0;
-        skill->maxXP = skill->maxXP * 2;
-    }
-}
-
-HoeToolSkill::HoeToolSkill()
-    : ItemSkill(ItemTypeEnum::HOE),
-      level(1),
-      xp(0.f),
-      maxXP(10.f),
-      nextActionCounter(0)
-{}
-
-bool HoeToolSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
-{
-    if (nextActionCounter == 0)
-    {
-        if (zActor->getStamina() > 0.5f / (float)level)
-        {
-            if (zTarget->zBlockType()->getId() == BlockTypeEnum::DIRT)
-            {
-                zActor->setStamina(
-                    zActor->getStamina() - 0.5f / (float)level);
-                zUsedItem->setDurability(zUsedItem->getDurability() - 0.5f);
-                Vec3<int> pos = zTarget->getPos();
-                int dimension = zTarget->getDimensionId();
-                xp += 0.5f;
-                Game::INSTANCE->doLater([pos, dimension]() {
-                    Game::INSTANCE->zDimension(dimension)->placeBlock(
-                        pos, BlockTypeEnum::FARMLAND);
-                });
-                nextActionCounter = 20;
-            }
-            else
-            {
-                zUsedItem->setDurability(
-                    zUsedItem->getDurability() - 0.5f / (float)level);
-                zActor->setStamina(zActor->getStamina() - 0.5f / (float)level);
-            }
-            return 1;
-        }
-    }
-    else if (nextActionCounter > 0)
-        nextActionCounter--;
-    return 0;
-}
-
-bool HoeToolSkill::use(Entity* zActor, Item* zUsedItem, Entity* zTarget)
-{
-    // a hoe can not be used on an entity
-    return 0;
-}

+ 0 - 43
FactoryCraft/Hoe.h

@@ -1,43 +0,0 @@
-#pragma once
-
-#include "ItemType.h"
-#include "ItemSkill.h"
-#include "BasicTool.h"
-
-class HoeToolItemType : public BasicToolItemType
-{
-protected:
-    void loadSuperItemSkill(
-        ItemSkill* zSkill, Framework::StreamReader* zReader) const override;
-    void saveSuperItemSkill(const ItemSkill* zSkill,
-        Framework::StreamWriter* zWriter) const override;
-
-public:
-    HoeToolItemType();
-    Item* createItem() const override;
-    ItemSkill* createDefaultItemSkill() const override;
-};
-
-class HoeToolLevelUpRule : public ItemSkillLevelUpRule
-{
-public:
-    HoeToolLevelUpRule();
-    void applyOn(ItemSkill* zSkill) override;
-};
-
-class HoeToolSkill : public ItemSkill
-{
-private:
-    int level;
-    float xp;
-    float maxXP;
-    int nextActionCounter;
-
-public:
-    HoeToolSkill();
-    bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) override;
-    bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
-
-    friend HoeToolItemType;
-    friend HoeToolLevelUpRule;
-};

+ 1 - 2
FactoryCraft/Inventory.cpp

@@ -400,8 +400,7 @@ void Inventory::loadInventory(Framework::StreamReader* zReader)
             {
                 int id = 0;
                 zReader->lese((char*)&id, 4);
-                Item* item
-                    = StaticRegistry<ItemType>::INSTANCE.zElement(id)->loadItem(
+                Item* item = Game::INSTANCE->zItemType(id)->loadItem(
                         zReader);
                 stack->addItems(new ItemStack(item, size), NO_DIRECTION);
             }

+ 29 - 21
FactoryCraft/Item.cpp

@@ -4,7 +4,7 @@
 
 #include "Game.h"
 
-Item::Item(int itemTypeId, const char* name)
+Item::Item(int itemTypeId, Framework::Text name)
     : ReferenceCounter(),
       itemTypeId(itemTypeId),
       blockTypeId(0),
@@ -17,11 +17,10 @@ Item::Item(int itemTypeId, const char* name)
       equippable(0),
       solid(1),
       usable(0),
-      maxStackSize(50),
       name(name)
 {
     foodEffect = [](Item* i, Entity* e) { return false; };
-    foodEffectDestroysItemTest = [](const Item* i, Entity *e) { return false; };
+    foodEffectDestroysItemTest = [](const Item* i, Entity* e) { return false; };
 }
 
 void Item::setHp(float hp)
@@ -45,7 +44,7 @@ void Item::setFoodEffect(std::function<bool(Item*, Entity*)> foodEffect,
 
 const ItemType* Item::zItemType() const
 {
-    return StaticRegistry<ItemType>::INSTANCE.zElement(itemTypeId);
+    return Game::INSTANCE->zItemType(itemTypeId);
 }
 
 int Item::getTypeId() const
@@ -55,7 +54,7 @@ int Item::getTypeId() const
 
 const BlockType* Item::zPlacedBlockType() const
 {
-    return StaticRegistry<BlockType>::INSTANCE.zElement(blockTypeId);
+    return Game::INSTANCE->zBlockType(blockTypeId);
 }
 
 float Item::getHp() const
@@ -93,6 +92,16 @@ bool Item::isSolid() const
     return solid;
 }
 
+void Item::setMaxDurability(float maxDurability)
+{
+    if (maxDurability != this->maxDurability)
+    {
+        float durabilityPercentage = durability / this->maxDurability;
+        this->maxDurability = maxDurability;
+        durability = maxDurability * durabilityPercentage;
+    }
+}
+
 float Item::getMaxDurability() const
 {
     return maxDurability;
@@ -100,7 +109,7 @@ float Item::getMaxDurability() const
 
 int Item::getMaxStackSize() const
 {
-    return maxStackSize;
+    return zItemType()->getMaxStackSize();
 }
 
 float Item::getMaxHp() const
@@ -119,7 +128,7 @@ bool Item::canBeStackedWith(const Item* zItem) const
         && zItem->durability == zItem->durability && maxHp == zItem->maxHp
         && eatable == zItem->eatable && placeable == zItem->placeable
         && equippable == zItem->eatable && solid == zItem->solid
-        && usable == zItem->usable && maxStackSize == zItem->maxStackSize
+        && usable == zItem->usable
         && name.istGleich(zItem->name);
 }
 
@@ -143,8 +152,7 @@ Framework::Text Item::getTooltipUIML() const
          + "</text></tip>";
 }
 
-void Item::applyInventoryEffects(Entity* zTarget)
-{}
+void Item::applyInventoryEffects(Entity* zTarget) {}
 
 void Item::removeInventoryEffects(Entity* zTarget) {}
 
@@ -170,35 +178,35 @@ Item* ItomJsonType::fromJson(Framework::JSON::JSONValue* zJson) const
 {
     const ItemType* type = ItemType::zByName(
         zJson->asObject()->zValue("type")->asString()->getString());
-    Item *result = type->createItem();
+    Item* result = type->createItem();
     for (auto attribute = zJson->asObject()->getFields(); attribute;
          attribute++)
     {
-        if (attribute.val().istGleich("type"))
-			continue;
+        if (attribute.val().istGleich("type")) continue;
         type->setItemAttribute(
             result, attribute, zJson->asObject()->zValue(attribute));
     }
     return result;
 }
 
-Framework::JSON::JSONValue* ItomJsonType::toJson(Item* zObject) const {
+Framework::JSON::JSONValue* ItomJsonType::toJson(Item* zObject) const
+{
     Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
-    result->addValue("type", new Framework::JSON::JSONString(
-		zObject->zItemType()->getName()));
+    result->addValue("type",
+        new Framework::JSON::JSONString(zObject->zItemType()->getName()));
     zObject->zItemType()->addItemAttributes(zObject, result);
-	return result;
+    return result;
 }
 
-Framework::JSON::Validator::JSONValidator* ItomJsonType::getValidator() const {
+Framework::JSON::Validator::JSONValidator* ItomJsonType::getValidator() const
+{
     Framework::RCArray<Framework::Text> itemTypes;
-    for (int index = 0; index < StaticRegistry<ItemType>::INSTANCE.getCount();
-         index++)
+    for (int index = 0; index < Game::INSTANCE->getItemTypeCount(); index++)
     {
-        if (StaticRegistry<ItemType>::INSTANCE.zElement(index))
+        if (Game::INSTANCE->zItemType(index))
         {
             itemTypes.add(new Framework::Text(
-                StaticRegistry<ItemType>::INSTANCE.zElement(index)->getName()));
+                Game::INSTANCE->zItemType(index)->getName()));
         }
     }
     return Framework::JSON::Validator::JSONValidator::buildForObject()

+ 2 - 2
FactoryCraft/Item.h

@@ -23,11 +23,10 @@ protected:
     bool equippable;
     bool solid;
     bool usable;
-    int maxStackSize;
     Framework::Text name;
     std::function<bool(Item*, Entity*)> foodEffect;
     std::function<bool(const Item*, Entity*)> foodEffectDestroysItemTest;
-    Item(int itemTypeId, const char* name);
+    Item(int itemTypeId, Framework::Text name);
 
 public:
     void setHp(float hp);
@@ -46,6 +45,7 @@ public:
     bool isPlaceable() const;
     bool isEquippable() const;
     bool isSolid() const;
+    void setMaxDurability(float maxDurability);
     float getMaxDurability() const;
     int getMaxStackSize() const;
     float getMaxHp() const;

+ 3 - 3
FactoryCraft/ItemEntity.cpp

@@ -85,15 +85,15 @@ bool ItemEntity::hasDefaultModel() const
     return 0;
 }
 
-ModelInfo ItemEntity::getSpecialModel() const
+ModelInfo *ItemEntity::zSpecialModel() const
 {
     const ItemType* zItemType = 0;
     if (!slot->isEmpty()) zItemType = slot->zStack()->zItem()->zItemType();
-    return !zItemType ? ModelInfo("", "", 0) : zItemType->getModel();
+    return !zItemType ? 0 : zItemType->zModel();
 }
 
 ItemEntityType::ItemEntityType()
-    : EntityType(EntityTypeEnum::ITEM, ModelInfo("", "", 0))
+    : EntityType("Item", 0)
 {}
 
 Entity* ItemEntityType::createEntity(

+ 1 - 1
FactoryCraft/ItemEntity.h

@@ -18,7 +18,7 @@ public:
 
     void onFall(float collisionSpeed) override;
     bool hasDefaultModel() const override;
-    ModelInfo getSpecialModel() const override;
+    ModelInfo* zSpecialModel() const override;
 
     friend ItemEntityType;
 };

+ 42 - 33
FactoryCraft/ItemSkill.cpp

@@ -3,21 +3,29 @@
 #include "Block.h"
 #include "Entity.h"
 #include "ItemType.h"
-#include "StaticRegistry.h"
 
-ItemSkill::ItemSkill(int itemTypeId)
+ItemSkill::ItemSkill(float xp, float maxXp, float level)
     : Framework::ReferenceCounter(),
-      itemTypeId(itemTypeId)
+      xp(xp),
+      maxXP(maxXp),
+      level(level),
+      itemTypeId(-1)
 {}
 
-const ItemType* ItemSkill::zSkillType()
+void ItemSkill::load(Framework::StreamReader* zReader)
 {
-    return StaticRegistry<ItemType>::INSTANCE.zElement(itemTypeId);
+    zReader->lese((char*)&xp, 4);
+    zReader->lese((char*)&maxXP, 4);
+    zReader->lese((char*)&level, 4);
+    zReader->lese((char*)&itemTypeId, 4);
 }
 
-int ItemSkill::getTypeId()
+void ItemSkill::save(Framework::StreamWriter* zWriter)
 {
-    return itemTypeId;
+    zWriter->schreibe((char*)&xp, 4);
+    zWriter->schreibe((char*)&maxXP, 4);
+    zWriter->schreibe((char*)&level, 4);
+    zWriter->schreibe((char*)&itemTypeId, 4);
 }
 
 bool ItemSkill::interact(Entity* zActor, Item* zUsedItem, Block* zTarget)
@@ -30,41 +38,42 @@ bool ItemSkill::interact(Entity* zActor, Item* zUsedItem, Entity* zTarget)
     return zTarget->interact(zUsedItem, zActor);
 }
 
-BasicItemSkill::BasicItemSkill(int itemTypeId,
-    float maxXP,
-    float durabilityModifier,
-    float speedModifier,
-    float luckModifier,
-    float staminaModifier,
-    float hungerModifier,
-    float xpIncrease)
-    : ItemSkill(itemTypeId),
-      level(1),
-      xp(0),
-      maxXP(maxXP),
-      durabilityModifier(durabilityModifier),
-      speedModifier(speedModifier),
-      luckModifier(luckModifier),
-      staminaModifier(staminaModifier),
-      hungerModifier(hungerModifier)
-{}
+void ItemSkill::setXp(float xp)
+{
+    this->xp = xp;
+}
+
+float ItemSkill::getXp() const
+{
+    return xp;
+}
 
-bool BasicItemSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
+void ItemSkill::setMaxXp(float maxXp)
 {
-    return false;
+    this->maxXP = maxXp;
 }
 
-bool BasicItemSkill::use(Entity* zActor, Item* zUsedItem, Entity* zTarget)
+float ItemSkill::getMaxXp() const
 {
-    return false;
+    return maxXP;
 }
 
-bool BasicItemSkill::interact(Entity* zActor, Item* zUsedItem, Block* zTarget)
+void ItemSkill::setLevel(float level)
 {
-    return false;
+    this->level = level;
 }
 
-bool BasicItemSkill::interact(Entity* zActor, Item* zUsedItem, Entity* zTarget)
+float ItemSkill::getLevel() const
 {
-    return false;
+    return level;
+}
+
+void ItemSkill::setItemTypeId(int itemTypeId)
+{
+    this->itemTypeId = itemTypeId;
+}
+
+int ItemSkill::getItemTypeId() const
+{
+    return itemTypeId;
 }

+ 15 - 36
FactoryCraft/ItemSkill.h

@@ -21,46 +21,25 @@ public:
 class ItemSkill : public virtual Framework::ReferenceCounter
 {
 private:
-    const int itemTypeId;
+    float xp;
+    float maxXP;
+    float level;
+    int itemTypeId;
 
 public:
-    ItemSkill(int itemTypeId);
+    ItemSkill(float xp, float maxXp, float level);
+    virtual void load(Framework::StreamReader* zReader);
+    virtual void save(Framework::StreamWriter* zWriter);
     virtual bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) = 0;
     virtual bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) = 0;
     virtual bool interact(Entity* zActor, Item* zUsedItem, Block* zTarget);
     virtual bool interact(Entity* zActor, Item* zUsedItem, Entity* zTarget);
-    const ItemType* zSkillType();
-    int getTypeId();
-};
-
-class BasicItemSkill : public ItemSkill
-{
-protected:
-    int level;
-    float xp;
-    float maxXP;
-    float durabilityModifier;
-    float speedModifier;
-    float luckModifier;
-    float staminaModifier;
-    float hungerModifier;
-
-    BasicItemSkill(int itemTypeId,
-        float maxXp = 100.f,
-        float durabilityModifier = 1.f,
-        float speedModifier = 1.f,
-        float luckModifier = 1.f,
-        float staminaModifier = 1.f,
-        float hungerModifier = 1.f,
-        float xpIncrease = 1.1f);
-
-public:
-    virtual bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) override;
-    virtual bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
-    virtual bool interact(
-        Entity* zActor, Item* zUsedItem, Block* zTarget) override;
-    virtual bool interact(
-        Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
-
-    friend ItemType;
+    void setXp(float xp);
+    float getXp() const;
+    void setMaxXp(float maxXp);
+    float getMaxXp() const;
+    void setLevel(float level);
+    float getLevel() const;
+    void setItemTypeId(int itemTypeId);
+    int getItemTypeId() const;
 };

+ 38 - 66
FactoryCraft/ItemType.cpp

@@ -3,29 +3,28 @@
 
 #include <InMemoryBuffer.h>
 
+#include "Game.h"
 #include "ItemSkill.h"
 #include "ItemStack.h"
 
-ItemType::ItemType(int id,
-    const char* name,
-    ItemSkillLevelUpRule* levelUpRule,
-    int brokenTypeId,
-    ModelInfo model)
+ItemType::ItemType(Framework::Text name, ModelInfo* model, int maxStackSize)
     : ReferenceCounter(),
-      id(id),
       name(name),
-      levelUpRule(levelUpRule),
-      brokenTypeId(brokenTypeId),
-      model(model)
+      model(model),
+      maxStackSize(maxStackSize)
 {
     tooltipUIML = Framework::Text("<tip><text width=\"auto\" height=\"auto\">")
                 + name + "</text></tip>";
-    StaticRegistry<ItemType>::INSTANCE.registerT(this, id);
 }
 
 ItemType::~ItemType()
 {
-    if (levelUpRule) levelUpRule->release();
+    if (model) model->release();
+}
+
+bool ItemType::initialize(Game* zGame)
+{
+    return true;
 }
 
 void ItemType::loadSuperItem(
@@ -42,7 +41,6 @@ void ItemType::loadSuperItem(
     zItem->equippable = (flags | 4) == flags;
     zItem->solid = (flags | 8) == flags;
     zItem->usable = (flags | 16) == flags;
-    zReader->lese((char*)&zItem->maxStackSize, 1);
     unsigned char len = 0;
     zReader->lese((char*)&len, 1);
     zItem->name.fillText(' ', len);
@@ -61,20 +59,11 @@ void ItemType::saveSuperItem(
                           | (zItem->equippable << 2) | (zItem->placeable << 1)
                           | (int)zItem->eatable);
     zWriter->schreibe((char*)&flags, 1);
-    zWriter->schreibe((char*)&zItem->maxStackSize, 1);
     unsigned char len = (unsigned char)zItem->name.getLength();
     zWriter->schreibe((char*)&len, 1);
     zWriter->schreibe(zItem->name, len);
 }
 
-void ItemType::loadSuperItemSkill(
-    ItemSkill* zSkill, Framework::StreamReader* zReader) const
-{}
-
-void ItemType::saveSuperItemSkill(
-    const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const
-{}
-
 int ItemType::getId() const
 {
     return id;
@@ -92,7 +81,7 @@ const Framework::Text& ItemType::getTooltipUIML() const
 
 const ItemType* ItemType::zBrokenItemType() const
 {
-    return StaticRegistry<ItemType>::INSTANCE.zElement(brokenTypeId);
+    return 0;
 }
 
 ItemStack* ItemType::createItemStack(int size) const
@@ -107,10 +96,7 @@ ItemSkill* ItemType::createDefaultItemSkill() const
     return 0;
 }
 
-void ItemType::levelUpItemSkill(ItemSkill* zSkill) const
-{
-    if (levelUpRule) levelUpRule->applyOn(zSkill);
-}
+void ItemType::levelUpItemSkill(ItemSkill* zSkill) const {}
 
 Item* ItemType::loadItem(Framework::StreamReader* zReader) const
 {
@@ -132,33 +118,12 @@ Item* ItemType::cloneItem(const Item* zItem) const
     return loadItem(&buffer);
 }
 
-ItemSkill* ItemType::loadItemSkill(Framework::StreamReader* zReader) const
-{
-    ItemSkill* skill = createDefaultItemSkill();
-    loadSuperItemSkill(skill, zReader);
-    return skill;
-}
-
-void ItemType::saveItemSkill(
-    const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const
-{
-    saveSuperItemSkill(zSkill, zWriter);
-}
-
 Item* ItemType::breakItem(const Item* zItem) const
 {
-    if (brokenTypeId)
-    {
-        const ItemType *type = StaticRegistry<ItemType>::INSTANCE.zElement(brokenTypeId);
-        if (type)
-        {
-            return type->createItem();
-        }
-    }
     return 0;
 }
 
-const ModelInfo& ItemType::getModel() const
+ModelInfo* ItemType::zModel() const
 {
     return model;
 }
@@ -187,14 +152,27 @@ void ItemType::setItemAttribute(
 void ItemType::addItemAttributes(
     Item* zItem, Framework::JSON::JSONObject* zItemObjet) const
 {
-    zItemObjet->addValue("hp", new Framework::JSON::JSONNumber((double)zItem->hp));
-    zItemObjet->addValue("maxHp", new Framework::JSON::JSONNumber((double)zItem->maxHp));
-    zItemObjet->addValue("durability", new Framework::JSON::JSONNumber((double)zItem->durability));
+    zItemObjet->addValue(
+        "hp", new Framework::JSON::JSONNumber((double)zItem->hp));
+    zItemObjet->addValue(
+        "maxHp", new Framework::JSON::JSONNumber((double)zItem->maxHp));
+    zItemObjet->addValue("durability",
+        new Framework::JSON::JSONNumber((double)zItem->durability));
     zItemObjet->addValue("maxDurability",
         new Framework::JSON::JSONNumber((double)zItem->maxDurability));
     zItemObjet->addValue("name", new Framework::JSON::JSONString(zItem->name));
 }
 
+void ItemType::setTypeId(int id)
+{
+    this->id = id;
+}
+
+int ItemType::getMaxStackSize() const
+{
+    return maxStackSize;
+}
+
 Item* ItemType::createBasicItem(int id,
     const char* name,
     float hp,
@@ -205,8 +183,7 @@ Item* ItemType::createBasicItem(int id,
     bool placeable,
     bool equippable,
     bool solid,
-    bool usable,
-    int maxStackSize)
+    bool usable)
 {
     Item* item = new Item(id, name);
     item->hp = hp;
@@ -218,32 +195,27 @@ Item* ItemType::createBasicItem(int id,
     item->equippable = equippable;
     item->solid = solid;
     item->usable = usable;
-    item->maxStackSize = maxStackSize;
     return item;
 }
 
 int ItemType::getTypeId(const char* name)
 {
-    for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
     {
-        if (StaticRegistry<ItemType>::INSTANCE.zElement(i)
-            && StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                   ->getName()
-                   .istGleich(name))
-            return StaticRegistry<ItemType>::INSTANCE.zElement(i)->getId();
+        if (Game::INSTANCE->zItemType(i)
+            && Game::INSTANCE->zItemType(i)->getName().istGleich(name))
+            return Game::INSTANCE->zItemType(i)->getId();
     }
     return 0;
 }
 
 const ItemType* ItemType::zByName(const char* name)
 {
-    for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
     {
-        if (StaticRegistry<ItemType>::INSTANCE.zElement(i)
-            && StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                   ->getName()
-                   .istGleich(name))
-            return StaticRegistry<ItemType>::INSTANCE.zElement(i);
+        if (Game::INSTANCE->zItemType(i)
+            && Game::INSTANCE->zItemType(i)->getName().istGleich(name))
+            return Game::INSTANCE->zItemType(i);
     }
     return 0;
 }

+ 15 - 35
FactoryCraft/ItemType.h

@@ -8,61 +8,43 @@
 #include "BlockType.h"
 #include "Effect.h"
 #include "ModelInfo.h"
-#include "StaticRegistry.h"
 
 class Item;
 class ItemStack;
 class ItemSkill;
 class ItemSkillLevelUpRule;
 
-class ItemTypeEnum : public BlockTypeEnum
+class ItemTypeEnum
 {
 public:
-    static const int WOOD_STICK = BlockTypeEnum::MAX_VALUE + 1;
-    static const int AXE = BlockTypeEnum::MAX_VALUE + 2;
-    static const int RESIN = BlockTypeEnum::MAX_VALUE + 3;
-    static const int PLAYER_HAND = BlockTypeEnum::MAX_VALUE + 4;
-    static const int AXE_BROKEN = BlockTypeEnum::MAX_VALUE + 5;
-    static const int HOE = BlockTypeEnum::MAX_VALUE + 6;
-    static const int BROKEN_HOE = BlockTypeEnum::MAX_VALUE + 7;
-    static const int FLINT = BlockTypeEnum::MAX_VALUE + 8;
-    static const int SHOVEL = BlockTypeEnum::MAX_VALUE + 9;
-    static const int SHOVEL_BROKEN = BlockTypeEnum::MAX_VALUE + 10;
-    static const int WOODEN_BUCKET = BlockTypeEnum::MAX_VALUE + 11;
+    static const int PLAYER_HAND = 0;
 };
 
 class ItemType : public virtual Framework::ReferenceCounter
 {
 protected:
-    const int id;
+    int id;
     const Framework::Text name;
     Framework::Text tooltipUIML;
-    ItemSkillLevelUpRule* levelUpRule;
-    int brokenTypeId;
-    const ModelInfo model;
+    ModelInfo *model;
+    int maxStackSize;
 
-    ItemType(int id,
-        const char* name,
-        ItemSkillLevelUpRule* levelUpRule,
-        int brokenTypeId,
-        ModelInfo model);
+    ItemType(Framework::Text name,
+        ModelInfo *model, int maxStackSize);
 
     virtual void loadSuperItem(
         Item* zItem, Framework::StreamReader* zReader) const;
     virtual void saveSuperItem(
         const Item* zItem, Framework::StreamWriter* zWriter) const;
-    virtual void loadSuperItemSkill(
-        ItemSkill* zSkill, Framework::StreamReader* zReader) const;
-    virtual void saveSuperItemSkill(
-        const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const;
 
 public:
     ~ItemType();
+    virtual bool initialize(Game* zGame);
 
     int getId() const;
     const Framework::Text& getName() const;
     const Framework::Text& getTooltipUIML() const;
-    const ItemType* zBrokenItemType() const;
+    virtual const ItemType* zBrokenItemType() const;
     virtual Item* createItem() const = 0;
     virtual ItemStack* createItemStack(int size) const;
     virtual ItemSkill* createDefaultItemSkill() const;
@@ -70,17 +52,16 @@ public:
     virtual Item* loadItem(Framework::StreamReader* zReader) const;
     virtual void saveItem(
         const Item* zItem, Framework::StreamWriter* zWriter) const;
-    virtual ItemSkill* loadItemSkill(Framework::StreamReader* zReader) const;
-    virtual void saveItemSkill(
-        const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const;
     virtual Item* cloneItem(const Item* zItem) const;
     virtual Item* breakItem(const Item* zItem) const;
-    const ModelInfo& getModel() const;
+    ModelInfo* zModel() const;
     virtual void setItemAttribute(Item* zItem,
         Framework::Text name,
         Framework::JSON::JSONValue* zValue) const;
-    virtual void addItemAttributes(Item* zItem,
-        Framework::JSON::JSONObject* zItemObjet) const;
+    virtual void addItemAttributes(
+        Item* zItem, Framework::JSON::JSONObject* zItemObjet) const;
+    void setTypeId(int id);
+    int getMaxStackSize() const;
 
     static Item* createBasicItem(int id,
         const char* name,
@@ -92,8 +73,7 @@ public:
         bool placeable,
         bool equippable,
         bool solid,
-        bool usable,
-        int maxStackSize);
+        bool usable);
     static int getTypeId(const char* name);
     static const ItemType* zByName(const char* name);
 };

+ 3 - 4
FactoryCraft/JsonExpression.cpp

@@ -528,12 +528,11 @@ JBoolExpression* JExpressionParser::parseBoolExpression(
 Framework::JSON::Validator::JSONValidator* JExpressionParser::getBoolValidator()
 {
     Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < StaticRegistry<BlockType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
     {
-        if (StaticRegistry<BlockType>::INSTANCE.zElement(i))
+        if (Game::INSTANCE->zBlockType(i))
         {
-            blockTypeNames.add(new Framework::Text(
-                StaticRegistry<BlockType>::INSTANCE.zElement(i)->getName()));
+            blockTypeNames.add(new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
         }
     }
     JSONValidator* refs

+ 34 - 0
FactoryCraft/JsonUtils.cpp

@@ -0,0 +1,34 @@
+#include "JsonUtils.h"
+
+#include <Datei.h>
+
+void loadAllJsonsFromDirectory(Framework::Text path,
+    std::function<void(Framework::JSON::JSONValue* zValue)> action)
+{
+    if (path.hatAt(path.getLength() - 1, "/")
+        || path.hatAt(path.getLength() - 1, "\\"))
+    {
+        path.remove(path.getLength() - 1, path.getLength());
+    }
+    Framework::Datei dir(path);
+    if (dir.istOrdner())
+    {
+        Framework::RCArray<Framework::Text> *list = dir.getDateiListe();
+        for (Framework::Text* name : *list)
+        {
+            Framework::Text nextPath = path + "/" + *name;
+            loadAllJsonsFromDirectory(nextPath, action);
+        }
+        list->release();
+    }
+    else if (path.hatAt(path.getLength() - 5, ".json") && dir.existiert())
+    {
+        Framework::JSON::JSONValue* value
+            = Framework::JSON::loadJSONFromFile(path);
+        if (value)
+        {
+            action(value);
+            value->release();
+        }
+	}
+}

+ 5 - 0
FactoryCraft/JsonUtils.h

@@ -0,0 +1,5 @@
+#pragma once
+
+#include <JSON.h>
+
+extern void loadAllJsonsFromDirectory(Framework::Text directory, std::function<void(Framework::JSON::JSONValue *zValue)> action);

+ 136 - 30
FactoryCraft/LightSources.cpp

@@ -1,7 +1,9 @@
 #include "LightSources.h"
 
-LightSourceItem::LightSourceItem(int itemType, int blockType, const char* name)
-    : BasicBlockItem(itemType, blockType, name),
+#include "Game.h"
+
+LightSourceItem::LightSourceItem(int itemType, int blockType, Framework::Text name)
+    : BasicBlockItem(itemType, blockType, name, 0),
       color(0XFFFFFFFF)
 {}
 
@@ -11,14 +13,13 @@ bool LightSourceItem::canBeStackedWith(const Item* zItem) const
     return BasicBlockItem::canBeStackedWith(zItem) && other->color == color;
 }
 
-LightSourceItemType::LightSourceItemType(
-    int id, const char* name, const ModelInfo model, int blockTypeId)
-    : BasicBlockItemType(id, name, 0, 0, model, blockTypeId)
-{
-    transparent = 1;
-    passable = 1;
-    hardness = 0;
-}
+LightSourceItemType::LightSourceItemType(Framework::Text name,
+    ModelInfo* model,
+    Framework::Text blockTypeName,
+    int maxStackSize)
+    : BasicBlockItemType(
+        name, model, true, true, 0.f, 1.f, blockTypeName, 0, maxStackSize)
+{}
 
 void LightSourceItemType::loadSuperItem(
     Item* zItem, Framework::StreamReader* zReader) const
@@ -38,7 +39,7 @@ void LightSourceItemType::saveSuperItem(
 
 Item* LightSourceItemType::createItem() const
 {
-    LightSourceItem* item = new LightSourceItem(id, blockTypeId, name);
+    LightSourceItem* item = new LightSourceItem(id, getBlockTypeId(), name);
     item->color = color;
     return item;
 }
@@ -51,7 +52,7 @@ LightSourceItemType* LightSourceItemType::setColor(int color)
 
 BasicLightSource::BasicLightSource(
     int typeId, Framework::Vec3<int> pos, int dimensionId)
-    : Block(typeId, 0, pos, dimensionId, 0)
+    : Block(typeId, pos, dimensionId, false)
 {}
 
 void BasicLightSource::setLight(int light)
@@ -69,13 +70,19 @@ bool BasicLightSource::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
 void BasicLightSource::onPostTick() {}
 
 BasicLightSourceBlockType::BasicLightSourceBlockType(
-    int typeId, int itemTypeId, ModelInfo model, const char* name)
-    : BlockType(typeId, 0, model, 1, 1, 1, name, false, color),
-      itemType(itemTypeId),
+    Framework::Text itemTypeName,
+    ModelInfo* model,
+    Framework::Text name,
+    float hardness,
+    int mapColor,
+    int lightColor,
+    Framework::RCArray<Framework::Text> groupNames)
+    : BlockType(0, model, 1, 1, 1, name, false, mapColor, groupNames, hardness),
+      itemTypeName(itemTypeName),
       transparent(1),
       passable(1),
-      hardness(1.f),
-      interactable(1)
+      interactable(1),
+      lightColor(lightColor)
 {}
 
 void BasicLightSourceBlockType::createSuperBlock(
@@ -87,11 +94,10 @@ void BasicLightSourceBlockType::createSuperBlock(
     block->passable = passable;
     block->hp = (float)getInitialMaxHP();
     block->maxHP = (float)getInitialMaxHP();
-    block->hardness = hardness;
-    block->zTool = 0;
+    block->hardness = getHardness();
     block->speedModifier = 1;
     block->interactable = interactable;
-    block->setLight(color);
+    block->setLight(lightColor);
     if (zItem)
     {
         dynamic_cast<BasicLightSource*>(zBlock)->setLight(
@@ -121,6 +127,19 @@ void BasicLightSourceBlockType::saveSuperBlock(
     zWriter->schreibe((char*)&block->lightEmisionColor, 4);
 }
 
+bool BasicLightSourceBlockType::initialize(Game* zGame)
+{
+    if (itemTypeName.getLength())
+    {
+        itemTypeId = zGame->getItemTypeId(itemTypeName);
+    }
+    else
+    {
+        itemTypeId = 0;
+    }
+    return itemTypeId >= 0 && BlockType::initialize(zGame);
+}
+
 Block* BasicLightSourceBlockType::createBlock(
     Framework::Vec3<int> position, int dimensionId) const
 {
@@ -129,19 +148,106 @@ Block* BasicLightSourceBlockType::createBlock(
 
 Item* BasicLightSourceBlockType::createItem() const
 {
-    return StaticRegistry<ItemType>::INSTANCE.zElement(itemType)->createItem();
+    return Game::INSTANCE->zItemType(itemTypeId)->createItem();
 }
 
-BasicLightSourceBlockType* BasicLightSourceBlockType::setHardness(
-    float hardness)
+int BasicLightSourceBlockType::getLightColor() const
 {
-    this->hardness = hardness;
-    return this;
+    return lightColor;
 }
 
-BasicLightSourceBlockType* BasicLightSourceBlockType::setColor(int color)
+Framework::Text BasicLightSourceBlockType::getItemTypeName() const
 {
-    this->color = color;
-    this->initialMapColor = color;
-    return this;
-}
+    return itemTypeName;
+}
+
+ItemType* BasicLightSourceBlockType::createItemType() const
+{
+    return (new LightSourceItemType(getItemTypeName(),
+                new ModelInfo(zModel()->getModelPath(),
+                    zModel()->getTexturePaths(),
+                    zModel()->isTransparent(),
+                    zModel()->getSize() / 2.f),
+                getName(), 50))
+        ->setColor(0x00F69A54);
+}
+
+BasicLightSourceBlockTypeFactory::BasicLightSourceBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+BasicLightSourceBlockType* BasicLightSourceBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    return new BasicLightSourceBlockType(
+        zJson->zValue("itemType")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("name")->asString()->getString(),
+        (float)zJson->zValue("hardness")->asNumber()->getNumber(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        (int)zJson->zValue("lightColor")->asString()->getString(),
+        groupNames);
+}
+
+Framework::JSON::JSONObject* BasicLightSourceBlockTypeFactory::toJson(
+    BasicLightSourceBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
+        new Framework::JSON::JSONString(zObject->getItemTypeName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    result->addValue("lightColor",
+        new Framework::JSON::JSONString(zObject->getLightColor()));
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+BasicLightSourceBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("itemType")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredNumber("hardness")
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredString("lightColor")
+        ->finishString()
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text BasicLightSourceBlockTypeFactory::getTypeToken() const
+{
+    return "lightSource";
+}

+ 42 - 11
FactoryCraft/LightSources.h

@@ -13,7 +13,7 @@ protected:
     int color;
 
 public:
-    LightSourceItem(int itemType, int blockType, const char* name);
+    LightSourceItem(int itemType, int blockType, Framework::Text name);
     virtual bool canBeStackedWith(const Item* zItem) const override;
 
     friend LightSourceItemType;
@@ -25,6 +25,12 @@ class LightSourceItemType : public BasicBlockItemType
 private:
     int color;
 
+public:
+    LightSourceItemType(Framework::Text name,
+        ModelInfo* model,
+        Framework::Text blockTypeName,
+        int maxStackSize);
+
 protected:
     virtual void loadSuperItem(
         Item* zItem, Framework::StreamReader* zReader) const override;
@@ -33,18 +39,18 @@ protected:
     virtual Item* createItem() const override;
 
 public:
-    LightSourceItemType(
-        int id, const char* name, const ModelInfo model, int blockTypeId);
     LightSourceItemType* setColor(int color);
 };
 
 class BasicLightSource : public Block
 {
+public:
+    BasicLightSource(int typeId, Framework::Vec3<int> pos, int dimensionId);
+
 protected:
     void setLight(int light);
 
 public:
-    BasicLightSource(int typeId, Framework::Vec3<int> pos, int dimensionId);
     virtual bool onTick(
         TickQueue* zQueue, int numTicks, bool& blocked) override;
     virtual void onPostTick() override;
@@ -55,12 +61,21 @@ public:
 class BasicLightSourceBlockType : public BlockType
 {
 private:
-    int itemType;
+    Framework::Text itemTypeName;
+    int itemTypeId;
     bool transparent;
     bool passable;
-    float hardness;
     bool interactable;
-    int color;
+    int lightColor;
+
+public:
+    BasicLightSourceBlockType(Framework::Text itemTypeName,
+        ModelInfo* model,
+        Framework::Text name,
+        float hardness,
+        int mapColor,
+        int lightColor,
+        Framework::RCArray<Framework::Text> groupNames);
 
 protected:
     virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
@@ -71,11 +86,27 @@ protected:
         Block* zBlock, Framework::StreamWriter* zWriter) const override;
 
 public:
-    BasicLightSourceBlockType(
-        int typeId, int itemTypeId, ModelInfo model, const char* name);
+    virtual bool initialize(Game* zGame) override;
     virtual Block* createBlock(
         Framework::Vec3<int> position, int dimensionId) const override;
     virtual Item* createItem() const override;
-    BasicLightSourceBlockType* setHardness(float hardness);
-    BasicLightSourceBlockType* setColor(int color);
+
+    int getLightColor() const;
+    Framework::Text getItemTypeName() const;
+    virtual ItemType* createItemType() const override;
+};
+
+class BasicLightSourceBlockTypeFactory
+    : public SubTypeFactory<BlockType, BasicLightSourceBlockType>
+{
+public:
+    BasicLightSourceBlockTypeFactory();
+    BasicLightSourceBlockType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        BasicLightSourceBlockType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 84 - 38
FactoryCraft/ModelInfo.cpp

@@ -2,41 +2,15 @@
 
 using namespace Framework;
 
-ModelInfo::ModelInfo(
-    const char* modelPath, const char* texturPath, int textureCount)
-    : modelPath(modelPath),
-      transparent(0)
-{
-    for (int i = 0; i < textureCount; i++)
-        texturePaths.add(new Text(texturPath));
-}
-
-ModelInfo::ModelInfo(
-    const char* modelPath, std::initializer_list<const char*> texturePaths)
-    : modelPath(modelPath),
-      transparent(0)
-{
-    for (const char* texturPath : texturePaths)
-        this->texturePaths.add(new Text(texturPath));
-}
-
-ModelInfo::ModelInfo(const ModelInfo& right)
-    : modelPath(right.modelPath),
-      transparent(right.transparent)
-{
-    for (int i = 0; i < right.texturePaths.getEintragAnzahl(); i++)
-        texturePaths.add(right.texturePaths.get(i));
-}
-
-ModelInfo& ModelInfo::operator=(const ModelInfo& right)
-{
-    modelPath = right.modelPath;
-    transparent = right.transparent;
-    texturePaths.leeren();
-    for (int i = 0; i < right.texturePaths.getEintragAnzahl(); i++)
-        texturePaths.add(right.texturePaths.get(i));
-    return *this;
-}
+ModelInfo::ModelInfo(const char* modelPath,
+    Framework::RCArray<Framework::Text> texturePaths,
+    bool transparent, float size)
+    : ReferenceCounter(),
+      modelPath(modelPath),
+      texturePaths(texturePaths),
+      transparent(transparent),
+      size(size)
+{}
 
 void ModelInfo::writeTo(Framework::StreamWriter* zWriter) const
 {
@@ -52,10 +26,82 @@ void ModelInfo::writeTo(Framework::StreamWriter* zWriter) const
         zWriter->schreibe(t->getText(), (int)len);
     }
     zWriter->schreibe((char*)&transparent, 1);
+    zWriter->schreibe((char*)&size, 4);
+}
+
+Framework::Text ModelInfo::getModelPath() const
+{
+    return modelPath;
+}
+
+Framework::RCArray<Framework::Text> ModelInfo::getTexturePaths() const
+{
+    return texturePaths;
+}
+
+bool ModelInfo::isTransparent() const
+{
+    return transparent;
+}
+
+float ModelInfo::getSize() const
+{
+    return size;
+}
+
+ModelInfoFactory::ModelInfoFactory()
+    : TypeFactory()
+{}
+
+ModelInfo* ModelInfoFactory::fromJson(Framework::JSON::JSONValue* zJson) const
+{
+    Framework::RCArray<Framework::Text> texturePaths;
+    for (Framework::JSON::JSONValue* v :
+        *zJson->asObject()->zValue("texturePaths")->asArray())
+    {
+        texturePaths.add(new Framework::Text(v->asString()->getString()));
+    }
+    return new ModelInfo(
+        zJson->asObject()->zValue("modelPath")->asString()->getString(),
+        texturePaths,
+        zJson->asObject()->zValue("transparent")->asBool()->getBool(),
+        (float)zJson->asObject()->zValue("size")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONValue* ModelInfoFactory::toJson(ModelInfo* zObject) const
+{
+    Framework::JSON::JSONObject* obj = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* arr = new Framework::JSON::JSONArray();
+    for (Framework::Text* t : zObject->texturePaths)
+    {
+        arr->addValue(new Framework::JSON::JSONString(t->getText()));
+    }
+    obj->addValue("texturePaths", arr);
+    obj->addValue(
+        "modelPath", new Framework::JSON::JSONString(zObject->modelPath));
+    obj->addValue(
+        "transparent", new Framework::JSON::JSONBool(zObject->transparent));
+    obj->addValue(
+        "size", new Framework::JSON::JSONNumber(zObject->size));
+    return obj;
 }
 
-ModelInfo& ModelInfo::setTransparent()
+Framework::JSON::Validator::JSONValidator*
+ModelInfoFactory::getValidator() const
 {
-    transparent = 1;
-    return *this;
+    return Framework::JSON::Validator::JSONValidator::buildForObject()
+        ->withRequiredArray("texturePaths")
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->withRequiredString("modelPath")
+        ->finishString()
+        ->withRequiredBool("transparent")
+        ->withDefault(false)
+        ->finishBool()
+        ->withRequiredNumber("size")
+        ->whichIsGreaterThen(0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->finishObject();
 }

+ 26 - 7
FactoryCraft/ModelInfo.h

@@ -3,20 +3,39 @@
 #include <Array.h>
 #include <Text.h>
 #include <Writer.h>
+#include "TypeRegistry.h"
 
-class ModelInfo
+class ModelInfoFactory;
+
+class ModelInfo : public virtual Framework::ReferenceCounter
 {
 private:
     Framework::Text modelPath;
     Framework::RCArray<Framework::Text> texturePaths;
     bool transparent;
+    float size;
 
 public:
-    ModelInfo(const char* modelPath, const char* texturPath, int textureCount);
-    ModelInfo(
-        const char* modelPath, std::initializer_list<const char*> texturePaths);
-    ModelInfo(const ModelInfo& right);
-    ModelInfo& operator=(const ModelInfo& right);
+    ModelInfo(const char* modelPath,
+        Framework::RCArray<Framework::Text> texturePaths,
+        bool transparent,
+        float size);
     void writeTo(Framework::StreamWriter* zWriter) const;
-    ModelInfo& setTransparent();
+
+    Framework::Text getModelPath() const;
+    Framework::RCArray<Framework::Text> getTexturePaths() const;
+    bool isTransparent() const;
+    float getSize() const;
+
+
+    friend ModelInfoFactory;
+};
+
+class ModelInfoFactory : public TypeFactory<ModelInfo>
+{
+public:
+    ModelInfoFactory();
+    ModelInfo* fromJson(Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(ModelInfo* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator() const override;
 };

+ 1 - 3
FactoryCraft/MultiblockStructure.cpp

@@ -128,9 +128,7 @@ int MultiblockStructure::getStructureTypeId() const
 MultiblockStructureType::MultiblockStructureType(int id)
     : ReferenceCounter(),
       id(id)
-{
-    StaticRegistry<MultiblockStructureType>::INSTANCE.registerT(this, id);
-}
+{}
 
 MultiblockStructureType::~MultiblockStructureType() {}
 

+ 0 - 1
FactoryCraft/MultiblockTree.h

@@ -1,7 +1,6 @@
 #pragma once
 
 #include "MultiblockStructure.h"
-#include "StaticRegistry.h"
 
 class MultiblockTree : public MultiblockStructure
 {

+ 17 - 4
FactoryCraft/NoBlock.cpp

@@ -1,10 +1,23 @@
 #include "NoBlock.h"
 
-NoBlockBlockType::NoBlockBlockType(int id, const Block* defaultB, const char *name)
-    : BlockType(id, 0, ModelInfo("", "", 0), 0, 1, 0, name, false, 0),
+NoBlockBlockType::NoBlockBlockType(const Block* defaultB, Framework::Text name)
+    : BlockType(0,
+        new ModelInfo("", Framework::RCArray<Framework::Text>(), 0, 1.f),
+        0,
+        1,
+        0,
+        name,
+        false,
+        0,
+        Framework::RCArray<Framework::Text>(), 0),
       defaultB(defaultB)
 {}
 
+ItemType* NoBlockBlockType::createItemType() const
+{
+    return 0;
+}
+
 Block* NoBlockBlockType::createBlock(
     Framework::Vec3<int> position, int dimensionId) const
 {
@@ -44,7 +57,7 @@ const Block* NoBlockBlockType::zDefault() const
 }
 
 NoBlock::NoBlock()
-    : Block(BlockTypeEnum::NO_BLOCK, 0, {0, 0, 0}, 0, false)
+    : Block(BlockTypeEnum::NO_BLOCK, {0, 0, 0}, 0, false)
 {
     transparent = 0;
     passable = 0;
@@ -63,7 +76,7 @@ void NoBlock::onPostTick() {}
 const NoBlock NoBlock::INSTANCE;
 
 AirBlock::AirBlock()
-    : Block(BlockTypeEnum::AIR, 0, {0, 0, 0}, 0, false)
+    : Block(BlockTypeEnum::AIR, {0, 0, 0}, 0, false)
 {
     transparent = 1;
     passable = 1;

+ 2 - 1
FactoryCraft/NoBlock.h

@@ -24,7 +24,8 @@ protected:
     virtual const Block* zDefault() const override;
 
 public:
-    NoBlockBlockType(int id, const Block* defaultB, const char* name);
+    NoBlockBlockType(const Block* defaultB, Framework::Text name);
+    virtual ItemType* createItemType() const override;
 };
 
 class NoBlock : public Block

+ 0 - 1
FactoryCraft/OverworldDimensionGenerator.h

@@ -2,7 +2,6 @@
 
 #include "DimensionGenerator.h"
 #include "Noise.h"
-#include "StaticRegistry.h"
 
 class OverworldDimensionGeneratorFactory : public DimensionGeneratorFactory
 {

+ 352 - 0
FactoryCraft/PlaceableProof.cpp

@@ -0,0 +1,352 @@
+#include "PlaceableProof.h"
+
+#include "BlockFilter.h"
+#include "Game.h"
+
+PlaceableProof::PlaceableProof()
+    : ReferenceCounter()
+{}
+
+PlaceableProofAnd::PlaceableProofAnd(Framework::RCArray<PlaceableProof> proofs)
+    : proofs(proofs)
+{}
+
+bool PlaceableProofAnd::isPlacable(
+    const Item* item, Framework::Vec3<float> pos, int dimensionId)
+{
+    for (PlaceableProof* proof : proofs)
+    {
+        if (!proof->isPlacable(item, pos, dimensionId))
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+const Framework::RCArray<PlaceableProof>& PlaceableProofAnd::getProofs() const
+{
+    return proofs;
+}
+
+PlaceableProofAndFactory::PlaceableProofAndFactory()
+    : SubTypeFactory()
+{}
+
+PlaceableProofAnd* PlaceableProofAndFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<PlaceableProof> proofs;
+    for (Framework::JSON::JSONValue* zProof :
+        *zJson->zValue("proofs")->asArray())
+    {
+        proofs.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(zProof));
+    }
+    return new PlaceableProofAnd(proofs);
+}
+
+Framework::JSON::JSONObject* PlaceableProofAndFactory::toJson(
+    PlaceableProofAnd* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* proofs = new Framework::JSON::JSONArray();
+    for (PlaceableProof* proof : zObject->getProofs())
+    {
+        proofs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(proof));
+    }
+    result->addValue("proofs", proofs);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+PlaceableProofAndFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("proofs")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<PlaceableProof>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text PlaceableProofAndFactory::getTypeToken() const
+{
+    return "and";
+}
+
+PlaceableProofOr::PlaceableProofOr(Framework::RCArray<PlaceableProof> proofs)
+    : proofs(proofs)
+{}
+
+bool PlaceableProofOr::isPlacable(
+    const Item* item, Framework::Vec3<float> pos, int dimensionId)
+{
+    for (PlaceableProof* proof : proofs)
+    {
+        if (proof->isPlacable(item, pos, dimensionId))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+const Framework::RCArray<PlaceableProof>& PlaceableProofOr::getProofs() const
+{
+    return proofs;
+}
+
+PlaceableProofOrFactory::PlaceableProofOrFactory()
+    : SubTypeFactory()
+{}
+
+PlaceableProofOr* PlaceableProofOrFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Framework::RCArray<PlaceableProof> proofs;
+    for (Framework::JSON::JSONValue* zProof :
+        *zJson->zValue("proofs")->asArray())
+    {
+        proofs.add(
+            Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(zProof));
+    }
+    return new PlaceableProofOr(proofs);
+}
+
+Framework::JSON::JSONObject* PlaceableProofOrFactory::toJson(
+    PlaceableProofOr* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    Framework::JSON::JSONArray* proofs = new Framework::JSON::JSONArray();
+    for (PlaceableProof* proof : zObject->getProofs())
+    {
+        proofs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(proof));
+    }
+    result->addValue("proofs", proofs);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+PlaceableProofOrFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredArray("proofs")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<PlaceableProof>())
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text PlaceableProofOrFactory::getTypeToken() const
+{
+    return "or";
+}
+
+PlaceableProofNot::PlaceableProofNot(PlaceableProof* proof)
+    : PlaceableProof()
+{}
+
+PlaceableProofNot::~PlaceableProofNot()
+{
+    proof->release();
+}
+
+bool PlaceableProofNot::isPlacable(
+    const Item* item, Framework::Vec3<float> pos, int dimensionId)
+{
+    return !proof->isPlacable(item, pos, dimensionId);
+}
+
+PlaceableProof* PlaceableProofNot::zProof() const
+{
+    return proof;
+}
+
+PlaceableProofNotFactory::PlaceableProofNotFactory()
+    : SubTypeFactory()
+{}
+
+PlaceableProofNot* PlaceableProofNotFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new PlaceableProofNot(
+        Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
+            zJson->zValue("proof")));
+}
+
+Framework::JSON::JSONObject* PlaceableProofNotFactory::toJson(
+    PlaceableProofNot* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "proof", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zProof()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+PlaceableProofNotFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder
+        ->withRequiredAttribute("proof",
+            Game::INSTANCE->zTypeRegistry()->getValidator<PlaceableProof>())
+        ->finishObject();
+}
+
+Framework::Text PlaceableProofNotFactory::getTypeToken() const
+{
+    return "not";
+}
+
+PlaceableProofBlockFilter::PlaceableProofBlockFilter(
+    Direction direction, int distance, BlockFilter* filter)
+    : PlaceableProof(),
+      direction(direction),
+      distance(distance),
+      filter(filter)
+{}
+
+PlaceableProofBlockFilter::~PlaceableProofBlockFilter()
+{
+    filter->release();
+}
+
+bool PlaceableProofBlockFilter::isPlacable(
+    const Item* item, Framework::Vec3<float> pos, int dimensionId)
+{
+    pos += (Framework::Vec3<float>)(::getDirection(direction) * distance);
+    Dimension* dim = Game::INSTANCE->zDimension(dimensionId);
+    return dim && pos.z >= 0 && pos.z < WORLD_HEIGHT
+        && filter->test(dim->zBlockOrDefault(pos));
+}
+
+Direction PlaceableProofBlockFilter::getDirection() const
+{
+    return direction;
+}
+
+int PlaceableProofBlockFilter::getDistance() const
+{
+    return distance;
+}
+
+BlockFilter* PlaceableProofBlockFilter::zFilter() const
+{
+    return filter;
+}
+
+PlaceableProofBlockFilterFactory::PlaceableProofBlockFilterFactory()
+    : SubTypeFactory()
+{}
+
+PlaceableProofBlockFilter* PlaceableProofBlockFilterFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    Direction dir = NO_DIRECTION;
+    if (zJson->zValue("direction")->asString()->getString().istGleich("top"))
+    {
+        dir = TOP;
+    }
+    else if (zJson->zValue("direction")
+                 ->asString()
+                 ->getString()
+                 .istGleich("bottom"))
+    {
+        dir = BOTTOM;
+    }
+    else if (zJson->zValue("direction")
+                 ->asString()
+                 ->getString()
+                 .istGleich("north"))
+    {
+        dir = NORTH;
+    }
+    else if (zJson->zValue("direction")
+                 ->asString()
+                 ->getString()
+                 .istGleich("east"))
+    {
+        dir = EAST;
+    }
+    else if (zJson->zValue("direction")
+                 ->asString()
+                 ->getString()
+                 .istGleich("south"))
+    {
+        dir = SOUTH;
+    }
+    else if (zJson->zValue("direction")
+                 ->asString()
+                 ->getString()
+                 .istGleich("west"))
+    {
+        dir = WEST;
+    }
+    return new PlaceableProofBlockFilter(dir,
+        (int)zJson->zValue("distance")->asNumber()->getNumber(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
+            zJson->zValue("filter")));
+}
+
+Framework::JSON::JSONObject* PlaceableProofBlockFilterFactory::toJson(
+    PlaceableProofBlockFilter* zObject) const
+{
+    Framework::Text dir = "";
+    if (zObject->getDirection() == NORTH)
+    {
+        dir = "north";
+    }
+    else if (zObject->getDirection() == EAST)
+    {
+        dir = "east";
+    }
+    else if (zObject->getDirection() == SOUTH)
+    {
+        dir = "south";
+    }
+    else if (zObject->getDirection() == WEST)
+    {
+        dir = "west";
+    }
+    else if (zObject->getDirection() == TOP)
+    {
+        dir = "top";
+    }
+    else if (zObject->getDirection() == BOTTOM)
+    {
+        dir = "bottom";
+    }
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("direction", new Framework::JSON::JSONString(dir));
+    result->addValue(
+        "distance", new Framework::JSON::JSONNumber(zObject->getDistance()));
+    result->addValue(
+        "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+PlaceableProofBlockFilterFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("direction")
+        ->whichIsOneOf({"top", "bottom", "north", "east", "south", "west"})
+        ->finishString()
+        ->withRequiredNumber("distance")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredAttribute("filter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
+        ->finishObject();
+}
+
+Framework::Text PlaceableProofBlockFilterFactory::getTypeToken() const
+{
+    return "blockFilter";
+}

+ 136 - 0
FactoryCraft/PlaceableProof.h

@@ -0,0 +1,136 @@
+#pragma once
+
+#include <Array.h>
+#include <TypeRegistry.h>
+#include <Vec3.h>
+
+#include "Area.h"
+
+class Item;
+class BlockFilter;
+
+class PlaceableProof : public Framework::ReferenceCounter
+{
+public:
+    PlaceableProof();
+    virtual bool isPlacable(
+        const Item* item, Framework::Vec3<float> pos, int dimensionId)
+        = 0;
+};
+
+class PlaceableProofAnd : public PlaceableProof
+{
+private:
+    Framework::RCArray<PlaceableProof> proofs;
+
+public:
+    PlaceableProofAnd(Framework::RCArray<PlaceableProof> proofs);
+    bool isPlacable(
+        const Item* item, Framework::Vec3<float> pos, int dimensionId) override;
+    const Framework::RCArray<PlaceableProof>& getProofs() const;
+};
+
+class PlaceableProofAndFactory
+    : public SubTypeFactory<PlaceableProof, PlaceableProofAnd>
+{
+public:
+    PlaceableProofAndFactory();
+    PlaceableProofAnd* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        PlaceableProofAnd* 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 PlaceableProofOr : public PlaceableProof
+{
+private:
+    Framework::RCArray<PlaceableProof> proofs;
+
+public:
+    PlaceableProofOr(Framework::RCArray<PlaceableProof> proofs);
+    bool isPlacable(
+        const Item* item, Framework::Vec3<float> pos, int dimensionId) override;
+    const Framework::RCArray<PlaceableProof>& getProofs() const;
+};
+
+class PlaceableProofOrFactory
+    : public SubTypeFactory<PlaceableProof, PlaceableProofOr>
+{
+public:
+    PlaceableProofOrFactory();
+    PlaceableProofOr* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        PlaceableProofOr* 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 PlaceableProofNot : public PlaceableProof
+{
+private:
+    PlaceableProof* proof;
+
+public:
+    PlaceableProofNot(PlaceableProof* proof);
+    ~PlaceableProofNot();
+    bool isPlacable(
+        const Item* item, Framework::Vec3<float> pos, int dimensionId) override;
+    PlaceableProof* zProof() const;
+};
+
+class PlaceableProofNotFactory
+    : public SubTypeFactory<PlaceableProof, PlaceableProofNot>
+{
+public:
+    PlaceableProofNotFactory();
+    PlaceableProofNot* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        PlaceableProofNot* 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 PlaceableProofBlockFilter : public PlaceableProof
+{
+private:
+    Direction direction;
+    int distance;
+    BlockFilter* filter;
+
+public:
+    PlaceableProofBlockFilter(
+        Direction direction, int distance, BlockFilter* filter);
+    ~PlaceableProofBlockFilter();
+    bool isPlacable(
+        const Item* item, Framework::Vec3<float> pos, int dimensionId) override;
+    Direction getDirection() const;
+    int getDistance() const;
+    BlockFilter* zFilter() const;
+};
+
+class PlaceableProofBlockFilterFactory
+    : public SubTypeFactory<PlaceableProof, PlaceableProofBlockFilter>
+{
+public:
+    PlaceableProofBlockFilterFactory();
+    PlaceableProofBlockFilter* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        PlaceableProofBlockFilter* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
+};
+
+// TODO: add item Filter

+ 4 - 2
FactoryCraft/Player.cpp

@@ -1,5 +1,6 @@
 #include "Player.h"
 
+#include "ArrayUtils.h"
 #include "Game.h"
 #include "ItemFilter.h"
 #include "PlayerHand.h"
@@ -404,8 +405,9 @@ void Player::onFall(float collisionSpeed)
 }
 
 PlayerEntityType::PlayerEntityType()
-    : EntityType(EntityTypeEnum::PLAYER,
-        ModelInfo("player", "player.ltdb/player.png", 6))
+    : EntityType(
+        "Player",
+        new ModelInfo("player", toArray("player.ltdb/player.png", 6), 0, 1.f))
 {}
 
 void PlayerEntityType::loadSuperEntity(

+ 3 - 26
FactoryCraft/PlayerHand.cpp

@@ -4,25 +4,9 @@
 #include "Entity.h"
 
 PlayerHandItemType::PlayerHandItemType()
-    : ItemType(ItemTypeEnum::PLAYER_HAND,
-        "PlayerHand",
-        new PlayerHandLevelUpRule(),
-        0,
-        ModelInfo("", "", 0))
+    : ItemType("PlayerHand", 0, 0)
 {}
 
-void PlayerHandItemType::loadSuperItemSkill(
-    ItemSkill* zSkill, Framework::StreamReader* zReader) const
-{
-    // TODO: load skill data
-}
-
-void PlayerHandItemType::saveSuperItemSkill(
-    const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const
-{
-    // TODO: store skill data
-}
-
 Item* PlayerHandItemType::createItem() const
 {
     return 0; // there is no player hand item
@@ -33,17 +17,10 @@ ItemSkill* PlayerHandItemType::createDefaultItemSkill() const
     return new PlayerHandSkill();
 }
 
-PlayerHandLevelUpRule::PlayerHandLevelUpRule()
-    : ItemSkillLevelUpRule()
-{}
-
-void PlayerHandLevelUpRule::applyOn(ItemSkill* zSkill)
-{
-    // TODO: level up the skill
-}
+void PlayerHandItemType::levelUpItemSkill(ItemSkill* zSkill) const {}
 
 PlayerHandSkill::PlayerHandSkill()
-    : ItemSkill(ItemTypeEnum::PLAYER_HAND)
+    : ItemSkill(0.f, 1.f, 1.f)
 {}
 
 bool PlayerHandSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)

+ 1 - 13
FactoryCraft/PlayerHand.h

@@ -5,23 +5,11 @@
 
 class PlayerHandItemType : public ItemType
 {
-protected:
-    void loadSuperItemSkill(
-        ItemSkill* zSkill, Framework::StreamReader* zReader) const override;
-    void saveSuperItemSkill(const ItemSkill* zSkill,
-        Framework::StreamWriter* zWriter) const override;
-
 public:
     PlayerHandItemType();
     Item* createItem() const override;
     ItemSkill* createDefaultItemSkill() const override;
-};
-
-class PlayerHandLevelUpRule : public ItemSkillLevelUpRule
-{
-public:
-    PlayerHandLevelUpRule();
-    void applyOn(ItemSkill* zSkill) override;
+    void levelUpItemSkill(ItemSkill* zSkill) const override;
 };
 
 class PlayerHandSkill : public ItemSkill

+ 4 - 2
FactoryCraft/QuestRequirement.cpp

@@ -59,12 +59,14 @@ void QuestRequirementOpenDialog::addRequirementUIML(QuestStorage* zStorage,
     container->setAttribute(
         "id", Framework::Text("requirement_") += getRequirementId());
     // TODO: add icon of dialog
-    auto text = new Framework::XML::Element("<text width=\"auto\" height=\"auto\"/>");
+    auto text
+        = new Framework::XML::Element("<text width=\"auto\" height=\"auto\"/>");
     text->setAttribute("id",
         Framework::Text("requirement_description_") += getRequirementId());
     text->setText(description);
     container->addChild(text);
-    auto status = new Framework::XML::Element("<text margin-top=\"10\" width=\"auto\" height=\"auto\"/>");
+    auto status = new Framework::XML::Element(
+        "<text margin-top=\"10\" width=\"auto\" height=\"auto\"/>");
     status->setAttribute("align-top", text->getAttributeValue("id"));
     status->setAttribute("align-x", text->getAttributeValue("id"));
     if (zStorage->zStorage(getRequirementId())->isFullfilled())

+ 1 - 1
FactoryCraft/QuestReward.cpp

@@ -166,7 +166,7 @@ void QuestRewardGiveItems::addRewardUIML(Framework::XML::Element* zParent,
 }
 
 QuestRewardGiveItemsType::QuestRewardGiveItemsType()
-    : SubTypeFactory<QuestReward, QuestRewardGiveItems>()
+    : SubTypeFactory()
 {}
 
 QuestRewardGiveItems* QuestRewardGiveItemsType::fromJson(

+ 1 - 1
FactoryCraft/RecipieList.cpp

@@ -1,6 +1,6 @@
 #include "RecipieList.h"
 
-RecipieList::RecipieList(const char* name)
+RecipieList::RecipieList(Framework::Text name)
     : ReferenceCounter(),
       name(name)
 {}

+ 1 - 1
FactoryCraft/RecipieList.h

@@ -11,7 +11,7 @@ private:
     Framework::Text name;
 
 public:
-    RecipieList(const char* name);
+    RecipieList(Framework::Text name);
     void addRecipie(Recipie* recipie);
     Recipie* zFirstRecipie(CraftingStorage* zStorage);
     const Framework::Text& getName() const;

+ 18 - 23
FactoryCraft/RecipieLoader.cpp

@@ -4,6 +4,7 @@
 #include <iostream>
 #include <stdexcept>
 
+#include "Game.h"
 #include "ItemType.h"
 
 using namespace Framework::JSON;
@@ -89,15 +90,13 @@ void RecipieLoader::loadRecipie(JSONObject* zRecipie)
                                          ->asString()
                                          ->getString();
         Item* item = 0;
-        for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
+        for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
         {
-            if (StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                && StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                       ->getName()
-                       .istGleich(outputType))
+            if (Game::INSTANCE->zItemType(i)
+                && Game::INSTANCE->zItemType(i)->getName().istGleich(
+                    outputType))
             {
-                item = StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                           ->createItem();
+                item = Game::INSTANCE->zItemType(i)->createItem();
                 break;
             }
         }
@@ -138,16 +137,13 @@ void RecipieLoader::loadRecipie(JSONObject* zRecipie)
                                              ->asString()
                                              ->getString();
             Item* item = 0;
-            for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount();
-                 i++)
+            for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
             {
-                if (StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                    && StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                           ->getName()
-                           .istGleich(outputType))
+                if (Game::INSTANCE->zItemType(i)
+                    && Game::INSTANCE->zItemType(i)->getName().istGleich(
+                        outputType))
                 {
-                    item = StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                               ->createItem();
+                    item = Game::INSTANCE->zItemType(i)->createItem();
                     break;
                 }
             }
@@ -164,8 +160,8 @@ ItemFilter* RecipieLoader::loadFilter(JSONObject* zFilter)
     {
         Framework::Text type
             = zFilter->zValue("itemType")->asString()->getString();
-        return new TypeItemFilter(StaticRegistry<ItemType>::INSTANCE.zElement(
-            ItemType::getTypeId(type)));
+        return new TypeItemFilter(
+            Game::INSTANCE->zItemType(ItemType::getTypeId(type)));
     }
     else if (zFilter->hasValue("operator"))
     {
@@ -233,7 +229,8 @@ Framework::Text RecipieLoader::getCrafingUIML(const ItemType* zTargetType)
             if (list->getName().istGleich("inventory"))
             {
                 result.append()
-                    << "\" itemIcon=\"" << ItemTypeEnum::CRAFTING_TABLE;
+                    << "\" itemIcon=\""
+                    << Game::INSTANCE->getItemTypeId("Crafting Table");
             }
             result += "\">";
             for (Recipie* recipie : recipies)
@@ -259,14 +256,12 @@ JSONValidator* RecipieLoader::zRecipieValidator()
 {
     if (validator) return validator;
     Framework::RCArray<Framework::Text> itemTypes;
-    for (int i = 0; i < StaticRegistry<ItemType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
     {
-        if (StaticRegistry<ItemType>::INSTANCE.zElement(i))
+        if (Game::INSTANCE->zItemType(i))
         {
             itemTypes.add(new Framework::Text(
-                StaticRegistry<ItemType>::INSTANCE.zElement(i)
-                    ->getName()
-                    .getText()));
+                Game::INSTANCE->zItemType(i)->getName().getText()));
         }
     }
     JSONValidator* typeFilterValidator

+ 0 - 91
FactoryCraft/Shovel.cpp

@@ -1,91 +0,0 @@
-#include "Shovel.h"
-#include "Game.h"
-
-ShovelToolItemType::ShovelToolItemType() // TODO: add broken Shovel
-    : BasicToolItemType(ItemTypeEnum::SHOVEL,
-        "Shovel",
-        new ShovelToolLevelUpRule(),
-        ItemTypeEnum::SHOVEL_BROKEN,
-        ModelInfo("tools.m3/shovel", "tools.ltdb/stonehoe.png", 1)) // use same texture as hoe
-{}
-
-Item* ShovelToolItemType::createItem() const
-{
-    return new BasicToolItem(ItemTypeEnum::SHOVEL, "Shovel");
-}
-
-ItemSkill* ShovelToolItemType::createDefaultItemSkill() const
-{
-    return new ShovelToolSkill();
-}
-
-void ShovelToolItemType::loadSuperItemSkill(
-    ItemSkill* zSkill, Framework::StreamReader* zReader) const
-{
-    ShovelToolSkill* skill = dynamic_cast<ShovelToolSkill*>(zSkill);
-    zReader->lese((char*)&skill->level, 4);
-    zReader->lese((char*)&skill->xp, 4);
-    zReader->lese((char*)&skill->maxXP, 4);
-}
-
-void ShovelToolItemType::saveSuperItemSkill(
-    const ItemSkill* zSkill, Framework::StreamWriter* zWriter) const
-{
-    const ShovelToolSkill* skill = dynamic_cast<const ShovelToolSkill*>(zSkill);
-    zWriter->schreibe((char*)&skill->level, 4);
-    zWriter->schreibe((char*)&skill->xp, 4);
-    zWriter->schreibe((char*)&skill->maxXP, 4);
-}
-
-ShovelToolLevelUpRule::ShovelToolLevelUpRule()
-    : ItemSkillLevelUpRule()
-{}
-
-void ShovelToolLevelUpRule::applyOn(ItemSkill* zSkill)
-{
-    ShovelToolSkill* skill = dynamic_cast<ShovelToolSkill*>(zSkill);
-    if (skill->xp >= skill->maxXP)
-    {
-        skill->level++;
-        skill->xp = 0;
-        skill->maxXP = skill->maxXP * 2;
-    }
-}
-
-ShovelToolSkill::ShovelToolSkill()
-    : ItemSkill(ItemTypeEnum::SHOVEL),
-      level(1),
-      xp(0.f),
-      maxXP(10.f)
-{}
-
-bool ShovelToolSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
-{
-    if (zActor->getStamina() > 0.0001f)
-    {
-        if (zTarget->zBlockType()->getId() == BlockTypeEnum::DIRT
-            || zTarget->zBlockType()->getId() == BlockTypeEnum::GRAVEL
-            || zTarget->zBlockType()->getId() == BlockTypeEnum::SAND)
-        {
-            float damage
-                = (2 + ((float)level / 3.f)) / (zTarget->getHardness() + 1);
-            zTarget->setHP(zTarget->getHP() - damage);
-            xp += damage / 20;
-            zActor->setStamina(zActor->getStamina() - 0.0001f);
-            zUsedItem->setDurability(zUsedItem->getDurability() - damage / 50);
-        }
-        else
-        {
-            zActor->setStamina(zActor->getStamina() - 0.0001f);
-            zUsedItem->setDurability(zUsedItem->getDurability() - 0.001f);
-        }
-        return true;
-    }
-    return false;
-}
-
-bool ShovelToolSkill::use(Entity* zActor, Item* zUsedItem, Entity* zTarget)
-{
-    // an Shovel can not be used on an entity
-    return 0;
-}

+ 0 - 41
FactoryCraft/Shovel.h

@@ -1,41 +0,0 @@
-#pragma once
-#include "BasicTool.h"
-#include "ItemSkill.h"
-#include "ItemType.h"
-
-class ShovelToolItemType : public BasicToolItemType
-{
-protected:
-    void loadSuperItemSkill(
-        ItemSkill* zSkill, Framework::StreamReader* zReader) const override;
-    void saveSuperItemSkill(const ItemSkill* zSkill,
-        Framework::StreamWriter* zWriter) const override;
-
-public:
-    ShovelToolItemType();
-    Item* createItem() const override;
-    ItemSkill* createDefaultItemSkill() const override;
-};
-
-class ShovelToolLevelUpRule : public ItemSkillLevelUpRule
-{
-public:
-    ShovelToolLevelUpRule();
-    void applyOn(ItemSkill* zSkill) override;
-};
-
-class ShovelToolSkill : public ItemSkill
-{
-private:
-    int level;
-    float xp;
-    float maxXP;
-
-public:
-    ShovelToolSkill();
-    bool use(Entity* zActor, Item* zUsedItem, Block* zTarget) override;
-    bool use(Entity* zActor, Item* zUsedItem, Entity* zTarget) override;
-
-    friend ShovelToolItemType;
-    friend ShovelToolLevelUpRule;
-};

+ 12 - 18
FactoryCraft/Start.cpp

@@ -55,7 +55,7 @@ public:
           infoLength(0)
     {}
 
-    #ifdef WIN32
+#ifdef WIN32
     void __CLR_OR_THIS_CALL _Lock() override
     {
         cs.lock();
@@ -65,7 +65,7 @@ public:
     {
         cs.unlock();
     }
-    #endif
+#endif
 
     int sync() override
     {
@@ -142,12 +142,6 @@ int main()
 {
     Framework::initFramework();
 
-    initializeBlockTypes();
-    initializeItemTypes();
-    initializeEntityTypes();
-    initializeDimensions();
-    initializeMultiblockTypes();
-
 #ifndef _WINDOWS
     struct rlimit core_limits;
     core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
@@ -161,16 +155,16 @@ int main()
     DateiPfadErstellen(pfad->getText());
     std::ofstream file;
     std::streambuf* sbuf = std::cout.rdbuf();
-// #ifndef _DEBUG
+    // #ifndef _DEBUG
     file.open(pfad->getText());
     std::ostream newCout(sbuf);
     DuplicatingStreamBuf duplicator(newCout, file);
     std::cout.rdbuf(&duplicator);
-/* #else
-    std::ostream newCout(sbuf);
-    DuplicatingStreamBuf duplicator(newCout);
-    std::cout.rdbuf(&duplicator);
-#endif */
+    /* #else
+        std::ostream newCout(sbuf);
+        DuplicatingStreamBuf duplicator(newCout);
+        std::cout.rdbuf(&duplicator);
+    #endif */
     pfad->release();
 
     std::cout << "Starting...\n";
@@ -182,9 +176,9 @@ int main()
         std::cout << "error: Datei konnte nicht gelesen werden. Das Programm "
                      "wird geschlossen.\n";
         dat->release();
-//#ifndef _DEBUG
+        // #ifndef _DEBUG
         file.close();
-//#endif
+        // #endif
         std::cout.rdbuf(sbuf);
         exit(1);
     }
@@ -251,9 +245,9 @@ int main()
     }
     dat->release();
     std::cout << "The server was shut down successfully.\n" << std::flush;
-//#ifndef _DEBUG
+    // #ifndef _DEBUG
     file.close();
-//#endif
+    // #endif
     std::cout.rdbuf(sbuf);
     Framework::releaseFramework();
     return 0;

+ 0 - 699
FactoryCraft/StaticInitializerOrder.cpp

@@ -1,699 +0,0 @@
-#include "BlockType.h"
-#include "ItemType.h"
-#include "StaticRegistry.h"
-// block types
-#include "BasicBlocks.h"
-#include "Chest.h"
-#include "Grass.h"
-#include "GrowingPlant.h"
-#include "NoBlock.h"
-#include "TreeSeblingBlock.h"
-// fluid blocks
-#include "FluidBlock.h"
-// dimensions
-#include "OverworldDimension.h"
-// entities
-#include "ItemEntity.h"
-#include "Player.h"
-// item skills
-#include "Axe.h"
-#include "BasicItems.h"
-#include "FluidContainer.h"
-#include "Hoe.h"
-#include "PlayerHand.h"
-#include "Shovel.h"
-// world updates
-#include "AddEntityUpdate.h"
-#include "EntityRemovedUpdate.h"
-// Multiblocks
-#include "Game.h"
-#include "LightSources.h"
-#include "MultiblockTree.h"
-
-using namespace Framework;
-
-void initializeBlockTypes()
-{
-    new NoBlockBlockType(BlockTypeEnum::NO_BLOCK, &NoBlock::INSTANCE, "");
-    new NoBlockBlockType(BlockTypeEnum::AIR, &AirBlock::INSTANCE, "Air");
-
-    (new BasicBlockType(BlockTypeEnum::DIRT,
-         ItemTypeEnum::DIRT,
-         ModelInfo("cube",
-             {"blocks.ltdb/dirt.png",
-                 "blocks.ltdb/dirt.png",
-                 "blocks.ltdb/dirt.png",
-                 "blocks.ltdb/dirt.png",
-                 "blocks.ltdb/lawn.png",
-                 "blocks.ltdb/dirt.png"}),
-         "Dirt",
-         0xFF3C7C29))
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::STONE,
-         ItemTypeEnum::STONE,
-         ModelInfo("cube", "blocks.ltdb/stone.png", 6),
-         "Stone",
-         0xFF8E8E8D))
-        ->setHardness(2.f)
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::SAND,
-         ItemTypeEnum::SAND,
-         ModelInfo("cube", "blocks.ltdb/sand.png", 6),
-         "Sand",
-         0xFFAE8558))
-        ->setHardness(0.5f)
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::WOOD_OAK,
-         ItemTypeEnum::WOOD_OAK,
-         ModelInfo("cube", "blocks.ltdb/oak.png", 6),
-         "Oak Wood",
-         0xFF7F7A70))
-        ->setHardness(1.5f)
-        ->initializeDefault();
-    (new BasicBlockType(
-         BlockTypeEnum::LEAVES_WOOD_OAK,
-         ItemTypeEnum::LEAVES_WOOD_OAK,
-         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
-         [](Vec3<int> pos, int dimensionId) {
-             AdditionalItemSpawningBlock* block
-                 = new AdditionalItemSpawningBlock(
-                     BlockTypeEnum::LEAVES_WOOD_OAK, 0, pos, dimensionId);
-             block->addSpawn({1, 1, 0.015, ItemTypeEnum::SEBLING_WOOD_OAK});
-             return (Block*)block;
-         },
-         "Oak Wood Leaves",
-         0xFF6A7C37))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-
-    (new BasicBlockType(BlockTypeEnum::GRAVEL,
-         ItemTypeEnum::GRAVEL,
-         ModelInfo("cube", "blocks.ltdb/gravel.png", 6),
-         "Gravel",
-         0xFF928D8C))
-        ->setHardness(0.75f)
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::STONE_GRANITE,
-         ItemTypeEnum::STONE_GRANITE,
-         ModelInfo("cube", "blocks.ltdb/granite.png", 6),
-         "Granite Stone",
-         0xFF3B3A3E))
-        ->setHardness(3.f)
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::STONE_COBBLE,
-         ItemTypeEnum::STONE_COBBLE,
-         ModelInfo("cube", "blocks.ltdb/cobble.png", 6),
-         "Cobble Stone",
-         0xFF7E7875))
-        ->setHardness(1.f)
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::WOOD_BIRCH,
-         ItemTypeEnum::WOOD_BIRCH,
-         ModelInfo("cube", "blocks.ltdb/birch.png", 6),
-         "Birch Wood",
-         0xFF99999D))
-        ->setHardness(1.5f)
-        ->initializeDefault();
-    (new BasicBlockType(
-         BlockTypeEnum::LEAVES_WOOD_BIRCH,
-         ItemTypeEnum::LEAVES_WOOD_BIRCH,
-         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
-         [](Vec3<int> pos, int dimensionId) {
-             AdditionalItemSpawningBlock* block
-                 = new AdditionalItemSpawningBlock(
-                     BlockTypeEnum::LEAVES_WOOD_BIRCH, 0, pos, dimensionId);
-             block->addSpawn({1, 1, 0.03, ItemTypeEnum::SEBLING_WOOD_BIRCH});
-             return (Block*)block;
-         },
-         "Birch Wood Leaves",
-         0xFF6A7C37))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-
-    (new BasicBlockType(BlockTypeEnum::WOOD_BEECH,
-         ItemTypeEnum::WOOD_BEECH,
-         ModelInfo("cube", "blocks.ltdb/beech.png", 6),
-         "Beech Wood",
-         0xFF778172))
-        ->setHardness(1.5f)
-        ->initializeDefault();
-    (new BasicBlockType(
-         BlockTypeEnum::LEAVES_WOOD_BEECH,
-         ItemTypeEnum::LEAVES_WOOD_BEECH,
-         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
-         [](Vec3<int> pos, int dimensionId) {
-             AdditionalItemSpawningBlock* block
-                 = new AdditionalItemSpawningBlock(
-                     BlockTypeEnum::LEAVES_WOOD_BEECH, 0, pos, dimensionId);
-             block->addSpawn({1, 1, 0.02, ItemTypeEnum::SEBLING_WOOD_BEECH});
-             return (Block*)block;
-         },
-         "Beech Wood Leaves",
-         0xFF6A7C37))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-
-    (new BasicBlockType(BlockTypeEnum::STONE_BASALT,
-         ItemTypeEnum::STONE_BASALT,
-         ModelInfo("cube", "blocks.ltdb/basalt.png", 6),
-         "Basalt Stone",
-         0xFF595552))
-        ->setHardness(2.f)
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::WOOD_PINE,
-         ItemTypeEnum::WOOD_PINE,
-         ModelInfo("cube", "blocks.ltdb/pine.png", 6),
-         "Pine Wood",
-         0xFF786C72))
-        ->setHardness(1.4f)
-        ->initializeDefault();
-    (new BasicBlockType(
-         BlockTypeEnum::LEAVES_WOOD_PINE,
-         ItemTypeEnum::LEAVES_WOOD_PINE,
-         ModelInfo("cube", "blocks.ltdb/leaves.png", 6),
-         [](Vec3<int> pos, int dimensionId) {
-             AdditionalItemSpawningBlock* block
-                 = new AdditionalItemSpawningBlock(
-                     BlockTypeEnum::LEAVES_WOOD_PINE, 0, pos, dimensionId);
-             block->addSpawn({1, 1, 0.025, ItemTypeEnum::SEBLING_WOOD_PINE});
-             return (Block*)block;
-         },
-         "Pine Wood Leaves",
-         0xFF6A7C37))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-
-    (new BasicLightSourceBlockType(BlockTypeEnum::TORCH,
-         ItemTypeEnum::TORCH,
-         ModelInfo("blocks.m3/torch", "blocks.ltdb/torch.png", 6),
-         "Torch"))
-        ->setHardness(0.f)
-        ->setColor(0x00F69A54)
-        ->initializeDefault();
-
-    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_OAK,
-         ItemTypeEnum::SEBLING_WOOD_OAK,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::WOOD_OAK,
-         BlockTypeEnum::LEAVES_WOOD_OAK,
-         "Oak Wood Sebling",
-         0xFD6A7B3A))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_BIRCH,
-         ItemTypeEnum::SEBLING_WOOD_BIRCH,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::WOOD_BIRCH,
-         BlockTypeEnum::LEAVES_WOOD_BIRCH,
-         "Birch Wood Sebling",
-         0xFD6A7B3A))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_BEECH,
-         ItemTypeEnum::SEBLING_WOOD_BEECH,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::WOOD_BEECH,
-         BlockTypeEnum::LEAVES_WOOD_BEECH,
-         "Beech Wood Sebling",
-         0xFD6A7B3A))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-    (new TreeSeblingBlockType(BlockTypeEnum::SEBLING_WOOD_PINE,
-         ItemTypeEnum::SEBLING_WOOD_PINE,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::WOOD_PINE,
-         BlockTypeEnum::LEAVES_WOOD_PINE,
-         "Pine Wood Sebling",
-         0xFD6A7B3A))
-        ->setHardness(0.1f)
-        ->initializeDefault();
-    (new GrassBlockType(BlockTypeEnum::GRASS,
-         ItemTypeEnum::GRASS,
-         ModelInfo("grass", "blocks.ltdb/grass.png", 1),
-         "Grass",
-         0x5076C011))
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::FARMLAND,
-         ItemTypeEnum::DIRT,
-         ModelInfo("cube",
-             {"blocks.ltdb/dirt.png",
-                 "blocks.ltdb/dirt.png",
-                 "blocks.ltdb/dirt.png",
-                 "blocks.ltdb/dirt.png",
-                 "blocks.ltdb/farmland.png",
-                 "blocks.ltdb/dirt.png"}),
-         "Farmland",
-         0xFF5E3819))
-        ->setTransparent(1)
-        ->setHardness(0.1f)
-        ->initializeDefault();
-    (new GrowingPlantBlockType(BlockTypeEnum::WHEAT_SEED,
-         ModelInfo("grass", "plants.ltdb/wheatseeds.png", 1).setTransparent(),
-         "WheatSeeds",
-         BlockTypeEnum::WHEAT,
-         "Growing wheat",
-         18000,
-         0x5076C011))
-        ->addGrowthState(0.2f,
-            ModelInfo("grass", "plants.ltdb/wheatseedsa.png", 1)
-                .setTransparent())
-        ->addGrowthState(0.4f,
-            ModelInfo("grass", "plants.ltdb/wheatseedsb.png", 1)
-                .setTransparent())
-        ->addGrowthState(0.6f,
-            ModelInfo("grass", "plants.ltdb/wheatseedsc.png", 1)
-                .setTransparent())
-        ->addGrowthState(0.8f,
-            ModelInfo("grass", "plants.ltdb/wheatseedsd.png", 1)
-                .setTransparent())
-        ->initializeDefault();
-    (new BasicBlockType(
-         BlockTypeEnum::WHEAT,
-         ItemTypeEnum::WHEAT,
-         ModelInfo("grass", "plants.ltdb/wheat.png", 1),
-         [](Vec3<int> pos, int dimensionId) {
-             AdditionalItemSpawningBlock* block
-                 = new AdditionalItemSpawningBlock(
-                     BlockTypeEnum::WHEAT, 0, pos, dimensionId);
-             block->addSpawn({0, 4, 1.0, ItemTypeEnum::WHEAT});
-             return (Block*)block;
-         },
-         "Wheat",
-         0x90A8C011))
-        ->initializeDefault();
-    (new FluidBlockType(BlockTypeEnum::WATER,
-         ModelInfo("fluid", "fluids.ltdb/water.png", 6),
-         "Water",
-         0xFF2323BF,
-         Vec3<float>(0.8f, 0.8f, 0.95f),
-         20,
-         8))
-        ->setFoodEffect([](FluidContainerItem* zItem, Entity* zUser) {
-            int drinkable = (int)(zUser->getMaxThirst() - zUser->getThirst());
-            if (zItem->getAmount() < drinkable) drinkable = zItem->getAmount();
-            if (!drinkable) return false;
-            zItem->setAmount(zItem->getAmount() - drinkable);
-            zUser->setThirst(zUser->getThirst() + drinkable);
-            return true;
-        })
-        ->initializeDefault();
-    (new BasicBlockType(BlockTypeEnum::CRAFTING_TABLE,
-         ItemTypeEnum::CRAFTING_TABLE,
-         ModelInfo("cube",
-             {"blocks.ltdb/woodplanks.png",
-                 "blocks.ltdb/woodplanks.png",
-                 "blocks.ltdb/woodplanks.png",
-                 "blocks.ltdb/woodplanks.png",
-                 "blocks.ltdb/craftingtable.p",
-                 "blocks.ltdb/woodplanks.png"}),
-         "Crafting Table",
-         0xFFC4A783))
-        ->initializeDefault(); // TODO: implement crafting table block type
-    (new BasicBlockType(
-         BlockTypeEnum::CHEST,
-         ItemTypeEnum::CHEST,
-         ModelInfo("blocks.m3/chest",
-             {"blocks.ltdb/chest.png", "blocks.ltdb/chestcover.png"}),
-         [](Framework::Vec3<int> pos, int dimensionId) {
-             return new Chest(BlockTypeEnum::CHEST, 0, pos, dimensionId);
-         },
-         "Chest",
-         0xFFE2C292,
-         1))
-        ->initializeDefault();
-}
-
-void initializeItemTypes()
-{
-    (new BasicBlockItemType(ItemTypeEnum::DIRT,
-        "Dirt",
-        0,
-        0,
-        ModelInfo("itemCube", "blocks.ltdb/dirt.png", 6),
-        BlockTypeEnum::DIRT));
-    (new BasicBlockItemType(ItemTypeEnum::STONE,
-         "Stone",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/stone.png", 6),
-         BlockTypeEnum::STONE))
-        ->setHardness(2.f);
-    (new BasicBlockItemType(ItemTypeEnum::SAND,
-         "Sand",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/sand.png", 6),
-         BlockTypeEnum::SAND))
-        ->setHardness(0.5f);
-    (new BasicBlockItemType(ItemTypeEnum::WOOD_OAK,
-         "Oak",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/oak.png", 6),
-         BlockTypeEnum::WOOD_OAK))
-        ->setHardness(1.5f);
-    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_OAK,
-         "Oak Leaves",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
-         BlockTypeEnum::LEAVES_WOOD_OAK))
-        ->setHardness(0.1f);
-    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_OAK,
-         "Oak Sebling",
-         0,
-         0,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::SEBLING_WOOD_OAK))
-        ->setHardness(0.1f);
-    (new BasicBlockItemType(ItemTypeEnum::GRAVEL,
-         "Gravel",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/gravel.png", 6),
-         BlockTypeEnum::GRAVEL))
-        ->setHardness(0.75f);
-    (new BasicBlockItemType(ItemTypeEnum::STONE_GRANITE,
-         "Granite",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/granite.png", 6),
-         BlockTypeEnum::STONE_GRANITE))
-        ->setHardness(3.f);
-    (new BasicBlockItemType(ItemTypeEnum::STONE_COBBLE,
-         "Cobble",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/cobble.png", 6),
-         BlockTypeEnum::STONE_COBBLE))
-        ->setHardness(1.f);
-    (new BasicBlockItemType(ItemTypeEnum::WOOD_BIRCH,
-         "Birch",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/birch.png", 6),
-         BlockTypeEnum::WOOD_BIRCH))
-        ->setHardness(1.5f);
-    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_BIRCH,
-         "Birch Leaves",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
-         BlockTypeEnum::LEAVES_WOOD_BIRCH))
-        ->setHardness(0.1f);
-    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_BIRCH,
-         "Birch Sebling",
-         0,
-         0,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::SEBLING_WOOD_BIRCH))
-        ->setHardness(0.1f);
-    (new BasicBlockItemType(ItemTypeEnum::WOOD_BEECH,
-         "Beech",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/beech.png", 6),
-         BlockTypeEnum::WOOD_BEECH))
-        ->setHardness(1.5f);
-    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_BEECH,
-         "Beech Leaves",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
-         BlockTypeEnum::LEAVES_WOOD_BEECH))
-        ->setHardness(0.1f);
-    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_BEECH,
-         "Beech Sebling",
-         0,
-         0,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::SEBLING_WOOD_BEECH))
-        ->setHardness(0.1f);
-    (new BasicBlockItemType(ItemTypeEnum::STONE_BASALT,
-         "Basalt",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/basalt.png", 6),
-         BlockTypeEnum::STONE_BASALT))
-        ->setHardness(2.f);
-    (new BasicBlockItemType(ItemTypeEnum::WOOD_PINE,
-         "Pine",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/pine.png", 6),
-         BlockTypeEnum::WOOD_PINE))
-        ->setHardness(1.4f);
-    (new BasicBlockItemType(ItemTypeEnum::LEAVES_WOOD_PINE,
-         "Pine Leaves",
-         0,
-         0,
-         ModelInfo("itemCube", "blocks.ltdb/leaves.png", 6),
-         BlockTypeEnum::LEAVES_WOOD_PINE))
-        ->setHardness(0.1f);
-    (new BasicBlockItemType(ItemTypeEnum::SEBLING_WOOD_PINE,
-         "Pine Sebling",
-         0,
-         0,
-         ModelInfo("blocks.m3/sebling", "blocks.ltdb/sebling.png", 1),
-         BlockTypeEnum::SEBLING_WOOD_PINE))
-        ->setHardness(0.1f);
-
-    (new LightSourceItemType(ItemTypeEnum::TORCH,
-         "Torch",
-         ModelInfo("items.m3/stick", "blocks.ltdb/torch.png", 6),
-         BlockTypeEnum::TORCH))
-        ->setColor(0x00F69A54);
-
-    new PlayerHandItemType();
-
-    (new NoBlockItemType(ItemTypeEnum::WOOD_STICK,
-        "WoodenStick",
-        0,
-        0,
-        ModelInfo("items.m3/stick", "items.ltdb/stick.png", 1),
-        []() {
-            return ItemType::createBasicItem(ItemTypeEnum::WOOD_STICK,
-                "Wooden Stick",
-                1.f,
-                1.f,
-                10.f,
-                10.f,
-                0,
-                0,
-                0,
-                1,
-                0,
-                50);
-        }));
-    (new NoBlockItemType(ItemTypeEnum::RESIN,
-        "Resin",
-        0,
-        0,
-        ModelInfo("itemCube", "items.ltdb/resin.png", 6),
-        []() {
-            return ItemType::createBasicItem(ItemTypeEnum::RESIN,
-                "Resin",
-                1.f,
-                1.f,
-                10.f,
-                10.f,
-                0,
-                0,
-                0,
-                1,
-                0,
-                50);
-        }));
-    new AxeToolItemType();
-    (new NoBlockItemType(ItemTypeEnum::AXE_BROKEN,
-        "Broken Axe",
-        0,
-        0,
-        ModelInfo("tools.m3/axe", "tools.ltdb/stoneaxe.png", 6),
-        []() {
-            return ItemType::createBasicItem(ItemTypeEnum::AXE_BROKEN,
-                "Broken Axe",
-                100.f,
-                100.f,
-                100.f,
-                100.f,
-                0,
-                0,
-                0,
-                1,
-                0,
-                10);
-        }));
-    new HoeToolItemType();
-    new NoBlockItemType(ItemTypeEnum::BROKEN_HOE,
-        "BrokenHoe",
-        0,
-        0,
-        ModelInfo("tools.m3/hoe", "tools.ltdb/stonehoe.png", 1),
-        []() {
-            return ItemType::createBasicItem(ItemTypeEnum::BROKEN_HOE,
-                "Broken Hoe",
-                100.f,
-                100.f,
-                100.f,
-                100.f,
-                0,
-                0,
-                0,
-                1,
-                0,
-                10);
-        });
-
-    (new NoBlockItemType(ItemTypeEnum::FLINT,
-        "Flint",
-        0,
-        0,
-        ModelInfo("items.m3/flint", "items.ltdb/flint.png", 1),
-        []() {
-            return ItemType::createBasicItem(ItemTypeEnum::FLINT,
-                "Flint",
-                1.f,
-                1.f,
-                10.f,
-                10.f,
-                0,
-                0,
-                0,
-                1,
-                0,
-                50);
-        }));
-
-    (new BasicBlockItemType(ItemTypeEnum::WHEAT_SEED,
-         "Wheat Seeds",
-         0,
-         0,
-         ModelInfo("grass", "plants.ltdb/wheatseeds.png", 1),
-         BlockTypeEnum::WHEAT_SEED))
-        ->setHardness(0.1f)
-        ->setPlacableProof(
-            [](const Item* self,
-                int dimensionId,
-                Framework::Vec3<int> worldPos) {
-                if (worldPos.z > 0)
-                {
-                    auto below = Game::INSTANCE->zBlockAt(
-                        worldPos + getDirection(Direction::BOTTOM),
-                        dimensionId);
-                    return (below.isA()
-                               && below.getA()->zBlockType()->getId()
-                                      == BlockTypeEnum::FARMLAND)
-                        || (below.isB()
-                            && below.getB() == BlockTypeEnum::FARMLAND);
-                }
-                return (bool)0;
-            },
-            1);
-    (new NoBlockItemType(ItemTypeEnum::WHEAT,
-        "Wheat",
-        0,
-        0,
-        ModelInfo("grass", "plants.ltdb/wheat.png", 1),
-        []() {
-            Item* item = ItemType::createBasicItem(ItemTypeEnum::WHEAT,
-                "Wheat",
-                1.f,
-                1.f,
-                10.f,
-                10.f,
-                1,
-                0,
-                0,
-                1,
-                0,
-                50);
-            item->setFoodEffect(
-                [](Item* zItem, Entity* zEntity) {
-                    float added = zItem->getHp() / 2.f;
-                    if (zEntity->getHunger() + added > zEntity->getMaxHunger())
-                    {
-                        added = zEntity->getMaxHunger() - zEntity->getHunger();
-                    }
-                    zEntity->setHunger(zEntity->getHunger() + added);
-                    zEntity->setThirst(
-                        zEntity->getThirst()
-                        + added * 2); // TODO: remove thirst addition
-                                      // when drinkable water exists
-                    zItem->setHp(zItem->getHp() - added * 2.f);
-                    return added != 0.f;
-                },
-                [](const Item* zItem, Entity* zEntity) {
-                    float addable = zItem->getHp() / 2.f;
-                    if (zEntity->getHunger() + addable
-                        > zEntity->getMaxHunger())
-                    {
-                        return 0;
-                    }
-                    return 1;
-                });
-            return item;
-        }));
-
-    (new BasicBlockItemType(ItemTypeEnum::CRAFTING_TABLE,
-        "Crafting Table",
-        0,
-        0,
-        ModelInfo("itemCube",
-            {"blocks.ltdb/woodplanks.png",
-                "blocks.ltdb/woodplanks.png",
-                "blocks.ltdb/woodplanks.png",
-                "blocks.ltdb/woodplanks.png",
-                "blocks.ltdb/craftingtable.p",
-                "blocks.ltdb/woodplanks.png"}),
-        BlockTypeEnum::CRAFTING_TABLE)); // TODO: implement crafting table item
-                                         // type
-
-    (new BasicBlockItemType(ItemTypeEnum::CHEST,
-        "Chest",
-        0,
-        0,
-        ModelInfo("blocks.m3/chest",
-            {"blocks.ltdb/chest.png", "blocks.ltdb/chestcover.png"}),
-        BlockTypeEnum::CHEST));
-
-    new ShovelToolItemType();
-    (new NoBlockItemType(ItemTypeEnum::SHOVEL_BROKEN,
-        "Broken Shovel",
-        0,
-        0,
-        ModelInfo("tools.m3/shovel", "tools.ltdb/stonehoe.png", 6),
-        []() {
-            return ItemType::createBasicItem(ItemTypeEnum::SHOVEL_BROKEN,
-                "Broken Shovel",
-                100.f,
-                100.f,
-                100.f,
-                100.f,
-                0,
-                0,
-                0,
-                1,
-                0,
-                10);
-        }));
-    new FluidContainerItemType(ItemTypeEnum::WOODEN_BUCKET,
-        "Wooden Bucket",
-        ModelInfo("items.m3/bucket", "blocks.ltdb/woodplanks.png", 1));
-}
-
-void initializeEntityTypes()
-{
-    new PlayerEntityType();
-    new ItemEntityType();
-}
-
-void initializeDimensions()
-{
-    // new OverworldDimension();
-}
-
-void initializeMultiblockTypes()
-{
-    new MultiblockTreeStructureType();
-}

+ 0 - 76
FactoryCraft/StaticRegistry.h

@@ -1,76 +0,0 @@
-#pragma once
-
-#include <iostream>
-
-template<typename T> class StaticRegistry
-{
-public:
-    static StaticRegistry<T> INSTANCE;
-
-private:
-    T** registry;
-    int count;
-
-    StaticRegistry()
-    {
-        count = 0;
-        registry = new T*[count];
-        memset(registry, 0, sizeof(T*) * count);
-    }
-
-    ~StaticRegistry()
-    {
-        for (int index = 0; index < count; index++)
-        {
-            if (registry[index])
-            {
-                registry[index]->release();
-                registry[index] = 0;
-            }
-        }
-        delete[] registry;
-    }
-
-public:
-    void registerT(T* type, int id)
-    {
-        if (id >= count)
-        {
-            T** temp = new T*[id + 1];
-            memcpy(temp, registry, sizeof(T*) * count);
-            memset(temp + count, 0, sizeof(T*) * (id + 1 - count));
-            delete[] registry;
-            registry = temp;
-            count = id + 1;
-        }
-        registry[id] = type;
-    }
-
-    const T* zElement(int id)
-    {
-        if (id < 0 || id >= count) return 0;
-        return registry[id];
-    }
-
-    int getCount() const
-    {
-        return count;
-    }
-
-    bool info(int id)
-    {
-        std::cout << typeid(*registry[id]).name() << " was registered as "
-                  << typeid(T).name() << " with id " << id << std::endl;
-        return 1;
-    }
-
-    friend T;
-};
-
-template<typename T> StaticRegistry<T> StaticRegistry<T>::INSTANCE;
-
-void initializeBlockTypes();
-void initializeItemTypes();
-void initializeEntityTypes();
-void initializeDimensions();
-void initializeMultiblockTypes();

+ 150 - 29
FactoryCraft/TreeSeblingBlock.cpp

@@ -7,12 +7,11 @@
 #include "TreeTemplate.h"
 
 TreeSeblingBlock::TreeSeblingBlock(int typeId,
-    const ItemType* zTool,
     Framework::Vec3<int> pos,
     int dimensionId,
     const BlockType* wood,
     const BlockType* leaves)
-    : Block(typeId, zTool, pos, dimensionId, 0),
+    : Block(typeId, pos, dimensionId, 0),
       seblingTicks(0),
       seblingTicksMax(10000),
       wood(wood),
@@ -60,30 +59,75 @@ void TreeSeblingBlock::onPostTick()
 Framework::Text TreeSeblingBlock::getTargetUIML()
 {
     return Text("<targetInfo><text width=\"auto\" height=\"auto\">")
-         + StaticRegistry<BlockType>::INSTANCE.zElement(typeId)->getName()
-         + "\n" + "Growth: " + Text((int)(seblingTicks / (float)seblingTicksMax * 100.f))
+         + Game::INSTANCE->zBlockType(typeId)->getName() + "\n" + "Growth: "
+         + Text((int)(seblingTicks / (float)seblingTicksMax * 100.f))
          + "%</text></targetInfo>";
 }
 
-TreeSeblingBlockType::TreeSeblingBlockType(int typeId,
-    int itemTypeId,
-    ModelInfo model,
-    int woodType,
-    int leavesType,
-    const char* name,
-    int mapColor)
-    : BlockType(typeId, 0, model, 1, 10, 0, name, false, mapColor),
-      itemType(itemTypeId),
+TreeSeblingBlockType::TreeSeblingBlockType(Framework::Text itemTypeName,
+    ModelInfo* model,
+    Framework::Text woodTypeName,
+    Framework::Text leavesTypeName,
+    Framework::Text name,
+    int mapColor,
+    float hardness,
+    Framework::RCArray<Framework::Text> groupNames)
+    : BlockType(
+        0, model, true, 10, false, name, false, mapColor, groupNames, hardness),
+      itemTypeName(itemTypeName),
       transparent(true),
       passable(true),
-      hardness(0.1f),
-      zTool(0),
       speedModifier(0.5f),
       interactable(1),
-      woodType(woodType),
-      leavesType(leavesType)
+      woodTypeName(woodTypeName),
+      leavesTypeName(leavesTypeName)
 {}
 
+bool TreeSeblingBlockType::initialize(Game* zGame)
+{
+    if (itemTypeName.getLength())
+    {
+        itemTypeId = zGame->getItemTypeId(itemTypeName);
+    }
+    else
+    {
+        itemTypeId = 0;
+    }
+    woodTypeId = zGame->getBlockTypeId(woodTypeName);
+    leavesTypeId = zGame->getBlockTypeId(leavesTypeName);
+    return itemTypeId >= 0 && BlockType::initialize(zGame);
+}
+
+Framework::Text TreeSeblingBlockType::getItemTypeName() const
+{
+    return itemTypeName;
+}
+
+Framework::Text TreeSeblingBlockType::getWoodTypeName() const
+{
+    return woodTypeName;
+}
+
+Framework::Text TreeSeblingBlockType::getLeavesTypeName() const
+{
+    return leavesTypeName;
+}
+
+ItemType* TreeSeblingBlockType::createItemType() const
+{
+    return new BasicBlockItemType(getItemTypeName(),
+        new ModelInfo(zModel()->getModelPath(),
+            zModel()->getTexturePaths(),
+            zModel()->isTransparent(),
+            zModel()->getSize() / 2.f),
+        transparent,
+        passable,
+        getHardness(),
+        speedModifier,
+        getName(),
+        0, 50);
+}
+
 void TreeSeblingBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
 {
     TreeSeblingBlock* block = dynamic_cast<TreeSeblingBlock*>(zBlock);
@@ -91,8 +135,7 @@ void TreeSeblingBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
     block->passable = passable;
     block->hp = (float)getInitialMaxHP();
     block->maxHP = (float)getInitialMaxHP();
-    block->hardness = hardness;
-    block->zTool = zTool;
+    block->hardness = getHardness();
     block->speedModifier = speedModifier;
     block->interactable = interactable;
     BlockType::createSuperBlock(zBlock, zItem);
@@ -106,9 +149,9 @@ void TreeSeblingBlockType::loadSuperBlock(
     zReader->lese((char*)&block->seblingTicksMax, 4);
     int id;
     zReader->lese((char*)&id, 4);
-    block->wood = StaticRegistry<BlockType>::INSTANCE.zElement(id);
+    block->wood = Game::INSTANCE->zBlockType(id);
     zReader->lese((char*)&id, 4);
-    block->leaves = StaticRegistry<BlockType>::INSTANCE.zElement(id);
+    block->leaves = Game::INSTANCE->zBlockType(id);
     BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
 }
 
@@ -127,22 +170,100 @@ void TreeSeblingBlockType::saveSuperBlock(
 
 Item* TreeSeblingBlockType::createItem() const
 {
-    return StaticRegistry<ItemType>::INSTANCE.zElement(itemType)->createItem();
+    return Game::INSTANCE->zItemType(itemTypeId)->createItem();
 }
 
 Block* TreeSeblingBlockType::createBlock(
     Framework::Vec3<int> position, int dimensionId) const
 {
     return new TreeSeblingBlock(getId(),
-        zTool,
         position,
         dimensionId,
-        StaticRegistry<BlockType>::INSTANCE.zElement(woodType),
-        StaticRegistry<BlockType>::INSTANCE.zElement(leavesType));
+        Game::INSTANCE->zBlockType(woodTypeId),
+        Game::INSTANCE->zBlockType(leavesTypeId));
 }
 
-TreeSeblingBlockType* TreeSeblingBlockType::setHardness(float hardness)
+TreeSeblingBlockTypeFactory::TreeSeblingBlockTypeFactory()
+    : SubTypeFactory()
+{}
+
+TreeSeblingBlockType* TreeSeblingBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    this->hardness = hardness;
-    return this;
-}
+    Framework::RCArray<Framework::Text> groupNames;
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("groupNames")->asArray())
+    {
+        groupNames.add(new Framework::Text(value->asString()->getString()));
+    }
+    return new TreeSeblingBlockType(
+        zJson->zValue("itemType")->asString()->getString(),
+        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")),
+        zJson->zValue("woodType")->asString()->getString(),
+        zJson->zValue("leavesType")->asString()->getString(),
+        zJson->zValue("name")->asString()->getString(),
+        (int)zJson->zValue("mapColor")->asString()->getString(),
+        (float)zJson->zValue("hardness")->asNumber()->getNumber(),
+        groupNames);
+}
+
+Framework::JSON::JSONObject* TreeSeblingBlockTypeFactory::toJson(
+    TreeSeblingBlockType* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
+        new Framework::JSON::JSONString(zObject->getItemTypeName()));
+    result->addValue(
+        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
+    result->addValue(
+        "name", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
+    result->addValue(
+        "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
+    result->addValue("woodType",
+        new Framework::JSON::JSONString(zObject->getWoodTypeName()));
+    result->addValue("leavesType",
+        new Framework::JSON::JSONString(zObject->getLeavesTypeName()));
+    Framework::JSON::JSONArray* groupNames = new Framework::JSON::JSONArray();
+    for (Framework::Text* groupName : zObject->getGroupNames())
+    {
+        groupNames->addValue(new Framework::JSON::JSONString(*groupName));
+    }
+    result->addValue("groupNames", groupNames);
+    return result;
+}
+
+Framework::JSON::Validator::JSONValidator*
+TreeSeblingBlockTypeFactory::getValidator(
+    Framework::JSON::Validator::ObjectValidationBuilder<
+        Framework::JSON::Validator::JSONValidator>* builder) const
+{
+    return builder->withRequiredString("itemType")
+        ->finishString()
+        ->withRequiredAttribute(
+            "model", Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+        ->withRequiredString("name")
+        ->finishString()
+        ->withRequiredNumber("hardness")
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredString("mapColor")
+        ->finishString()
+        ->withRequiredString("woodType")
+        ->finishString()
+        ->withRequiredString("leavesType")
+        ->finishString()
+        ->withRequiredArray("groupNames")
+        ->withDefault(new Framework::JSON::JSONArray())
+        ->addAcceptedStringInArray()
+        ->finishString()
+        ->finishArray()
+        ->finishObject();
+}
+
+Framework::Text TreeSeblingBlockTypeFactory::getTypeToken() const
+{
+    return "treeSapling";
+}

+ 39 - 15
FactoryCraft/TreeSeblingBlock.h

@@ -14,7 +14,6 @@ private:
 
 public:
     TreeSeblingBlock(int typeId,
-        const ItemType* zTool,
         Framework::Vec3<int> pos,
         int dimensionId,
         const BlockType* wood,
@@ -30,32 +29,57 @@ public:
 class TreeSeblingBlockType : public BlockType
 {
 private:
-    int itemType;
+    Framework::Text itemTypeName;
+    int itemTypeId;
     bool transparent;
     bool passable;
-    float hardness;
-    const ItemType* zTool;
     float speedModifier;
     bool interactable;
-    int woodType;
-    int leavesType;
+    Framework::Text woodTypeName;
+    Framework::Text leavesTypeName;
+    int woodTypeId;
+    int leavesTypeId;
+
+public:
+    TreeSeblingBlockType(Framework::Text itemTypeName,
+        ModelInfo* model,
+        Framework::Text woodTypeName,
+        Framework::Text leavesTypeName,
+        Framework::Text name,
+        int mapColor,
+        float hardness,
+        Framework::RCArray<Framework::Text> groupNames);
 
 protected:
-    virtual void createSuperBlock(Block* zBlock, Item* zItem ) const override;
+    virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
     virtual void loadSuperBlock(Block* zBlock,
         Framework::StreamReader* zReader,
         int dimensionId) const override;
     virtual void saveSuperBlock(
         Block* zBlock, Framework::StreamWriter* zWriter) const override;
     virtual Item* createItem() const override;
-    virtual Block* createBlock(Framework::Vec3<int> position, int dimensionId) const override;
+    virtual Block* createBlock(
+        Framework::Vec3<int> position, int dimensionId) const override;
+
+public:
+    virtual bool initialize(Game* zGame) override;
+    Framework::Text getItemTypeName() const;
+    Framework::Text getWoodTypeName() const;
+    Framework::Text getLeavesTypeName() const;
+    virtual ItemType* createItemType() const override;
+};
 
+class TreeSeblingBlockTypeFactory
+    : public SubTypeFactory<BlockType, TreeSeblingBlockType>
+{
 public:
-    TreeSeblingBlockType(int typeId,
-        int itemTypeId,
-        ModelInfo model,
-        int woodType,
-        int leavesType,
-        const char* name, int mapColor);
-    TreeSeblingBlockType* setHardness(float hardness);
+    TreeSeblingBlockTypeFactory();
+    TreeSeblingBlockType* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJson(
+        TreeSeblingBlockType* zObject) const override;
+    Framework::JSON::Validator::JSONValidator* getValidator(
+        Framework::JSON::Validator::ObjectValidationBuilder<
+            Framework::JSON::Validator::JSONValidator>* builder) const override;
+    Framework::Text getTypeToken() const override;
 };

+ 13 - 12
FactoryCraft/TreeTemplate.cpp

@@ -75,16 +75,16 @@ GeneratedStructure* TreeTemplate::generateAt(
 
 const BlockType* TreeTemplate::getWoodType() const
 {
-    return StaticRegistry<BlockType>::INSTANCE.zElement(woodBlockTypeId);
+    return Game::INSTANCE->zBlockType(woodBlockTypeId);
 }
 
 const BlockType* TreeTemplate::getLeavesType() const
 {
-    return StaticRegistry<BlockType>::INSTANCE.zElement(leaveBlockType);
+    return Game::INSTANCE->zBlockType(leaveBlockType);
 }
 
 TreeTemplateFactory::TreeTemplateFactory()
-    : SubTypeFactory<GeneratorTemplate, TreeTemplate>()
+    : SubTypeFactory()
 {}
 
 TreeTemplate* TreeTemplateFactory::fromJson(
@@ -108,9 +108,11 @@ Framework::JSON::JSONObject* TreeTemplateFactory::toJson(
     TreeTemplate* zObject) const
 {
     Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
-    result->addValue(
-        "propability", new Framework::JSON::JSONNumber((double)zObject->getPropability()));
-    result->addValue("wood", new Framework::JSON::JSONString(BlockType::getTypeName(zObject->woodBlockTypeId)));
+    result->addValue("propability",
+        new Framework::JSON::JSONNumber((double)zObject->getPropability()));
+    result->addValue("wood",
+        new Framework::JSON::JSONString(
+            BlockType::getTypeName(zObject->woodBlockTypeId)));
     result->addValue("leaves",
         new Framework::JSON::JSONString(
             BlockType::getTypeName(zObject->leaveBlockType)));
@@ -126,16 +128,15 @@ Framework::JSON::Validator::JSONValidator* TreeTemplateFactory::getValidator(
         Framework::JSON::Validator::JSONValidator>* builder) const
 {
     Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < StaticRegistry<BlockType>::INSTANCE.getCount(); i++)
+    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
     {
-        if (StaticRegistry<BlockType>::INSTANCE.zElement(i))
+        if (Game::INSTANCE->zBlockType(i))
         {
-            blockTypeNames.add(new Framework::Text(
-                StaticRegistry<BlockType>::INSTANCE.zElement(i)->getName()));
+            blockTypeNames.add(
+                new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
         }
     }
-    return builder
-        ->withRequiredString("type")
+    return builder->withRequiredString("type")
         ->withExactMatch("Tree")
         ->finishString()
         ->withRequiredString("wood")

+ 55 - 0
FactoryCraft/TypeRegistry.cpp

@@ -1,14 +1,27 @@
 #include "TypeRegistry.h"
 
+#include "BasicBlocks.h"
+#include "BlockFilter.h"
 #include "BlockInstanceGeneratorRule.h"
 #include "BlockTypeGeneratorRule.h"
+#include "Chest.h"
 #include "Dimension.h"
 #include "DimensionGenerator.h"
+#include "FluidBlock.h"
 #include "GeneratorRule.h"
+#include "Grass.h"
+#include "GrowingPlant.h"
+#include "LightSources.h"
+#include "ModelInfo.h"
 #include "OverworldDimension.h"
 #include "OverworldDimensionGenerator.h"
+#include "PlaceableProof.h"
 #include "Quest.h"
+#include "TreeSeblingBlock.h"
 #include "TreeTemplate.h"
+#include "BasicItems.h"
+#include "BasicTool.h"
+#include "FluidContainer.h"
 
 TypeRegistry::TypeRegistry()
     : ReferenceCounter()
@@ -33,6 +46,48 @@ TypeRegistry::TypeRegistry()
     registerType(new ItomJsonType());
     registerType(new ItemStackInfoType());
     registerSubType(new QuestRewardGiveItemsType());
+
+    // block types
+    registerType(new ModelInfoFactory());
+    registerSubType(new BasicBlockTypeFactory());
+    registerSubType(new AdditionalItemSpawningBlockTypeFactory());
+    registerSubType(new BasicLightSourceBlockTypeFactory());
+    registerSubType(new ChestBlockTypeFactory());
+    registerSubType(new FluidBlockTypeFactory());
+    registerSubType(new GrassBlockTypeFactory());
+    registerSubType(new GrowingPlantBlockTypeFactory());
+    registerSubType(new TreeSeblingBlockTypeFactory());
+
+    // block filter
+    registerSubType(new BlockFilterAndFactory());
+    registerSubType(new BlockFilterOrFactory());
+    registerSubType(new BlockFilterNotFactory());
+    registerSubType(new BlockFilterBlockTypeFactory());
+    registerSubType(new BlockFilterTypeGroupFactory());
+    registerSubType(new BlockFilterMaxHardnessFactory());
+    registerSubType(new BlockFilterMinHardnessFactory());
+    registerSubType(new BlockFilterMaxHeatFactory());
+
+    // placeable proof
+    registerSubType(new PlaceableProofAndFactory());
+    registerSubType(new PlaceableProofOrFactory());
+    registerSubType(new PlaceableProofNotFactory());
+    registerSubType(new PlaceableProofBlockFilterFactory());
+
+    // item types
+    registerSubType(new BasicBlockItemTypeFactory());
+    registerSubType(new BasicItemTypeFactory());
+    registerSubType(new BasicToolItemTypeFactory());
+    registerSubType(new FluidContainerItemTypeFactory());
+
+    // item skills
+    registerSubType(new XPBasedLevelUpRuleFactory());
+    registerType(new DamagingItemSkillConfigFactory());
+    registerSubType(new DamagingItemSkillFactory());
+    registerType(new BlockReplaceItemSkillConfigFactory());
+    registerSubType(new BlockReplaceItemSkillFactory());
+    registerType(new FluidContainerItemSkillConfigFactory());
+    registerSubType(new FluidContainerItemSkillFactory());
 }
 
 void TypeRegistry::registerGeneratorRuleFactory(GeneratorRuleFactory* factory)

+ 53 - 15
FactoryCraft/TypeRegistry.h

@@ -111,6 +111,8 @@ template<typename T> class PolymorphTypeFactory : public TypeFactory<T>
 {
 private:
     Framework::RCArray<SubTypeFactoryRef<T>> factories;
+    Framework::RCArray<Framework::Text> typeNames;
+    static thread_local bool insideGetValidator;
 
 public:
     PolymorphTypeFactory()
@@ -135,33 +137,65 @@ public:
 
     Framework::JSON::JSONValue* toJson(T* zObject) const override
     {
+        auto name = typeNames.begin();
         for (SubTypeFactoryRef<T>* factory : factories)
         {
-            Framework::JSON::JSONObject* result = factory->toJSON(zObject);
-            if (result)
+            if (name->istGleich(typeid(*zObject).name()))
             {
-                result->addValue("type",
-                    new Framework::JSON::JSONString(factory->getTypetoken()));
-                return result;
+                Framework::JSON::JSONObject* result = factory->toJSON(zObject);
+                if (result)
+                {
+                    result->addValue("type",
+                        new Framework::JSON::JSONString(
+                            factory->getTypetoken()));
+                    return result;
+                }
             }
+            name++;
         }
         return 0;
     }
 
     Framework::JSON::Validator::JSONValidator* getValidator() const override
     {
-        auto validator
-            = Framework::JSON::Validator::JSONValidator::buildForOneOf()
-                  ->typeSpecifiedByAttribute("type");
-        for (SubTypeFactoryRef<T>* factory : factories)
+        Framework::JSON::Validator::JSONValidator* result = 0;
+        if (!insideGetValidator)
         {
-            validator = validator->addAcceptedType(factory->getValidator(
-                Framework::JSON::Validator::JSONValidator::buildForObject()
-                    ->withRequiredString("type")
-                    ->withExactMatch(factory->getTypetoken())
-                    ->finishString()));
+            insideGetValidator = true;
+            auto validator
+                = Framework::JSON::Validator::JSONValidator::buildForOneOf()
+                      ->typeSpecifiedByAttribute("type");
+            for (SubTypeFactoryRef<T>* factory : factories)
+            {
+                validator = validator->addAcceptedType(factory->getValidator(
+                    Framework::JSON::Validator::JSONValidator::buildForObject()
+                        ->withRequiredString("type")
+                        ->withExactMatch(factory->getTypetoken())
+                        ->finishString()
+                        ->setObjectReferenceId(
+                            ((Framework::Text("_type_") += typeid(T).name())
+                                += "_")
+                            += factory->getTypetoken())));
+            }
+            result = validator->finishOneOf();
+            insideGetValidator = false;
         }
-        return validator->finishOneOf();
+        else
+        {
+            auto validator
+                = Framework::JSON::Validator::JSONValidator::buildForOneOf()
+                      ->typeSpecifiedByAttribute("type");
+            for (SubTypeFactoryRef<T>* factory : factories)
+            {
+                validator = validator->addAcceptedType(Framework::JSON::
+                        Validator::JSONValidator::buildForObjectReference(
+                            ((Framework::Text("_type_") += typeid(T).name())
+                                += "_")
+                            += factory->getTypetoken()));
+            }
+            result = validator->finishOneOf();
+        }
+        return result;
     }
 
     template<typename S,
@@ -191,9 +225,13 @@ public:
                 return factory->getValidator(builder);
             },
             dynamic_cast<Framework::ReferenceCounter*>(factory)));
+        typeNames.add(new Framework::Text(typeid(S).name()));
     }
 };
 
+template<typename T>
+thread_local bool PolymorphTypeFactory<T>::insideGetValidator = false;
+
 class TypeFatoryRef : public Framework::ReferenceCounter
 {
 private:

+ 6 - 5
FactoryCraft/WorldLoader.cpp

@@ -24,7 +24,9 @@ WorldLoader::WorldLoader()
                               + Text(name->getText()) + "/entities");
             if (entities.open(Datei::Style::lesen))
             {
-                Dimension* dim = Game::INSTANCE->zTypeRegistry()->createDimension((int)*name);
+                Dimension* dim
+                    = Game::INSTANCE->zTypeRegistry()->createDimension(
+                        (int)*name);
                 if (dim)
                 {
                     while (!entities.istEnde())
@@ -32,15 +34,14 @@ WorldLoader::WorldLoader()
                         int type = 0;
                         entities.lese((char*)&type, 4);
                         dim->addEntity(
-                            StaticRegistry<EntityType>::INSTANCE.zElement(type)
-                                ->loadEntity(&entities));
+                            Game::INSTANCE->zEntityType(type)->loadEntity(
+                                &entities));
                     }
                     Game::INSTANCE->addDimension(dim);
                 }
                 else
                 {
-                    std::cout << "ERROR: could not create dimension "
-                              << *name
+                    std::cout << "ERROR: could not create dimension " << *name
                               << ". No Factory was provided.\n";
                 }
             }

+ 0 - 2
FactoryCraft/WorldUpdate.h

@@ -4,8 +4,6 @@
 #include <Vec3.h>
 #include <Writer.h>
 
-#include "StaticRegistry.h"
-
 class Dimension;
 
 class WorldUpdateTypeEnum

+ 14 - 3
NoiseTest/NoiseTest.cpp

@@ -29,12 +29,17 @@ bool showValue = 1;
 
 class A
 {
-
+    virtual void f(){};
 };
 
-class HelloWorld : public A
+class B : public A
 {
+    virtual void f() override{};
+};
 
+class C : public B
+{
+    virtual void f() override{};
 };
 
 void updateView()
@@ -99,9 +104,15 @@ void updateView()
 
 int main()
 {
-    A *b = new HelloWorld();
+    A* c = new C();
+    A* b = new B();
+    A* a = new A();
+    std::cout << typeid(*c).name() << std::endl;
     std::cout << typeid(*b).name() << std::endl;
+    std::cout << typeid(*a).name() << std::endl;
+    delete a;
     delete b;
+    delete c;
     /*
     Framework::initFramework();
     FastNoiseLite* noise = new FastNoiseLite(1);

+ 46 - 43
NoiseTest/NoiseTest.vcxproj.filters

@@ -13,78 +13,81 @@
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
     </Filter>
+    <Filter Include="Quelldateien\factoryCraftFiles">
+      <UniqueIdentifier>{523405f9-3e0b-417b-b49e-8627d92e6119}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="NoiseTest.cpp">
       <Filter>Quelldateien</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\FastNoiseWrapper.cpp">
-      <Filter>Quelldateien</Filter>
-    </ClCompile>
-    <ClCompile Include="..\FactoryCraft\Noise.cpp">
-      <Filter>Quelldateien</Filter>
-    </ClCompile>
-    <ClCompile Include="..\FactoryCraft\NoiseInterpolator.cpp">
-      <Filter>Quelldateien</Filter>
-    </ClCompile>
-    <ClCompile Include="..\FactoryCraft\ShapedNoise.cpp">
-      <Filter>Quelldateien</Filter>
-    </ClCompile>
-    <ClCompile Include="..\FactoryCraft\RandNoise.cpp">
-      <Filter>Quelldateien</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\FactorizeNoise.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\FastNoiseWrapper.cpp">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClCompile>
     <ClCompile Include="..\FactoryCraft\FlattenNoise.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClCompile>
     <ClCompile Include="..\FactoryCraft\MultiplyNoise.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClCompile>
     <ClCompile Include="..\FactoryCraft\NegateNoise.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\Noise.cpp">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\NoiseInterpolator.cpp">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\RandNoise.cpp">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClCompile>
     <ClCompile Include="..\FactoryCraft\ScaleNoise.cpp">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\ShapedNoise.cpp">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\FactoryCraft\FactorizeNoise.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
+    </ClInclude>
     <ClInclude Include="..\FactoryCraft\FastNoiseLite.h">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
     <ClInclude Include="..\FactoryCraft\FastNoiseWrapper.h">
-      <Filter>Quelldateien</Filter>
-    </ClInclude>
-    <ClInclude Include="..\FactoryCraft\Noise.h">
-      <Filter>Quelldateien</Filter>
-    </ClInclude>
-    <ClInclude Include="..\FactoryCraft\NoiseInterpolator.h">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
-    <ClInclude Include="NoiseCombiner.h">
-      <Filter>Quelldateien</Filter>
+    <ClInclude Include="..\FactoryCraft\FlattenNoise.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\ShapedNoise.h">
-      <Filter>Quelldateien</Filter>
+    <ClInclude Include="..\FactoryCraft\MultiplyNoise.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\RandNoise.h">
-      <Filter>Quelldateien</Filter>
+    <ClInclude Include="..\FactoryCraft\NegateNoise.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\FactorizeNoise.h">
-      <Filter>Quelldateien</Filter>
+    <ClInclude Include="..\FactoryCraft\Noise.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\FlattenNoise.h">
-      <Filter>Quelldateien</Filter>
+    <ClInclude Include="NoiseCombiner.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\MultiplyNoise.h">
-      <Filter>Quelldateien</Filter>
+    <ClInclude Include="..\FactoryCraft\NoiseInterpolator.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\NegateNoise.h">
-      <Filter>Quelldateien</Filter>
+    <ClInclude Include="..\FactoryCraft\RandNoise.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
     <ClInclude Include="..\FactoryCraft\ScaleNoise.h">
-      <Filter>Quelldateien</Filter>
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\ShapedNoise.h">
+      <Filter>Quelldateien\factoryCraftFiles</Filter>
     </ClInclude>
   </ItemGroup>
 </Project>

+ 9 - 9
Windows Version/Windows Version.vcxproj

@@ -159,12 +159,13 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
   <ItemGroup>
     <ClCompile Include="..\FactoryCraft\AddEntityUpdate.cpp" />
     <ClCompile Include="..\FactoryCraft\Area.cpp" />
-    <ClCompile Include="..\FactoryCraft\Axe.cpp" />
-    <ClCompile Include="..\FactoryCraft\BasicBlock.cpp" />
+    <ClCompile Include="..\FactoryCraft\ArrayUtils.cpp" />
+    <ClCompile Include="..\FactoryCraft\BasicBlocks.cpp" />
     <ClCompile Include="..\FactoryCraft\BasicItems.cpp" />
     <ClCompile Include="..\FactoryCraft\BasicTool.cpp" />
     <ClCompile Include="..\FactoryCraft\BiomGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\Block.cpp" />
+    <ClCompile Include="..\FactoryCraft\BlockFilter.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockInfoCommand.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockInstanceGeneratorRule.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockType.cpp" />
@@ -197,7 +198,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\GeneratorRule.cpp" />
     <ClCompile Include="..\FactoryCraft\GrantCommand.cpp" />
     <ClCompile Include="..\FactoryCraft\Grass.cpp" />
-    <ClCompile Include="..\FactoryCraft\Hoe.cpp" />
     <ClCompile Include="..\FactoryCraft\InformationObserver.cpp" />
     <ClCompile Include="..\FactoryCraft\Inventory.cpp" />
     <ClCompile Include="..\FactoryCraft\Item.cpp" />
@@ -210,6 +210,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\ItemType.cpp" />
     <ClCompile Include="..\FactoryCraft\JNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\JsonExpression.cpp" />
+    <ClCompile Include="..\FactoryCraft\JsonUtils.cpp" />
     <ClCompile Include="..\FactoryCraft\LightSources.cpp" />
     <ClCompile Include="..\FactoryCraft\ModelInfo.cpp" />
     <ClCompile Include="..\FactoryCraft\MultiblockStructure.cpp" />
@@ -222,6 +223,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\OverworldDimension.cpp" />
     <ClCompile Include="..\FactoryCraft\OverworldDimensionGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\NoiseInterpolator.cpp" />
+    <ClCompile Include="..\FactoryCraft\PlaceableProof.cpp" />
     <ClCompile Include="..\FactoryCraft\Player.cpp" />
     <ClCompile Include="..\FactoryCraft\PlayerHand.cpp" />
     <ClCompile Include="..\FactoryCraft\PlayerRegister.cpp" />
@@ -238,9 +240,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\ScaleNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\Server.cpp" />
     <ClCompile Include="..\FactoryCraft\ShapedNoise.cpp" />
-    <ClCompile Include="..\FactoryCraft\Shovel.cpp" />
     <ClCompile Include="..\FactoryCraft\Start.cpp" />
-    <ClCompile Include="..\FactoryCraft\StaticInitializerOrder.cpp" />
     <ClCompile Include="..\FactoryCraft\StructureCollection.cpp" />
     <ClCompile Include="..\FactoryCraft\TickOrganizer.cpp" />
     <ClCompile Include="..\FactoryCraft\TickQueue.cpp" />
@@ -257,6 +257,8 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\WormCaveGenerator.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\FactoryCraft\ArrayUtils.h" />
+    <ClInclude Include="..\FactoryCraft\BlockFilter.h" />
     <ClInclude Include="..\FactoryCraft\BlockInfoCommand.h" />
     <ClInclude Include="..\FactoryCraft\BlockInstanceGeneratorRule.h" />
     <ClInclude Include="..\FactoryCraft\FactorizeNoise.h" />
@@ -268,7 +270,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\ChunkMap.h" />
     <ClInclude Include="..\FactoryCraft\AddEntityUpdate.h" />
     <ClInclude Include="..\FactoryCraft\Area.h" />
-    <ClInclude Include="..\FactoryCraft\Axe.h" />
     <ClInclude Include="..\FactoryCraft\BasicBlocks.h" />
     <ClInclude Include="..\FactoryCraft\BasicItems.h" />
     <ClInclude Include="..\FactoryCraft\BasicTool.h" />
@@ -299,7 +300,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\GrantCommand.h" />
     <ClInclude Include="..\FactoryCraft\Grass.h" />
     <ClInclude Include="..\FactoryCraft\Chat.h" />
-    <ClInclude Include="..\FactoryCraft\Hoe.h" />
     <ClInclude Include="..\FactoryCraft\InformationObserver.h" />
     <ClInclude Include="..\FactoryCraft\Inventory.h" />
     <ClInclude Include="..\FactoryCraft\Item.h" />
@@ -312,6 +312,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\ItemType.h" />
     <ClInclude Include="..\FactoryCraft\JNoise.h" />
     <ClInclude Include="..\FactoryCraft\JsonExpression.h" />
+    <ClInclude Include="..\FactoryCraft\JsonUtils.h" />
     <ClInclude Include="..\FactoryCraft\LightSources.h" />
     <ClInclude Include="..\FactoryCraft\DimensionMap.h" />
     <ClInclude Include="..\FactoryCraft\ModelInfo.h" />
@@ -325,6 +326,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\OverworldDimension.h" />
     <ClInclude Include="..\FactoryCraft\OverworldDimensionGenerator.h" />
     <ClInclude Include="..\FactoryCraft\NoiseInterpolator.h" />
+    <ClInclude Include="..\FactoryCraft\PlaceableProof.h" />
     <ClInclude Include="..\FactoryCraft\Player.h" />
     <ClInclude Include="..\FactoryCraft\PlayerHand.h" />
     <ClInclude Include="..\FactoryCraft\PlayerRegister.h" />
@@ -342,8 +344,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\Server.h" />
     <ClInclude Include="..\FactoryCraft\Dimension.h" />
     <ClInclude Include="..\FactoryCraft\ShapedNoise.h" />
-    <ClInclude Include="..\FactoryCraft\Shovel.h" />
-    <ClInclude Include="..\FactoryCraft\StaticRegistry.h" />
     <ClInclude Include="..\FactoryCraft\StructureCollection.h" />
     <ClInclude Include="..\FactoryCraft\Tickable.h" />
     <ClInclude Include="..\FactoryCraft\TickOrganizer.h" />

+ 28 - 25
Windows Version/Windows Version.vcxproj.filters

@@ -106,6 +106,9 @@
     <Filter Include="inventory\items\fluidContainer">
       <UniqueIdentifier>{6e68779b-e8d4-48be-84dc-4d4623a8fd85}</UniqueIdentifier>
     </Filter>
+    <Filter Include="server\utils">
+      <UniqueIdentifier>{05682bc5-0ac5-4ac3-bc89-bc7fb952f350}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\FactoryCraft\Server.cpp">
@@ -117,15 +120,12 @@
     <ClCompile Include="..\FactoryCraft\Block.cpp">
       <Filter>world</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\BasicBlock.cpp">
+    <ClCompile Include="..\FactoryCraft\BasicBlocks.cpp">
       <Filter>world\blocks</Filter>
     </ClCompile>
     <ClCompile Include="..\FactoryCraft\Start.cpp">
       <Filter>server</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\StaticInitializerOrder.cpp">
-      <Filter>static</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\ItemType.cpp">
       <Filter>inventory</Filter>
     </ClCompile>
@@ -276,9 +276,6 @@
     <ClCompile Include="..\FactoryCraft\Grass.cpp">
       <Filter>world\blocks</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\Hoe.cpp">
-      <Filter>inventory\items\tools</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\BasicTool.cpp">
       <Filter>inventory\items\tools</Filter>
     </ClCompile>
@@ -291,9 +288,6 @@
     <ClCompile Include="..\FactoryCraft\RecipieList.cpp">
       <Filter>inventory\recipies</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\Axe.cpp">
-      <Filter>inventory\items\tools</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\SaveCommand.cpp">
       <Filter>chat\commands</Filter>
     </ClCompile>
@@ -327,9 +321,6 @@
     <ClCompile Include="..\FactoryCraft\Chest.cpp">
       <Filter>world\blocks\storage</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\Shovel.cpp">
-      <Filter>inventory\items\tools</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\JsonExpression.cpp">
       <Filter>server\config</Filter>
     </ClCompile>
@@ -402,6 +393,18 @@
     <ClCompile Include="..\FactoryCraft\FluidContainer.cpp">
       <Filter>inventory\items\fluidContainer</Filter>
     </ClCompile>
+    <ClCompile Include="..\FactoryCraft\BlockFilter.cpp">
+      <Filter>world</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\ArrayUtils.cpp">
+      <Filter>server\utils</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\PlaceableProof.cpp">
+      <Filter>world</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\JsonUtils.cpp">
+      <Filter>server\config</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\FactoryCraft\Chunk.h">
@@ -452,9 +455,6 @@
     <ClInclude Include="..\FactoryCraft\BasicBlocks.h">
       <Filter>world\blocks</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\StaticRegistry.h">
-      <Filter>static</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\WorldGenerator.h">
       <Filter>world\generator</Filter>
     </ClInclude>
@@ -584,9 +584,6 @@
     <ClInclude Include="..\FactoryCraft\Grass.h">
       <Filter>world\blocks</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\Hoe.h">
-      <Filter>inventory\items\tools</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\BasicTool.h">
       <Filter>inventory\items\tools</Filter>
     </ClInclude>
@@ -596,9 +593,6 @@
     <ClInclude Include="..\FactoryCraft\FluidBlock.h">
       <Filter>world\blocks\fluids</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\Axe.h">
-      <Filter>inventory\items\tools</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\ChatCommand.h">
       <Filter>chat</Filter>
     </ClInclude>
@@ -632,9 +626,6 @@
     <ClInclude Include="..\FactoryCraft\Chest.h">
       <Filter>world\blocks\storage</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\Shovel.h">
-      <Filter>inventory\items\tools</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\JsonExpression.h">
       <Filter>server\config</Filter>
     </ClInclude>
@@ -710,5 +701,17 @@
     <ClInclude Include="..\FactoryCraft\FluidContainer.h">
       <Filter>inventory\items\fluidContainer</Filter>
     </ClInclude>
+    <ClInclude Include="..\FactoryCraft\BlockFilter.h">
+      <Filter>world</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\ArrayUtils.h">
+      <Filter>server\utils</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\PlaceableProof.h">
+      <Filter>world</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\JsonUtils.h">
+      <Filter>server\config</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

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

@@ -0,0 +1,566 @@
+[
+  {
+    "type": "basicBlock",
+    "name": "Dirt",
+    "itemType": "Dirt",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/lawn.png",
+        "blocks.ltdb/dirt.png"
+      ]
+    },
+    "mapColor": "0xFF3C7C29",
+    "groupNames": [ "Shovel" ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Stone",
+    "itemType": "Stone",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/stone.png",
+        "blocks.ltdb/stone.png",
+        "blocks.ltdb/stone.png",
+        "blocks.ltdb/stone.png",
+        "blocks.ltdb/stone.png",
+        "blocks.ltdb/stone.png"
+      ]
+    },
+    "mapColor": "0xFF8E8E8D",
+    "hardness": 2
+  },
+  {
+    "type": "basicBlock",
+    "name": "Sand",
+    "itemType": "Sand",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/sand.png",
+        "blocks.ltdb/sand.png",
+        "blocks.ltdb/sand.png",
+        "blocks.ltdb/sand.png",
+        "blocks.ltdb/sand.png",
+        "blocks.ltdb/sand.png"
+      ]
+    },
+    "mapColor": "0xFFAE8558",
+    "hardness": 0.5,
+    "groupNames": [ "Shovel" ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Oak Wood",
+    "itemType": "Oak Wood",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/oak.png",
+        "blocks.ltdb/oak.png",
+        "blocks.ltdb/oak.png",
+        "blocks.ltdb/oak.png",
+        "blocks.ltdb/oak.png",
+        "blocks.ltdb/oak.png"
+      ]
+    },
+    "mapColor": "0xFF7F7A70",
+    "hardness": 1.5,
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "additionalItemsBlockType",
+    "name": "Oak Wood Leaves",
+    "itemType": "Oak Wood Leaves",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png"
+      ]
+    },
+    "mapColor": "0xFF6A7C37",
+    "hardness": 0.1,
+    "spawns": [
+      {
+        "min": 1,
+        "max": 1,
+        "itemType": "Oak Wood Sapling",
+        "chance": 0.015
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Gravel",
+    "itemType": "Gravel",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/gravel.png",
+        "blocks.ltdb/gravel.png",
+        "blocks.ltdb/gravel.png",
+        "blocks.ltdb/gravel.png",
+        "blocks.ltdb/gravel.png",
+        "blocks.ltdb/gravel.png"
+      ]
+    },
+    "mapColor": "0xFF928D8C",
+    "hardness": 0.75,
+    "groupNames": [ "Shovel" ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Granite Stone",
+    "itemType": "Granite Stone",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/granite.png",
+        "blocks.ltdb/granite.png",
+        "blocks.ltdb/granite.png",
+        "blocks.ltdb/granite.png",
+        "blocks.ltdb/granite.png",
+        "blocks.ltdb/granite.png"
+      ]
+    },
+    "mapColor": "0xFF3B3A3E",
+    "hardness": 3
+  },
+  {
+    "type": "basicBlock",
+    "name": "Cobble Stone",
+    "itemType": "Cobble Stone",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/cobble.png",
+        "blocks.ltdb/cobble.png",
+        "blocks.ltdb/cobble.png",
+        "blocks.ltdb/cobble.png",
+        "blocks.ltdb/cobble.png",
+        "blocks.ltdb/cobble.png"
+      ]
+    },
+    "mapColor": "0xFF7E7875"
+  },
+  {
+    "type": "basicBlock",
+    "name": "Birch Wood",
+    "itemType": "Birch Wood",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/birch.png",
+        "blocks.ltdb/birch.png",
+        "blocks.ltdb/birch.png",
+        "blocks.ltdb/birch.png",
+        "blocks.ltdb/birch.png",
+        "blocks.ltdb/birch.png"
+      ]
+    },
+    "mapColor": "0xFF99999D",
+    "hardness": 1.5,
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "additionalItemsBlockType",
+    "name": "Birch Wood Leaves",
+    "itemType": "Birch Wood Leaves",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png"
+      ]
+    },
+    "mapColor": "0xFF6A7C37",
+    "hardness": 0.1,
+    "spawns": [
+      {
+        "min": 1,
+        "max": 1,
+        "itemType": "Birch Wood Sapling",
+        "chance": 0.03
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Beech Wood",
+    "itemType": "Beech Wood",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/beech.png",
+        "blocks.ltdb/beech.png",
+        "blocks.ltdb/beech.png",
+        "blocks.ltdb/beech.png",
+        "blocks.ltdb/beech.png",
+        "blocks.ltdb/beech.png"
+      ]
+    },
+    "mapColor": "0xFF778172",
+    "hardness": 1.5,
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "additionalItemsBlockType",
+    "name": "Beech Wood Leaves",
+    "itemType": "Beech Wood Leaves",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png"
+      ]
+    },
+    "mapColor": "0xFF6A7C37",
+    "hardness": 0.1,
+    "spawns": [
+      {
+        "min": 1,
+        "max": 1,
+        "itemType": "Beech Wood Sapling",
+        "chance": 0.02
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Basalt Stone",
+    "itemType": "Basalt Stone",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/basalt.png",
+        "blocks.ltdb/basalt.png",
+        "blocks.ltdb/basalt.png",
+        "blocks.ltdb/basalt.png",
+        "blocks.ltdb/basalt.png",
+        "blocks.ltdb/basalt.png"
+      ]
+    },
+    "mapColor": "0xFF595552",
+    "hardness": 2
+  },
+  {
+    "type": "basicBlock",
+    "name": "Pine Wood",
+    "itemType": "Pine Wood",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/pine.png",
+        "blocks.ltdb/pine.png",
+        "blocks.ltdb/pine.png",
+        "blocks.ltdb/pine.png",
+        "blocks.ltdb/pine.png",
+        "blocks.ltdb/pine.png"
+      ]
+    },
+    "mapColor": "0xFF786C72",
+    "hardness": 1.4,
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "additionalItemsBlockType",
+    "name": "Pine Wood Leaves",
+    "itemType": "Pine Wood Leaves",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png",
+        "blocks.ltdb/leaves.png"
+      ]
+    },
+    "mapColor": "0xFF6A7C37",
+    "hardness": 0.1,
+    "spawns": [
+      {
+        "min": 1,
+        "max": 1,
+        "itemType": "Pine Wood Sapling",
+        "chance": 0.025
+      }
+    ]
+  },
+  {
+    "type": "lightSource",
+    "name": "Torch",
+    "itemType": "Torch",
+    "model": {
+      "modelPath": "blocks.m3/torch",
+      "texturePaths": [
+        "blocks.ltdb/torch.png",
+        "blocks.ltdb/torch.png",
+        "blocks.ltdb/torch.png",
+        "blocks.ltdb/torch.png",
+        "blocks.ltdb/torch.png",
+        "blocks.ltdb/torch.png"
+      ]
+    },
+    "mapColor": "0x00F69A54",
+    "lightColor": "0x00F69A54",
+    "hardness": 0,
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "treeSapling",
+    "name": "Oak Wood Sapling",
+    "itemType": "Oak Wood Sapling",
+    "model": {
+      "modelPath": "blocks.m3/sebling",
+      "texturePaths": [
+        "blocks.ltdb/sebling.png"
+      ]
+    },
+    "mapColor": "0xFD6A7B3A",
+    "hardness": 0.1,
+    "woodType": "Oak Wood",
+    "leavesType": "Oak Wood Leaves",
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "treeSapling",
+    "name": "Birch Wood Sapling",
+    "itemType": "Birch Wood Sapling",
+    "model": {
+      "modelPath": "blocks.m3/sebling",
+      "texturePaths": [
+        "blocks.ltdb/sebling.png"
+      ]
+    },
+    "mapColor": "0xFD6A7B3A",
+    "hardness": 0.1,
+    "woodType": "Birch Wood",
+    "leavesType": "Birch Wood Leaves",
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "treeSapling",
+    "name": "Beech Wood Sapling",
+    "itemType": "Beech Wood Sapling",
+    "model": {
+      "modelPath": "blocks.m3/sebling",
+      "texturePaths": [
+        "blocks.ltdb/sebling.png"
+      ]
+    },
+    "mapColor": "0xFD6A7B3A",
+    "hardness": 0.1,
+    "woodType": "Beech Wood",
+    "leavesType": "Beech Wood Leaves",
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "treeSapling",
+    "name": "Pine Wood Sapling",
+    "itemType": "Pine Wood Sapling",
+    "model": {
+      "modelPath": "blocks.m3/sebling",
+      "texturePaths": [
+        "blocks.ltdb/sebling.png"
+      ]
+    },
+    "mapColor": "0xFD6A7B3A",
+    "hardness": 0.1,
+    "woodType": "Pine Wood",
+    "leavesType": "Pine Wood Leaves",
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "grass",
+    "name": "Grass",
+    "model": {
+      "modelPath": "grass",
+      "texturePaths": [
+        "blocks.ltdb/grass.png"
+      ],
+      "transparent": true
+    },
+    "mapColor": "0x5076C011",
+    "spawns": [
+      {
+        "min": 1,
+        "max": 1,
+        "itemType": "Wheat Seeds",
+        "chance": 0.1
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Farmland",
+    "itemType": "Farmland",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/dirt.png",
+        "blocks.ltdb/farmland.png",
+        "blocks.ltdb/dirt.png"
+      ]
+    },
+    "mapColor": "0xFF5E3819",
+    "hardness": 0.1,
+    "groupNames": [ "Shovel" ]
+  },
+  {
+    "type": "growingPlant",
+    "name": "WheatSeeds",
+    "readableName": "Growing wheat",
+    "blockTypeAfterGrowth": "Wheat",
+    "model": {
+      "modelPath": "grass",
+      "texturePaths": [
+        "plants.ltdb/wheatseeds.png"
+      ],
+      "transparent": true
+    },
+    "mapColor": "0x5076C011",
+    "hardness": 0.1,
+    "ticksNeeded": 18000,
+    "states": [
+      {
+        "percentage": 0.2,
+        "model": {
+          "modelPath": "grass",
+          "texturePaths": [
+            "plants.ltdb/wheatseedsa.png"
+          ],
+          "transparent": true
+        }
+      },
+      {
+        "percentage": 0.4,
+        "model": {
+          "modelPath": "grass",
+          "texturePaths": [
+            "plants.ltdb/wheatseedsb.png"
+          ],
+          "transparent": true
+        }
+      },
+      {
+        "percentage": 0.6,
+        "model": {
+          "modelPath": "grass",
+          "texturePaths": [
+            "plants.ltdb/wheatseedsc.png"
+          ],
+          "transparent": true
+        }
+      },
+      {
+        "percentage": 0.8,
+        "model": {
+          "modelPath": "grass",
+          "texturePaths": [
+            "plants.ltdb/wheatseedsd.png"
+          ],
+          "transparent": true
+        }
+      }
+    ]
+  },
+  {
+    "type": "additionalItemsBlockType",
+    "name": "Wheat",
+    "itemType": "Wheat",
+    "model": {
+      "modelPath": "grass",
+      "texturePaths": [
+        "plants.ltdb/wheat.png"
+      ]
+    },
+    "mapColor": "0x90A8C011",
+    "spawns": [
+      {
+        "min": 0,
+        "max": 4,
+        "itemType": "Wheat",
+        "chance": 1.0
+      }
+    ]
+  },
+  {
+    "type": "fluid",
+    "name": "Water",
+    "model": {
+      "modelPath": "fluid",
+      "texturePaths": [
+        "fluids.ltdb/water.png",
+        "fluids.ltdb/water.png",
+        "fluids.ltdb/water.png",
+        "fluids.ltdb/water.png",
+        "fluids.ltdb/water.png",
+        "fluids.ltdb/water.png"
+      ]
+    },
+    "mapColor": "0xFF2323BF",
+    "lightWeight": {
+      "red": 0.8,
+      "green": 0.8,
+      "blue": 0.95
+    },
+    "ticksToFlow": 20,
+    "flowDistance": 8,
+    "thirstRecoveryPerL": 1
+  },
+  {
+    "type": "basicBlock",
+    "name": "Crafting Table",
+    "itemType": "Crafting Table",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/woodplanks.png",
+        "blocks.ltdb/woodplanks.png",
+        "blocks.ltdb/woodplanks.png",
+        "blocks.ltdb/woodplanks.png",
+        "blocks.ltdb/craftingtable.png",
+        "blocks.ltdb/woodplanks.png"
+      ]
+    },
+    "mapColor": "0xFFC4A783",
+    "groupNames": [ "Wood" ]
+  },
+  {
+    "type": "chest",
+    "name": "Wooden Chest",
+    "itemType": "Wooden Chest",
+    "model": {
+      "modelPath": "blocks.m3/chest",
+      "texturePaths": [
+        "blocks.ltdb/chest.png",
+        "blocks.ltdb/chestcover.png"
+      ]
+    },
+    "mapColor": "0xFFE2C292",
+    "groupNames": [ "Wood" ]
+  }
+]

+ 244 - 0
Windows Version/data/items/itemTypes.json

@@ -0,0 +1,244 @@
+[
+  {
+    "type": "basic",
+    "name": "Wooden Stick",
+    "model": {
+      "modelPath": "items.m3/stick",
+      "texturePaths": [
+        "items.ltdb/stick.png"
+      ]
+    },
+    "itemName": "Wooden Stick",
+    "hp": 1,
+    "durability": 10
+  },
+  {
+    "type": "basic",
+    "name": "Resin",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "items.ltdb/resin.png",
+        "items.ltdb/resin.png",
+        "items.ltdb/resin.png",
+        "items.ltdb/resin.png",
+        "items.ltdb/resin.png",
+        "items.ltdb/resin.png"
+      ]
+    },
+    "itemName": "Resin",
+    "hp": 1,
+    "durability": 10
+  },
+  {
+    "type": "basic",
+    "name": "Broken Axe",
+    "model": {
+      "modelPath": "tools.m3/axe",
+      "texturePaths": [
+        "tools.ltdb/stoneaxe.png"
+      ]
+    },
+    "itemName": "Broken Axe",
+    "hp": 100,
+    "durability": 100,
+    "maxStack": 10
+  },
+  {
+    "type": "basic",
+    "name": "Broken Hoe",
+    "model": {
+      "modelPath": "tools.m3/hoe",
+      "texturePaths": [
+        "tools.ltdb/stonehoe.png"
+      ]
+    },
+    "itemName": "Broken Hoe",
+    "hp": 100,
+    "durability": 100,
+    "maxStack": 10
+  },
+  {
+    "type": "basic",
+    "name": "Flint",
+    "model": {
+      "modelPath": "items.m3/flint",
+      "texturePaths": [
+        "items.ltdb/flint.png"
+      ]
+    },
+    "itemName": "Flint",
+    "hp": 1,
+    "durability": 10
+  },
+  {
+    "type": "basic",
+    "name": "Flint",
+    "model": {
+      "modelPath": "items.m3/flint",
+      "texturePaths": [
+        "items.ltdb/flint.png"
+      ]
+    },
+    "itemName": "Flint",
+    "hp": 1,
+    "durability": 10
+  },
+  {
+    "type": "basic",
+    "name": "Broken Shovel",
+    "model": {
+      "modelPath": "tools.m3/shovel",
+      "texturePaths": [
+        "tools.ltdb/stonehoe.png"
+      ]
+    },
+    "itemName": "Broken Shovel",
+    "hp": 100,
+    "durability": 100,
+    "maxStack": 10
+  },
+  {
+    "type": "basic",
+    "name": "Wheat",
+    "model": {
+      "modelPath": "grass",
+      "texturePaths": [
+        "plants.ltdb/wheat.png"
+      ]
+    },
+    "itemName": "Wheat",
+    "hp": 1,
+    "durability": 10,
+    "maxStack": 10,
+    "hungerRecoveryPerHp": 0.5
+  },
+  {
+    "type": "tool",
+    "name": "Hoe",
+    "model": {
+      "modelPath": "tools.m3/hoe",
+      "texturePaths": [
+        "tools.ltdb/stonehoe.png"
+      ]
+    },
+    "maxStack": 10,
+    "brokenItemTypeName": "Broken Hoe",
+    "levelUpRule": {
+      "type": "xpBased"
+    },
+    "itemSkill": {
+      "type": "replaceBlock",
+      "configs": [
+        {
+          "targetFilter": {
+            "type": "types",
+            "typeNames": [ "Dirt" ]
+          },
+          "replacementBlockType": "Farmland"
+        }
+      ]
+    }
+  },
+  {
+    "type": "tool",
+    "name": "Shovel",
+    "model": {
+      "modelPath": "tools.m3/shovel",
+      "texturePaths": [
+        "tools.ltdb/stonehoe.png"
+      ]
+    },
+    "maxStack": 10,
+    "brokenItemTypeName": "Broken Shovel",
+    "levelUpRule": {
+      "type": "xpBased"
+    },
+    "itemSkill": {
+      "type": "damaging",
+      "configs": [
+        {
+          "targetFilter": {
+            "type": "groups",
+            "groupNames": [ "Shovel" ]
+          }
+        }
+      ]
+    }
+  },
+  {
+    "type": "tool",
+    "name": "Axe",
+    "model": {
+      "modelPath": "tools.m3/axe",
+      "texturePaths": [
+        "tools.ltdb/stoneaxe.png"
+      ]
+    },
+    "maxStack": 10,
+    "brokenItemTypeName": "Broken Axe",
+    "levelUpRule": {
+      "type": "xpBased"
+    },
+    "itemSkill": {
+      "type": "damaging",
+      "configs": [
+        {
+          "targetFilter": {
+            "type": "groups",
+            "groupNames": [ "Wood" ]
+          }
+        }
+      ]
+    }
+  },
+  {
+    "type": "fluidContainer",
+    "name": "Wooden Bucket",
+    "model": {
+      "modelPath": "items.m3/bucket",
+      "texturePaths": [
+        "blocks.ltdb/woodplanks.png"
+      ]
+    },
+    "maxStack": 10,
+    "levelUpRule": {
+      "type": "xpBased"
+    },
+    "itemSkill": {
+      "type": "fluidGathering",
+      "configs": [
+        {
+          "targetFilter": {
+            "type": "maxHeat",
+            "heat": 90
+          }
+        }
+      ]
+    }
+  },
+  {
+    "type": "placeable",
+    "name": "Wheat Seeds",
+    "model": {
+      "modelPath": "grass",
+      "texturePaths": [
+        "plants.ltdb/wheatseeds.png"
+      ],
+      "transparent": false
+    },
+    "hardness": 0.1,
+    "transparent": true,
+    "passable": true,
+    "speedModifier": 0.5,
+    "blockType": "WheatSeeds",
+    "placeableProof": {
+      "type": "blockFilter",
+      "direction": "bottom",
+      "filter": {
+        "type": "types",
+        "typeNames": [ "Farmland" ]
+      }
+    }
+  }
+]

+ 1 - 1
Windows Version/data/quests/quests.json

@@ -51,7 +51,7 @@
             "items": [
               {
                 "item": {
-                  "type": "WoodenStick"
+                  "type": "Wooden Stick"
                 },
                 "count": 10
               }

+ 18 - 18
Windows Version/data/recipies/basicItems.json

@@ -206,16 +206,16 @@
         "filter": {
           "left": {
             "left": {
-              "itemType": "Oak"
+              "itemType": "Oak Wood"
             },
             "operator": "||",
             "right": {
-              "itemType": "Birch"
+              "itemType": "Birch Wood"
             }
           },
           "operator": "||",
           "right": {
-            "itemType": "Beech"
+            "itemType": "Beech Wood"
           }
         },
         "x": 0,
@@ -223,7 +223,7 @@
       }
     ],
     "output": {
-      "itemType": "WoodenStick"
+      "itemType": "Wooden Stick"
     },
     "type": "shaped",
     "width": 1
@@ -241,7 +241,7 @@
       },
       {
         "filter": {
-          "itemType": "Pine"
+          "itemType": "Pine Wood"
         },
         "x": 0,
         "y": 1
@@ -266,7 +266,7 @@
       },
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 0,
         "y": 1
@@ -286,21 +286,21 @@
         "filter": {
           "left": {
             "left": {
-              "itemType": "Beech Leaves"
+              "itemType": "Beech Wood Leaves"
             },
             "operator": "||",
             "right": {
-              "itemType": "Birch Leaves"
+              "itemType": "Birch Wood Leaves"
             }
           },
           "operator": "||",
           "right": {
             "left": {
-              "itemType": "Oak Leaves"
+              "itemType": "Oak Wood Leaves"
             },
             "operator": "||",
             "right": {
-              "itemType": "Pine Leaves"
+              "itemType": "Pine Wood Leaves"
             }
           }
         },
@@ -309,7 +309,7 @@
       }
     ],
     "output": {
-      "itemType": "WoodenStick"
+      "itemType": "Wooden Stick"
     },
     "type": "shaped",
     "width": 1
@@ -320,49 +320,49 @@
     "inputs": [
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 0,
         "y": 0
       },
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 0,
         "y": 1
       },
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 0,
         "y": 2
       },
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 1,
         "y": 2
       },
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 2,
         "y": 2
       },
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 2,
         "y": 1
       },
       {
         "filter": {
-          "itemType": "WoodenStick"
+          "itemType": "Wooden Stick"
         },
         "x": 2,
         "y": 0

+ 9 - 9
Windows Version/data/recipies/blocks.json

@@ -16,61 +16,61 @@
 				"x": 0,
 				"y": 0,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 0,
 				"y": 1,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 0,
 				"y": 2,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 1,
 				"y": 0,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 1,
 				"y": 2,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 2,
 				"y": 0,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 2,
 				"y": 1,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 2,
 				"y": 2,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			}
 		],
 		"output": {
-			"itemType": "Chest"
+			"itemType": "Wooden Chest"
 		}
 	}
 ]

+ 6 - 6
Windows Version/data/recipies/tools.json

@@ -23,14 +23,14 @@
 				"x": 1,
 				"y": 1,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 1,
 				"y": 2,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			}
 		],
@@ -69,14 +69,14 @@
 				"x": 1,
 				"y": 1,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 1,
 				"y": 2,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			}
 		],
@@ -101,14 +101,14 @@
 				"x": 0,
 				"y": 1,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			},
 			{
 				"x": 0,
 				"y": 2,
 				"filter": {
-					"itemType": "WoodenStick"
+					"itemType": "Wooden Stick"
 				}
 			}
 		],

+ 0 - 1
Windows Version/data/syntax/generatorValidation.xml

@@ -1 +0,0 @@
-<array removeInvalidEntries="true"><oneOf typeSpecifiedBy="dimension"><object><value name="dimension"><string equals="Overworld"/></value><value name="bioms"><array><object><value name="name"><string/></value><value name="condition"><oneOf typeSpecifiedBy="type"><object id="jeb_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jeb_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><bool/></value></object><object id="jeb_blockType"><value name="type"><string oneOf='["blockType"]'/></value><value name="blockType"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="x"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jeb_bool_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["&&","||"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jeb_variable"/><objectRef ref="jeb_constant"/><objectRef ref="jeb_blockType"/><objectRef ref="jeb_bool_operator"/><objectRef ref="jeb_float_operator"/></oneOf></array></value></object><object id="jeb_float_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='[">","<",">=","<=","==","!=",">i","<i",">=i","<=i","==i","!=i"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></array></value></object></oneOf></value><value name="structurCollections"><array><object><value name="activeNoise"><oneOf typeSpecifiedBy="type"><object id="jn_random"><value name="type"><string equals="random"/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jn_factorize"><value name="type"><string equals="factorize"/></value><value name="factorA"><number greater="0.000000" less="1.000000"/></value><value name="noiseA"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="noiseB"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_multiply"><value name="type"><string equals="multiply"/></value><value name="base"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="multiplier"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_negate"><value name="type"><string equals="negate"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_flatten"><value name="type"><string equals="flatten"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number default="1.000000"/></value><value name="addition"><number default="0.000000"/></value></object><object id="jn_scale"><value name="type"><string equals="scale"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number/></value></object><object id="jn_fastNoiseLite"><value name="type"><string oneOf='["Cellular","ValueCubic","Perlin","OpenSimplex2S","OpenSimplex2","Value"]'/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="rotationType3D"><string optional="true" oneOf='["None","ImproveXYPlanes","ImproveXZPlanes"]'/></value><value name="frequency"><number optional="true"/></value><value name="fractalType"><string optional="true" oneOf='["None","FBm","Ridged","PingPong","DomainWarpProgressive","DomainWarpIndependent"]'/></value><value name="fractalOctaves"><number optional="true"/></value><value name="fractalLacunarity"><number optional="true"/></value><value name="fractalGain"><number optional="true"/></value><value name="cellularDistanceFunction"><string optional="true" oneOf='["Hybrid","Manhattan","EuclideanSq","Euclidean"]'/></value><value name="cellularReturnType"><string optional="true" oneOf='["CellValue","Distance","Distance2","Distance2Add","Distance2Sub","Distance2Mul","Distance2Div"]'/></value><value name="cellularJitter"><number optional="true"/></value><value name="domainWarpType"><string optional="true" oneOf='["BasicGrid","OpenSimplex2","OpenSimplex2Reduced"]'/></value><value name="domainWarpAmp"><number optional="true"/></value><value name="multiplier"><number optional="true" greater="0.000000"/></value></object></oneOf></value><value name="structureNoise"><oneOf typeSpecifiedBy="type"><object id="jn_random"><value name="type"><string equals="random"/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jn_factorize"><value name="type"><string equals="factorize"/></value><value name="factorA"><number greater="0.000000" less="1.000000"/></value><value name="noiseA"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="noiseB"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_multiply"><value name="type"><string equals="multiply"/></value><value name="base"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="multiplier"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_negate"><value name="type"><string equals="negate"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_flatten"><value name="type"><string equals="flatten"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number default="1.000000"/></value><value name="addition"><number default="0.000000"/></value></object><object id="jn_scale"><value name="type"><string equals="scale"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number/></value></object><object id="jn_fastNoiseLite"><value name="type"><string oneOf='["Cellular","ValueCubic","Perlin","OpenSimplex2S","OpenSimplex2","Value"]'/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="rotationType3D"><string optional="true" oneOf='["None","ImproveXYPlanes","ImproveXZPlanes"]'/></value><value name="frequency"><number optional="true"/></value><value name="fractalType"><string optional="true" oneOf='["None","FBm","Ridged","PingPong","DomainWarpProgressive","DomainWarpIndependent"]'/></value><value name="fractalOctaves"><number optional="true"/></value><value name="fractalLacunarity"><number optional="true"/></value><value name="fractalGain"><number optional="true"/></value><value name="cellularDistanceFunction"><string optional="true" oneOf='["Hybrid","Manhattan","EuclideanSq","Euclidean"]'/></value><value name="cellularReturnType"><string optional="true" oneOf='["CellValue","Distance","Distance2","Distance2Add","Distance2Sub","Distance2Mul","Distance2Div"]'/></value><value name="cellularJitter"><number optional="true"/></value><value name="domainWarpType"><string optional="true" oneOf='["BasicGrid","OpenSimplex2","OpenSimplex2Reduced"]'/></value><value name="domainWarpAmp"><number optional="true"/></value><value name="multiplier"><number optional="true" greater="0.000000"/></value></object></oneOf></value><value name="threshold"><number greater="0.000000"/></value><value name="condition"><oneOf typeSpecifiedBy="type"><object id="jeb_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jeb_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><bool/></value></object><object id="jeb_blockType"><value name="type"><string oneOf='["blockType"]'/></value><value name="blockType"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="x"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jeb_bool_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["&&","||"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jeb_variable"/><objectRef ref="jeb_constant"/><objectRef ref="jeb_blockType"/><objectRef ref="jeb_bool_operator"/><objectRef ref="jeb_float_operator"/></oneOf></array></value></object><object id="jeb_float_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='[">","<",">=","<=","==","!=",">i","<i",">=i","<=i","==i","!=i"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></array></value></object></oneOf></value><value name="structures"><array><oneOf typeSpecifiedBy="type"><object><value name="type"><string equals="Tree"/><string equals="Tree"/></value><value name="wood"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="leaves"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="minSize"><number greater="0.000000"/></value><value name="maxSize"><number greater="0.000000"/></value><value name="propability"><number greater="0.000000"/></value></object></oneOf></array></value></object></array></value><value name="blocks"><array><oneOf typeSpecifiedBy="type"><object><value name="type"><string equals="blockType"/></value><value name="blockType"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="noise"><oneOf typeSpecifiedBy="type"><object optional="true" id="jn_random"><value name="type"><string equals="random"/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object optional="true" id="jn_factorize"><value name="type"><string equals="factorize"/></value><value name="factorA"><number greater="0.000000" less="1.000000"/></value><value name="noiseA"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="noiseB"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object optional="true" id="jn_multiply"><value name="type"><string equals="multiply"/></value><value name="base"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="multiplier"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object optional="true" id="jn_negate"><value name="type"><string equals="negate"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object optional="true" id="jn_flatten"><value name="type"><string equals="flatten"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number default="1.000000"/></value><value name="addition"><number default="0.000000"/></value></object><object optional="true" id="jn_scale"><value name="type"><string equals="scale"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number/></value></object><object optional="true" id="jn_fastNoiseLite"><value name="type"><string oneOf='["Cellular","ValueCubic","Perlin","OpenSimplex2S","OpenSimplex2","Value"]'/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="rotationType3D"><string optional="true" oneOf='["None","ImproveXYPlanes","ImproveXZPlanes"]'/></value><value name="frequency"><number optional="true"/></value><value name="fractalType"><string optional="true" oneOf='["None","FBm","Ridged","PingPong","DomainWarpProgressive","DomainWarpIndependent"]'/></value><value name="fractalOctaves"><number optional="true"/></value><value name="fractalLacunarity"><number optional="true"/></value><value name="fractalGain"><number optional="true"/></value><value name="cellularDistanceFunction"><string optional="true" oneOf='["Hybrid","Manhattan","EuclideanSq","Euclidean"]'/></value><value name="cellularReturnType"><string optional="true" oneOf='["CellValue","Distance","Distance2","Distance2Add","Distance2Sub","Distance2Mul","Distance2Div"]'/></value><value name="cellularJitter"><number optional="true"/></value><value name="domainWarpType"><string optional="true" oneOf='["BasicGrid","OpenSimplex2","OpenSimplex2Reduced"]'/></value><value name="domainWarpAmp"><number optional="true"/></value><value name="multiplier"><number optional="true" greater="0.000000"/></value></object></oneOf></value><value name="condition"><oneOf typeSpecifiedBy="type"><object id="jeb_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jeb_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><bool/></value></object><object id="jeb_blockType"><value name="type"><string oneOf='["blockType"]'/></value><value name="blockType"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="x"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jeb_bool_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["&&","||"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jeb_variable"/><objectRef ref="jeb_constant"/><objectRef ref="jeb_blockType"/><objectRef ref="jeb_bool_operator"/><objectRef ref="jeb_float_operator"/></oneOf></array></value></object><object id="jeb_float_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='[">","<",">=","<=","==","!=",">i","<i",">=i","<=i","==i","!=i"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></array></value></object></oneOf></value><value name="threshold"><number optional="true" greaterOrEqual="0.000000" lessOrEqual="1.000000"/></value></object><object><value name="type"><string equals="blockInstance"/></value><value name="blockType"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="noise"><oneOf typeSpecifiedBy="type"><object optional="true" id="jn_random"><value name="type"><string equals="random"/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object optional="true" id="jn_factorize"><value name="type"><string equals="factorize"/></value><value name="factorA"><number greater="0.000000" less="1.000000"/></value><value name="noiseA"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="noiseB"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object optional="true" id="jn_multiply"><value name="type"><string equals="multiply"/></value><value name="base"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="multiplier"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object optional="true" id="jn_negate"><value name="type"><string equals="negate"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object optional="true" id="jn_flatten"><value name="type"><string equals="flatten"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number default="1.000000"/></value><value name="addition"><number default="0.000000"/></value></object><object optional="true" id="jn_scale"><value name="type"><string equals="scale"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number/></value></object><object optional="true" id="jn_fastNoiseLite"><value name="type"><string oneOf='["Cellular","ValueCubic","Perlin","OpenSimplex2S","OpenSimplex2","Value"]'/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="rotationType3D"><string optional="true" oneOf='["None","ImproveXYPlanes","ImproveXZPlanes"]'/></value><value name="frequency"><number optional="true"/></value><value name="fractalType"><string optional="true" oneOf='["None","FBm","Ridged","PingPong","DomainWarpProgressive","DomainWarpIndependent"]'/></value><value name="fractalOctaves"><number optional="true"/></value><value name="fractalLacunarity"><number optional="true"/></value><value name="fractalGain"><number optional="true"/></value><value name="cellularDistanceFunction"><string optional="true" oneOf='["Hybrid","Manhattan","EuclideanSq","Euclidean"]'/></value><value name="cellularReturnType"><string optional="true" oneOf='["CellValue","Distance","Distance2","Distance2Add","Distance2Sub","Distance2Mul","Distance2Div"]'/></value><value name="cellularJitter"><number optional="true"/></value><value name="domainWarpType"><string optional="true" oneOf='["BasicGrid","OpenSimplex2","OpenSimplex2Reduced"]'/></value><value name="domainWarpAmp"><number optional="true"/></value><value name="multiplier"><number optional="true" greater="0.000000"/></value></object></oneOf></value><value name="condition"><oneOf typeSpecifiedBy="type"><object id="jeb_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jeb_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><bool/></value></object><object id="jeb_blockType"><value name="type"><string oneOf='["blockType"]'/></value><value name="blockType"><string oneOf='["","Air","Dirt","Sand","Gravel","Stone","Granite Stone","Cobble Stone","Basalt Stone","Oak Wood","Birch Wood","Beech Wood","Pine Wood","Oak Wood Leaves","Birch Wood Leaves","Beech Wood Leaves","Pine Wood Leaves","Oak Wood Sebling","Birch Wood Sebling","Beech Wood Sebling","Pine Wood Sebling","Torch","Grass","Farmland","WheatSeeds","Wheat","Water","Crafting Table","Chest"]'/></value><value name="x"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jeb_bool_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["&&","||"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jeb_variable"/><objectRef ref="jeb_constant"/><objectRef ref="jeb_blockType"/><objectRef ref="jeb_bool_operator"/><objectRef ref="jeb_float_operator"/></oneOf></array></value></object><object id="jeb_float_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='[">","<",">=","<=","==","!=",">i","<i",">=i","<=i","==i","!=i"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></array></value></object></oneOf></value><value name="threshold"><number optional="true" greaterOrEqual="0.000000" lessOrEqual="1.000000"/></value></object></oneOf></array></value></object></array></value><value name="biomNoise"><oneOf typeSpecifiedBy="type"><object id="jn_random"><value name="type"><string equals="random"/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jn_factorize"><value name="type"><string equals="factorize"/></value><value name="factorA"><number greater="0.000000" less="1.000000"/></value><value name="noiseA"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="noiseB"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_multiply"><value name="type"><string equals="multiply"/></value><value name="base"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="multiplier"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_negate"><value name="type"><string equals="negate"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_flatten"><value name="type"><string equals="flatten"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number default="1.000000"/></value><value name="addition"><number default="0.000000"/></value></object><object id="jn_scale"><value name="type"><string equals="scale"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number/></value></object><object id="jn_fastNoiseLite"><value name="type"><string oneOf='["Cellular","ValueCubic","Perlin","OpenSimplex2S","OpenSimplex2","Value"]'/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="rotationType3D"><string optional="true" oneOf='["None","ImproveXYPlanes","ImproveXZPlanes"]'/></value><value name="frequency"><number optional="true"/></value><value name="fractalType"><string optional="true" oneOf='["None","FBm","Ridged","PingPong","DomainWarpProgressive","DomainWarpIndependent"]'/></value><value name="fractalOctaves"><number optional="true"/></value><value name="fractalLacunarity"><number optional="true"/></value><value name="fractalGain"><number optional="true"/></value><value name="cellularDistanceFunction"><string optional="true" oneOf='["Hybrid","Manhattan","EuclideanSq","Euclidean"]'/></value><value name="cellularReturnType"><string optional="true" oneOf='["CellValue","Distance","Distance2","Distance2Add","Distance2Sub","Distance2Mul","Distance2Div"]'/></value><value name="cellularJitter"><number optional="true"/></value><value name="domainWarpType"><string optional="true" oneOf='["BasicGrid","OpenSimplex2","OpenSimplex2Reduced"]'/></value><value name="domainWarpAmp"><number optional="true"/></value><value name="multiplier"><number optional="true" greater="0.000000"/></value></object></oneOf></value><value name="dimensionSeed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="heightLayers"><array default="[]" removeInvalidEntries="true"><object><value name="name"><string/></value><value name="noise"><oneOf typeSpecifiedBy="type"><object id="jn_random"><value name="type"><string equals="random"/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object><object id="jn_factorize"><value name="type"><string equals="factorize"/></value><value name="factorA"><number greater="0.000000" less="1.000000"/></value><value name="noiseA"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="noiseB"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_multiply"><value name="type"><string equals="multiply"/></value><value name="base"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="multiplier"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_negate"><value name="type"><string equals="negate"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value></object><object id="jn_flatten"><value name="type"><string equals="flatten"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number default="1.000000"/></value><value name="addition"><number default="0.000000"/></value></object><object id="jn_scale"><value name="type"><string equals="scale"/></value><value name="noise"><oneOf typeSpecifiedBy="type"><objectRef ref="jn_random"/><objectRef ref="jn_factorize"/><objectRef ref="jn_multiply"/><objectRef ref="jn_negate"/><objectRef ref="jn_flatten"/><objectRef ref="jn_scale"/><objectRef ref="jn_fastNoiseLite"/></oneOf></value><value name="factor"><number/></value></object><object id="jn_fastNoiseLite"><value name="type"><string oneOf='["Cellular","ValueCubic","Perlin","OpenSimplex2S","OpenSimplex2","Value"]'/></value><value name="seed"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value><value name="rotationType3D"><string optional="true" oneOf='["None","ImproveXYPlanes","ImproveXZPlanes"]'/></value><value name="frequency"><number optional="true"/></value><value name="fractalType"><string optional="true" oneOf='["None","FBm","Ridged","PingPong","DomainWarpProgressive","DomainWarpIndependent"]'/></value><value name="fractalOctaves"><number optional="true"/></value><value name="fractalLacunarity"><number optional="true"/></value><value name="fractalGain"><number optional="true"/></value><value name="cellularDistanceFunction"><string optional="true" oneOf='["Hybrid","Manhattan","EuclideanSq","Euclidean"]'/></value><value name="cellularReturnType"><string optional="true" oneOf='["CellValue","Distance","Distance2","Distance2Add","Distance2Sub","Distance2Mul","Distance2Div"]'/></value><value name="cellularJitter"><number optional="true"/></value><value name="domainWarpType"><string optional="true" oneOf='["BasicGrid","OpenSimplex2","OpenSimplex2Reduced"]'/></value><value name="domainWarpAmp"><number optional="true"/></value><value name="multiplier"><number optional="true" greater="0.000000"/></value></object></oneOf></value><value name="value"><oneOf typeSpecifiedBy="type"><object id="jef_variable"><value name="type"><string oneOf='["variable"]'/></value><value name="name"><string/></value></object><object id="jef_constant"><value name="type"><string oneOf='["constant"]'/></value><value name="value"><number/></value></object><object id="jef_noise"><value name="type"><string oneOf='["noise"]'/></value><value name="name"><string default='"noise"'/></value><value name="x"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="y"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value><value name="z"><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></value></object><object id="jef_operator"><value name="type"><string oneOf='["operator"]'/></value><value name="operator"><string oneOf='["+","-","*","/"]'/></value><value name="values"><array><oneOf typeSpecifiedBy="type"><objectRef ref="jef_variable"/><objectRef ref="jef_constant"/><objectRef ref="jef_noise"/><objectRef ref="jef_operator"/></oneOf></array></value></object></oneOf></value></object></array></value></object></oneOf></array>