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

Merge branch 'feature/animals' of Kolja-Strohm-Games/FactoryCraft-Server into master

Kolja Strohm пре 1 месец
родитељ
комит
6bb6467692
224 измењених фајлова са 15225 додато и 6186 уклоњено
  1. 185 0
      ConfigEditor/ConfigEditor.vcxproj
  2. 22 0
      ConfigEditor/ConfigEditor.vcxproj.filters
  3. BIN
      ConfigEditor/data/schriften/ksgs.ltds
  4. BIN
      ConfigEditor/error_core_memory_dump.dmp
  5. 18 2
      FactoryCraft.sln
  6. 0 42
      FactoryCraft/AddEntityUpdate.cpp
  7. 0 19
      FactoryCraft/AddEntityUpdate.h
  8. 22 98
      FactoryCraft/Animal.cpp
  9. 12 17
      FactoryCraft/Animal.h
  10. 1 1
      FactoryCraft/AnimalAI.h
  11. 139 240
      FactoryCraft/BasicBlocks.cpp
  12. 154 72
      FactoryCraft/BasicBlocks.h
  13. 23 21
      FactoryCraft/BasicItems.cpp
  14. 4 5
      FactoryCraft/BasicItems.h
  15. 254 264
      FactoryCraft/BasicTool.cpp
  16. 26 33
      FactoryCraft/BasicTool.h
  17. 156 52
      FactoryCraft/BiomGenerator.cpp
  18. 25 20
      FactoryCraft/BiomGenerator.h
  19. 100 93
      FactoryCraft/Block.cpp
  20. 21 24
      FactoryCraft/Block.h
  21. 15 0
      FactoryCraft/BlockComponent.cpp
  22. 28 0
      FactoryCraft/BlockComponent.h
  23. 83 98
      FactoryCraft/BlockFilter.cpp
  24. 32 51
      FactoryCraft/BlockFilter.h
  25. 4 4
      FactoryCraft/BlockInfoCommand.cpp
  26. 15 22
      FactoryCraft/BlockInstanceGeneratorRule.cpp
  27. 4 4
      FactoryCraft/BlockInstanceGeneratorRule.h
  28. 67 0
      FactoryCraft/BlockReplacementDrop.cpp
  29. 35 0
      FactoryCraft/BlockReplacementDrop.h
  30. 44 8
      FactoryCraft/BlockType.cpp
  31. 97 20
      FactoryCraft/BlockType.h
  32. 16 21
      FactoryCraft/BlockTypeGeneratorRule.cpp
  33. 4 4
      FactoryCraft/BlockTypeGeneratorRule.h
  34. 49 0
      FactoryCraft/BlockTypeNameFactory.cpp
  35. 20 0
      FactoryCraft/BlockTypeNameFactory.h
  36. 2 4
      FactoryCraft/ChatCommand.cpp
  37. 53 116
      FactoryCraft/Chest.cpp
  38. 8 11
      FactoryCraft/Chest.h
  39. 665 460
      FactoryCraft/Chunk.cpp
  40. 24 14
      FactoryCraft/Chunk.h
  41. 13 6
      FactoryCraft/ChunkMap.cpp
  42. 19 39
      FactoryCraft/CraftingStorage.cpp
  43. 9 5
      FactoryCraft/CraftingStorage.h
  44. 54 0
      FactoryCraft/DefaultBlockItemDrop.cpp
  45. 27 0
      FactoryCraft/DefaultBlockItemDrop.h
  46. 67 0
      FactoryCraft/DefaultInventoryDrop.cpp
  47. 27 0
      FactoryCraft/DefaultInventoryDrop.h
  48. 218 157
      FactoryCraft/Dimension.cpp
  49. 16 10
      FactoryCraft/Dimension.h
  50. 417 110
      FactoryCraft/DimensionGenerator.cpp
  51. 50 27
      FactoryCraft/DimensionGenerator.h
  52. 53 0
      FactoryCraft/DropChanceCondition.cpp
  53. 34 0
      FactoryCraft/DropChanceCondition.h
  54. 18 0
      FactoryCraft/DropCondition.h
  55. 218 0
      FactoryCraft/DropConditionOperator.cpp
  56. 103 0
      FactoryCraft/DropConditionOperator.h
  57. 38 0
      FactoryCraft/DropConfig.cpp
  58. 71 0
      FactoryCraft/DropConfig.h
  59. 94 0
      FactoryCraft/DropUsedItemCondition.cpp
  60. 60 0
      FactoryCraft/DropUsedItemCondition.h
  61. 0 25
      FactoryCraft/Effect.h
  62. 0 14
      FactoryCraft/EffectFactory.h
  63. 271 93
      FactoryCraft/Entity.cpp
  64. 20 11
      FactoryCraft/Entity.h
  65. 129 0
      FactoryCraft/EntityGenerator.cpp
  66. 44 0
      FactoryCraft/EntityGenerator.h
  67. 0 22
      FactoryCraft/EntityRemovedUpdate.cpp
  68. 0 19
      FactoryCraft/EntityRemovedUpdate.h
  69. 32 4
      FactoryCraft/EntityType.cpp
  70. 79 7
      FactoryCraft/EntityType.h
  71. 61 10
      FactoryCraft/FactoryCraft.vcxproj
  72. 207 33
      FactoryCraft/FactoryCraft.vcxproj.filters
  73. 553 0
      FactoryCraft/FireBasedProcessingBlockComponent.cpp
  74. 75 0
      FactoryCraft/FireBasedProcessingBlockComponent.h
  75. 2 3
      FactoryCraft/FlattenNoise.cpp
  76. 53 72
      FactoryCraft/FluidBlock.cpp
  77. 4 7
      FactoryCraft/FluidBlock.h
  78. 70 72
      FactoryCraft/FluidContainer.cpp
  79. 13 14
      FactoryCraft/FluidContainer.h
  80. 142 371
      FactoryCraft/Game.cpp
  81. 13 58
      FactoryCraft/Game.h
  82. 268 0
      FactoryCraft/GameClient.cpp
  83. 55 0
      FactoryCraft/GameClient.h
  84. 1 2
      FactoryCraft/GeneratedStructure.cpp
  85. 55 13
      FactoryCraft/GeneratorRule.cpp
  86. 62 17
      FactoryCraft/GeneratorRule.h
  87. 15 6
      FactoryCraft/GeneratorTemplate.h
  88. 19 19
      FactoryCraft/Grass.cpp
  89. 8 11
      FactoryCraft/Grass.h
  90. 49 36
      FactoryCraft/GrowingPlant.cpp
  91. 7 5
      FactoryCraft/GrowingPlant.h
  92. 40 0
      FactoryCraft/InteractionConfig.cpp
  93. 77 0
      FactoryCraft/InteractionConfig.h
  94. 121 78
      FactoryCraft/Inventory.cpp
  95. 30 15
      FactoryCraft/Inventory.h
  96. 14 27
      FactoryCraft/Item.cpp
  97. 6 8
      FactoryCraft/Item.h
  98. 11 7
      FactoryCraft/ItemEntity.cpp
  99. 86 62
      FactoryCraft/ItemFilter.cpp
  100. 41 27
      FactoryCraft/ItemFilter.h
  101. 35 42
      FactoryCraft/ItemModifier.cpp
  102. 16 24
      FactoryCraft/ItemModifier.h
  103. 3 2
      FactoryCraft/ItemSkill.cpp
  104. 14 8
      FactoryCraft/ItemSkill.h
  105. 185 10
      FactoryCraft/ItemSlot.cpp
  106. 17 3
      FactoryCraft/ItemSlot.h
  107. 2 1
      FactoryCraft/ItemStack.cpp
  108. 2 2
      FactoryCraft/ItemType.cpp
  109. 13 9
      FactoryCraft/ItemType.h
  110. 49 0
      FactoryCraft/ItemTypeNameFactory.cpp
  111. 20 0
      FactoryCraft/ItemTypeNameFactory.h
  112. 106 117
      FactoryCraft/JNoise.cpp
  113. 3 3
      FactoryCraft/JNoise.h
  114. 590 297
      FactoryCraft/JsonExpression.cpp
  115. 91 81
      FactoryCraft/JsonExpression.h
  116. 36 33
      FactoryCraft/LightSources.cpp
  117. 4 5
      FactoryCraft/LightSources.h
  118. 81 20
      FactoryCraft/ModelInfo.cpp
  119. 7 6
      FactoryCraft/ModelInfo.h
  120. 16 1
      FactoryCraft/MultiblockStructure.cpp
  121. 11 1
      FactoryCraft/MultiblockStructure.h
  122. 107 0
      FactoryCraft/MultiblockStructureManager.cpp
  123. 19 0
      FactoryCraft/MultiblockStructureManager.h
  124. 27 9
      FactoryCraft/MultiblockTree.cpp
  125. 4 1
      FactoryCraft/MultiblockTree.h
  126. 49 2
      FactoryCraft/NetworkMessage.cpp
  127. 3 1
      FactoryCraft/NetworkMessage.h
  128. 0 0
      FactoryCraft/NeutralAnimalAI.cpp
  129. 6 0
      FactoryCraft/NeutralAnimalAI.h
  130. 5 10
      FactoryCraft/NoBlock.cpp
  131. 3 7
      FactoryCraft/NoBlock.h
  132. 6 1
      FactoryCraft/Noise.cpp
  133. 1 0
      FactoryCraft/Noise.h
  134. 95 0
      FactoryCraft/OpenDialogInteractionConfig.cpp
  135. 41 0
      FactoryCraft/OpenDialogInteractionConfig.h
  136. 43 53
      FactoryCraft/PlaceableProof.cpp
  137. 16 24
      FactoryCraft/PlaceableProof.h
  138. 269 0
      FactoryCraft/PlantConfig.cpp
  139. 63 0
      FactoryCraft/PlantConfig.h
  140. 12 12
      FactoryCraft/Player.cpp
  141. 2 1
      FactoryCraft/Player.h
  142. 7 3
      FactoryCraft/PlayerHand.cpp
  143. 98 106
      FactoryCraft/Quest.cpp
  144. 20 32
      FactoryCraft/Quest.h
  145. 13 15
      FactoryCraft/QuestRequirement.cpp
  146. 16 9
      FactoryCraft/QuestRequirement.h
  147. 23 22
      FactoryCraft/QuestReward.cpp
  148. 22 17
      FactoryCraft/QuestReward.h
  149. 0 5
      FactoryCraft/RandNoise.cpp
  150. 0 1
      FactoryCraft/RandNoise.h
  151. 179 119
      FactoryCraft/Recipie.cpp
  152. 113 37
      FactoryCraft/Recipie.h
  153. 62 0
      FactoryCraft/RecipieGroupConfig.cpp
  154. 31 0
      FactoryCraft/RecipieGroupConfig.h
  155. 16 1
      FactoryCraft/RecipieList.cpp
  156. 4 2
      FactoryCraft/RecipieList.h
  157. 96 30
      FactoryCraft/RecipieLoader.cpp
  158. 2 1
      FactoryCraft/RecipieLoader.h
  159. 2 1
      FactoryCraft/ScaleNoise.cpp
  160. 9 13
      FactoryCraft/Server.cpp
  161. 4 6
      FactoryCraft/Server.h
  162. 8 4
      FactoryCraft/ShapedNoise.cpp
  163. 132 0
      FactoryCraft/SpecificItemDrop.cpp
  164. 40 0
      FactoryCraft/SpecificItemDrop.h
  165. 26 26
      FactoryCraft/Start.cpp
  166. 38 40
      FactoryCraft/StructureCollection.cpp
  167. 6 11
      FactoryCraft/StructureCollection.h
  168. 0 2
      FactoryCraft/TickWorker.cpp
  169. 27 26
      FactoryCraft/TreeSeblingBlock.cpp
  170. 4 4
      FactoryCraft/TreeSeblingBlock.h
  171. 26 34
      FactoryCraft/TreeTemplate.cpp
  172. 4 5
      FactoryCraft/TreeTemplate.h
  173. 64 9
      FactoryCraft/TypeRegistry.cpp
  174. 161 202
      FactoryCraft/TypeRegistry.h
  175. 140 0
      FactoryCraft/UICraftingGrid.cpp
  176. 44 0
      FactoryCraft/UICraftingGrid.h
  177. 135 0
      FactoryCraft/UICraftingProgress.cpp
  178. 44 0
      FactoryCraft/UICraftingProgress.h
  179. 127 0
      FactoryCraft/UIDialogElement.cpp
  180. 37 0
      FactoryCraft/UIDialogElement.h
  181. 202 0
      FactoryCraft/UIElement.cpp
  182. 300 0
      FactoryCraft/UIElement.h
  183. 135 0
      FactoryCraft/UIFuelState.cpp
  184. 43 0
      FactoryCraft/UIFuelState.h
  185. 159 0
      FactoryCraft/UIInventory.cpp
  186. 45 0
      FactoryCraft/UIInventory.h
  187. 80 0
      FactoryCraft/UIObservable.cpp
  188. 38 0
      FactoryCraft/UIObservable.h
  189. 153 0
      FactoryCraft/UIReference.cpp
  190. 93 0
      FactoryCraft/UIReference.h
  191. 65 0
      FactoryCraft/UIText.cpp
  192. 31 0
      FactoryCraft/UIText.h
  193. 64 20
      FactoryCraft/WorldGenerator.cpp
  194. 6 1
      FactoryCraft/WorldGenerator.h
  195. 2 3
      FactoryCraft/WorldLoader.cpp
  196. 0 1
      FactoryCraft/WorldLoader.h
  197. 0 30
      FactoryCraft/WorldUpdate.cpp
  198. 0 35
      FactoryCraft/WorldUpdate.h
  199. 103 53
      FactoryCraft/WormCaveGenerator.cpp
  200. 5 4
      FactoryCraft/WormCaveGenerator.h
  201. 4 4
      NoiseTest/NoiseTest.vcxproj
  202. 69 14
      Windows Version/Windows Version.vcxproj
  203. 204 30
      Windows Version/Windows Version.vcxproj.filters
  204. 973 147
      Windows Version/data/blocks/blockTypes.json
  205. 239 0
      Windows Version/data/blocks/plants.json
  206. 13 0
      Windows Version/data/entities/animals.json
  207. 569 644
      Windows Version/data/generator/overworld.json
  208. 104 17
      Windows Version/data/items/itemTypes.json
  209. BIN
      Windows Version/data/models/blocks.m3
  210. BIN
      Windows Version/data/models/entities.m3
  211. BIN
      Windows Version/data/models/items.m3
  212. BIN
      Windows Version/data/models/plants.m3
  213. BIN
      Windows Version/data/models/tools.m3
  214. 61 61
      Windows Version/data/quests/quests.json
  215. 10 0
      Windows Version/data/recipieGroups/groups.json
  216. 38 35
      Windows Version/data/recipies/basicItems.json
  217. 206 103
      Windows Version/data/recipies/blocks.json
  218. 23 0
      Windows Version/data/recipies/fire.json
  219. 53 53
      Windows Version/data/recipies/tools.json
  220. BIN
      Windows Version/error_core_memory_dump.dmp
  221. 165 0
      assembly/assembly.vcxproj
  222. 27 0
      assembly/assembly.vcxproj.filters
  223. 307 0
      assembly/start.cpp
  224. 18 0
      assembly/test.asm

+ 185 - 0
ConfigEditor/ConfigEditor.vcxproj

@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{1ef64c4f-fdb8-4c8e-9d85-b71937ddcadd}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>ConfigEditor</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <IncludePath>..\..\..\..\..\Allgemein\Framework;..\FactoryCraft;..\..\..\..\..\Allgemein\Network\Network;..\..\..\..\..\Allgemein\Network;$(IncludePath)</IncludePath>
+    <LibraryPath>..\..\..\..\..\Allgemein\Framework\x64\debug;..\..\..\..\..\Allgemein\Network\x64\debug;$(LibraryPath)</LibraryPath>
+    <SourcePath>..\FactoryCraft;$(SourcePath)</SourcePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>..\..\Framework;$(IncludePath)</IncludePath>
+    <LibraryPath>..\..\Framework\Release;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>..\..\..\..\..\Allgemein\Framework;..\FactoryCraft;..\..\..\..\..\Allgemein\Network\Network;..\..\..\..\..\Allgemein\Network;$(IncludePath)</IncludePath>
+    <LibraryPath>..\..\..\..\..\Allgemein\Framework\x64\release;..\..\..\..\..\Allgemein\Network\x64\release;$(LibraryPath)</LibraryPath>
+    <SourcePath>..\FactoryCraft;$(SourcePath)</SourcePath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>Framework.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <LanguageStandard>stdcpp20</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>Framework.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <CustomBuildStep>
+      <Command>copy ..\..\..\..\..\Allgemein\Network\x64\debug\Network.dll Network.dll
+copy ..\..\..\..\..\Allgemein\Framework\x64\debug\Framework.dll Framework.dll</Command>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>kopieren...;%(Outputs)</Outputs>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>Framework.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <CustomBuildStep>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>kopieren...;%(Outputs)</Outputs>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <LanguageStandard>stdcpp20</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>Framework.lib;Network.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <CustomBuildStep>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>kopieren...;%(Outputs)</Outputs>
+      <Command>copy ..\..\..\..\..\Allgemein\Network\x64\release\Network.dll Network.dll
+copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 22 - 0
ConfigEditor/ConfigEditor.vcxproj.filters

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Quelldateien">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Headerdateien">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Ressourcendateien">
+      <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>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp">
+      <Filter>Headerdateien</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

BIN
ConfigEditor/data/schriften/ksgs.ltds


BIN
ConfigEditor/error_core_memory_dump.dmp


+ 18 - 2
FactoryCraft.sln

@@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Windows Version", "Windows
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NoiseTest", "NoiseTest\NoiseTest.vcxproj", "{096A454C-3835-4A4E-89FE-34EDCCD80467}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "assembly", "assembly\assembly.vcxproj", "{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|ARM = Debug|ARM
@@ -28,8 +30,6 @@ Global
 		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|ARM64.Build.0 = Debug|ARM64
 		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|ARM64.Deploy.0 = Debug|ARM64
 		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|x64.ActiveCfg = Debug|x64
-		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|x64.Build.0 = Debug|x64
-		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|x64.Deploy.0 = Debug|x64
 		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|x86.ActiveCfg = Debug|x86
 		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|x86.Build.0 = Debug|x86
 		{A1B59831-7E37-4F83-A545-0E27609E8295}.Debug|x86.Deploy.0 = Debug|x86
@@ -77,6 +77,22 @@ Global
 		{096A454C-3835-4A4E-89FE-34EDCCD80467}.Release|x64.Build.0 = Release|x64
 		{096A454C-3835-4A4E-89FE-34EDCCD80467}.Release|x86.ActiveCfg = Release|Win32
 		{096A454C-3835-4A4E-89FE-34EDCCD80467}.Release|x86.Build.0 = Release|Win32
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|ARM.ActiveCfg = Debug|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|ARM.Build.0 = Debug|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|ARM64.ActiveCfg = Debug|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|ARM64.Build.0 = Debug|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|x64.ActiveCfg = Debug|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|x64.Build.0 = Debug|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|x86.ActiveCfg = Debug|Win32
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Debug|x86.Build.0 = Debug|Win32
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|ARM.ActiveCfg = Release|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|ARM.Build.0 = Release|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|ARM64.ActiveCfg = Release|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|ARM64.Build.0 = Release|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|x64.ActiveCfg = Release|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|x64.Build.0 = Release|x64
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|x86.ActiveCfg = Release|Win32
+		{1C0B0808-0D8E-49A6-87C2-1D03CA6B937D}.Release|x86.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 42
FactoryCraft/AddEntityUpdate.cpp

@@ -1,42 +0,0 @@
-#include "AddEntityUpdate.h"
-
-#include "Dimension.h"
-#include "Entity.h"
-#include "EntityType.h"
-
-AddEntityUpdate::AddEntityUpdate(Entity* entity, int dimension)
-    : WorldUpdate(WorldUpdateTypeEnum::ADD_ENTITY, dimension, entity->getLocation()),
-      entity(entity)
-{}
-
-AddEntityUpdate::~AddEntityUpdate()
-{
-    entity->release();
-}
-
-void AddEntityUpdate::onUpdate(Dimension* zDimension)
-{
-    zDimension->addEntity(dynamic_cast<Entity*>(entity->getThis()));
-}
-
-void AddEntityUpdate::write(Framework::StreamWriter* zWriter)
-{
-    int id = entity->zType()->getId();
-    zWriter->schreibe((char*)&id, 4);
-    id = entity->getId();
-    zWriter->schreibe((char*)&id, 4);
-    Framework::Vec3<float> pos = entity->getPosition();
-    zWriter->schreibe((char*)&pos.x, 4);
-    zWriter->schreibe((char*)&pos.y, 4);
-    zWriter->schreibe((char*)&pos.z, 4);
-    float maxSpeed = entity->getMaxSpeed();
-    zWriter->schreibe((char*)&maxSpeed, 4);
-    float gravityMultiplier = entity->getGravityMultiplier();
-    zWriter->schreibe((char*)&gravityMultiplier, 4);
-    float jumpSpeed = entity->getJumpSpeed();
-    zWriter->schreibe((char*)&jumpSpeed, 4);
-    bool special = !entity->hasDefaultModel();
-    zWriter->schreibe((char*)&special, 1);
-    if (special) entity->zSpecialModel()->writeTo(zWriter);
-
-}

+ 0 - 19
FactoryCraft/AddEntityUpdate.h

@@ -1,19 +0,0 @@
-#pragma once
-#include "WorldUpdate.h"
-
-class Entity;
-
-class AddEntityUpdate : public WorldUpdate
-{
-private:
-    Entity* entity;
-
-protected:
-    void write(Framework::StreamWriter* zWriter) override;
-
-public:
-    AddEntityUpdate(Entity* entity, int dimension);
-    ~AddEntityUpdate();
-
-    void onUpdate(Dimension* zDimension) override;
-};

+ 22 - 98
FactoryCraft/Animal.cpp

@@ -1,9 +1,7 @@
 #include "Animal.h"
 
-#include "AddEntityUpdate.h"
+#include "Dimension.h"
 #include "Game.h"
-#include "ItemEntity.h"
-#include "ItemStack.h"
 #include "TypeRegistry.h"
 
 Animal::Animal(
@@ -19,50 +17,6 @@ Animal::~Animal()
     }
 }
 
-void Animal::onDeath()
-{
-    if (!removed)
-    {
-        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()));
-                    }
-                }
-            }
-        }
-    }
-    Entity::onDeath();
-}
-
-void Animal::setSpawns(const Framework::Array<SpawnConfig>& spawnConfig)
-{
-    spawns = spawnConfig;
-}
-
 void Animal::setAI(AnimalAI* ai)
 {
     if (this->ai)
@@ -77,13 +31,14 @@ bool Animal::interact(Item* zItem, Entity* zActor)
     return false;
 }
 
-void Animal::takeDamage(Entity* zSource, float damage)
+void Animal::takeDamage(
+    Entity* zSource, Item* zUsedItem, ItemSkill* zUsedSkill, float damage)
 {
     if (damage > 0)
     {
         ai->onDamage(zSource, damage);
     }
-    Entity::takeDamage(zSource, damage);
+    Entity::takeDamage(zSource, zUsedItem, zUsedSkill, damage);
 }
 
 void Animal::tick(const Dimension* zDimension)
@@ -91,8 +46,8 @@ void Animal::tick(const Dimension* zDimension)
     Entity::tick(zDimension);
 }
 
-AnimalEntityType::AnimalEntityType(Framework::Text name, ModelInfo* model)
-    : EntityType(name, model)
+AnimalEntityType::AnimalEntityType()
+    : EntityType()
 {}
 
 AnimalEntityType::~AnimalEntityType()
@@ -119,70 +74,39 @@ Entity* AnimalEntityType::createEntity(
     Framework::Vec3<float> position, int dimensionId, int entityId) const
 {
     Animal* result = new Animal(getId(), position, dimensionId, entityId);
-    result->setAI(Game::INSTANCE->zTypeRegistry()->fromJson<AnimalAI>(ai));
-    result->setSpawns(spawns);
+    // result->setAI(Game::INSTANCE->zTypeRegistry()->fromJson<AnimalAI>(ai));
     return result;
 }
 
 AnimalEntityTypeFactory::AnimalEntityTypeFactory()
-    : SubTypeFactory()
+    : EntityTypeFactoryBase()
 {}
 
 AnimalEntityType* AnimalEntityTypeFactory::createValue(
     Framework::JSON::JSONObject* zJson) const
 {
-    Framework::Text name = zJson->zValue("typeName")->asString()->getString();
-    AnimalEntityType* result = new AnimalEntityType(name,
-        Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
-            zJson->zValue("model")));
+    AnimalEntityType* result = new AnimalEntityType();
+    result->ai = zJson->getValue("ai")->asObject();
     return result;
 }
 
-void AnimalEntityTypeFactory::fromJson(
-    AnimalEntityType* zResult, Framework::JSON::JSONObject* zJson) const
+void AnimalEntityTypeFactory::addToJson(
+    Framework::JSON::JSONObject* zJson, AnimalEntityType* zObject) const
 {
-    Framework::JSON::JSONArray* spawnsJson = zJson->zValue("spawns")->asArray();
-    for (int i = 0; i < spawnsJson->getLength(); i++)
-    {
-        Framework::JSON::JSONObject* spawnJson
-            = spawnsJson->zValue(i)->asObject();
-        zResult->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,
-        });
-    }
-    zResult->ai = zJson->getValue("ai")->asObject();
+    zJson->addValue("ai", zObject->ai->clone());
 }
 
-void AnimalEntityTypeFactory::toJson(
-    AnimalEntityType* zObject, Framework::JSON::JSONObject* zResult) const
+const char* AnimalEntityTypeFactory::getTypeToken() const
 {
-    Framework::JSON::JSONArray* spawnsJson = new Framework::JSON::JSONArray();
-    for (int i = 0; i < zObject->spawns.getEintragAnzahl(); i++)
-    {
-        SpawnConfig spawn = zObject->spawns.get(i);
-        Framework::JSON::JSONObject* spawnJson
-            = new Framework::JSON::JSONObject();
-        spawnJson->addValue("min", new Framework::JSON::JSONNumber(spawn.min));
-        spawnJson->addValue("max", new Framework::JSON::JSONNumber(spawn.max));
-        spawnJson->addValue(
-            "chance", new Framework::JSON::JSONNumber(spawn.chance));
-        spawnJson->addValue(
-            "itemType", new Framework::JSON::JSONString(spawn.itemTypeName));
-        spawnsJson->addValue(spawnJson);
-    }
-    zResult->addValue("spawns", spawnsJson);
-    zResult->addValue(
-        "typeName", new Framework::JSON::JSONString(zObject->getName()));
-    zResult->addValue(
-        "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
-    zResult->addValue("ai", zObject->ai->clone());
+    return "animal";
 }
 
-Framework::Text AnimalEntityTypeFactory::getTypeToken() const
+JSONObjectValidationBuilder* AnimalEntityTypeFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
 {
-    return "animal";
+    return EntityTypeFactoryBase::addToValidator(builder)
+        /* TODO: write AnimalAI factories
+        ->withRequiredAttribute(
+        "ai", Game::INSTANCE->zTypeRegistry()->getValidator<AnimalAI>())*/
+        ;
 }

+ 12 - 17
FactoryCraft/Animal.h

@@ -1,29 +1,26 @@
 #pragma once
 
 #include "AnimalAI.h"
-#include "BasicBlocks.h"
 #include "Entity.h"
 #include "EntityType.h"
 
 class Animal : public Entity
 {
 private:
-    Framework::Array<SpawnConfig> spawns;
     AnimalAI* ai;
 
-protected:
-    void onDeath() override;
-
 public:
     Animal(int typeId,
         Framework::Vec3<float> location,
         int dimensionId,
         int entityId);
     ~Animal();
-    void setSpawns(const Framework::Array<SpawnConfig>& spawnConfig);
     void setAI(AnimalAI* ai);
     bool interact(Item* zItem, Entity* zActor) override;
-    void takeDamage(Entity* zSource, float damage) override;
+    void takeDamage(Entity* zSource,
+        Item* zUsedItem,
+        ItemSkill* zUsedSkill,
+        float damage) override;
     void tick(const Dimension* zDimension) override;
 };
 
@@ -33,7 +30,6 @@ class AnimalEntityType : public EntityType
 {
 private:
     Framework::JSON::JSONObject* ai;
-    Framework::Array<SpawnConfig> spawns;
 
 protected:
     virtual void loadSuperEntity(
@@ -42,7 +38,7 @@ protected:
         Entity* zEntity, Framework::StreamWriter* zWriter) const;
 
 public:
-    AnimalEntityType(Framework::Text name, ModelInfo* model);
+    AnimalEntityType();
     ~AnimalEntityType();
 
     Entity* createEntity(Framework::Vec3<float> position,
@@ -52,16 +48,15 @@ public:
     friend AnimalEntityTypeFactory;
 };
 
-class AnimalEntityTypeFactory
-    : public SubTypeFactory<EntityType, AnimalEntityType>
+class AnimalEntityTypeFactory : public EntityTypeFactoryBase<AnimalEntityType>
 {
 public:
     AnimalEntityTypeFactory();
-    AnimalEntityType* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(AnimalEntityType* zResult,
+    virtual AnimalEntityType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(AnimalEntityType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
-    Framework::Text getTypeToken() const override;
+    virtual void addToJson(Framework::JSON::JSONObject* zJson,
+        AnimalEntityType* zObject) const override;
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
 };

+ 1 - 1
FactoryCraft/AnimalAI.h

@@ -27,4 +27,4 @@ public:
     virtual void onEntityEntersView(Entity* zEntity);
     virtual void onEntityLeavesView(Entity* zEntity);
     virtual int desideAction() = 0;
-};
+};

+ 139 - 240
FactoryCraft/BasicBlocks.cpp

@@ -1,11 +1,10 @@
 #include "BasicBlocks.h"
 
-#include "AddEntityUpdate.h"
+#include "BlockType.h"
 #include "Game.h"
-#include "ItemEntity.h"
+#include "ItemSlot.h"
+#include "ItemType.h"
 #include "ModelInfo.h"
-#include "TreeSeblingBlock.h"
-#include "ItemStack.h"
 
 BasicBlock::BasicBlock(int typeId, Framework::Vec3<int> pos, int dimensionId)
     : BasicBlock(typeId, pos, dimensionId, false)
@@ -16,13 +15,94 @@ BasicBlock::BasicBlock(
     : Block(typeId, pos, dimensionId, hasInventory)
 {}
 
+void BasicBlock::addComponent(BlockComponent* component)
+{
+    components.add(component);
+}
+
+Framework::XML::Element* BasicBlock::getTargetUIML() const
+{
+    Framework::XML::Element* element
+        = Block::getTargetUIML(); // Get the base element from Block class
+    int index = 0;
+    Framework::XML::Element* last
+        = element->getChildCount() > 0
+            ? element->zChild(element->getChildCount() - 1)
+            : 0;
+    for (BlockComponent* component : components)
+    {
+        Framework::XML::Element* compElement = component->getTooltipUIML();
+        if (compElement)
+        {
+            if (last)
+            {
+                if (!last->hasAttribute("id"))
+                {
+                    last->setAttribute(
+                        "id", Framework::Text("_component_") + (index - 1));
+                }
+                compElement->setAttribute(
+                    "alignTop", last->getAttributeValue("id"));
+                compElement->setAttribute("marginTop", "5");
+            }
+            element->addChild(compElement);
+            last = compElement;
+        }
+        index++;
+    }
+    return element;
+}
+
 bool BasicBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
 {
-    return 0;
+    bool ative = false;
+    for (BlockComponent* component : components)
+    {
+        ative |= component->tick(numTicks);
+    }
+    return ative;
 }
 
 void BasicBlock::onPostTick() {}
 
+void BasicBlock::getLightEmisionColor(unsigned char* result) const
+{
+    Block::getLightEmisionColor(result);
+    for (BlockComponent* component : components)
+    {
+        int color = component->getLightColor();
+        result[0] = (unsigned char)MIN(result[0] + ((color >> 16) & 0xFF), 255);
+        result[1] = (unsigned char)MIN(result[1] + ((color >> 8) & 0xFF), 255);
+        result[2] = (unsigned char)MIN(result[2] + (color & 0xFF), 255);
+    }
+}
+
+TickSourceType BasicBlock::isTickSource() const
+{
+    return components.getEintragAnzahl() > 0 ? TickSourceType::EACH_TICK
+                                             : TickSourceType::NONE;
+}
+
+void BasicBlock::onApiCall(char messageType,
+    Framework::StreamReader* zRequest,
+    NetworkMessage* zResponse,
+    Entity* zSource)
+{
+    switch (messageType)
+    {
+    case 2: // component request
+        {
+            int index;
+            zRequest->lese((char*)&index, sizeof(int));
+            if (index >= 0 && index < components.getEintragAnzahl())
+            {
+                components.z(index)->api(zRequest, zResponse, zSource);
+            }
+            break;
+        }
+    }
+}
+
 BasicBlockType::BasicBlockType()
     : BlockType(),
       itemTypeName(),
@@ -45,6 +125,28 @@ bool BasicBlockType::initialize(Game* zGame)
     return itemTypeId >= 0 && BlockType::initialize(zGame);
 }
 
+void BasicBlockType::loadSuperBlock(
+    Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
+{
+    BasicBlock* block = dynamic_cast<BasicBlock*>(zBlock);
+    for (BlockComponent* component : block->components)
+    {
+        component->loadComponent(zReader);
+    }
+    BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
+}
+
+void BasicBlockType::saveSuperBlock(
+    Block* zBlock, Framework::StreamWriter* zWriter) const
+{
+    BasicBlock* block = dynamic_cast<BasicBlock*>(zBlock);
+    for (BlockComponent* component : block->components)
+    {
+        component->saveComponent(zWriter);
+    }
+    BlockType::saveSuperBlock(zBlock, zWriter);
+}
+
 void BasicBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
 {
     BasicBlock* block = dynamic_cast<BasicBlock*>(zBlock);
@@ -55,17 +157,34 @@ void BasicBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
     block->hardness = getHardness();
     block->speedModifier = speedModifier;
     block->interactable = interactable;
+    for (ItemSlot* slot : itemSlots)
+    {
+        block->addSlot(new ItemSlot(*slot));
+    }
+    for (Framework::JSON::JSONValue* component : components)
+    {
+        BlockComponent* blockComponent
+            = Game::INSTANCE->zTypeRegistry()->fromJson<BlockComponent>(
+                component);
+        blockComponent->initialize(block);
+        block->addComponent(blockComponent);
+    }
     BlockType::createSuperBlock(zBlock, zItem);
 }
 
 Block* BasicBlockType::createBlock(
     Framework::Vec3<int> position, int dimensionId) const
 {
-    return new BasicBlock(getId(), position, dimensionId);
+    return new BasicBlock(
+        getId(), position, dimensionId, itemSlots.getEintragAnzahl() > 0);
 }
 
 Item* BasicBlockType::createItem() const
 {
+    if (getItemTypeName().istGleich(""))
+    {
+        return 0;
+    }
     return Game::INSTANCE->zItemType(itemTypeId)->createItem();
 }
 
@@ -76,6 +195,10 @@ Framework::Text BasicBlockType::getItemTypeName() const
 
 ItemType* BasicBlockType::createItemType() const
 {
+    if (getItemTypeName().istGleich(""))
+    {
+        return 0;
+    }
     return new BasicBlockItemType(getItemTypeName(),
         new ModelInfo(zModel()->getModelPath(),
             zModel()->getTexturePaths(),
@@ -85,7 +208,7 @@ ItemType* BasicBlockType::createItemType() const
         passable,
         getHardness(),
         speedModifier,
-        getItemTypeName(),
+        getName(),
         0,
         50,
         getGroupNames());
@@ -141,247 +264,23 @@ bool BasicBlockType::isInteractable() const
     return interactable;
 }
 
-BasicBlockTypeFactory::BasicBlockTypeFactory()
-    : BlockTypeFactoryBase()
-{}
-
-BasicBlockType* BasicBlockTypeFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new BasicBlockType();
-}
-
-void BasicBlockTypeFactory::fromJson(
-    BasicBlockType* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setItemTypeName(
-        zJson->zValue("itemType")->asString()->getString());
-    zResult->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
-    zResult->setPassable(zJson->zValue("passable")->asBool()->getBool());
-    zResult->setSpeedModifier(
-        (float)zJson->zValue("speedModifier")->asNumber()->getNumber());
-    zResult->setInteractable(
-        (float)zJson->zValue("interactable")->asBool()->getBool());
-    BlockTypeFactoryBase::fromJson(zResult, zJson);
-}
-
-void BasicBlockTypeFactory::toJson(
-    BasicBlockType* zObject, Framework::JSON::JSONObject* zResult) const
+const Framework::RCArray<ItemSlot>& BasicBlockType::getInventorySlots() const
 {
-    zResult->addValue("itemType",
-        new Framework::JSON::JSONString(zObject->getItemTypeName()));
-    zResult->addValue(
-        "transparent", new Framework::JSON::JSONBool(zObject->isTransparent()));
-    zResult->addValue(
-        "passable", new Framework::JSON::JSONBool(zObject->isPassable()));
-    zResult->addValue("speedModifier",
-        new Framework::JSON::JSONNumber(zObject->getSpeedModifier()));
-    zResult->addValue("interactable",
-        new Framework::JSON::JSONBool(zObject->isInteractable()));
-    BlockTypeFactoryBase::toJson(zObject, zResult);
+    return itemSlots;
 }
 
-JSONObjectValidationBuilder* BasicBlockTypeFactory::addToValidator(
-    JSONObjectValidationBuilder* builder) const
+void BasicBlockType::addInventorySlot(ItemSlot* slot)
 {
-    return BlockTypeFactoryBase::addToValidator(
-        builder->withRequiredString("itemType")
-            ->withDefault("")
-            ->finishString()
-            ->withRequiredBool("transparent")
-            ->withDefault(false)
-            ->finishBool()
-            ->withRequiredBool("passable")
-            ->withDefault(false)
-            ->finishBool()
-            ->withRequiredNumber("speedModifier")
-            ->withDefault(1.0)
-            ->finishNumber()
-            ->withRequiredBool("interactable")
-            ->withDefault(true)
-            ->finishBool());
-}
-
-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();
-}
-
-AdditionalItemSpawningBlockType::AdditionalItemSpawningBlockType()
-    : BasicBlockType(),
-      spawns()
-{}
-
-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);
-}
-
-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;
-}
-
-void AdditionalItemSpawningBlockType::addSpawn(SpawnConfig config)
-{
-    spawns.add(config);
-}
-
-const Framework::Array<SpawnConfig>&
-AdditionalItemSpawningBlockType::getSpawns() const
-{
-    return spawns;
-}
-
-AdditionalItemSpawningBlockTypeFactory::AdditionalItemSpawningBlockTypeFactory()
-    : BlockTypeFactoryBase()
-{}
-
-AdditionalItemSpawningBlockType*
-AdditionalItemSpawningBlockTypeFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new AdditionalItemSpawningBlockType();
-}
-
-void AdditionalItemSpawningBlockTypeFactory::fromJson(
-    AdditionalItemSpawningBlockType* zResult,
-    Framework::JSON::JSONObject* zJson) const
-{
-    Framework::JSON::JSONArray* spawnsJson = zJson->zValue("spawns")->asArray();
-    for (int i = 0; i < spawnsJson->getLength(); i++)
-    {
-        Framework::JSON::JSONObject* spawnJson
-            = spawnsJson->zValue(i)->asObject();
-        zResult->addSpawn(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,
-        });
-    }
-    super.fromJson(zResult, zJson);
-}
-
-void AdditionalItemSpawningBlockTypeFactory::toJson(
-    AdditionalItemSpawningBlockType* zObject,
-    Framework::JSON::JSONObject* zResult) const
-{
-    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);
-    }
-    zResult->addValue("spawns", spawns);
-    return super.toJson(zObject, zResult);
+    itemSlots.add(slot);
 }
 
-JSONObjectValidationBuilder*
-AdditionalItemSpawningBlockTypeFactory::addToValidator(
-    JSONObjectValidationBuilder* builder) const
+const Framework::RCArray<Framework::JSON::JSONValue>&
+BasicBlockType::getComponents() const
 {
-    return super.addToValidator(
-        builder->withRequiredAttribute("spawns",
-            Framework::JSON::Validator::JSONValidator::buildForArray()
-                ->addAcceptedObjectInArray()
-                ->withRequiredString("itemType")
-                ->finishString()
-                ->withRequiredNumber("chance")
-                ->finishNumber()
-                ->withRequiredNumber("min")
-                ->finishNumber()
-                ->withRequiredNumber("max")
-                ->finishNumber()
-                ->finishObject()
-                ->finishArray()));
+    return components;
 }
 
-Framework::Text AdditionalItemSpawningBlockTypeFactory::getTypeToken() const
+void BasicBlockType::addComponent(Framework::JSON::JSONValue* component)
 {
-    return "additionalItemsBlockType";
+    components.add(component);
 }

+ 154 - 72
FactoryCraft/BasicBlocks.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "Block.h"
+#include "BlockComponent.h"
 #include "BlockType.h"
 #include "Item.h"
 #include "TypeRegistry.h"
@@ -11,28 +12,30 @@ class BasicBlockType;
 
 class BasicBlock : public Block
 {
+private:
+    Framework::RCArray<BlockComponent> components;
+
 public:
     BasicBlock(int typeId, Framework::Vec3<int> pos, int dimensionId);
     BasicBlock(int typeId,
         Framework::Vec3<int> pos,
         int dimensionId,
         bool hasInventory);
+    void addComponent(BlockComponent* component);
+    virtual Framework::XML::Element* getTargetUIML() const override;
     virtual bool onTick(
         TickQueue* zQueue, int numTicks, bool& blocked) override;
     virtual void onPostTick() override;
+    void getLightEmisionColor(unsigned char* result) const override;
+    virtual TickSourceType isTickSource() const override;
+    virtual void onApiCall(char messageType,
+        Framework::StreamReader* zRequest,
+        NetworkMessage* zResponse,
+        Entity* zSource) override;
 
     friend BasicBlockType;
 };
 
-struct SpawnConfig
-{
-    int min;
-    int max;
-    double chance;
-    Framework::Text itemTypeName;
-    int typeId;
-};
-
 class BasicBlockType : public BlockType
 {
 private:
@@ -42,13 +45,22 @@ private:
     bool passable;
     float speedModifier;
     bool interactable;
+    Framework::RCArray<ItemSlot> itemSlots;
+    Framework::RCArray<Framework::JSON::JSONValue> components;
+
+public:
+    BasicBlockType();
+    virtual bool initialize(Game* zGame) override;
 
 protected:
+    virtual void loadSuperBlock(Block* zBlock,
+        Framework::StreamReader* zReader,
+        int dimensionId) const override;
+    virtual void saveSuperBlock(
+        Block* zBlock, Framework::StreamWriter* zWriter) const override;
     virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
 
 public:
-    BasicBlockType();
-    virtual bool initialize(Game* zGame) override;
     virtual Block* createBlock(
         Framework::Vec3<int> position, int dimensionId) const override;
     virtual Item* createItem() const override;
@@ -64,69 +76,139 @@ public:
     float getSpeedModifier() const;
     void setInteractable(bool interactable);
     bool isInteractable() const;
+    const Framework::RCArray<ItemSlot>& getInventorySlots() const;
+    void addInventorySlot(ItemSlot* slot);
+    const Framework::RCArray<Framework::JSON::JSONValue>& getComponents() const;
+    void addComponent(Framework::JSON::JSONValue* component);
 };
 
-class BasicBlockTypeFactory : public BlockTypeFactoryBase<BasicBlockType>
-{
-public:
-    BasicBlockTypeFactory();
-    BasicBlockType* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BasicBlockType* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BasicBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
-    JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
-};
-
-class AdditionalItemSpawningBlock : public BasicBlock
-{
-private:
-    Framework::Array<SpawnConfig> spawns;
-
-public:
-    AdditionalItemSpawningBlock(
-        int typeId, Framework::Vec3<int> pos, int dimensionId);
-    void addSpawn(SpawnConfig config);
-    virtual void onDestroy() override;
-};
-
-class AdditionalItemSpawningBlockType : public BasicBlockType
+template<class T,
+    typename = std::enable_if<std::is_base_of<BasicBlockType, T>::value>>
+class BasicBlockTypeFactory : public BlockTypeFactoryBase<T>
 {
-private:
-    Framework::Array<SpawnConfig> spawns;
-
-public:
-    AdditionalItemSpawningBlockType();
-
-protected:
-    virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
-
-public:
-    virtual bool initialize(Game* zGame) override;
-    virtual Block* createBlock(
-        Framework::Vec3<int> position, int dimensionId) const override;
-    void addSpawn(SpawnConfig config);
-    const Framework::Array<SpawnConfig>& getSpawns() const;
-};
-
-class AdditionalItemSpawningBlockTypeFactory
-    : public BlockTypeFactoryBase<AdditionalItemSpawningBlockType>
-{
-private:
-    BasicBlockTypeFactory super;
-
 public:
-    AdditionalItemSpawningBlockTypeFactory();
-    AdditionalItemSpawningBlockType* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(AdditionalItemSpawningBlockType* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(AdditionalItemSpawningBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
-    JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    BasicBlockTypeFactory()
+        : BlockTypeFactoryBase<T>()
+    {}
+
+    virtual T* createValue(Framework::JSON::JSONObject* zJson) const override
+    {
+        return (T*)new BasicBlockType();
+    }
+
+    virtual T* fromJson(Framework::JSON::JSONObject* zJson) const override
+    {
+        T* result = BlockTypeFactoryBase<T>::fromJson(zJson);
+        if (zJson->zValue("itemType")->getType()
+            == Framework::AbstractType::STRING)
+        {
+            result->setItemTypeName(
+                zJson->zValue("itemType")->asString()->getString());
+        }
+        else
+        {
+            result->setItemTypeName("");
+        }
+        result->setTransparent(
+            zJson->zValue("transparent")->asBool()->getBool());
+        result->setPassable(zJson->zValue("passable")->asBool()->getBool());
+        result->setSpeedModifier(
+            (float)zJson->zValue("speedModifier")->asNumber()->getNumber());
+        result->setInteractable(
+            (float)zJson->zValue("interactable")->asBool()->getBool());
+        for (Framework::JSON::JSONValue* value :
+            *zJson->zValue("inventorySlots")->asArray())
+        {
+            result->addInventorySlot(
+                Game::INSTANCE->zTypeRegistry()->fromJson<ItemSlot>(
+                    value->asObject()));
+        }
+        for (Framework::JSON::JSONValue* component :
+            *zJson->zValue("components")->asArray())
+        {
+            result->addComponent(dynamic_cast<Framework::JSON::JSONValue*>(
+                component->getThis()));
+        }
+        return result;
+    }
+
+    virtual Framework::JSON::JSONObject* toJsonObject(T* zObject) const override
+    {
+        Framework::JSON::JSONObject* result
+            = BlockTypeFactoryBase<T>::toJsonObject(zObject);
+        if (zObject->getItemTypeName().istGleich(""))
+        {
+            result->addValue("itemType", new Framework::JSON::JSONValue());
+        }
+        else
+        {
+            result->addValue("itemType",
+                new Framework::JSON::JSONString(zObject->getItemTypeName()));
+        }
+        result->addValue("transparent",
+            new Framework::JSON::JSONBool(zObject->isTransparent()));
+        result->addValue(
+            "passable", new Framework::JSON::JSONBool(zObject->isPassable()));
+        result->addValue("speedModifier",
+            new Framework::JSON::JSONNumber(zObject->getSpeedModifier()));
+        result->addValue("interactable",
+            new Framework::JSON::JSONBool(zObject->isInteractable()));
+        Framework::JSON::JSONArray* inventorySlots
+            = new Framework::JSON::JSONArray();
+        for (ItemSlot* slot : zObject->getInventorySlots())
+        {
+            inventorySlots->addValue(
+                Game::INSTANCE->zTypeRegistry()->toJson<ItemSlot>(slot));
+        }
+        result->addValue("inventorySlots", inventorySlots);
+        Framework::JSON::JSONArray* components
+            = new Framework::JSON::JSONArray();
+        for (Framework::JSON::JSONValue* component : zObject->getComponents())
+        {
+            components->addValue(dynamic_cast<Framework::JSON::JSONValue*>(
+                component->getThis()));
+        }
+        result->addValue("components", components);
+        return result;
+    }
+
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override
+    {
+        return BlockTypeFactoryBase<T>::addToValidator(
+            builder
+                ->withRequiredAttribute("itemType",
+                    Game::INSTANCE->zTypeRegistry()
+                        ->getValidator<Framework::Text>(
+                            ItemTypeNameFactory::TYPE_ID),
+                    true,
+                    false)
+                ->withRequiredBool("transparent")
+                ->withDefault(false)
+                ->finishBool()
+                ->withRequiredBool("passable")
+                ->withDefault(false)
+                ->finishBool()
+                ->withRequiredNumber("speedModifier")
+                ->withDefault(1.0)
+                ->finishNumber()
+                ->withRequiredBool("interactable")
+                ->withDefault(true)
+                ->finishBool())
+            ->withRequiredArray("inventorySlots")
+            ->withDefault(new Framework::JSON::JSONArray())
+            ->addAcceptedTypeInArray(
+                Game::INSTANCE->zTypeRegistry()->getValidator<ItemSlot>())
+            ->finishArray()
+            ->withRequiredArray("components")
+            ->withDefault(new Framework::JSON::JSONArray())
+            ->addAcceptedTypeInArray(
+                Game::INSTANCE->zTypeRegistry()->getValidator<BlockComponent>())
+            ->finishArray();
+    }
+
+    virtual const char* getTypeToken() const override
+    {
+        return "basicBlock";
+    }
 };

+ 23 - 21
FactoryCraft/BasicItems.cpp

@@ -1,9 +1,7 @@
 #include "BasicItems.h"
 
-#include "Game.h"
-#include "ModelInfo.h"
-#include "Item.h"
 #include "Entity.h"
+#include "Item.h"
 
 BasicItemType::BasicItemType()
     : ItemType(),
@@ -139,36 +137,40 @@ BasicItemType* BasicItemTypeFactory::createValue(
     return new BasicItemType();
 }
 
-void BasicItemTypeFactory::fromJson(
-    BasicItemType* zResult, Framework::JSON::JSONObject* zJson) const
+BasicItemType* BasicItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setItemName(
+    BasicItemType* result = ItemTypeFactoryBase::fromJson(zJson);
+    result->setItemName(
         Framework::Text(zJson->zValue("itemName")->asString()->getString()));
-    zResult->setHp((float)zJson->zValue("hp")->asNumber()->getNumber());
-    zResult->setDurability(
+    result->setHp((float)zJson->zValue("hp")->asNumber()->getNumber());
+    result->setDurability(
         (float)zJson->zValue("durability")->asNumber()->getNumber());
-    zResult->setSolid(zJson->zValue("solid")->asBool()->getBool());
-    zResult->setHungerRecoveryPerHp(
+    result->setSolid(zJson->zValue("solid")->asBool()->getBool());
+    result->setHungerRecoveryPerHp(
         (float)zJson->zValue("hungerRecoveryPerHp")->asNumber()->getNumber());
-    zResult->setThirstRecoveryPerHp(
+    result->setThirstRecoveryPerHp(
         (float)zJson->zValue("thirstRecoveryPerHp")->asNumber()->getNumber());
-    ItemTypeFactoryBase::fromJson(zResult, zJson);
+    return result;
 }
 
-void BasicItemTypeFactory::toJson(
-    BasicItemType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BasicItemTypeFactory::toJsonObject(
+    BasicItemType* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result
+        = ItemTypeFactoryBase::toJsonObject(zObject);
+    result->addValue(
         "itemName", new Framework::JSON::JSONString(zObject->getItemName()));
-    zResult->addValue("hp", new Framework::JSON::JSONNumber(zObject->getHp()));
-    zResult->addValue("durability",
+    result->addValue("hp", new Framework::JSON::JSONNumber(zObject->getHp()));
+    result->addValue("durability",
         new Framework::JSON::JSONNumber(zObject->getDurability()));
-    zResult->addValue(
+    result->addValue(
         "solid", new Framework::JSON::JSONBool(zObject->isSolid()));
-    zResult->addValue("hungerRecoveryPerHp",
+    result->addValue("hungerRecoveryPerHp",
         new Framework::JSON::JSONNumber(zObject->getHungerRecoveryPerHp()));
-    zResult->addValue("thirstRecoveryPerHp",
+    result->addValue("thirstRecoveryPerHp",
         new Framework::JSON::JSONNumber(zObject->getThirstRecoveryPerHp()));
+    return result;
 }
 
 JSONObjectValidationBuilder* BasicItemTypeFactory::addToValidator(
@@ -198,7 +200,7 @@ JSONObjectValidationBuilder* BasicItemTypeFactory::addToValidator(
             ->finishNumber());
 }
 
-Framework::Text BasicItemTypeFactory::getTypeToken() const
+const char* BasicItemTypeFactory::getTypeToken() const
 {
     return "basic";
 }

+ 4 - 5
FactoryCraft/BasicItems.h

@@ -35,11 +35,10 @@ public:
     BasicItemTypeFactory();
     BasicItemType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BasicItemType* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BasicItemType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    BasicItemType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BasicItemType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 254 - 264
FactoryCraft/BasicTool.cpp

@@ -1,7 +1,5 @@
 #include "BasicTool.h"
 
-#include <numeric>
-
 #include "Block.h"
 #include "Dimension.h"
 #include "Entity.h"
@@ -83,43 +81,41 @@ XPBasedLevelUpRuleFactory::XPBasedLevelUpRuleFactory()
     : SubTypeFactory()
 {}
 
-XPBasedLevelUpRule* XPBasedLevelUpRuleFactory::createValue(
+XPBasedLevelUpRule* XPBasedLevelUpRuleFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new XPBasedLevelUpRule();
-}
-
-void XPBasedLevelUpRuleFactory::fromJson(
-    XPBasedLevelUpRule* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    XPBasedLevelUpRule* result = new XPBasedLevelUpRule();
     if (zJson->hasValue("maxLevel"))
     {
-        zResult->setMaxLevel(
+        result->setMaxLevel(
             (float)zJson->zValue("maxLevel")->asNumber()->getNumber());
     }
-    zResult->setXpIncrease(
+    result->setXpIncrease(
         (float)zJson->zValue("xpIncrease")->asNumber()->getNumber());
-    zResult->setXpMultiplier(
+    result->setXpMultiplier(
         (float)zJson->zValue("xpMultiplier")->asNumber()->getNumber());
-    zResult->setLevelIncrease(
+    result->setLevelIncrease(
         (float)zJson->zValue("levelIncrease")->asNumber()->getNumber());
-    zResult->setLevelMultiplier(
+    result->setLevelMultiplier(
         (float)zJson->zValue("levelMultiplier")->asNumber()->getNumber());
+    return result;
 }
 
-void XPBasedLevelUpRuleFactory::toJson(
-    XPBasedLevelUpRule* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* XPBasedLevelUpRuleFactory::toJsonObject(
+    XPBasedLevelUpRule* zObject) const
 {
-    zResult->addValue("xpIncrease",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("xpIncrease",
         new Framework::JSON::JSONNumber(zObject->getXpIncrease()));
-    zResult->addValue("xpMultiplier",
+    result->addValue("xpMultiplier",
         new Framework::JSON::JSONNumber(zObject->getXpMultiplier()));
-    zResult->addValue("levelIncrease",
+    result->addValue("levelIncrease",
         new Framework::JSON::JSONNumber(zObject->getLevelIncrease()));
-    zResult->addValue("levelMultiplier",
+    result->addValue("levelMultiplier",
         new Framework::JSON::JSONNumber(zObject->getLevelMultiplier()));
-    zResult->addValue(
+    result->addValue(
         "maxLevel", new Framework::JSON::JSONNumber(zObject->getMaxLevel()));
+    return result;
 }
 
 JSONObjectValidationBuilder* XPBasedLevelUpRuleFactory::addToValidator(
@@ -146,7 +142,7 @@ JSONObjectValidationBuilder* XPBasedLevelUpRuleFactory::addToValidator(
         ->finishNumber();
 }
 
-Framework::Text XPBasedLevelUpRuleFactory::getTypeToken() const
+const char* XPBasedLevelUpRuleFactory::getTypeToken() const
 {
     return "xpBased";
 }
@@ -290,17 +286,17 @@ void BasicToolItemType::setItemAttribute(
 {
     BasicToolItem* item = dynamic_cast<BasicToolItem*>(zItem);
     if (name.istGleich("headMaterialHardness")
-        && zValue->getType() == Framework::JSON::JSONType::NUMBER)
+        && zValue->getType() == Framework::AbstractType::NUMBER)
     {
         item->setHeadMaterialHardness((float)zValue->asNumber()->getNumber());
     }
     else if (name.istGleich("rodMaterialHardness")
-             && zValue->getType() == Framework::JSON::JSONType::NUMBER)
+             && zValue->getType() == Framework::AbstractType::NUMBER)
     {
         item->setRodMaterialHardness((float)zValue->asNumber()->getNumber());
     }
     else if (name.istGleich("handleMaterialHardness")
-             && zValue->getType() == Framework::JSON::JSONType::NUMBER)
+             && zValue->getType() == Framework::AbstractType::NUMBER)
     {
         item->setHandleMaterialHardness((float)zValue->asNumber()->getNumber());
     }
@@ -494,90 +490,93 @@ BasicToolItemType* BasicToolItemTypeFactory::createValue(
     return new BasicToolItemType();
 }
 
-void BasicToolItemTypeFactory::fromJson(
-    BasicToolItemType* zResult, Framework::JSON::JSONObject* zJson) const
+BasicToolItemType* BasicToolItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setHandleMaterialHardness(
+    BasicToolItemType* result = ItemTypeFactoryBase::fromJson(zJson);
+    result->setHandleMaterialHardness(
         (float)zJson->zValue("headMaterialHardness")->asNumber()->getNumber());
-    zResult->setRodMaterialHardness(
+    result->setRodMaterialHardness(
         (float)zJson->zValue("rodMaterialHardness")->asNumber()->getNumber());
-    zResult->setHandleMaterialHardness(
+    result->setHandleMaterialHardness(
         (float)zJson->zValue("handleMaterialHardness")
             ->asNumber()
             ->getNumber());
-    zResult->setBaseDurability(
+    result->setBaseDurability(
         (float)zJson->zValue("baseDurability")->asNumber()->getNumber());
-    zResult->setBaseDurabilityMultiplier(
+    result->setBaseDurabilityMultiplier(
         (float)zJson->zValue("baseDurabilityMultiplier")
             ->asNumber()
             ->getNumber());
-    zResult->setHeadMaterialDurability(
+    result->setHeadMaterialDurability(
         (float)zJson->zValue("headMaterialDurability")
             ->asNumber()
             ->getNumber());
-    zResult->setHeadMaterialDurabilityMultiplier(
+    result->setHeadMaterialDurabilityMultiplier(
         (float)zJson->zValue("headMaterialDurabilityMultiplier")
             ->asNumber()
             ->getNumber());
-    zResult->setRodMaterialDurability(
+    result->setRodMaterialDurability(
         (float)zJson->zValue("rodMaterialDurability")->asNumber()->getNumber());
-    zResult->setRodMaterialDurabilityMultiplier(
+    result->setRodMaterialDurabilityMultiplier(
         (float)zJson->zValue("rodMaterialDurabilityMultiplier")
             ->asNumber()
             ->getNumber());
-    zResult->setHandleMaterialDurability(
+    result->setHandleMaterialDurability(
         (float)zJson->zValue("handleMaterialDurability")
             ->asNumber()
             ->getNumber());
-    zResult->setHandleMaterialDurabilityMultiplier(
+    result->setHandleMaterialDurabilityMultiplier(
         (float)zJson->zValue("handleMaterialDurabilityMultiplier")
             ->asNumber()
             ->getNumber());
-    zResult->setLevelUpRule(
+    result->setLevelUpRule(
         Game::INSTANCE->zTypeRegistry()->fromJson<ItemSkillLevelUpRule>(
             zJson->zValue("levelUpRule")));
-    zResult->setBrokenItemTypeName(
+    result->setBrokenItemTypeName(
         zJson->zValue("brokenItemTypeName")->asString()->getString());
-    zResult->setItemSkillConfigJson(zJson->getValue("itemSkill")->asObject());
-    ItemTypeFactoryBase::fromJson(zResult, zJson);
+    result->setItemSkillConfigJson(zJson->getValue("itemSkill")->asObject());
+    return result;
 }
 
-void BasicToolItemTypeFactory::toJson(
-    BasicToolItemType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BasicToolItemTypeFactory::toJsonObject(
+    BasicToolItemType* zObject) const
 {
-    zResult->addValue("headMaterialHardness",
+    Framework::JSON::JSONObject* result
+        = ItemTypeFactoryBase::toJsonObject(zObject);
+    result->addValue("headMaterialHardness",
         new Framework::JSON::JSONNumber(zObject->getHeadMaterialHardness()));
-    zResult->addValue("rodMaterialHardness",
+    result->addValue("rodMaterialHardness",
         new Framework::JSON::JSONNumber(zObject->getRodMaterialHardness()));
-    zResult->addValue("handleMaterialHardness",
+    result->addValue("handleMaterialHardness",
         new Framework::JSON::JSONNumber(zObject->getHandleMaterialHardness()));
-    zResult->addValue("baseDurability",
+    result->addValue("baseDurability",
         new Framework::JSON::JSONNumber(zObject->getBaseDurablility()));
-    zResult->addValue("baseDurabilityMultiplier",
+    result->addValue("baseDurabilityMultiplier",
         new Framework::JSON::JSONNumber(
             zObject->getBaseDurabilityMultiplier()));
-    zResult->addValue("headMaterialDurability",
+    result->addValue("headMaterialDurability",
         new Framework::JSON::JSONNumber(zObject->getHeadMaterialDurability()));
-    zResult->addValue("headMaterialDurabilityMultiplier",
+    result->addValue("headMaterialDurabilityMultiplier",
         new Framework::JSON::JSONNumber(
             zObject->getHeadMaterialDurabilityMultiplier()));
-    zResult->addValue("rodMaterialDurability",
+    result->addValue("rodMaterialDurability",
         new Framework::JSON::JSONNumber(zObject->getRodMaterialDurability()));
-    zResult->addValue("rodMaterialDurabilityMultiplier",
+    result->addValue("rodMaterialDurabilityMultiplier",
         new Framework::JSON::JSONNumber(
             zObject->getRodMaterialDurabilityMultiplier()));
-    zResult->addValue("handleMaterialDurability",
+    result->addValue("handleMaterialDurability",
         new Framework::JSON::JSONNumber(
             zObject->getHandleMaterialDurability()));
-    zResult->addValue("handleMaterialDurabilityMultiplier",
+    result->addValue("handleMaterialDurabilityMultiplier",
         new Framework::JSON::JSONNumber(
             zObject->getHandleMaterialDurabilityMultiplier()));
-    zResult->addValue("levelUpRule",
+    result->addValue("levelUpRule",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zLevelUpRule()));
-    zResult->addValue("brokenItemTypeName",
+    result->addValue("brokenItemTypeName",
         new Framework::JSON::JSONString(zObject->zBrokenItemType()->getName()));
-    zResult->addValue("itemSkill", zObject->getItemSkillConfigJson());
-    ItemTypeFactoryBase::toJson(zObject, zResult);
+    result->addValue("itemSkill", zObject->getItemSkillConfigJson());
+    return result;
 }
 
 JSONObjectValidationBuilder* BasicToolItemTypeFactory::addToValidator(
@@ -628,8 +627,9 @@ JSONObjectValidationBuilder* BasicToolItemTypeFactory::addToValidator(
             ->withDefault(0.0)
             ->whichIsGreaterOrEqual(0.0)
             ->finishNumber()
-            ->withRequiredString("brokenItemTypeName")
-            ->finishString()
+            ->withRequiredAttribute("brokenItemTypeName",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    ItemTypeNameFactory::TYPE_ID))
             ->withRequiredAttribute("levelUpRule",
                 Game::INSTANCE->zTypeRegistry()
                     ->getValidator<ItemSkillLevelUpRule>())
@@ -637,7 +637,7 @@ JSONObjectValidationBuilder* BasicToolItemTypeFactory::addToValidator(
                 Game::INSTANCE->zTypeRegistry()->getValidator<ItemSkill>()));
 }
 
-Framework::Text BasicToolItemTypeFactory::getTypeToken() const
+const char* BasicToolItemTypeFactory::getTypeToken() const
 {
     return "tool";
 }
@@ -772,93 +772,87 @@ float BlockReplaceItemSkillConfig::getXpGain() const
 }
 
 BlockReplaceItemSkillConfigFactory::BlockReplaceItemSkillConfigFactory()
-    : TypeFactory()
+    : ObjectTypeFactory()
 {}
 
-BlockReplaceItemSkillConfig* BlockReplaceItemSkillConfigFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new BlockReplaceItemSkillConfig();
-}
-
-void BlockReplaceItemSkillConfigFactory::fromJson(
-    BlockReplaceItemSkillConfig* zResult,
+BlockReplaceItemSkillConfig* BlockReplaceItemSkillConfigFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setTargetBlockFilter(
+    BlockReplaceItemSkillConfig* result = new BlockReplaceItemSkillConfig();
+    result->setTargetBlockFilter(
         Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
             zJson->asObject()->zValue("targetFilter")));
-    zResult->setCooldownTicks((int)zJson->asObject()
-                                  ->zValue("cooldownTicks")
-                                  ->asNumber()
-                                  ->getNumber());
-    zResult->setReplacementBlockTypeId(
+    result->setCooldownTicks((int)zJson->asObject()
+            ->zValue("cooldownTicks")
+            ->asNumber()
+            ->getNumber());
+    result->setReplacementBlockTypeId(
         Game::INSTANCE->getBlockTypeId(zJson->asObject()
-                                           ->zValue("replacementBlockType")
-                                           ->asString()
-                                           ->getString()));
-    zResult->setCooldownTicks((int)zJson->asObject()
-                                  ->zValue("cooldownTicks")
-                                  ->asNumber()
-                                  ->getNumber());
-    zResult->setStaminaCost((float)zJson->asObject()
-                                ->zValue("staminaCost")
-                                ->asNumber()
-                                ->getNumber());
-    zResult->setStaminaCostDevider((float)zJson->asObject()
-                                       ->zValue("staminaCostDevider")
-                                       ->asNumber()
-                                       ->getNumber());
-    zResult->setAdditionalStaminaCostDeviderPerLevel(
-        (float)zJson->asObject()
+                ->zValue("replacementBlockType")
+                ->asString()
+                ->getString()));
+    result->setCooldownTicks((int)zJson->asObject()
+            ->zValue("cooldownTicks")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCost((float)zJson->asObject()
+            ->zValue("staminaCost")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCostDevider((float)zJson->asObject()
+            ->zValue("staminaCostDevider")
+            ->asNumber()
+            ->getNumber());
+    result->setAdditionalStaminaCostDeviderPerLevel((float)zJson->asObject()
             ->zValue("additionalStaminaCostDeviderPerLevel")
             ->asNumber()
             ->getNumber());
-    zResult->setDurabilityCost((float)zJson->asObject()
-                                   ->zValue("durabilityCost")
-                                   ->asNumber()
-                                   ->getNumber());
-    zResult->setDurabilityCostDevider((float)zJson->asObject()
-                                          ->zValue("durabilityCostDevider")
-                                          ->asNumber()
-                                          ->getNumber());
-    zResult->setAdditionalDurabilityCostDeviderPerLevel(
-        (float)zJson->asObject()
+    result->setDurabilityCost((float)zJson->asObject()
+            ->zValue("durabilityCost")
+            ->asNumber()
+            ->getNumber());
+    result->setDurabilityCostDevider((float)zJson->asObject()
+            ->zValue("durabilityCostDevider")
+            ->asNumber()
+            ->getNumber());
+    result->setAdditionalDurabilityCostDeviderPerLevel((float)zJson->asObject()
             ->zValue("additionalDurabilityCostDeviderPerLevel")
             ->asNumber()
             ->getNumber());
-    zResult->setXpGain(
+    result->setXpGain(
         (float)zJson->asObject()->zValue("xpGain")->asNumber()->getNumber());
+    return result;
 }
 
-void BlockReplaceItemSkillConfigFactory::toJson(
-    BlockReplaceItemSkillConfig* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockReplaceItemSkillConfigFactory::toJsonObject(
+    BlockReplaceItemSkillConfig* zObject) const
 {
-    zResult->addValue("targetFilter",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("targetFilter",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetBlockFilter()));
-    zResult->addValue("replacementBlockType",
+    result->addValue("replacementBlockType",
         new Framework::JSON::JSONString(
             Game::INSTANCE->zBlockType(zObject->getReplacementBlockTypeId())
                 ->getName()));
-    zResult->addValue("cooldownTicks",
+    result->addValue("cooldownTicks",
         new Framework::JSON::JSONNumber(zObject->getCooldownTicks()));
-    zResult->addValue("staminaCost",
+    result->addValue("staminaCost",
         new Framework::JSON::JSONNumber(zObject->getStaminaCost()));
-    zResult->addValue("staminaCostDevider",
+    result->addValue("staminaCostDevider",
         new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider()));
-    zResult->addValue("additionalStaminaCostDeviderPerLevel",
+    result->addValue("additionalStaminaCostDeviderPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->getAdditionalStaminaCostDeviderPerLevel()));
-    zResult->addValue("durabilityCost",
+    result->addValue("durabilityCost",
         new Framework::JSON::JSONNumber(zObject->getDurabilityCost()));
-    zResult->addValue("durabilityCostDevider",
+    result->addValue("durabilityCostDevider",
         new Framework::JSON::JSONNumber(zObject->getDurabilityCostDevider()));
-    zResult->addValue("additionalDurabilityCostDeviderPerLevel",
+    result->addValue("additionalDurabilityCostDeviderPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->getAdditionalDurabilityCostDeviderPerLevel()));
-    zResult->addValue(
+    result->addValue(
         "xpGain", new Framework::JSON::JSONNumber(zObject->getXpGain()));
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockReplaceItemSkillConfigFactory::addToValidator(
@@ -867,8 +861,9 @@ JSONObjectValidationBuilder* BlockReplaceItemSkillConfigFactory::addToValidator(
     return builder
         ->withRequiredAttribute("targetFilter",
             Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>())
-        ->withRequiredString("replacementBlockType")
-        ->finishString()
+        ->withRequiredAttribute("replacementBlockType",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                BlockTypeNameFactory::TYPE_ID))
         ->withRequiredNumber("cooldownTicks")
         ->whichIsGreaterOrEqual(0)
         ->withDefault(20)
@@ -1034,9 +1029,10 @@ BlockReplaceItemSkill* BlockReplaceItemSkillFactory::createValue(
     return new BlockReplaceItemSkill();
 }
 
-void BlockReplaceItemSkillFactory::fromJson(
-    BlockReplaceItemSkill* zResult, Framework::JSON::JSONObject* zJson) const
+BlockReplaceItemSkill* BlockReplaceItemSkillFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
+    BlockReplaceItemSkill* result = ItemSkillFactoryBase::fromJson(zJson);
     BlockReplaceItemSkillConfig* invalidUseConfig
         = new BlockReplaceItemSkillConfig();
     invalidUseConfig->setStaminaCost(
@@ -1062,41 +1058,41 @@ void BlockReplaceItemSkillFactory::fromJson(
     invalidUseConfig->setCooldownTicks(
         (int)zJson->zValue("invalidCooldownTicks")->asNumber()->getNumber());
     invalidUseConfig->setXpGain(0.f);
-    zResult->setInvalidUseConfig(invalidUseConfig);
+    result->setInvalidUseConfig(invalidUseConfig);
     Framework::RCArray<BlockReplaceItemSkillConfig> configs;
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("configs")->asArray())
     {
-        zResult->addConfig(Game::INSTANCE->zTypeRegistry()
-                               ->fromJson<BlockReplaceItemSkillConfig>(value));
+        result->addConfig(Game::INSTANCE->zTypeRegistry()
+                ->fromJson<BlockReplaceItemSkillConfig>(value));
     }
-    ItemSkillFactoryBase::fromJson(zResult, zJson);
+    return result;
 }
 
-void BlockReplaceItemSkillFactory::toJson(
-    BlockReplaceItemSkill* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockReplaceItemSkillFactory::toJsonObject(
+    BlockReplaceItemSkill* zObject) const
 {
-    zResult->addValue("invalidStaminaCost",
+    Framework::JSON::JSONObject* result
+        = ItemSkillFactoryBase::toJsonObject(zObject);
+    result->addValue("invalidStaminaCost",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCost()));
-    zResult->addValue("invalidStaminaCostDevider",
+    result->addValue("invalidStaminaCostDevider",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCostDevider()));
-    zResult->addValue("invalidAdditionalStaminaCostDeviderPerLevel",
-        new Framework::JSON::JSONNumber(
-            zObject->zInvalidUseConfig()
+    result->addValue("invalidAdditionalStaminaCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(zObject->zInvalidUseConfig()
                 ->getAdditionalStaminaCostDeviderPerLevel()));
-    zResult->addValue("invalidDurabilityCost",
+    result->addValue("invalidDurabilityCost",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getDurabilityCost()));
-    zResult->addValue("invalidDurabilityCostDevider",
+    result->addValue("invalidDurabilityCostDevider",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getDurabilityCostDevider()));
-    zResult->addValue("invalidAdditionalDurabilityCostDeviderPerLevel",
-        new Framework::JSON::JSONNumber(
-            zObject->zInvalidUseConfig()
+    result->addValue("invalidAdditionalDurabilityCostDeviderPerLevel",
+        new Framework::JSON::JSONNumber(zObject->zInvalidUseConfig()
                 ->getAdditionalDurabilityCostDeviderPerLevel()));
-    zResult->addValue("invalidCooldownTicks",
+    result->addValue("invalidCooldownTicks",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getCooldownTicks()));
     Framework::JSON::JSONArray* configs = new Framework::JSON::JSONArray();
@@ -1104,8 +1100,8 @@ void BlockReplaceItemSkillFactory::toJson(
     {
         configs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(config));
     }
-    zResult->addValue("configs", configs);
-    ItemSkillFactoryBase::toJson(zObject, zResult);
+    result->addValue("configs", configs);
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockReplaceItemSkillFactory::addToValidator(
@@ -1141,13 +1137,12 @@ JSONObjectValidationBuilder* BlockReplaceItemSkillFactory::addToValidator(
             ->withDefault(20)
             ->finishNumber()
             ->withRequiredArray("configs")
-            ->addAcceptedTypeInArray(
-                Game::INSTANCE->zTypeRegistry()
+            ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
                     ->getValidator<BlockReplaceItemSkillConfig>())
             ->finishArray());
 }
 
-Framework::Text BlockReplaceItemSkillFactory::getTypeToken() const
+const char* BlockReplaceItemSkillFactory::getTypeToken() const
 {
     return "replaceBlock";
 }
@@ -1398,152 +1393,144 @@ float DamagingItemSkillConfig::getXpGainPerDamage() const
 }
 
 DamagingItemSkillConfigFactory::DamagingItemSkillConfigFactory()
-    : TypeFactory()
+    : ObjectTypeFactory()
 {}
 
-DamagingItemSkillConfig* DamagingItemSkillConfigFactory::createValue(
+DamagingItemSkillConfig* DamagingItemSkillConfigFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new DamagingItemSkillConfig();
-}
-
-void DamagingItemSkillConfigFactory::fromJson(
-    DamagingItemSkillConfig* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setTargetBlockFilter(
+    DamagingItemSkillConfig* result = new DamagingItemSkillConfig();
+    result->setTargetBlockFilter(
         Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
             zJson->zValue("targetFilter")));
-    zResult->setDamage(
+    result->setDamage(
         (float)zJson->asObject()->zValue("damage")->asNumber()->getNumber());
-    zResult->setDamagePerHeadHardness((float)zJson->asObject()
-                                          ->zValue("damagePerHeadHardness")
-                                          ->asNumber()
-                                          ->getNumber());
-    zResult->setBaseDamageMultiplier((float)zJson->asObject()
-                                         ->zValue("baseDamageMultiplier")
-                                         ->asNumber()
-                                         ->getNumber());
-    zResult->setDamageMultiplierPerHeadHardness(
-        (float)zJson->asObject()
+    result->setDamagePerHeadHardness((float)zJson->asObject()
+            ->zValue("damagePerHeadHardness")
+            ->asNumber()
+            ->getNumber());
+    result->setBaseDamageMultiplier((float)zJson->asObject()
+            ->zValue("baseDamageMultiplier")
+            ->asNumber()
+            ->getNumber());
+    result->setDamageMultiplierPerHeadHardness((float)zJson->asObject()
             ->zValue("damageMultiplierPerHeadHardness")
             ->asNumber()
             ->getNumber());
-    zResult->setDamagePerLevel((float)zJson->asObject()
-                                   ->zValue("damagePerLevel")
-                                   ->asNumber()
-                                   ->getNumber());
-    zResult->setDamageMultiplierPerLevel(
-        (float)zJson->asObject()
+    result->setDamagePerLevel((float)zJson->asObject()
+            ->zValue("damagePerLevel")
+            ->asNumber()
+            ->getNumber());
+    result->setDamageMultiplierPerLevel((float)zJson->asObject()
             ->zValue("damageMultiplierPerLevel")
             ->asNumber()
             ->getNumber());
-    zResult->setDamageDevider((float)zJson->asObject()
-                                  ->zValue("damageDevider")
-                                  ->asNumber()
-                                  ->getNumber());
-    zResult->setDamageDeviderPerHardness(
-        (float)zJson->asObject()
+    result->setDamageDevider((float)zJson->asObject()
+            ->zValue("damageDevider")
+            ->asNumber()
+            ->getNumber());
+    result->setDamageDeviderPerHardness((float)zJson->asObject()
             ->zValue("damageDeviderPerHardness")
             ->asNumber()
             ->getNumber());
-    zResult->setStaminaCost((float)zJson->asObject()
-                                ->zValue("staminaCost")
-                                ->asNumber()
-                                ->getNumber());
-    zResult->setStaminaCostPerDamage((float)zJson->asObject()
-                                         ->zValue("staminaCostPerDamage")
-                                         ->asNumber()
-                                         ->getNumber());
-    zResult->setStaminaCostPerHardness((float)zJson->asObject()
-                                           ->zValue("staminaCostPerHardness")
-                                           ->asNumber()
-                                           ->getNumber());
-    zResult->setStaminaCostDevider((float)zJson->asObject()
-                                       ->zValue("staminaCostDevider")
-                                       ->asNumber()
-                                       ->getNumber());
-    zResult->setStaminaCostDeviderPerLevel(
-        (float)zJson->asObject()
+    result->setStaminaCost((float)zJson->asObject()
+            ->zValue("staminaCost")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCostPerDamage((float)zJson->asObject()
+            ->zValue("staminaCostPerDamage")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCostPerHardness((float)zJson->asObject()
+            ->zValue("staminaCostPerHardness")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCostDevider((float)zJson->asObject()
+            ->zValue("staminaCostDevider")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCostDeviderPerLevel((float)zJson->asObject()
             ->zValue("staminaCostDeviderPerLevel")
             ->asNumber()
             ->getNumber());
-    zResult->setDurabilityCost((float)zJson->asObject()
-                                   ->zValue("durabilityCost")
-                                   ->asNumber()
-                                   ->getNumber());
-    zResult->setDurabilityCostPerDamage((float)zJson->asObject()
-                                            ->zValue("durabilityCostPerDamage")
-                                            ->asNumber()
-                                            ->getNumber());
-    zResult->setDurabilityCostPerHardness(
-        (float)zJson->asObject()
+    result->setDurabilityCost((float)zJson->asObject()
+            ->zValue("durabilityCost")
+            ->asNumber()
+            ->getNumber());
+    result->setDurabilityCostPerDamage((float)zJson->asObject()
+            ->zValue("durabilityCostPerDamage")
+            ->asNumber()
+            ->getNumber());
+    result->setDurabilityCostPerHardness((float)zJson->asObject()
             ->zValue("durabilityCostPerHardness")
             ->asNumber()
             ->getNumber());
-    zResult->setDurabilityCostDevider((float)zJson->asObject()
-                                          ->zValue("durabilityCostDevider")
-                                          ->asNumber()
-                                          ->getNumber());
-    zResult->setAdditionalDurabilityCostDeviderPerLevel(
-        (float)zJson->asObject()
+    result->setDurabilityCostDevider((float)zJson->asObject()
+            ->zValue("durabilityCostDevider")
+            ->asNumber()
+            ->getNumber());
+    result->setAdditionalDurabilityCostDeviderPerLevel((float)zJson->asObject()
             ->zValue("additionalDurabilityCostDeviderPerLevel")
             ->asNumber()
             ->getNumber());
-    zResult->setXpGainPerDamage((float)zJson->asObject()
-                                    ->zValue("xpGainPerDamage")
-                                    ->asNumber()
-                                    ->getNumber());
+    result->setXpGainPerDamage((float)zJson->asObject()
+            ->zValue("xpGainPerDamage")
+            ->asNumber()
+            ->getNumber());
+    return result;
 }
 
-void DamagingItemSkillConfigFactory::toJson(DamagingItemSkillConfig* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* DamagingItemSkillConfigFactory::toJsonObject(
+    DamagingItemSkillConfig* zObject) const
 {
-    zResult->addValue("targetFilter",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("targetFilter",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetBlockFilter()));
-    zResult->addValue(
+    result->addValue(
         "damage", new Framework::JSON::JSONNumber(zObject->getDamage()));
-    zResult->addValue("damagePerHeadHardness",
+    result->addValue("damagePerHeadHardness",
         new Framework::JSON::JSONNumber(zObject->getDamagePerHeadHardness()));
-    zResult->addValue("baseDamageMultiplier",
+    result->addValue("baseDamageMultiplier",
         new Framework::JSON::JSONNumber(zObject->getBaseDamageMultiplier()));
-    zResult->addValue("damageMultiplierPerHeadHardness",
+    result->addValue("damageMultiplierPerHeadHardness",
         new Framework::JSON::JSONNumber(
             zObject->getDamageMultiplierPerHeadHardness()));
-    zResult->addValue("damagePerLevel",
+    result->addValue("damagePerLevel",
         new Framework::JSON::JSONNumber(zObject->getDamagePerLevel()));
-    zResult->addValue("damageMultiplierPerLevel",
+    result->addValue("damageMultiplierPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->getDamageMultiplierPerLevel()));
-    zResult->addValue("damageDevider",
+    result->addValue("damageDevider",
         new Framework::JSON::JSONNumber(zObject->getDamageDevider()));
-    zResult->addValue("damageDeviderPerHardness",
+    result->addValue("damageDeviderPerHardness",
         new Framework::JSON::JSONNumber(
             zObject->getDamageDeviderPerHardness()));
-    zResult->addValue("staminaCost",
+    result->addValue("staminaCost",
         new Framework::JSON::JSONNumber(zObject->getStaminaCost()));
-    zResult->addValue("staminaCostPerDamage",
+    result->addValue("staminaCostPerDamage",
         new Framework::JSON::JSONNumber(zObject->getStaminaCostPerDamage()));
-    zResult->addValue("staminaCostPerHardness",
+    result->addValue("staminaCostPerHardness",
         new Framework::JSON::JSONNumber(zObject->getStaminaCostPerHardness()));
-    zResult->addValue("staminaCostDevider",
+    result->addValue("staminaCostDevider",
         new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider()));
-    zResult->addValue("staminaCostDeviderPerLevel",
+    result->addValue("staminaCostDeviderPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->getStaminaCostDeviderPerLevel()));
-    zResult->addValue("durabilityCost",
+    result->addValue("durabilityCost",
         new Framework::JSON::JSONNumber(zObject->getDurabilityCost()));
-    zResult->addValue("durabilityCostPerDamage",
+    result->addValue("durabilityCostPerDamage",
         new Framework::JSON::JSONNumber(zObject->getDurabilityCostPerDamage()));
-    zResult->addValue("durabilityCostPerHardness",
+    result->addValue("durabilityCostPerHardness",
         new Framework::JSON::JSONNumber(
             zObject->getDurabilityCostPerHardness()));
-    zResult->addValue("durabilityCostDevider",
+    result->addValue("durabilityCostDevider",
         new Framework::JSON::JSONNumber(zObject->getDurabilityCostDevider()));
-    zResult->addValue("additionalDurabilityCostDeviderPerLevel",
+    result->addValue("additionalDurabilityCostDeviderPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->getAdditionalDurabilityCostDeviderPerLevel()));
-    zResult->addValue("xpGainPerDamage",
+    result->addValue("xpGainPerDamage",
         new Framework::JSON::JSONNumber(zObject->getXpGainPerDamage()));
+    return result;
 }
 
 JSONObjectValidationBuilder* DamagingItemSkillConfigFactory::addToValidator(
@@ -1704,10 +1691,13 @@ bool DamagingItemSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
     {
         durabilityCost /= durabilityDevider;
     }
-    zUsedItem->setDurability(zUsedItem->getDurability() - durabilityCost);
+    if (zUsedItem)
+    {
+        zUsedItem->setDurability(zUsedItem->getDurability() - durabilityCost);
+    }
     zActor->setStamina(zActor->getStamina() - staminaCost);
     setXp(getXp() + usedConfig->getXpGainPerDamage() * damage);
-    zTarget->setHP(zTarget->getHP() - damage);
+    zTarget->setHP(zActor, zUsedItem, this, zTarget->getHP() - damage);
     return true;
 }
 
@@ -1748,13 +1738,14 @@ DamagingItemSkill* DamagingItemSkillFactory::createValue(
     return new DamagingItemSkill();
 }
 
-void DamagingItemSkillFactory::fromJson(
-    DamagingItemSkill* zResult, Framework::JSON::JSONObject* zJson) const
+DamagingItemSkill* DamagingItemSkillFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
+    DamagingItemSkill* result = ItemSkillFactoryBase::fromJson(zJson);
     for (Framework::JSON::JSONValue* configValue :
         *zJson->zValue("configs")->asArray())
     {
-        zResult->addConfig(
+        result->addConfig(
             Game::INSTANCE->zTypeRegistry()->fromJson<DamagingItemSkillConfig>(
                 configValue));
     }
@@ -1796,47 +1787,48 @@ void DamagingItemSkillFactory::fromJson(
         (float)zJson->zValue("invalidDurabilityCostDeviderPerLevel")
             ->asNumber()
             ->getNumber());
-    zResult->setInvalidUseConfig(invalidUseConfig);
-    ItemSkillFactoryBase::fromJson(zResult, zJson);
+    result->setInvalidUseConfig(invalidUseConfig);
+    return result;
 }
 
-void DamagingItemSkillFactory::toJson(
-    DamagingItemSkill* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* DamagingItemSkillFactory::toJsonObject(
+    DamagingItemSkill* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result
+        = ItemSkillFactoryBase::toJsonObject(zObject);
+    result->addValue(
         "maxXp", new Framework::JSON::JSONNumber(zObject->getMaxXp()));
-    zResult->addValue("invalidStaminaCost",
+    result->addValue("invalidStaminaCost",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCost()));
-    zResult->addValue("invalidStaminaCostPerHardness",
+    result->addValue("invalidStaminaCostPerHardness",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCostPerHardness()));
-    zResult->addValue("invalidStaminaCostDevider",
+    result->addValue("invalidStaminaCostDevider",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCostDevider()));
-    zResult->addValue("invalidStaminaCostDeviderPerLevel",
+    result->addValue("invalidStaminaCostDeviderPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCostDeviderPerLevel()));
-    zResult->addValue("invalidDurabilityCost",
+    result->addValue("invalidDurabilityCost",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getDurabilityCost()));
-    zResult->addValue("invalidDurabilityCostPerHardness",
+    result->addValue("invalidDurabilityCostPerHardness",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getDurabilityCostPerHardness()));
-    zResult->addValue("invalidDurabilityCostDevider",
+    result->addValue("invalidDurabilityCostDevider",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getDurabilityCostDevider()));
-    zResult->addValue("invalidDurabilityCostDeviderPerLevel",
-        new Framework::JSON::JSONNumber(
-            zObject->zInvalidUseConfig()
+    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));
     }
-    zResult->addValue("configs", configs);
-    ItemSkillFactoryBase::toJson(zObject, zResult);
+    result->addValue("configs", configs);
+    return result;
 }
 
 JSONObjectValidationBuilder* DamagingItemSkillFactory::addToValidator(
@@ -1855,7 +1847,7 @@ JSONObjectValidationBuilder* DamagingItemSkillFactory::addToValidator(
             ->whichIsGreaterOrEqual(0.0)
             ->withDefault(0.8)
             ->finishNumber()
-            ->withRequiredNumber("invalidAdditionalStaminaCostDeviderPerLevel")
+            ->withRequiredNumber("invalidStaminaCostDeviderPerLevel")
             ->whichIsGreaterOrEqual(0.0)
             ->withDefault(0.2)
             ->finishNumber()
@@ -1871,19 +1863,17 @@ JSONObjectValidationBuilder* DamagingItemSkillFactory::addToValidator(
             ->whichIsGreaterOrEqual(0.0)
             ->withDefault(0.98)
             ->finishNumber()
-            ->withRequiredNumber(
-                "invalidAdditionalDurabilityCostDeviderPerLevel")
+            ->withRequiredNumber("invalidDurabilityCostDeviderPerLevel")
             ->whichIsGreaterOrEqual(0.0)
             ->withDefault(0.02)
             ->finishNumber()
             ->withRequiredArray("configs")
-            ->addAcceptedTypeInArray(
-                Game::INSTANCE->zTypeRegistry()
+            ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
                     ->getValidator<DamagingItemSkillConfig>())
             ->finishArray());
 }
 
-Framework::Text DamagingItemSkillFactory::getTypeToken() const
+const char* DamagingItemSkillFactory::getTypeToken() const
 {
     return "damaging";
 }

+ 26 - 33
FactoryCraft/BasicTool.h

@@ -1,9 +1,9 @@
 #pragma once
 
-#include "BasicItems.h"
 #include "BlockFilter.h"
 #include "Item.h"
 #include "ItemSkill.h"
+#include "ItemType.h"
 
 class BasicToolItemType;
 
@@ -36,15 +36,13 @@ class XPBasedLevelUpRuleFactory
 {
 public:
     XPBasedLevelUpRuleFactory();
-    XPBasedLevelUpRule* createValue(
+    XPBasedLevelUpRule* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(XPBasedLevelUpRule* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(XPBasedLevelUpRule* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        XPBasedLevelUpRule* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BasicToolItem : public Item
@@ -141,13 +139,13 @@ public:
     BasicToolItemTypeFactory();
     BasicToolItemType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BasicToolItemType* zResult,
+    BasicToolItemType* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BasicToolItemType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BasicToolItemType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockReplaceItemSkillConfig : public Framework::ReferenceCounter
@@ -192,16 +190,14 @@ public:
 };
 
 class BlockReplaceItemSkillConfigFactory
-    : public TypeFactory<BlockReplaceItemSkillConfig>
+    : public ObjectTypeFactory<BlockReplaceItemSkillConfig>
 {
 public:
     BlockReplaceItemSkillConfigFactory();
-    BlockReplaceItemSkillConfig* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockReplaceItemSkillConfig* zResult,
+    BlockReplaceItemSkillConfig* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockReplaceItemSkillConfig* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockReplaceItemSkillConfig* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -235,13 +231,13 @@ public:
     BlockReplaceItemSkillFactory();
     BlockReplaceItemSkill* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockReplaceItemSkill* zResult,
+    BlockReplaceItemSkill* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockReplaceItemSkill* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockReplaceItemSkill* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class DamagingItemSkillConfig : public Framework::ReferenceCounter
@@ -316,16 +312,14 @@ public:
 };
 
 class DamagingItemSkillConfigFactory
-    : public TypeFactory<DamagingItemSkillConfig>
+    : public ObjectTypeFactory<DamagingItemSkillConfig>
 {
 public:
     DamagingItemSkillConfigFactory();
-    DamagingItemSkillConfig* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(DamagingItemSkillConfig* zResult,
+    DamagingItemSkillConfig* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(DamagingItemSkillConfig* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DamagingItemSkillConfig* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -347,18 +341,17 @@ public:
     const Framework::RCArray<DamagingItemSkillConfig>& getConfigs() const;
 };
 
-class DamagingItemSkillFactory
-    : public ItemSkillFactoryBase<DamagingItemSkill>
+class DamagingItemSkillFactory : public ItemSkillFactoryBase<DamagingItemSkill>
 {
 public:
     DamagingItemSkillFactory();
     DamagingItemSkill* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(DamagingItemSkill* zResult,
+    DamagingItemSkill* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(DamagingItemSkill* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DamagingItemSkill* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 156 - 52
FactoryCraft/BiomGenerator.cpp

@@ -1,8 +1,8 @@
 #include "BiomGenerator.h"
 
-#include "Constants.h"
+#include "Chunk.h"
+#include "Entity.h"
 #include "Game.h"
-#include "JNoise.h"
 
 BiomGenerator::BiomGenerator()
     : ReferenceCounter(),
@@ -20,22 +20,30 @@ void BiomGenerator::initialize(JExpressionMemory* zMemory)
     {
         rule->initialize(zMemory);
     }
+    for (EntityGenerator* entity : entityGenerators)
+    {
+        entity->initialize(zMemory);
+    }
     for (StructureTemplateCollection* collection : templates)
     {
         collection->initialize(zMemory);
     }
+    for (PlantConfig* plantConfig : plantConfigs)
+    {
+        plantConfig->initialize(zMemory);
+    }
+    if (condition)
+    {
+        condition->compile(zMemory);
+    }
 }
 
-Framework::Either<Block*, int> BiomGenerator::generateBlock(int x,
-    int y,
-    int z,
-    int dimensionId,
-    JExpressionMemory* zMemory,
-    Chunk* partialGeneratedChunk)
+Framework::Either<Block*, int> BiomGenerator::generateBlock(
+    int x, int y, int z, int dimensionId, Chunk* partialGeneratedChunk)
 {
     for (GeneratorRule* rule : rules)
     {
-        if (rule->checkCondition(x, y, z, zMemory))
+        if (rule->checkCondition(x, y, z))
         {
             auto result = rule->generateBlock(x, y, z, dimensionId);
             if ((result.isA() && result.getA())
@@ -48,33 +56,70 @@ Framework::Either<Block*, int> BiomGenerator::generateBlock(int x,
     return BlockTypeEnum::AIR;
 }
 
-bool BiomGenerator::isApplicable(JExpressionMemory* zMemory)
+bool BiomGenerator::isApplicable()
 {
-    return condition->getValue(zMemory);
+    return !condition || condition->getValue();
 }
 
 void BiomGenerator::generateStructures(int x,
     int y,
     int z,
     int dimensionId,
-    JExpressionMemory* zMemory,
-    Framework::Vec3<int> minPos,
-    Framework::Vec3<int> maxPos,
+    Framework::Vec3<int>& minPos,
+    Framework::Vec3<int>& maxPos,
     Framework::RCArray<GeneratedStructure>* zResult)
 {
-    int minSearchX = minPos.x - maxStructureOffset.x;
-    int minSearchY = minPos.y - maxStructureOffset.y;
-    int minSearchZ = MAX(minPos.z - maxStructureOffset.z, 0);
-    int maxSearchX = maxPos.x - minStructureOffset.x;
-    int maxSearchY = maxPos.y - minStructureOffset.y;
-    int maxSearchZ = MIN(maxPos.z - minStructureOffset.z, WORLD_HEIGHT - 1);
-    if (x >= minSearchX && x <= maxSearchX && y >= minSearchY && y <= maxSearchY
-        && z >= minSearchZ && z <= maxSearchZ)
+    for (StructureTemplateCollection* collection : templates)
     {
-        for (StructureTemplateCollection* collection : templates)
+        collection->generateStructures(
+            x, y, z, dimensionId, minPos, maxPos, zResult);
+    }
+}
+
+void BiomGenerator::generatePlants(int x,
+    int y,
+    int z,
+    int dimensionId,
+    Chunk* zChunk,
+    bool underground,
+    bool underwater,
+    int seaFluidBlockTypeId)
+{
+    PlantConfig* chosenConfig = 0;
+    double maxValue = 0.0;
+    for (PlantConfig* plantConfig : plantConfigs)
+    {
+        double value = plantConfig->doesGeneratePlant(x,
+            y,
+            z,
+            dimensionId,
+            zChunk,
+            underground,
+            underwater,
+            seaFluidBlockTypeId);
+        if (value > maxValue)
         {
-            collection->generateStructures(
-                x, y, z, dimensionId, zMemory, minPos, maxPos, zResult);
+            maxValue = value;
+            chosenConfig = plantConfig;
+        }
+    }
+    if (chosenConfig)
+    {
+        chosenConfig->generatePlantAt(x, y, z, dimensionId, zChunk);
+    }
+}
+
+void BiomGenerator::generateEntities(
+    int x, int y, int z, int dimensionId, Chunk* zChunk)
+{
+    for (EntityGenerator* entityGen : entityGenerators)
+    {
+        if (entityGen->isGenerated(x, y, z, dimensionId))
+        {
+            Entity* entity = entityGen->generate(
+                Framework::Vec3<float>((float)x, (float)y, (float)z),
+                dimensionId);
+            zChunk->addGeneratedEntity(entity);
         }
     }
 }
@@ -154,23 +199,42 @@ BiomGenerator::getGeneratorRules() const
     return rules;
 }
 
-BiomGeneratorFactory::BiomGeneratorFactory()
-    : TypeFactory()
-{}
+void BiomGenerator::addEntityGenerator(EntityGenerator* generator)
+{
+    entityGenerators.add(generator);
+}
 
-BiomGenerator* BiomGeneratorFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
+const Framework::RCArray<EntityGenerator>&
+BiomGenerator::getEntityGenerators() const
+{
+    return entityGenerators;
+}
+
+void BiomGenerator::addPlantConfig(PlantConfig* config)
 {
-    return new BiomGenerator();
+    plantConfigs.add(config);
 }
 
-void BiomGeneratorFactory::fromJson(
-    BiomGenerator* zResult, Framework::JSON::JSONObject* zJson) const
+const Framework::RCArray<PlantConfig>& BiomGenerator::getPlantConfigs() const
 {
-    zResult->setName(zJson->zValue("name")->asString()->getString());
-    zResult->setCondition(
-        Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(
-            zJson->zValue("condition")));
+    return plantConfigs;
+}
+
+BiomGeneratorFactory::BiomGeneratorFactory()
+    : ObjectTypeFactory()
+{}
+
+BiomGenerator* BiomGeneratorFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    BiomGenerator* result = new BiomGenerator();
+    result->setName(zJson->zValue("name")->asString()->getString());
+    if (zJson->hasValue("condition"))
+    {
+        result->setCondition(
+            Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(
+                zJson->zValue("condition")));
+    }
     bool first = 1;
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("structurCollections")->asArray())
@@ -178,39 +242,70 @@ void BiomGeneratorFactory::fromJson(
         StructureTemplateCollection* collection
             = Game::INSTANCE->zTypeRegistry()
                   ->fromJson<StructureTemplateCollection>(value);
-        zResult->addTemplate(collection);
+        result->addTemplate(collection);
     }
     for (Framework::JSON::JSONValue* value :
         *zJson->asObject()->zValue("blocks")->asArray())
     {
-        zResult->addGeneratorRule(
+        result->addGeneratorRule(
             Game::INSTANCE->zTypeRegistry()->fromJson<GeneratorRule>(value));
     }
+    for (Framework::JSON::JSONValue* value :
+        *zJson->asObject()->zValue("entities")->asArray())
+    {
+        result->addEntityGenerator(
+            Game::INSTANCE->zTypeRegistry()->fromJson<EntityGenerator>(value));
+    }
+    for (Framework::JSON::JSONValue* value :
+        *zJson->asObject()->zValue("plants")->asArray())
+    {
+        result->addPlantConfig(
+            Game::INSTANCE->zTypeRegistry()->fromJson<PlantConfig>(value));
+    }
+    return result;
 }
 
-void BiomGeneratorFactory::toJson(
-    BiomGenerator* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BiomGeneratorFactory::toJsonObject(
+    BiomGenerator* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "name", new Framework::JSON::JSONString(zObject->getName()));
-    zResult->addValue("condition",
-        Game::INSTANCE->zTypeRegistry()->toJson<JBoolExpression>(
-            zObject->getCondition()));
+    if (zObject->getCondition())
+    {
+        result->addValue("condition",
+            Game::INSTANCE->zTypeRegistry()->toJson<JBoolExpression>(
+                zObject->getCondition()));
+    }
     Framework::JSON::JSONArray* collections = new Framework::JSON::JSONArray();
     for (StructureTemplateCollection* collection : zObject->getTemplates())
     {
-        collections->addValue(
-            Game::INSTANCE->zTypeRegistry()
+        collections->addValue(Game::INSTANCE->zTypeRegistry()
                 ->toJson<StructureTemplateCollection>(collection));
     }
-    zResult->addValue("structurCollections", collections);
+    result->addValue("structurCollections", collections);
     Framework::JSON::JSONArray* rules = new Framework::JSON::JSONArray();
     for (GeneratorRule* rule : zObject->getGeneratorRules())
     {
         rules->addValue(
             Game::INSTANCE->zTypeRegistry()->toJson<GeneratorRule>(rule));
     }
-    zResult->addValue("blocks", rules);
+    result->addValue("blocks", rules);
+    Framework::JSON::JSONArray* entities = new Framework::JSON::JSONArray();
+    for (EntityGenerator* entity : zObject->getEntityGenerators())
+    {
+        entities->addValue(
+            Game::INSTANCE->zTypeRegistry()->toJson<EntityGenerator>(entity));
+    }
+    result->addValue("entities", entities);
+    Framework::JSON::JSONArray* plants = new Framework::JSON::JSONArray();
+    for (PlantConfig* plant : zObject->getPlantConfigs())
+    {
+        plants->addValue(
+            Game::INSTANCE->zTypeRegistry()->toJson<PlantConfig>(plant));
+    }
+    result->addValue("plants", plants);
+    return result;
 }
 
 JSONObjectValidationBuilder* BiomGeneratorFactory::addToValidator(
@@ -219,14 +314,23 @@ JSONObjectValidationBuilder* BiomGeneratorFactory::addToValidator(
     return builder->withRequiredString("name")
         ->finishString()
         ->withRequiredAttribute("condition",
-            Game::INSTANCE->zTypeRegistry()->getValidator<JBoolExpression>())
+            Game::INSTANCE->zTypeRegistry()->getValidator<JBoolExpression>(),
+            false,
+            true)
         ->withRequiredArray("structurCollections")
-        ->addAcceptedTypeInArray(
-            Game::INSTANCE->zTypeRegistry()
+        ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
                 ->getValidator<StructureTemplateCollection>())
         ->finishArray()
         ->withRequiredArray("blocks")
         ->addAcceptedTypeInArray(
             Game::INSTANCE->zTypeRegistry()->getValidator<GeneratorRule>())
+        ->finishArray()
+        ->withRequiredArray("entities")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<EntityGenerator>())
+        ->finishArray()
+        ->withRequiredArray("plants")
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<PlantConfig>())
         ->finishArray();
 }

+ 25 - 20
FactoryCraft/BiomGenerator.h

@@ -4,9 +4,10 @@
 #include <JSON.h>
 #include <ReferenceCounter.h>
 
+#include "EntityGenerator.h"
 #include "GeneratorRule.h"
-#include "JNoise.h"
 #include "JsonExpression.h"
+#include "PlantConfig.h"
 #include "StructureCollection.h"
 
 class Block;
@@ -21,30 +22,33 @@ private:
     JBoolExpression* condition;
     Framework::Vec3<int> minStructureOffset;
     Framework::Vec3<int> maxStructureOffset;
-
-protected:
-    int seed;
+    Framework::RCArray<EntityGenerator> entityGenerators;
+    Framework::RCArray<PlantConfig> plantConfigs;
 
 public:
     BiomGenerator();
     ~BiomGenerator();
 
     void initialize(JExpressionMemory* zMemory);
-    Framework::Either<Block*, int> generateBlock(int x,
+    Framework::Either<Block*, int> generateBlock(
+        int x, int y, int z, int dimensionId, Chunk* partialGeneratedChunk);
+    bool isApplicable();
+    void generateStructures(int x,
         int y,
         int z,
         int dimensionId,
-        JExpressionMemory* zMemory,
-        Chunk* partialGeneratedChunk);
-    bool isApplicable(JExpressionMemory* zMemory);
-    void generateStructures(int x,
+        Framework::Vec3<int>& minPos,
+        Framework::Vec3<int>& maxPos,
+        Framework::RCArray<GeneratedStructure>* zResult);
+    void generatePlants(int x,
         int y,
         int z,
         int dimensionId,
-        JExpressionMemory* zMemory,
-        Framework::Vec3<int> minPos,
-        Framework::Vec3<int> maxPos,
-        Framework::RCArray<GeneratedStructure>* zResult);
+        Chunk* zChunk,
+        bool underground,
+        bool underwater,
+        int seaFluidBlockTypeId);
+    void generateEntities(int x, int y, int z, int dimensionId, Chunk* zChunk);
 
     const Framework::RCArray<StructureTemplateCollection>& getTemplates() const;
     Framework::Vec3<int> getMinStructureOffset() const;
@@ -58,18 +62,19 @@ public:
     const Framework::RCArray<StructureTemplateCollection>& getTemplates();
     void addGeneratorRule(GeneratorRule* rule);
     const Framework::RCArray<GeneratorRule>& getGeneratorRules() const;
+    void addEntityGenerator(EntityGenerator* generator);
+    const Framework::RCArray<EntityGenerator>& getEntityGenerators() const;
+    void addPlantConfig(PlantConfig* config);
+    const Framework::RCArray<PlantConfig>& getPlantConfigs() const;
 };
 
-class BiomGeneratorFactory : public TypeFactory<BiomGenerator>
+class BiomGeneratorFactory : public ObjectTypeFactory<BiomGenerator>
 {
 public:
     BiomGeneratorFactory();
-    BiomGenerator* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BiomGenerator* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BiomGenerator* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    BiomGenerator* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BiomGenerator* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };

+ 100 - 93
FactoryCraft/Block.cpp

@@ -1,12 +1,11 @@
 #include "Block.h"
 
-#include "AddEntityUpdate.h"
 #include "Dimension.h"
 #include "Game.h"
+#include "InteractionConfig.h"
 #include "Inventory.h"
-#include "ItemEntity.h"
+#include "ItemType.h"
 #include "MultiblockStructure.h"
-#include "NoBlock.h"
 #include "PlaceableProof.h"
 #include "TickQueue.h"
 #include "WorldGenerator.h"
@@ -30,14 +29,13 @@ Block::Block(
     currentTickTimeout = 0;
     interactable = 0;
     deadAndRemoved = 0;
-    memset(zNeighbours, 0, sizeof(Block*) * 6);
     memset(lightEmisionColor, 0, 3);
     mapColor = 0;
 }
 
 Block::~Block() {}
 
-void Block::onDestroy()
+void Block::onDestroy(Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill)
 {
     if (!deadAndRemoved)
     {
@@ -45,7 +43,8 @@ void Block::onDestroy()
         {
             Framework::Vec3<int> pos
                 = getPos() + getDirection(getDirectionFromIndex(i));
-            if (neighbourTypes[i] == BlockTypeEnum::NO_BLOCK)
+            int type = Game::INSTANCE->getBlockType(pos, getDimensionId());
+            if (type == BlockTypeEnum::NO_BLOCK)
             {
                 Game::INSTANCE->zDimension(dimensionId)
                     ->placeBlock(pos,
@@ -57,20 +56,43 @@ void Block::onDestroy()
                 Game::INSTANCE->zDimension(dimensionId)->sendBlockInfo(pos);
             }
         }
-        Item* blockItem = zBlockType()->getItemFromBlock(this);
-        if (blockItem)
+        getThis();
+        if (zActor)
         {
-            Game::INSTANCE->spawnItem(
-                location + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
-                dimensionId,
-                blockItem);
+            for (const DropConfig* config : zBlockType()->getDropConfigs())
+            {
+                config->onObjectDestroyed(zActor,
+                    zUsedItem,
+                    zUsedSkill,
+                    this); // a nother block might replace this block during the
+                           // drops
+            }
         }
+        Framework::Either<Block*, int> block
+            = Game::INSTANCE->zBlockAt(getPos(), dimensionId, 0);
         deadAndRemoved = 1;
-        for (MultiblockStructure* structure : structures)
-            structure->onBlockRemoved(this);
-        Game::INSTANCE->zDimension(dimensionId)
-            ->placeBlock(
-                getPos(), BlockTypeEnum::AIR); // this will be deleted here
+        if (block.isA()
+            && block.getA() == this) // no other block has replaced this block
+        {
+            for (MultiblockStructure* structure : structures)
+                structure->onBlockRemoved(zActor, zUsedItem, zUsedSkill, this);
+            Game::INSTANCE->zDimension(dimensionId)
+                ->placeBlock(getPos(), BlockTypeEnum::AIR);
+        }
+        else
+        {
+            if (structures.getEintragAnzahl() > 0)
+            { // replace this block in the structures
+                Block* zReplacement = block.isA()
+                                        ? block.getA()
+                                        : Game::INSTANCE->zRealBlockInstance(
+                                              getPos(), dimensionId);
+                for (MultiblockStructure* structure : structures)
+                    structure->onBlockReplaced(
+                        zActor, zUsedItem, zUsedSkill, this, zReplacement);
+            }
+        }
+        release();
     }
 }
 
@@ -124,6 +146,12 @@ void Block::broadcastPassableSpeedModifierChange()
     broadcastMessage(message);
 }
 
+void Block::onApiCall(char messageType,
+    Framework::StreamReader* zRequest,
+    NetworkMessage* zResponse,
+    Entity* zSource)
+{}
+
 void Block::tick(TickQueue* zQueue)
 {
     if (wasTicked) return;
@@ -180,29 +208,6 @@ void Block::postTick()
     }
 }
 
-void Block::setNeighbour(
-    Direction dir, Framework::Either<Block*, int> neighbour)
-{
-    if (neighbour.isA())
-        setNeighbourBlock(dir, neighbour);
-    else
-    {
-        setNeighbourBlock(dir, 0);
-        setNeighbourType(dir, neighbour);
-    }
-}
-
-void Block::setNeighbourBlock(Direction dir, Block* zN)
-{
-    if (zN) setNeighbourType(dir, zN->zBlockType()->getId());
-    zNeighbours[getDirectionIndex(dir)] = zN;
-}
-
-void Block::setNeighbourType(Direction dir, int type)
-{
-    neighbourTypes[getDirectionIndex(dir)] = type;
-}
-
 void Block::addToStructure(MultiblockStructure* structure)
 {
     if (structure->isBlockMember(this))
@@ -223,7 +228,7 @@ void Block::onUnloaded()
         structure->onBlockUnloaded(this);
 }
 
-Framework::Text Block::getTargetUIML()
+Framework::XML::Element* Block::getTargetUIML() const
 {
     return Game::INSTANCE->zBlockType(typeId)->getTargetUIML();
 }
@@ -233,12 +238,19 @@ void Block::sendModelInfo(NetworkMessage* zMessage)
     // overwritten by some blocks
 }
 
-bool Block::interact(Item* zItem, Entity* zActor)
+bool Block::interact(Item* zItem, Entity* zActor, bool& itemChanged)
 {
+    bool result = 0;
+    for (InteractionConfig* config : zBlockType()->getInteractionConfigs())
+    {
+        result |= config->doInteraction(this, zItem, zActor, itemChanged);
+    }
     return false;
 }
 
-void Block::api(Framework::StreamReader* zRequest, NetworkMessage* zResponse)
+void Block::api(Framework::StreamReader* zRequest,
+    NetworkMessage* zResponse,
+    Entity* zSource)
 {
     char id = 0;
     zRequest->lese(&id, 1);
@@ -249,14 +261,19 @@ void Block::api(Framework::StreamReader* zRequest, NetworkMessage* zResponse)
         sendModelInfo(zResponse);
         break;
     case 1: // dialog closed
-        short nameLen;
-        zRequest->lese((char*)&nameLen, 2);
-        char* name = new char[nameLen + 1];
-        zRequest->lese(name, nameLen);
-        name[nameLen] = 0;
-        onDialogClosed(name);
-        delete[] name;
-        break;
+        {
+            short nameLen;
+            zRequest->lese((char*)&nameLen, 2);
+            char* name = new char[nameLen + 1];
+            zRequest->lese(name, nameLen);
+            name[nameLen] = 0;
+            onDialogClosed(name);
+            delete[] name;
+            break;
+        }
+        // 2 is handled in BasicBlock
+    default: // component request handled in BasicBlock
+        onApiCall(id, zRequest, zResponse, zSource);
     }
 }
 
@@ -315,24 +332,14 @@ const Framework::Vec3<int> Block::getPos() const
     return (Framework::Vec3<int>)location;
 }
 
-bool Block::isVisible() const
-{
-    if (passable || transparent) return 1;
-    for (int i = 0; i < 6; i++)
-    {
-        const Block* neighbour = CONST_BLOCK(zNeighbours[i], neighbourTypes[i]);
-        if (neighbour->isPassable() || neighbour->isTransparent()) return 1;
-    }
-    return 0;
-}
-
-void Block::setHP(float hp)
+void Block::setHP(
+    Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, float hp)
 {
     bool isDead = this->hp == 0.f;
     this->hp = MAX(0.f, hp);
     if (!isDead && this->hp == 0.f)
     {
-        onDestroy(); // this will be deleted
+        onDestroy(zActor, zUsedItem, zUsedSkill); // this will be deleted
     }
     else
     {
@@ -351,9 +358,11 @@ bool Block::isDeadAndRemoved() const
     return deadAndRemoved;
 }
 
-const unsigned char* Block::getLightEmisionColor() const
+void Block::getLightEmisionColor(unsigned char* result) const
 {
-    return lightEmisionColor;
+    result[0] = lightEmisionColor[0];
+    result[1] = lightEmisionColor[0];
+    result[2] = lightEmisionColor[0];
 }
 
 void Block::filterPassingLight(unsigned char rgb[3]) const
@@ -362,11 +371,6 @@ void Block::filterPassingLight(unsigned char rgb[3]) const
         memset(rgb, 0, 3);
 }
 
-Block* Block::zNeighbor(Direction dir) const
-{
-    return zNeighbours[getDirectionIndex(dir)];
-}
-
 void Block::updateModel(ModelInfo* zInfo) const
 {
     Dimension* dim = Game::INSTANCE->zDimension(getDimensionId());
@@ -604,44 +608,47 @@ BasicBlockItemType* BasicBlockItemTypeFactory::createValue(
     return new BasicBlockItemType();
 }
 
-void BasicBlockItemTypeFactory::fromJson(
-    BasicBlockItemType* zResult, Framework::JSON::JSONObject* zJson) const
+BasicBlockItemType* BasicBlockItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
-    zResult->setPassable(zJson->zValue("passable")->asBool()->getBool());
-    zResult->setHardness(
+    BasicBlockItemType* result = ItemTypeFactoryBase::fromJson(zJson);
+    result->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
+    result->setPassable(zJson->zValue("passable")->asBool()->getBool());
+    result->setHardness(
         (float)zJson->zValue("hardness")->asNumber()->getNumber());
-    zResult->setSpeedModifier(
+    result->setSpeedModifier(
         (float)zJson->zValue("speedModifier")->asNumber()->getNumber());
-    zResult->setBlockTypeName(
+    result->setBlockTypeName(
         zJson->zValue("blockType")->asString()->getString());
-    zResult->setPlaceableProof(
+    result->setPlaceableProof(
         zJson->zValue("placeableProof")->getType()
-                == Framework::JSON::JSONType::OBJECT
+                == Framework::AbstractType::OBJECT
             ? Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
-                zJson->zValue("placeableProof"))
+                  zJson->zValue("placeableProof"))
             : 0);
-    ItemTypeFactoryBase::fromJson(zResult, zJson);
+    return result;
 }
 
-void BasicBlockItemTypeFactory::toJson(
-    BasicBlockItemType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BasicBlockItemTypeFactory::toJsonObject(
+    BasicBlockItemType* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result
+        = ItemTypeFactoryBase::toJsonObject(zObject);
+    result->addValue(
         "transparent", new Framework::JSON::JSONBool(zObject->isTransparent()));
-    zResult->addValue(
+    result->addValue(
         "passable", new Framework::JSON::JSONBool(zObject->isPassable()));
-    zResult->addValue(
+    result->addValue(
         "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
-    zResult->addValue("speedModifier",
+    result->addValue("speedModifier",
         new Framework::JSON::JSONNumber(zObject->getSpeedModifier()));
-    zResult->addValue("blockType",
+    result->addValue("blockType",
         new Framework::JSON::JSONString(zObject->getBlockTypeName()));
-    zResult->addValue("placeableProof",
+    result->addValue("placeableProof",
         zObject->zPlaceableProof() ? Game::INSTANCE->zTypeRegistry()->toJson(
-            zObject->zPlaceableProof())
+                                         zObject->zPlaceableProof())
                                    : new Framework::JSON::JSONValue());
-    ItemTypeFactoryBase::toJson(zObject, zResult);
+    return result;
 }
 
 JSONObjectValidationBuilder* BasicBlockItemTypeFactory::addToValidator(
@@ -670,7 +677,7 @@ JSONObjectValidationBuilder* BasicBlockItemTypeFactory::addToValidator(
             ->finishObject());
 }
 
-Framework::Text BasicBlockItemTypeFactory::getTypeToken() const
+const char* BasicBlockItemTypeFactory::getTypeToken() const
 {
     return "placeable";
 }

+ 21 - 24
FactoryCraft/Block.h

@@ -1,21 +1,18 @@
 #pragma once
 
-#include <Either.h>
-#include <Trie.h>
 #include <Vec3.h>
-#include <VecN.h>
 
 #include "Inventory.h"
 #include "Item.h"
+#include "ItemType.h"
 #include "MultiblockStructure.h"
 #include "NetworkMessage.h"
-#include "ReferenceCounter.h"
 #include "Tickable.h"
 #include "TickSourceType.h"
 
 #define CONST_BLOCK(maybeBlock, type) \
-    (maybeBlock ? maybeBlock          \
-                : Game::INSTANCE->zBlockType((int)type)->zDefault())
+    ((maybeBlock) ? (maybeBlock)      \
+                  : Game::INSTANCE->zBlockType((int)(type))->zDefault())
 
 class ItemType;
 class Chunk;
@@ -41,8 +38,6 @@ protected:
     float hardness;
     int typeId;
     float speedModifier;
-    Block* zNeighbours[6];
-    int neighbourTypes[6];
 
     int minTickTimeout;
     int maxTickTimeout;
@@ -69,12 +64,17 @@ protected:
     /// the order of blocks called will be exactly the same as onTick
     /// </summary>
     virtual void onPostTick() = 0;
-    virtual void onDestroy();
+    virtual void onDestroy(
+        Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill);
 
     virtual void onDialogClosed(Framework::Text dialogId);
     void broadcastModelInfoChange();
     void broadcastMessage(NetworkMessage* message);
     void broadcastPassableSpeedModifierChange();
+    virtual void onApiCall(char messageType,
+        Framework::StreamReader* zRequest,
+        NetworkMessage* zResponse,
+        Entity* zSource);
 
 public:
     Block(int typeId,
@@ -88,14 +88,12 @@ public:
     void addToStructure(MultiblockStructure* structure);
     virtual void onLoaded();
     virtual void onUnloaded();
-    virtual void setNeighbour(
-        Direction dir, Framework::Either<Block*, int> neighbor);
-    virtual void setNeighbourBlock(Direction dir, Block* zN);
-    virtual void setNeighbourType(Direction dir, int type);
-    virtual Framework::Text getTargetUIML();
+    virtual Framework::XML::Element* getTargetUIML() const;
     virtual void sendModelInfo(NetworkMessage* zMessage);
-    virtual bool interact(Item* zItem, Entity* zActor);
-    void api(Framework::StreamReader* zRequest, NetworkMessage* zResponse);
+    virtual bool interact(Item* zItem, Entity* zActor, bool& itemChanged);
+    void api(Framework::StreamReader* zRequest,
+        NetworkMessage* zResponse,
+        Entity* zSource);
     virtual TickSourceType isTickSource() const;
     virtual bool needsTick() const;
     const BlockType* zBlockType() const;
@@ -107,12 +105,11 @@ public:
     float getHardness() const;
     float getSpeedModifier() const;
     const Framework::Vec3<int> getPos() const;
-    bool isVisible() const;
-    void setHP(float hp);
+    void setHP(
+        Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, float hp);
     bool isDeadAndRemoved() const;
-    const unsigned char* getLightEmisionColor() const;
+    virtual void getLightEmisionColor(unsigned char* result) const;
     virtual void filterPassingLight(unsigned char rgb[3]) const;
-    Block* zNeighbor(Direction dir) const;
     void updateModel(ModelInfo* zInfo) const;
     int getMapColor() const;
 
@@ -198,11 +195,11 @@ public:
     BasicBlockItemTypeFactory();
     BasicBlockItemType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BasicBlockItemType* zResult,
+    BasicBlockItemType* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BasicBlockItemType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BasicBlockItemType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 15 - 0
FactoryCraft/BlockComponent.cpp

@@ -0,0 +1,15 @@
+#include "BlockComponent.h"
+
+BlockComponent::BlockComponent()
+    : Framework::ReferenceCounter()
+{}
+
+bool BlockComponent::isLightSource() const
+{
+    return 0;
+}
+
+int BlockComponent::getLightColor() const
+{
+    return 0;
+}

+ 28 - 0
FactoryCraft/BlockComponent.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include <Reader.h>
+#include <ReferenceCounter.h>
+#include <Writer.h>
+#include <XML.h>
+
+class Block;
+class Entity;
+
+class NetworkMessage;
+
+class BlockComponent : public virtual Framework::ReferenceCounter
+{
+public:
+    BlockComponent();
+    virtual void initialize(Block* zBlock) = 0;
+    virtual bool tick(int numTicks) = 0;
+    virtual void api(Framework::StreamReader* zRequest,
+        NetworkMessage* zResponse,
+        Entity* zSource)
+        = 0;
+    virtual Framework::XML::Element* getTooltipUIML() const = 0;
+    virtual void loadComponent(Framework::StreamReader* zReader) = 0;
+    virtual void saveComponent(Framework::StreamWriter* zWriter) const = 0;
+    virtual bool isLightSource() const;
+    virtual int getLightColor() const;
+};

+ 83 - 98
FactoryCraft/BlockFilter.cpp

@@ -38,32 +38,30 @@ BlockFilterAndFactory::BlockFilterAndFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterAnd* BlockFilterAndFactory::createValue(
+BlockFilterAnd* BlockFilterAndFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterAnd();
-}
-
-void BlockFilterAndFactory::fromJson(
-    BlockFilterAnd* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    BlockFilterAnd* result = new BlockFilterAnd();
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("filters")->asArray())
     {
-        zResult->addFilter(
+        result->addFilter(
             Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(value));
     }
+    return result;
 }
 
-void BlockFilterAndFactory::toJson(
-    BlockFilterAnd* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterAndFactory::toJsonObject(
+    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));
     }
-    zResult->addValue("filters", filters);
+    result->addValue("filters", filters);
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterAndFactory::addToValidator(
@@ -75,7 +73,7 @@ JSONObjectValidationBuilder* BlockFilterAndFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text BlockFilterAndFactory::getTypeToken() const
+const char* BlockFilterAndFactory::getTypeToken() const
 {
     return "and";
 }
@@ -110,32 +108,30 @@ BlockFilterOrFactory::BlockFilterOrFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterOr* BlockFilterOrFactory::createValue(
+BlockFilterOr* BlockFilterOrFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterOr();
-}
-
-void BlockFilterOrFactory::fromJson(
-    BlockFilterOr* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    BlockFilterOr* result = new BlockFilterOr();
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("filters")->asArray())
     {
-        zResult->addFilter(
+        result->addFilter(
             Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(value));
     }
+    return result;
 }
 
-void BlockFilterOrFactory::toJson(
-    BlockFilterOr* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterOrFactory::toJsonObject(
+    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));
     }
-    zResult->addValue("filters", filters);
+    result->addValue("filters", filters);
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterOrFactory::addToValidator(
@@ -147,7 +143,7 @@ JSONObjectValidationBuilder* BlockFilterOrFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text BlockFilterOrFactory::getTypeToken() const
+const char* BlockFilterOrFactory::getTypeToken() const
 {
     return "or";
 }
@@ -182,24 +178,22 @@ BlockFilterNotFactory::BlockFilterNotFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterNot* BlockFilterNotFactory::createValue(
+BlockFilterNot* BlockFilterNotFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterNot();
-}
-
-void BlockFilterNotFactory::fromJson(
-    BlockFilterNot* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
+    BlockFilterNot* result = new BlockFilterNot();
+    result->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
         zJson->zValue("filter")));
+    return result;
 }
 
-void BlockFilterNotFactory::toJson(
-    BlockFilterNot* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterNotFactory::toJsonObject(
+    BlockFilterNot* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterNotFactory::addToValidator(
@@ -209,7 +203,7 @@ JSONObjectValidationBuilder* BlockFilterNotFactory::addToValidator(
         "filter", Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>());
 }
 
-Framework::Text BlockFilterNotFactory::getTypeToken() const
+const char* BlockFilterNotFactory::getTypeToken() const
 {
     return "not";
 }
@@ -244,45 +238,44 @@ BlockFilterBlockTypeFactory::BlockFilterBlockTypeFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterBlockType* BlockFilterBlockTypeFactory::createValue(
+BlockFilterBlockType* BlockFilterBlockTypeFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterBlockType();
-}
-
-void BlockFilterBlockTypeFactory::fromJson(
-    BlockFilterBlockType* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    BlockFilterBlockType* result = new BlockFilterBlockType();
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("typeNames")->asArray())
     {
-        zResult->addBlockTypeId(
+        result->addBlockTypeId(
             Game::INSTANCE->getBlockTypeId(value->asString()->getString()));
     }
+    return result;
 }
 
-void BlockFilterBlockTypeFactory::toJson(
-    BlockFilterBlockType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterBlockTypeFactory::toJsonObject(
+    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()));
     }
-    zResult->addValue("typeNames", typeNames);
+    result->addValue("typeNames", typeNames);
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterBlockTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
     return builder->withRequiredArray("typeNames")
-        ->addAcceptedStringInArray()
-        ->finishString()
+        ->addAcceptedTypeInArray(
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                BlockTypeNameFactory::TYPE_ID))
         ->finishArray();
 }
 
-Framework::Text BlockFilterBlockTypeFactory::getTypeToken() const
+const char* BlockFilterBlockTypeFactory::getTypeToken() const
 {
     return "types";
 }
@@ -322,31 +315,29 @@ BlockFilterTypeGroupFactory::BlockFilterTypeGroupFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterTypeGroup* BlockFilterTypeGroupFactory::createValue(
+BlockFilterTypeGroup* BlockFilterTypeGroupFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterTypeGroup();
-}
-
-void BlockFilterTypeGroupFactory::fromJson(
-    BlockFilterTypeGroup* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    BlockFilterTypeGroup* result = new BlockFilterTypeGroup();
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("groupNames")->asArray())
     {
-        zResult->addGroupName(value->asString()->getString());
+        result->addGroupName(value->asString()->getString());
     }
+    return result;
 }
 
-void BlockFilterTypeGroupFactory::toJson(
-    BlockFilterTypeGroup* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterTypeGroupFactory::toJsonObject(
+    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));
     }
-    zResult->addValue("groupNames", groupNames);
+    result->addValue("groupNames", groupNames);
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterTypeGroupFactory::addToValidator(
@@ -358,7 +349,7 @@ JSONObjectValidationBuilder* BlockFilterTypeGroupFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text BlockFilterTypeGroupFactory::getTypeToken() const
+const char* BlockFilterTypeGroupFactory::getTypeToken() const
 {
     return "groups";
 }
@@ -386,24 +377,22 @@ BlockFilterMaxHardnessFactory::BlockFilterMaxHardnessFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterMaxHardness* BlockFilterMaxHardnessFactory::createValue(
+BlockFilterMaxHardness* BlockFilterMaxHardnessFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterMaxHardness();
-}
-
-void BlockFilterMaxHardnessFactory::fromJson(
-    BlockFilterMaxHardness* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setMaxHardness(
+    BlockFilterMaxHardness* result = new BlockFilterMaxHardness();
+    result->setMaxHardness(
         (float)zJson->zValue("maxHardness")->asNumber()->getNumber());
+    return result;
 }
 
-void BlockFilterMaxHardnessFactory::toJson(
-    BlockFilterMaxHardness* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterMaxHardnessFactory::toJsonObject(
+    BlockFilterMaxHardness* zObject) const
 {
-    zResult->addValue("maxHardness",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("maxHardness",
         new Framework::JSON::JSONNumber(zObject->getMaxHardness()));
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterMaxHardnessFactory::addToValidator(
@@ -414,7 +403,7 @@ JSONObjectValidationBuilder* BlockFilterMaxHardnessFactory::addToValidator(
         ->finishNumber();
 }
 
-Framework::Text BlockFilterMaxHardnessFactory::getTypeToken() const
+const char* BlockFilterMaxHardnessFactory::getTypeToken() const
 {
     return "maxHardness";
 }
@@ -443,24 +432,22 @@ BlockFilterMinHardnessFactory::BlockFilterMinHardnessFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterMinHardness* BlockFilterMinHardnessFactory::createValue(
+BlockFilterMinHardness* BlockFilterMinHardnessFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterMinHardness();
-}
-
-void BlockFilterMinHardnessFactory::fromJson(
-    BlockFilterMinHardness* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setMinHardness(
+    BlockFilterMinHardness* result = new BlockFilterMinHardness();
+    result->setMinHardness(
         (float)zJson->zValue("minHardness")->asNumber()->getNumber());
+    return result;
 }
 
-void BlockFilterMinHardnessFactory::toJson(
-    BlockFilterMinHardness* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterMinHardnessFactory::toJsonObject(
+    BlockFilterMinHardness* zObject) const
 {
-    zResult->addValue("minHardness",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("minHardness",
         new Framework::JSON::JSONNumber(zObject->getMinHardness()));
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterMinHardnessFactory::addToValidator(
@@ -471,7 +458,7 @@ JSONObjectValidationBuilder* BlockFilterMinHardnessFactory::addToValidator(
         ->finishNumber();
 }
 
-Framework::Text BlockFilterMinHardnessFactory::getTypeToken() const
+const char* BlockFilterMinHardnessFactory::getTypeToken() const
 {
     return "minHardness";
 }
@@ -502,23 +489,21 @@ BlockFilterMaxHeatFactory::BlockFilterMaxHeatFactory()
     : SubTypeFactory()
 {}
 
-BlockFilterMaxHeat* BlockFilterMaxHeatFactory::createValue(
+BlockFilterMaxHeat* BlockFilterMaxHeatFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new BlockFilterMaxHeat();
-}
-
-void BlockFilterMaxHeatFactory::fromJson(
-    BlockFilterMaxHeat* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setMaxHeat((float)zJson->zValue("heat")->asNumber()->getNumber());
+    BlockFilterMaxHeat* result = new BlockFilterMaxHeat();
+    result->setMaxHeat((float)zJson->zValue("heat")->asNumber()->getNumber());
+    return result;
 }
 
-void BlockFilterMaxHeatFactory::toJson(
-    BlockFilterMaxHeat* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockFilterMaxHeatFactory::toJsonObject(
+    BlockFilterMaxHeat* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "heat", new Framework::JSON::JSONNumber(zObject->getMaxHeat()));
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockFilterMaxHeatFactory::addToValidator(
@@ -527,7 +512,7 @@ JSONObjectValidationBuilder* BlockFilterMaxHeatFactory::addToValidator(
     return builder->withRequiredNumber("heat")->finishNumber();
 }
 
-Framework::Text BlockFilterMaxHeatFactory::getTypeToken() const
+const char* BlockFilterMaxHeatFactory::getTypeToken() const
 {
     return "maxHeat";
 }

+ 32 - 51
FactoryCraft/BlockFilter.h

@@ -29,15 +29,12 @@ class BlockFilterAndFactory : public SubTypeFactory<BlockFilter, BlockFilterAnd>
 {
 public:
     BlockFilterAndFactory();
-    BlockFilterAnd* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterAnd* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterAnd* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    BlockFilterAnd* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterAnd* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockFilterOr : public BlockFilter
@@ -56,15 +53,12 @@ class BlockFilterOrFactory : public SubTypeFactory<BlockFilter, BlockFilterOr>
 {
 public:
     BlockFilterOrFactory();
-    BlockFilterOr* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterOr* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterOr* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    BlockFilterOr* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterOr* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockFilterNot : public BlockFilter
@@ -84,15 +78,12 @@ class BlockFilterNotFactory : public SubTypeFactory<BlockFilter, BlockFilterNot>
 {
 public:
     BlockFilterNotFactory();
-    BlockFilterNot* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterNot* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterNot* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    BlockFilterNot* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterNot* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockFilterBlockType : public BlockFilter
@@ -112,15 +103,13 @@ class BlockFilterBlockTypeFactory
 {
 public:
     BlockFilterBlockTypeFactory();
-    BlockFilterBlockType* createValue(
+    BlockFilterBlockType* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterBlockType* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterBlockType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockFilterTypeGroup : public BlockFilter
@@ -140,15 +129,13 @@ class BlockFilterTypeGroupFactory
 {
 public:
     BlockFilterTypeGroupFactory();
-    BlockFilterTypeGroup* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterTypeGroup* zResult,
+    BlockFilterTypeGroup* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterTypeGroup* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterTypeGroup* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockFilterMaxHardness : public BlockFilter
@@ -168,15 +155,13 @@ class BlockFilterMaxHardnessFactory
 {
 public:
     BlockFilterMaxHardnessFactory();
-    BlockFilterMaxHardness* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterMaxHardness* zResult,
+    BlockFilterMaxHardness* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterMaxHardness* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterMaxHardness* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockFilterMinHardness : public BlockFilter
@@ -196,15 +181,13 @@ class BlockFilterMinHardnessFactory
 {
 public:
     BlockFilterMinHardnessFactory();
-    BlockFilterMinHardness* createValue(
+    BlockFilterMinHardness* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterMinHardness* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterMinHardness* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterMinHardness* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class BlockFilterMaxHeat : public BlockFilter
@@ -224,13 +207,11 @@ class BlockFilterMaxHeatFactory
 {
 public:
     BlockFilterMaxHeatFactory();
-    BlockFilterMaxHeat* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockFilterMaxHeat* zResult,
+    BlockFilterMaxHeat* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockFilterMaxHeat* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockFilterMaxHeat* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 4 - 4
FactoryCraft/BlockInfoCommand.cpp

@@ -57,6 +57,8 @@ bool BlockInfoCommand::execute(
         else
         {
             Block* zBlock = block.getA();
+            unsigned char lightColor[3];
+            zBlock->getLightEmisionColor(lightColor);
             result.append()
                 << "Block instance found.\n"
                 << "  Block Type: " << zBlock->zBlockType()->getName() << " ("
@@ -69,10 +71,8 @@ bool BlockInfoCommand::execute(
                 << "  Tick source: " << zBlock->isTickSource() << "\n"
                 << "  Interactable by hand: " << zBlock->isInteractable(0)
                 << "\n"
-                << "  Light emission: ("
-                << (int)zBlock->getLightEmisionColor()[0] << ", "
-                << (int)zBlock->getLightEmisionColor()[1] << ", "
-                << (int)zBlock->getLightEmisionColor()[2] << ")\n";
+                << "  Light emission: (" << (int)lightColor[0] << ", "
+                << (int)lightColor[1] << ", " << (int)lightColor[2] << ")\n";
         }
         result += "  Light data: ";
         Chunk* zChunk = Game::INSTANCE->zDimension(dimension)->zChunk(

+ 15 - 22
FactoryCraft/BlockInstanceGeneratorRule.cpp

@@ -1,5 +1,6 @@
 #include "BlockInstanceGeneratorRule.h"
 
+#include "BlockType.h"
 #include "Game.h"
 
 BlockInstanceGeneratorRule::BlockInstanceGeneratorRule()
@@ -34,44 +35,36 @@ BlockInstanceGeneratorRule* BlockInstanceGeneratorRuleFactory::createValue(
     return new BlockInstanceGeneratorRule();
 }
 
-void BlockInstanceGeneratorRuleFactory::fromJson(
-    BlockInstanceGeneratorRule* zResult,
+BlockInstanceGeneratorRule* BlockInstanceGeneratorRuleFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setBlockTypeId(Game::INSTANCE->getBlockTypeId(
+    BlockInstanceGeneratorRule* result = GeneratorRuleFactory::fromJson(zJson);
+    result->setBlockTypeId(Game::INSTANCE->getBlockTypeId(
         zJson->zValue("blockType")->asString()->getString()));
-    GeneratorRuleFactory::fromJson(zResult, zJson);
+    return result;
 }
 
-void BlockInstanceGeneratorRuleFactory::toJson(
-    BlockInstanceGeneratorRule* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockInstanceGeneratorRuleFactory::toJsonObject(
+    BlockInstanceGeneratorRule* zObject) const
 {
-    zResult->addValue("blockType",
+    Framework::JSON::JSONObject* result
+        = GeneratorRuleFactory::toJsonObject(zObject);
+    result->addValue("blockType",
         new Framework::JSON::JSONString(
             Game::INSTANCE->zBlockType(zObject->getBlockTypeId())->getName()));
-    GeneratorRuleFactory::toJson(zObject, zResult);
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockInstanceGeneratorRuleFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zBlockType(i))
-        {
-            blockTypeNames.add(
-                new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
-        }
-    }
     return GeneratorRuleFactory::addToValidator(
-        builder->withRequiredString("blockType")
-            ->whichIsOneOf(blockTypeNames)
-            ->finishString());
+        builder->withRequiredAttribute("blockType",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                BlockTypeNameFactory::TYPE_ID)));
 }
 
-Framework::Text BlockInstanceGeneratorRuleFactory::getTypeToken() const
+const char* BlockInstanceGeneratorRuleFactory::getTypeToken() const
 {
     return "blockInstance";
 }

+ 4 - 4
FactoryCraft/BlockInstanceGeneratorRule.h

@@ -22,11 +22,11 @@ public:
     BlockInstanceGeneratorRuleFactory();
     BlockInstanceGeneratorRule* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockInstanceGeneratorRule* zResult,
+    BlockInstanceGeneratorRule* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockInstanceGeneratorRule* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockInstanceGeneratorRule* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 67 - 0
FactoryCraft/BlockReplacementDrop.cpp

@@ -0,0 +1,67 @@
+#include "BlockReplacementDrop.h"
+
+#include "Block.h"
+#include "BlockType.h"
+#include "Dimension.h"
+
+BlockReplacementDrop::BlockReplacementDrop(Framework::Text blockTypeName)
+    : DropConfig(),
+      blockTypeName(blockTypeName),
+      zBlockType(0)
+{}
+
+void BlockReplacementDrop::initialize()
+{
+    int id = Game::INSTANCE->getBlockTypeId(blockTypeName);
+    zBlockType = Game::INSTANCE->zBlockType(id < 0 ? BlockTypeEnum::AIR : id);
+}
+
+Framework::Text BlockReplacementDrop::getBlockTypeName() const
+{
+    return blockTypeName;
+}
+
+void BlockReplacementDrop::doDrop(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject) const
+{
+    if (zBlockType && zDestroyedObject.isA())
+    {
+        Game::INSTANCE->zDimension(zDestroyedObject.getA()->getDimensionId())
+            ->placeBlock(
+                zDestroyedObject.getA()->getPos(), zBlockType->getId());
+    }
+}
+
+BlockReplacementDropFactory::BlockReplacementDropFactory()
+    : DropConfigFactory<BlockReplacementDrop>()
+{}
+
+JSONObjectValidationBuilder* BlockReplacementDropFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return DropConfigFactory::addToValidator(builder)->withRequiredAttribute(
+        "blockType",
+        Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+            BlockTypeNameFactory::TYPE_ID));
+}
+
+const char* BlockReplacementDropFactory::getTypeToken() const
+{
+    return "blockReplacement";
+}
+
+BlockReplacementDrop* BlockReplacementDropFactory::createInstance(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new BlockReplacementDrop(
+        zJson->zValue("blockType")->asString()->getString());
+}
+
+void BlockReplacementDropFactory::addToJson(
+    Framework::JSON::JSONObject* zJson, BlockReplacementDrop* zObject) const
+{
+    zJson->addValue("blockTypeName",
+        new Framework::JSON::JSONString(zObject->getBlockTypeName()));
+}

+ 35 - 0
FactoryCraft/BlockReplacementDrop.h

@@ -0,0 +1,35 @@
+#pragma once
+
+#include "DropConfig.h"
+
+class BlockType;
+
+class BlockReplacementDrop : public DropConfig
+{
+private:
+    const BlockType* zBlockType;
+    Framework::Text blockTypeName;
+
+public:
+    BlockReplacementDrop(Framework::Text blockTypeName);
+    void initialize() override;
+    Framework::Text getBlockTypeName() const;
+    void doDrop(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) const override;
+};
+
+class BlockReplacementDropFactory
+    : public DropConfigFactory<BlockReplacementDrop>
+{
+public:
+    BlockReplacementDropFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+    BlockReplacementDrop* createInstance(
+        Framework::JSON::JSONObject* zJson) const override;
+    void addToJson(Framework::JSON::JSONObject* zJson,
+        BlockReplacementDrop* zObject) const override;
+};

+ 44 - 8
FactoryCraft/BlockType.cpp

@@ -1,11 +1,9 @@
 #include "BlockType.h"
 
-#include "BasicBlocks.h"
 #include "Block.h"
+#include "Dimension.h"
 #include "Game.h"
-#include "ItemType.h"
 #include "MultiblockStructure.h"
-#include "Dimension.h"
 
 using namespace Framework;
 
@@ -21,7 +19,8 @@ BlockType::BlockType()
       initialMapColor(0),
       defaultBlock(0),
       groupNames(),
-      hardness(1.f)
+      hardness(1.f),
+      damagableByHand(0)
 {}
 
 BlockType::~BlockType()
@@ -111,6 +110,10 @@ void BlockType::createSuperItem(Block* zBlock, Item* zItem) const
 
 bool BlockType::initialize(Game* zGame)
 {
+    for (DropConfig* config : dropConfigs)
+    {
+        config->initialize();
+    }
     return true;
 }
 
@@ -123,6 +126,16 @@ BlockType* BlockType::initializeDefault()
     return this;
 }
 
+void BlockType::addDropConfig(DropConfig* config)
+{
+    dropConfigs.add(config);
+}
+
+const Framework::RCArray<DropConfig>& BlockType::getDropConfigs() const
+{
+    return dropConfigs;
+}
+
 const Block* BlockType::zDefault() const
 {
     return defaultBlock;
@@ -148,17 +161,19 @@ void BlockType::writeTypeInfo(StreamWriter* zWriter) const
     zModel()->writeTo(zWriter);
 }
 
-Framework::Text BlockType::getTargetUIML() const
+Framework::XML::Element* BlockType::getTargetUIML() const
 {
-    return Text("<targetInfo><text width=\"auto\" height=\"auto\">") + name
-         + "</text></targetInfo>";
+    return new Framework::XML::Element(
+        Framework::Text(
+            "<targetInfo><text id=\"type\" width=\"auto\" height=\"auto\">")
+        + name + "</text></targetInfo>");
 }
 
 Block* BlockType::loadBlock(Framework::Vec3<int> position,
     Framework::StreamReader* zReader,
     int dimensionId) const
 {
-    Block* result = createBlock(position, dimensionId);
+    Block* result = createBlockAt(position, dimensionId, 0);
     loadSuperBlock(result, zReader, dimensionId);
     return result;
 }
@@ -296,6 +311,27 @@ float BlockType::getHardness() const
     return hardness;
 }
 
+void BlockType::setDamagableByHand(bool damagableByHand)
+{
+    this->damagableByHand = damagableByHand;
+}
+
+bool BlockType::isDamagableByHand() const
+{
+    return damagableByHand;
+}
+
+void BlockType::addInteractionConfig(InteractionConfig* config)
+{
+    interactionConfigs.add(config);
+}
+
+const Framework::RCArray<InteractionConfig>&
+BlockType::getInteractionConfigs() const
+{
+    return interactionConfigs;
+}
+
 int BlockType::getTypeId(const char* name)
 {
     Text n = name;

+ 97 - 20
FactoryCraft/BlockType.h

@@ -4,7 +4,10 @@
 #include <Either.h>
 #include <Vec3.h>
 #include <Writer.h>
+#include <XML.h>
 
+#include "DropConfig.h"
+#include "InteractionConfig.h"
 #include "ModelInfo.h"
 
 class Item;
@@ -30,11 +33,15 @@ private:
     Framework::Text name;
     bool needModelSubscription;
     int initialMapColor;
-    Block* defaultBlock;
     Framework::RCArray<Framework::Text> groupNames;
     float hardness;
+    Framework::RCArray<DropConfig> dropConfigs;
+    bool damagableByHand;
+    Framework::RCArray<InteractionConfig> interactionConfigs;
 
 protected:
+    Block* defaultBlock;
+
     BlockType();
     virtual ~BlockType();
 
@@ -51,13 +58,15 @@ protected:
 
 public:
     virtual bool initialize(Game* zGame);
-    BlockType* initializeDefault();
-    virtual const Block* zDefault() const;
+    virtual BlockType* initializeDefault();
+    void addDropConfig(DropConfig* config);
+    const Framework::RCArray<DropConfig>& getDropConfigs() const;
+    const Block* zDefault() const;
 
     virtual ItemType* createItemType() const = 0;
 
     void writeTypeInfo(Framework::StreamWriter* zWriter) const;
-    virtual Framework::Text getTargetUIML() const;
+    virtual Framework::XML::Element* getTargetUIML() const;
     virtual Block* loadBlock(Framework::Vec3<int> position,
         Framework::StreamReader* zReader,
         int dimensionId) const;
@@ -89,6 +98,10 @@ public:
     const Framework::RCArray<Framework::Text>& getGroupNames() const;
     void setHardness(float hardness);
     float getHardness() const;
+    void setDamagableByHand(bool damagableByHand);
+    bool isDamagableByHand() const;
+    void addInteractionConfig(InteractionConfig* config);
+    const Framework::RCArray<InteractionConfig>& getInteractionConfigs() const;
 
     static int getTypeId(const char* name);
     static Framework::Text getTypeName(int id);
@@ -104,10 +117,10 @@ public:
         : SubTypeFactory<BlockType, S>()
     {}
 
-    virtual void fromJson(
-        S* zResult, Framework::JSON::JSONObject* zJson) const override
+    virtual S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
-        BlockType* zType = dynamic_cast<BlockType*>(zResult);
+        S* result = createValue(zJson);
+        BlockType* zType = dynamic_cast<BlockType*>(result);
         zType->setModel(Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
             zJson->zValue("model")->asObject()));
         zType->setInitialMaxHP(
@@ -130,26 +143,42 @@ public:
         zType->setGroupNames(groupNames);
         zType->setHardness(
             (float)zJson->zValue("hardness")->asNumber()->getNumber());
+        for (Framework::JSON::JSONValue* value :
+            *zJson->zValue("drops")->asArray())
+        {
+            zType->addDropConfig(
+                Game::INSTANCE->zTypeRegistry()->fromJson<DropConfig>(value));
+        }
+        zType->setDamagableByHand(
+            zJson->zValue("damagableByHand")->asBool()->getBool());
+        for (Framework::JSON::JSONValue* value :
+            *zJson->zValue("interactions")->asArray())
+        {
+            zType->addInteractionConfig(
+                Game::INSTANCE->zTypeRegistry()->fromJson<InteractionConfig>(
+                    value));
+        }
+        return result;
     }
 
-    virtual void toJson(
-        S* zObject, Framework::JSON::JSONObject* zResult) const override
+    virtual Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
-        BlockType* zType = dynamic_cast<BlockType*>(zResult);
-        zResult->addValue("model",
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+        BlockType* zType = dynamic_cast<BlockType*>(zObject);
+        result->addValue("model",
             Game::INSTANCE->zTypeRegistry()->toJson<ModelInfo>(
                 zType->zModel()));
-        zResult->addValue("maxHp",
+        result->addValue("maxHp",
             new Framework::JSON::JSONNumber((double)zType->getInitialMaxHP()));
-        zResult->addValue("needsClientInstance",
+        result->addValue("needsClientInstance",
             new Framework::JSON::JSONBool(zType->doesNeedClientInstance()));
-        zResult->addValue("lightSource",
+        result->addValue("lightSource",
             new Framework::JSON::JSONBool(zType->isLightSource()));
-        zResult->addValue(
+        result->addValue(
             "name", new Framework::JSON::JSONString(zType->getName()));
-        zResult->addValue("needModelSubscription",
+        result->addValue("needModelSubscription",
             new Framework::JSON::JSONBool(zType->doesNeedModelSubscription()));
-        zResult->addValue("mapColor",
+        result->addValue("mapColor",
             new Framework::JSON::JSONString(
                 Framework::Text(zType->getMapColor())));
         Framework::JSON::JSONArray* groupNames
@@ -158,14 +187,45 @@ public:
         {
             groupNames->addValue(new Framework::JSON::JSONString(*groupName));
         }
-        zResult->addValue("groupNames", groupNames);
-        zResult->addValue(
+        result->addValue("groupNames", groupNames);
+        Framework::JSON::JSONArray* drops = new Framework::JSON::JSONArray();
+        for (DropConfig* drop : zType->getDropConfigs())
+        {
+            drops->addValue(
+                Game::INSTANCE->zTypeRegistry()->toJson<DropConfig>(drop));
+        }
+        result->addValue("drops", drops);
+        result->addValue(
             "hardness", new Framework::JSON::JSONNumber(zType->getHardness()));
+        result->addValue("damagableByHand",
+            new Framework::JSON::JSONBool(zType->isDamagableByHand()));
+        Framework::JSON::JSONArray* interactions
+            = new Framework::JSON::JSONArray();
+        for (InteractionConfig* interaction : zType->getInteractionConfigs())
+        {
+            interactions->addValue(
+                Game::INSTANCE->zTypeRegistry()->toJson<InteractionConfig>(
+                    interaction));
+        }
+        result->addValue("interactions", interactions);
+        return result;
     }
 
     virtual JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override
     {
+        Framework::JSON::JSONArray* defaultDrops
+            = new Framework::JSON::JSONArray();
+        Framework::JSON::JSONObject* defaultBlockItemDrop
+            = new Framework::JSON::JSONObject();
+        defaultBlockItemDrop->addValue(
+            "type", new Framework::JSON::JSONString("blockItem"));
+        Framework::JSON::JSONObject* defaultDropCondition
+            = new Framework::JSON::JSONObject();
+        defaultDropCondition->addValue(
+            "type", new Framework::JSON::JSONString("allways"));
+        defaultBlockItemDrop->addValue("condition", defaultDropCondition);
+        defaultDrops->addValue(defaultBlockItemDrop);
         return builder
             ->withRequiredAttribute("model",
                 Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
@@ -192,6 +252,23 @@ public:
             ->finishArray()
             ->withRequiredNumber("hardness")
             ->withDefault(1.0)
-            ->finishNumber();
+            ->finishNumber()
+            ->withRequiredAttribute("drops",
+                Framework::Validator::DataValidator::buildForArray()
+                    ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                            ->getValidator<DropConfig>())
+                    ->withDefault(defaultDrops)
+                    ->finishArray())
+            ->withRequiredBool("damagableByHand")
+            ->withDefault(false)
+            ->finishBool()
+            ->withRequiredArray("interactions")
+            ->withDefault(new Framework::JSON::JSONArray())
+            ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                    ->getValidator<InteractionConfig>())
+            ->finishArray();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };

+ 16 - 21
FactoryCraft/BlockTypeGeneratorRule.cpp

@@ -1,5 +1,6 @@
 #include "BlockTypeGeneratorRule.h"
 
+#include "BlockType.h"
 #include "Game.h"
 
 BlockTypeGeneratorRule::BlockTypeGeneratorRule()
@@ -33,42 +34,36 @@ BlockTypeGeneratorRule* BlockTypeGeneratorRuleFactory::createValue(
     return new BlockTypeGeneratorRule();
 }
 
-void BlockTypeGeneratorRuleFactory::fromJson(
-    BlockTypeGeneratorRule* zResult, Framework::JSON::JSONObject* zJson) const
+BlockTypeGeneratorRule* BlockTypeGeneratorRuleFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setBlockTypeId(Game::INSTANCE->getBlockTypeId(
+    BlockTypeGeneratorRule* result = GeneratorRuleFactory::fromJson(zJson);
+    result->setBlockTypeId(Game::INSTANCE->getBlockTypeId(
         zJson->zValue("blockType")->asString()->getString()));
-    GeneratorRuleFactory::fromJson(zResult, zJson);
+    return result;
 }
 
-void BlockTypeGeneratorRuleFactory::toJson(
-    BlockTypeGeneratorRule* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BlockTypeGeneratorRuleFactory::toJsonObject(
+    BlockTypeGeneratorRule* zObject) const
 {
-    zResult->addValue("blockType",
+    Framework::JSON::JSONObject* result
+        = GeneratorRuleFactory::toJsonObject(zObject);
+    result->addValue("blockType",
         new Framework::JSON::JSONString(
             Game::INSTANCE->zBlockType(zObject->getBlockTypeId())->getName()));
-    GeneratorRuleFactory::toJson(zObject, zResult);
+    return result;
 }
 
 JSONObjectValidationBuilder* BlockTypeGeneratorRuleFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zBlockType(i))
-        {
-            blockTypeNames.add(
-                new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
-        }
-    }
     return GeneratorRuleFactory::addToValidator(
-        builder->withRequiredString("blockType")
-            ->whichIsOneOf(blockTypeNames)
-            ->finishString());
+        builder->withRequiredAttribute("blockType",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                BlockTypeNameFactory::TYPE_ID)));
 }
 
-Framework::Text BlockTypeGeneratorRuleFactory::getTypeToken() const
+const char* BlockTypeGeneratorRuleFactory::getTypeToken() const
 {
     return "blockType";
 }

+ 4 - 4
FactoryCraft/BlockTypeGeneratorRule.h

@@ -22,11 +22,11 @@ public:
     BlockTypeGeneratorRuleFactory();
     BlockTypeGeneratorRule* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BlockTypeGeneratorRule* zResult,
+    BlockTypeGeneratorRule* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BlockTypeGeneratorRule* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BlockTypeGeneratorRule* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 49 - 0
FactoryCraft/BlockTypeNameFactory.cpp

@@ -0,0 +1,49 @@
+#include "BlockTypeNameFactory.h"
+
+const Framework::Text BlockTypeNameFactory::TYPE_ID = "BlockTypeName";
+
+BlockTypeNameFactory::BlockTypeNameFactory()
+    : SimpleTypeFactory<Framework::Text*>(),
+      blockTypeNames(0)
+{}
+
+BlockTypeNameFactory::~BlockTypeNameFactory()
+{
+    if (blockTypeNames)
+    {
+        blockTypeNames->release();
+    }
+}
+
+void BlockTypeNameFactory::setBlockTypeNames(
+    Framework::RCArray<Framework::Text>* blockTypeNames)
+{
+    this->blockTypeNames = blockTypeNames;
+}
+
+Framework::Text* BlockTypeNameFactory::fromJson(
+    Framework::JSON::JSONValue* zJson) const
+{
+    return new Framework::Text(zJson->asString()->getString());
+}
+
+Framework::JSON::JSONValue* BlockTypeNameFactory::toJson(
+    Framework::Text* value) const
+{
+    return new Framework::JSON::JSONString(value->getText());
+}
+
+Framework::Validator::DataValidator* BlockTypeNameFactory::getValidator() const
+{
+    if (!blockTypeNames)
+    {
+        return Framework::Validator::DataValidator::buildForString()
+            ->finishString();
+    }
+    else
+    {
+        return Framework::Validator::DataValidator::buildForString()
+            ->whichIsOneOf(*blockTypeNames)
+            ->finishString();
+    }
+}

+ 20 - 0
FactoryCraft/BlockTypeNameFactory.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "TypeRegistry.h"
+
+class BlockTypeNameFactory : public SimpleTypeFactory<Framework::Text*>
+{
+public:
+    static const Framework::Text TYPE_ID;
+
+private:
+    Framework::RCArray<Framework::Text>* blockTypeNames;
+
+public:
+    BlockTypeNameFactory();
+    ~BlockTypeNameFactory();
+    void setBlockTypeNames(Framework::RCArray<Framework::Text>* blockTypeNames);
+    Framework::Text* fromJson(Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(Framework::Text* value) const override;
+    Framework::Validator::DataValidator* getValidator() const override;
+};

+ 2 - 4
FactoryCraft/ChatCommand.cpp

@@ -1,7 +1,5 @@
 #include "ChatCommand.h"
 
-#include <AsynchronCall.h>
-
 #include "Game.h"
 #include "Player.h"
 
@@ -40,7 +38,7 @@ void ChatCommand::addAutocompletePossibilities(
     if (possibilities.getEintragAnzahl() == 0
         || (possibilities.getEintragAnzahl() == 1 && appendToLast
             && possibilities.z(0)->istGleich(
-                args.get(args.getEintragAnzahl() - 1))))
+                *args.z(args.getEintragAnzahl() - 1))))
     {
         Framework::Text help = getHelp();
         while (help.hat("\n"))
@@ -139,7 +137,7 @@ Framework::RCArray<Framework::Text> ChatCommandParameter::getAutocompleteValues(
 
 PlayerNameParameter::PlayerNameParameter()
     : ChatCommandParameter(
-        "player", "The name of the player (has to be online)", 0)
+          "player", "The name of the player (has to be online)", 0)
 {}
 
 bool PlayerNameParameter::isLegalValue(Framework::Text value) const

+ 53 - 116
FactoryCraft/Chest.cpp

@@ -1,68 +1,31 @@
 #include "Chest.h"
 
-#include <TextFeld.h>
-
 #include "Chunk.h"
 #include "Dimension.h"
 #include "Entity.h"
 #include "Game.h"
-#include "ItemSlot.h"
-#include "UIController.h"
-#include "UIDialog.h"
 
 Chest::Chest(int typeId, Framework::Vec3<int> pos, int dimensionId)
     : BasicBlock(typeId, pos, dimensionId, 1),
       open(0),
       userEntityId(0)
-{
-    for (int i = 0; i < 30; i++)
-    {
-        ItemSlot* slot = new ItemSlot(
-            "Inventory", 50, i, i, ANY_DIRECTION, ANY_DIRECTION, 0);
-        addSlot(slot);
-    }
-}
-
-void Chest::onDestroy()
-{
-    for (ItemSlot* slot : *this)
-    {
-        if (!slot->isEmpty())
-        {
-            Game::INSTANCE->spawnItem(
-                location + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
-                getDimensionId(),
-                slot->takeItemsOut(slot->getNumberOfItems(), NO_DIRECTION));
-        }
-    }
-    BasicBlock::onDestroy();
-}
+{}
 
 void Chest::onDialogClosed(Framework::Text dialogId)
 {
-    if (dialogId.istGleich(getDialogId()))
-    {
-        open = 0;
-        userEntityId = 0;
-        NetworkMessage* msg = new NetworkMessage();
-        msg->animateBlockBone(getDimensionId(),
-            Game::getChunkCenter(getPos().x, getPos().y),
-            Chunk::index(Dimension::chunkCoordinates(getPos())),
-            1,
-            1.0,
-            Framework::Vec3<float>(0.5f, 0.f, 0.45f),
-            Framework::Vec3<float>(
-                0.0f, 0.f, 0.f)); // close the chest over one second
-        broadcastMessage(msg);
-    }
-}
-
-Framework::Text Chest::getDialogId() const
-{
-    Framework::Text dialogId = "chest_inventory_";
-    dialogId.append() << getDimensionId() << "," << getPos().x << ","
-                      << getPos().y << "," << getPos().z;
-    return dialogId;
+    open = 0;
+    userEntityId = 0;
+    NetworkMessage* msg = new NetworkMessage();
+    auto pos = Dimension::chunkCoordinates(getPos());
+    msg->animateBlockBone(getDimensionId(),
+        Game::getChunkCenter(getPos().x, getPos().y),
+        Chunk::index(pos.x, pos.y) * WORLD_HEIGHT + pos.z,
+        1,
+        1.0,
+        Framework::Vec3<float>(0.5f, 0.f, 0.45f),
+        Framework::Vec3<float>(
+            0.0f, 0.f, 0.f)); // close the chest over one second
+    broadcastMessage(msg);
 }
 
 bool Chest::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
@@ -71,83 +34,53 @@ bool Chest::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
     {
         if (!Game::INSTANCE->zEntity(userEntityId))
         {
-            onDialogClosed(getDialogId());
+            onDialogClosed("");
         }
     }
     return open;
 }
 
-bool Chest::interact(Item* zItem, Entity* zActor)
+bool Chest::interact(Item* zItem, Entity* zActor, bool& itemChanged)
 {
     lock();
+    bool result = 0;
     if (open)
     {
         if (!Game::INSTANCE->zEntity(userEntityId)) open = 0;
     }
     if (!open)
     {
-        userEntityId = zActor->getId();
-        open = 1;
-        Framework::Text uiml = "";
-        uiml.append()
-            << "<dialog id=\"" << getDialogId()
-            << "\" title=\"Chest\" "
-               "notifyOnClose=\""
-            << getDimensionId() << "," << getPos().x << "," << getPos().y << ","
-            << getPos().z
-            << "\" "
-               "width=\"610\" "
-               "height=\"480\">"
-            << "<inventory id=\"chest_inventory\" margin-bottom=\"18\" "
-               "align-bottom=\"player_label\" align-left=\"start\" "
-               "margin-left=\"9\" width=\"592\" height=\"172\" rowSize=\"10\" "
-               "numSlots=\"30\" slotNameFilter=\"\" target=\""
-            << getDimensionId() << "," << getPos().x << "," << getPos().y << ","
-            << getPos().z << "\"/>"
-            << "<text id=\"player_label\" width=\"100%\" height=\"auto\" "
-               "style=\""
-            << std::uppercase << std::hex
-            << (Framework::TextFeld::Style::Text
-                   | Framework::TextFeld::Style::Center)
-            << std::dec << std::nouppercase
-            << "\" margin-bottom=\"9\" "
-               "align-bottom=\"player_inventory\">Player "
-               "Inventory</text>"
-            << "<inventory id=\"player_inventory\" margin-bottom=\"18\" "
-               "align-bottom=\"item_bar\" align-left=\"start\" "
-               "margin-left=\"9\" width=\"592\" height=\"172\" rowSize=\"10\" "
-               "numSlots=\"30\" slotNameFilter=\"Inventory\" target=\""
-            << zActor->getId() << "\"/>"
-            << "<inventory id=\"item_bar\" margin-bottom=\"9\" "
-               "align-bottom=\"end\" align-left=\"start\" margin-left=\"9\" "
-               "width=\"592\" height=\"52\" rowSize=\"10\" numSlots=\"10\" "
-               "slotNameFilter=\"ItemBar\" target=\""
-            << zActor->getId() << "\"/>"
-            << "</dialog>";
-        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())),
-            1,
-            1.0,
-            Framework::Vec3<float>(0.5f, 0.f, 0.45f),
-            Framework::Vec3<float>(
-                0.0f, (float)(PI / 2.0), 0.f)); // open the chest over 1 second
-        broadcastMessage(msg);
+        result = Block::interact(zItem, zActor, itemChanged);
+        if (result)
+        {
+            userEntityId = zActor->getId();
+            open = 1;
+            NetworkMessage* msg = new NetworkMessage();
+            auto pos = Dimension::chunkCoordinates(getPos());
+            msg->animateBlockBone(getDimensionId(),
+                Game::getChunkCenter(getPos().x, getPos().y),
+                Chunk::index(pos.x, pos.y) * WORLD_HEIGHT + pos.z,
+                1,
+                1.0,
+                Framework::Vec3<float>(0.5f, 0.f, 0.45f),
+                Framework::Vec3<float>(0.0f,
+                    (float)(PI / 2.0),
+                    0.f)); // open the chest over 1 second
+            broadcastMessage(msg);
+        }
     }
     unlock();
-    return false; // item was not changed
+    return result;
 }
 
 void Chest::sendModelInfo(NetworkMessage* zMessage)
 {
     if (open)
     {
+        auto pos = Dimension::chunkCoordinates(getPos());
         zMessage->animateBlockBone(getDimensionId(),
             Game::getChunkCenter(getPos().x, getPos().y),
-            Chunk::index(Dimension::chunkCoordinates(getPos())),
+            Chunk::index(pos.x, pos.y) * WORLD_HEIGHT + pos.z,
             1,
             0.0,
             Framework::Vec3<float>(0.5f, 0.f, 0.45f),
@@ -167,8 +100,7 @@ Block* ChestBlockType::createBlock(
 }
 
 ChestBlockTypeFactory::ChestBlockTypeFactory()
-    : SubTypeFactory(),
-      super()
+    : BasicBlockTypeFactory()
 {}
 
 ChestBlockType* ChestBlockTypeFactory::createValue(
@@ -177,25 +109,30 @@ ChestBlockType* ChestBlockTypeFactory::createValue(
     return new ChestBlockType();
 }
 
-void ChestBlockTypeFactory::fromJson(
-    ChestBlockType* zResult, Framework::JSON::JSONObject* zJson) const
+ChestBlockType* ChestBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    super.fromJson(zResult, zJson);
+    return BasicBlockTypeFactory::fromJson(zJson);
 }
 
-void ChestBlockTypeFactory::toJson(
-    ChestBlockType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* ChestBlockTypeFactory::toJsonObject(
+    ChestBlockType* zObject) const
 {
-    super.toJson(zObject, zResult);
+    return BasicBlockTypeFactory::toJsonObject(zObject);
 }
 
 JSONObjectValidationBuilder* ChestBlockTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return super.addToValidator(builder);
+    return BasicBlockTypeFactory::addToValidator(builder);
 }
 
-Framework::Text ChestBlockTypeFactory::getTypeToken() const
+const char* ChestBlockTypeFactory::getTypeToken() const
 {
     return "chest";
-}
+}
+
+const char* ChestBlockTypeFactory::getTypeName() const
+{
+    return typeid(ChestBlockType).name();
+}

+ 8 - 11
FactoryCraft/Chest.h

@@ -8,9 +8,7 @@ private:
     bool open;
     int userEntityId;
 
-    virtual void onDestroy() override;
     virtual void onDialogClosed(Framework::Text dialogId) override;
-    Framework::Text getDialogId() const;
 
 protected:
     virtual bool onTick(
@@ -18,7 +16,8 @@ protected:
 
 public:
     Chest(int typeId, Framework::Vec3<int> pos, int dimensionId);
-    virtual bool interact(Item* zItem, Entity* zActor) override;
+    virtual bool interact(
+        Item* zItem, Entity* zActor, bool& itemChanged) override;
     virtual void sendModelInfo(NetworkMessage* zMessage) override;
 };
 
@@ -30,19 +29,17 @@ public:
         Framework::Vec3<int> position, int dimensionId) const override;
 };
 
-class ChestBlockTypeFactory : public SubTypeFactory<BlockType, ChestBlockType>
+class ChestBlockTypeFactory : public BasicBlockTypeFactory<ChestBlockType>
 {
-    BasicBlockTypeFactory super;
-
 public:
     ChestBlockTypeFactory();
     ChestBlockType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(ChestBlockType* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(ChestBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    ChestBlockType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        ChestBlockType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
+    const char* getTypeName() const;
 };

+ 665 - 460
FactoryCraft/Chunk.cpp

@@ -1,15 +1,15 @@
 #include "Chunk.h"
 
-#include <AsynchronCall.h>
 #include <InMemoryBuffer.h>
 #include <Logging.h>
 
+#include "BlockType.h"
 #include "Constants.h"
 #include "Dimension.h"
 #include "Entity.h"
+#include "EntityType.h"
 #include "FluidBlock.h"
 #include "Game.h"
-#include "NoBlock.h"
 #include "WorldGenerator.h"
 
 Chunk::Chunk(Framework::Punkt location, int dimensionId)
@@ -20,13 +20,11 @@ Chunk::Chunk(Framework::Punkt location, int dimensionId)
       worldUpdated(1),
       currentlyLoading(1)
 {
-    blocks = new Block*[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
-    blockIds = new unsigned short[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
+    blocks = new Block**[WORLD_HEIGHT];
+    blockIds = new unsigned short*[WORLD_HEIGHT];
     lightData = new unsigned char[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6];
-    memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*));
-    memset(blockIds,
-        0,
-        CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(unsigned short));
+    memset(blocks, 0, WORLD_HEIGHT * sizeof(Block**));
+    memset(blockIds, 0, WORLD_HEIGHT * sizeof(unsigned short*));
     memset(lightData, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
     zNeighbours[0] = 0;
     zNeighbours[1] = 0;
@@ -44,9 +42,16 @@ Chunk::Chunk(Framework::Punkt location,
 
 Chunk::~Chunk()
 {
-    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
+    for (int h = 0; h < WORLD_HEIGHT; h++)
     {
-        if (blocks[i]) blocks[i]->release();
+        for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++)
+        {
+            if (blocks[h] && blocks[h][i]) blocks[h][i]->release();
+        }
+        delete[] blocks[h];
+        blocks[h] = 0;
+        delete[] blockIds[h];
+        blockIds[h] = 0;
     }
     delete[] blocks;
     delete[] blockIds;
@@ -83,20 +88,20 @@ void Chunk::tick(TickQueue* zQueue)
 
 void Chunk::postTick() {}
 
-void Chunk::addLightSource(int index)
+void Chunk::addLightSource(int z, int index)
 {
     for (int i : lightSources)
     {
-        if (i == index) return;
+        if (i == index * WORLD_HEIGHT + z) return;
     }
-    lightSources.add(index);
+    lightSources.add(index * WORLD_HEIGHT + z);
 }
 
-void Chunk::removeLightSource(int index)
+void Chunk::removeLightSource(int z, int index)
 {
     for (auto i = lightSources.begin(); i; i++)
     {
-        if (i.val() == index)
+        if (i.val() == index * WORLD_HEIGHT + z)
         {
             i.remove();
             return;
@@ -104,66 +109,186 @@ void Chunk::removeLightSource(int index)
     }
 }
 
-void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
+void Chunk::sendToClient(Framework::StreamWriter* zWriter, bool* instanceMap)
 {
-    for (int z = 0; z < WORLD_HEIGHT; z++)
+    for (int x = 0; x < CHUNK_SIZE; x++)
     {
-        for (int x = -1; x <= CHUNK_SIZE; x++)
+        for (int y = 0; y < CHUNK_SIZE; y++)
         {
-            for (int y = -1; y <= CHUNK_SIZE; y++)
+            for (int z = 0; z < WORLD_HEIGHT; z++)
             {
-                if ((x < 0 || x == CHUNK_SIZE) && (y < 0 || y > CHUNK_SIZE))
+                int index = Chunk::index(x, y);
+                const BlockType* type = Game::INSTANCE->zBlockType(
+                    blockIds[z] ? blockIds[z][index] : 0);
+                if (isVisible(z, index) && type->doesNeedClientInstance())
                 {
-                    continue;
+                    int mI = index * WORLD_HEIGHT + z;
+                    if (z < WORLD_HEIGHT - 1)
+                    {
+                        instanceMap[mI + (CHUNK_SIZE + 1) * WORLD_HEIGHT + 1]
+                            = 1;
+                    }
+                    if (z > 0)
+                    {
+                        instanceMap[mI + (CHUNK_SIZE + 1) * WORLD_HEIGHT - 1]
+                            = 1;
+                    }
+                    instanceMap[mI + WORLD_HEIGHT] = 1;
+                    instanceMap[mI + (2 * CHUNK_SIZE + 1) * WORLD_HEIGHT] = 1;
+                    instanceMap[mI + CHUNK_SIZE * WORLD_HEIGHT] = 1;
+                    instanceMap[mI + (CHUNK_SIZE + 2) * WORLD_HEIGHT] = 1;
+                    assert(blockIds[z]);
+                    zWriter->schreibe((char*)&blockIds[z][index], 2);
+                    zWriter->schreibe((char*)&mI, 4);
+                    char state = 0;
+                    if (type->isFluid())
+                    {
+                        state |= 1;
+                    }
+                    if ((blocks[z] && blocks[z][index]
+                            && blocks[z][index]->isPassable())
+                        || (type->zDefault()->isPassable()))
+                    {
+                        state |= 2;
+                    }
+                    zWriter->schreibe((char*)&state, 1);
+                    if ((state | 1) == state)
+                    {
+                        FluidBlock* fluidBlock
+                            = blocks[z]
+                                ? dynamic_cast<FluidBlock*>(blocks[z][index])
+                                : 0;
+                        char data
+                            = fluidBlock ? fluidBlock->getFlowOptions() : 0;
+                        zWriter->schreibe(&data, 1);
+                        data = fluidBlock ? fluidBlock->getDistanceToSource()
+                                          : 0;
+                        zWriter->schreibe(&data, 1);
+                    }
+                    if ((state | 2) == state)
+                    {
+                        float speedModifier
+                            = blocks[z] && blocks[z][index]
+                                ? blocks[z][index]->getSpeedModifier()
+                                : type->zDefault()->getSpeedModifier();
+                        zWriter->schreibe((char*)&speedModifier, 4);
+                    }
                 }
-                bool needSend = 0;
-                for (int i = 0; i < 6; i++)
+            }
+        }
+    }
+    unsigned short end = 0;
+    zWriter->schreibe((char*)&end, 2);
+}
+
+void Chunk::sendLightToClient(
+    Framework::StreamWriter* zWriter, bool* instanceMap)
+{
+    cs.lock();
+    Chunk* zNeighbours[4];
+    for (int i = 0; i < 4; i++)
+    {
+        zNeighbours[i]
+            = this->zNeighbours[i]
+                ? dynamic_cast<Chunk*>(this->zNeighbours[i]->getThis())
+                : 0;
+        if (zNeighbours[i])
+        {
+            Direction dir = getDirectionFromIndex(i);
+            switch (dir)
+            {
+            case WEST:
+                for (int z = 0; z < WORLD_HEIGHT; z++)
                 {
-                    Framework::Vec3<int> pos
-                        = Framework::Vec3<int>(x, y, z)
-                        + getDirection(getDirectionFromIndex(i));
-                    if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
+                    for (int j = 0; j < CHUNK_SIZE; j++)
                     {
-                        if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
-                            && pos.y < CHUNK_SIZE)
+                        int type = zNeighbours[i]->getBlockTypeAt(
+                            {CHUNK_SIZE - 1, j, z});
+                        if (type
+                            && Game::INSTANCE->zBlockType(type)
+                                ->doesNeedClientInstance())
                         {
-                            int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT
-                                   + pos.z;
-                            int type = blockIds[bi];
-                            needSend |= type != BlockTypeEnum::NO_BLOCK
-                                     && Game::INSTANCE->zBlockType(type)
-                                            ->doesNeedClientInstance();
+                            instanceMap[(CHUNK_SIZE + j + 1) * WORLD_HEIGHT + z]
+                                = 1;
                         }
-                        else
+                    }
+                }
+                break;
+            case NORTH:
+                for (int z = 0; z < WORLD_HEIGHT; z++)
+                {
+                    for (int j = 0; j < CHUNK_SIZE; j++)
+                    {
+                        int type = zNeighbours[i]->getBlockTypeAt(
+                            {j, CHUNK_SIZE - 1, z});
+                        if (type
+                            && Game::INSTANCE->zBlockType(type)
+                                ->doesNeedClientInstance())
                         {
-                            if (x >= 0 && x < CHUNK_SIZE && y >= 0
-                                && y < CHUNK_SIZE)
-                            {
-                                cs.lock();
-                                if (i < 4 && zNeighbours[i])
-                                {
-                                    Framework::Vec3<int> offset
-                                        = getDirection(getDirectionFromIndex(i))
-                                        * 16;
-                                    int bi = ((pos.x - offset.x) * CHUNK_SIZE
-                                                 + (pos.y - offset.y))
-                                               * WORLD_HEIGHT
-                                           + (pos.z - offset.z);
-                                    int type = zNeighbours[i]->blockIds[bi];
-                                    needSend |= Game::INSTANCE->zBlockType(type)
-                                                    ->doesNeedClientInstance();
-                                }
-                                cs.unlock();
-                            }
+                            instanceMap[((j + 1) * CHUNK_SIZE + 1)
+                                            * WORLD_HEIGHT
+                                        + z]
+                                = 1;
                         }
-                        if (needSend) break;
                     }
                 }
-                if (needSend)
+                break;
+            case EAST:
+                for (int z = 0; z < WORLD_HEIGHT; z++)
+                {
+                    for (int j = 0; j < CHUNK_SIZE; j++)
+                    {
+                        int type = zNeighbours[i]->getBlockTypeAt({0, j, z});
+                        if (type
+                            && Game::INSTANCE->zBlockType(type)
+                                ->doesNeedClientInstance())
+                        {
+                            instanceMap[((CHUNK_SIZE)*CHUNK_SIZE + j + 1)
+                                            * WORLD_HEIGHT
+                                        + z]
+                                = 1;
+                        }
+                    }
+                }
+                break;
+            case SOUTH:
+                for (int z = 0; z < WORLD_HEIGHT; z++)
+                {
+                    for (int j = 0; j < CHUNK_SIZE; j++)
+                    {
+                        int type = zNeighbours[i]->getBlockTypeAt({j, 0, z});
+                        if (type
+                            && Game::INSTANCE->zBlockType(type)
+                                ->doesNeedClientInstance())
+                        {
+                            instanceMap[((j + 1) * CHUNK_SIZE + CHUNK_SIZE)
+                                            * WORLD_HEIGHT
+                                        + z]
+                                = 1;
+                        }
+                    }
+                }
+                break;
+            }
+        }
+    }
+    cs.unlock();
+    for (int z = 0; z < WORLD_HEIGHT; z++)
+    {
+        for (int x = -1; x <= CHUNK_SIZE; x++)
+        {
+            for (int y = -1; y <= CHUNK_SIZE; y++)
+            {
+                if ((x < 0 || x == CHUNK_SIZE) && (y < 0 || y == CHUNK_SIZE))
+                {
+                    continue;
+                }
+                if (instanceMap[((x + 1) * CHUNK_SIZE + y + 1) * WORLD_HEIGHT
+                                + z])
                 {
                     if (x >= 0 && x < CHUNK_SIZE && y >= 0 && y < CHUNK_SIZE)
                     {
-                        int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
+                        int index = Chunk::index(x, y) * WORLD_HEIGHT + z;
                         zWriter->schreibe((char*)&index, 4);
                         zWriter->schreibe((char*)(lightData + index * 6), 6);
                     }
@@ -171,32 +296,28 @@ void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
                     {
                         int dir;
                         int index = 0;
+                        int tmpX = x;
+                        int tmpY = y;
+                        index = (((x + CHUNK_SIZE) % CHUNK_SIZE) * CHUNK_SIZE
+                                    + ((y + CHUNK_SIZE) % CHUNK_SIZE))
+                                  * WORLD_HEIGHT
+                              + z;
                         if (x == -1)
                         {
                             dir = getDirectionIndex(WEST);
-                            index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + y)
-                                      * WORLD_HEIGHT
-                                  + z;
                         }
                         else if (y == -1)
                         {
                             dir = getDirectionIndex(NORTH);
-                            index = (x * CHUNK_SIZE + CHUNK_SIZE - 1)
-
-                                      * WORLD_HEIGHT
-                                  + z;
                         }
                         else if (x == CHUNK_SIZE)
                         {
                             dir = getDirectionIndex(EAST);
-                            index = y * WORLD_HEIGHT + z;
                         }
                         else if (y == CHUNK_SIZE)
                         {
                             dir = getDirectionIndex(SOUTH);
-                            index = (x * CHUNK_SIZE) * WORLD_HEIGHT + z;
                         }
-                        cs.lock();
                         if (zNeighbours[dir])
                         {
                             int i = -1;
@@ -209,7 +330,6 @@ void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
                                         + index * 6),
                                 6);
                         }
-                        cs.unlock();
                     }
                 }
             }
@@ -217,75 +337,70 @@ void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
     }
     int end = -2;
     zWriter->schreibe((char*)&end, 4);
+    for (int i = 0; i < 4; i++)
+    {
+        if (zNeighbours[i])
+        {
+            zNeighbours[i]->release();
+        }
+    }
 }
 
-bool Chunk::isVisible(int index) const
+bool Chunk::isVisible(int z, int index) const
 {
-    if (!blocks[index])
+    unsigned short blockType = blockIds[z] ? blockIds[z][index] : 0;
+    if (blockType)
     {
-        unsigned short blockType
-            = blocks[index]
-                ? (unsigned short)blocks[index]->zBlockType()->getId()
-                : blockIds[index];
-        if (blockType)
+        if (CONST_BLOCK(0, blockType)->isTransparent()
+            || CONST_BLOCK(0, blockType)->isPassable())
+            return 1;
+        else
         {
-            if (CONST_BLOCK(0, blockIds[index])->isTransparent()
-                || CONST_BLOCK(0, blockIds[index])->isPassable())
-                return 1;
-            else
+            Framework::Vec3<int> indexPos
+                = {(index) / CHUNK_SIZE, (index) % CHUNK_SIZE, z};
+            for (int d = 0; d < 6; d++)
             {
-                Framework::Vec3<int> indexPos
-                    = {(index / WORLD_HEIGHT) / CHUNK_SIZE,
-                        (index / WORLD_HEIGHT) % CHUNK_SIZE,
-                        index % WORLD_HEIGHT};
-                for (int d = 0; d < 6; d++)
+                Framework::Either<Block*, int> n = BlockTypeEnum::NO_BLOCK;
+                Framework::Vec3<int> pos
+                    = getDirection((Directions)getDirectionFromIndex(d))
+                    + indexPos;
+                if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
+                    && pos.y < CHUNK_SIZE && pos.z >= 0 && pos.z < WORLD_HEIGHT)
                 {
-                    Framework::Either<Block*, int> n = BlockTypeEnum::NO_BLOCK;
-                    Framework::Vec3<int> pos
-                        = getDirection((Directions)getDirectionFromIndex(d))
-                        + indexPos;
-                    if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
-                        && pos.y < CHUNK_SIZE && pos.z >= 0
-                        && pos.z < WORLD_HEIGHT)
-                    {
-                        n = zBlockAt(pos);
-                    }
-                    else if (pos.z >= 0 && pos.z < WORLD_HEIGHT && d < 4
-                             && zNeighbours[d])
-                    {
-                        if (pos.x < 0) pos.x += CHUNK_SIZE;
-                        if (pos.x >= CHUNK_SIZE) pos.x -= CHUNK_SIZE;
-                        if (pos.y < 0) pos.y += CHUNK_SIZE;
-                        if (pos.y >= CHUNK_SIZE) pos.y -= CHUNK_SIZE;
-                        n = zNeighbours[d]->zBlockAt(pos);
-                    }
-                    else if (pos.z >= 0 && pos.z < WORLD_HEIGHT && d < 4
-                             && !zNeighbours[d])
-                    {
-                        return 1;
-                    }
-                    if (n.isA()
-                        && (((Block*)n)->isPassable()
-                            || ((Block*)n)->isTransparent()))
-                        return 1;
-                    if (n.isB()
-                        && (CONST_BLOCK(0, n)->isTransparent()
-                            || CONST_BLOCK(0, n)->isPassable()))
-                        return 1;
+                    n = zBlockAt(pos);
                 }
+                else if (pos.z >= 0 && pos.z < WORLD_HEIGHT && d < 4
+                         && zNeighbours[d])
+                {
+                    if (pos.x < 0) pos.x += CHUNK_SIZE;
+                    if (pos.x >= CHUNK_SIZE) pos.x -= CHUNK_SIZE;
+                    if (pos.y < 0) pos.y += CHUNK_SIZE;
+                    if (pos.y >= CHUNK_SIZE) pos.y -= CHUNK_SIZE;
+                    n = zNeighbours[d]->zBlockAt(pos);
+                }
+                else if (pos.z >= 0 && pos.z < WORLD_HEIGHT && d < 4
+                         && !zNeighbours[d])
+                {
+                    return 1;
+                }
+                if (n.isA()
+                    && (((Block*)n)->isPassable()
+                        || ((Block*)n)->isTransparent()))
+                    return 1;
+                if (n.isB()
+                    && (CONST_BLOCK(0, n)->isTransparent()
+                        || CONST_BLOCK(0, n)->isPassable()))
+                    return 1;
             }
         }
-        return 0;
     }
-    else
-        return blocks[index]->isVisible();
+    return 0;
 }
 
-void Chunk::broadcastLightData(int index, bool foreground)
+void Chunk::broadcastLightData(int z, int index, bool foreground)
 {
-    int x = (index / WORLD_HEIGHT) / CHUNK_SIZE;
-    int y = (index / WORLD_HEIGHT) % CHUNK_SIZE;
-    int z = index % WORLD_HEIGHT;
+    int x = index / CHUNK_SIZE;
+    int y = index % CHUNK_SIZE;
     NetworkMessage* msg = new NetworkMessage();
     msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
     char* message = new char[19];
@@ -293,7 +408,7 @@ void Chunk::broadcastLightData(int index, bool foreground)
     *(int*)(message + 1) = x + this->location.x - CHUNK_SIZE / 2;
     *(int*)(message + 5) = y + this->location.y - CHUNK_SIZE / 2;
     *(int*)(message + 9) = z;
-    memcpy(message + 13, lightData + index * 6, 6);
+    memcpy(message + 13, lightData + (index * WORLD_HEIGHT + z) * 6, 6);
     msg->setMessage(message, 19);
     if (!foreground) msg->setUseBackground();
     notifyObservers(msg);
@@ -306,18 +421,17 @@ Framework::Either<Block*, int> Chunk::zBlockNeighbor(
         && location.y < CHUNK_SIZE && location.z >= 0
         && location.z < WORLD_HEIGHT)
     {
-        int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT
-                  + location.z;
+        int index = Chunk::index(location.x, location.y);
         if (zNeighborChunk)
         {
             *zNeighborChunk = this;
         }
-        if (blocks[index])
-            return blocks[index];
+        if (blocks[location.z] && blocks[location.z][index])
+            return blocks[location.z][index];
         else
-            return (int)blockIds[index];
+            return blockIds[location.z] ? (int)blockIds[location.z][index] : 0;
     }
-    if (added && location.z >= 0 && location.z < WORLD_HEIGHT)
+    if (location.z >= 0 && location.z < WORLD_HEIGHT)
         return Game::INSTANCE->zBlockAt(
             {location.x + this->location.x - CHUNK_SIZE / 2,
                 location.y + this->location.y - CHUNK_SIZE / 2,
@@ -352,19 +466,24 @@ void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
         if (observer->getEntityId() == zEntity->getId()) return;
     }
     int id = zEntity->getId();
-    observers.add(new InformationObserver(id));
+    InformationObserver* observer = new InformationObserver(id);
+    observers.add(observer);
     laterHandler.addTodo([this, id]() {
         Framework::InMemoryBuffer buffer;
         buffer.schreibe("\4", 1);
         buffer.schreibe((char*)&location.x, 4);
         buffer.schreibe((char*)&location.y, 4);
-        sendToClient(&buffer);
-        sendLightToClient(&buffer);
+        bool instanceMap[(CHUNK_SIZE + 2) * (CHUNK_SIZE + 2) * WORLD_HEIGHT];
+        memset(instanceMap, 0, sizeof(instanceMap));
+        sendToClient(&buffer, instanceMap);
+        sendLightToClient(&buffer, instanceMap);
         NetworkMessage* msg = new NetworkMessage();
         msg->addressDimension(Game::INSTANCE->zDimension(dimensionId));
+#ifdef _DEBUG
         Framework::Logging::debug()
             << "chunk size: " << location.x << ", " << location.y << ": "
             << buffer.getSize() << "b";
+#endif
         char* message = new char[buffer.getSize()];
         buffer.lese(message, (int)buffer.getSize());
         msg->setMessage(message, (int)buffer.getSize());
@@ -377,6 +496,15 @@ void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
         else
             msg->release();
     });
+    for (Entity* entity : entitiesInChunk)
+    {
+        NetworkMessage* msg = new NetworkMessage();
+        msg->addEntityMessage(entity);
+        if (!msg->isEmpty())
+        {
+            observer->sendMessage(msg);
+        }
+    }
 }
 
 void Chunk::removeObserver(Entity* zEntity)
@@ -386,6 +514,15 @@ void Chunk::removeObserver(Entity* zEntity)
     {
         if (observer->getEntityId() == zEntity->getId())
         {
+            for (Entity* entity : entitiesInChunk)
+            {
+                NetworkMessage* msg = new NetworkMessage();
+                msg->removeEntityMessage(entity);
+                if (!msg->isEmpty())
+                {
+                    observer->sendMessage(msg);
+                }
+            }
             observers.remove(index);
             return;
         }
@@ -423,76 +560,175 @@ void Chunk::api(Framework::StreamReader* zRequest,
 
 void Chunk::initializeLightning()
 {
-    unsigned char dayLight[6] = {255, 255, 255, 0, 0, 0};
-    unsigned char noLight[6] = {0, 0, 0, 0, 0, 0};
-    while (true)
+    unsigned char dayLight[3] = {255, 255, 255};
+    unsigned char noLight[3] = {0, 0, 0};
+    unsigned short visited[CHUNK_SIZE][WORLD_HEIGHT];
+    memset(visited, 0, sizeof(visited));
+    int minZ = 0;
+    int goUps = 0;
+    for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
     {
-        bool changes = false;
-        for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
+        minZ = z;
+        unsigned char max[3] = {0, 0, 0};
+        bool allVisited = 1;
+        for (int x = 0; x < CHUNK_SIZE; x++)
         {
-            for (int x = 0; x < CHUNK_SIZE; x++)
+            for (int y = 0; y < CHUNK_SIZE; y++)
             {
-                for (int y = 0; y < CHUNK_SIZE; y++)
+                if (visited[y][z] & (1 << x)) continue;
+                unsigned char* lightAbove
+                    = z == WORLD_HEIGHT - 1
+                        ? dayLight
+                        : getLightData(Framework::Vec3<int>(x, y, z + 1));
+                if (lightAbove[0] | lightAbove[1] | lightAbove[2])
                 {
-                    int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
+                    visited[y][z] |= 1 << x;
                     unsigned char* light
                         = getLightData(Framework::Vec3<int>(x, y, z));
-                    unsigned char newLight[6] = {0, 0, 0, 0, 0, 0};
-                    for (int i = 0; i < 6; i++)
-                    {
-                        unsigned char* neighborLeight;
-                        Framework::Vec3<int> neighborPos
-                            = Framework::Vec3<int>(x, y, z)
-                            + getDirection(getDirectionFromIndex(i));
-                        if (neighborPos.z < 0 || neighborPos.x < 0
-                            || neighborPos.y < 0 || neighborPos.x >= CHUNK_SIZE
-                            || neighborPos.y >= CHUNK_SIZE)
-                        {
-                            neighborLeight = noLight;
-                        }
-                        else if (neighborPos.z >= WORLD_HEIGHT)
-                        {
-                            neighborLeight = dayLight;
-                        }
-                        else
-                        {
-                            neighborLeight = getLightData(neighborPos);
-                        }
-                        for (int j = 0; j < 3; j++)
-                            newLight[j] = (unsigned char)MAX(newLight[j],
-                                i == getDirectionIndex(TOP)
-                                    ? neighborLeight[j]
-                                    : (unsigned char)((float)neighborLeight[j]
-                                                      * 0.8f));
-                        for (int j = 3; j < 6; j++)
-                            newLight[j] = (unsigned char)MAX(newLight[j],
-                                (unsigned char)((float)neighborLeight[j]
-                                                * 0.85f));
-                    }
+                    int index = Chunk::index(x, y);
                     const Block* current
-                        = blocks[index]
-                            ? blocks[index]
-                            : Game::INSTANCE->zBlockType(blockIds[index])
+                        = (blocks[z] && blocks[z][index])
+                            ? blocks[z][index]
+                            : Game::INSTANCE
+                                  ->zBlockType(
+                                      blockIds[z] ? blockIds[z][index] : 0)
                                   ->zDefault();
-                    // add own light emission
-                    for (int j = 3; j < 6; j++)
-                        newLight[j] = (unsigned char)MAX(newLight[j],
-                            current->getLightEmisionColor()[j - 3]);
-                    current->filterPassingLight(newLight);
-                    current->filterPassingLight(newLight + 3);
-                    for (int i = 0; i < 6; i++)
+                    light[0] = lightAbove[0];
+                    light[1] = lightAbove[1];
+                    light[2] = lightAbove[2];
+                    current->filterPassingLight(light);
+                    max[0] = MAX(max[0], lightAbove[0]);
+                    max[1] = MAX(max[1], lightAbove[1]);
+                    max[2] = MAX(max[2], lightAbove[2]);
+                }
+                else
+                {
+                    allVisited = 0;
+                }
+            }
+        }
+        if (!(max[0] | max[1] | max[2])) break;
+        if (!allVisited)
+        {
+            bool goUp = 1;
+            while (goUp)
+            {
+                goUp = 0;
+                bool changes = 1;
+                while (changes)
+                {
+                    changes = 0;
+                    for (int x = 0; x < CHUNK_SIZE; x++)
                     {
-                        if (newLight[i] != light[i])
+                        for (int y = 0; y < CHUNK_SIZE; y++)
                         {
-                            changes = 1;
-                            memcpy(light, newLight, 6);
-                            break;
+                            int index = Chunk::index(x, y);
+                            unsigned char* light
+                                = getLightData(Framework::Vec3<int>(x, y, z));
+                            const Block* current
+                                = (blocks[z] && blocks[z][index])
+                                    ? blocks[z][index]
+                                    : Game::INSTANCE
+                                          ->zBlockType(blockIds[z]
+                                                           ? blockIds[z][index]
+                                                           : 0)
+                                          ->zDefault();
+                            unsigned char newLight[3] = {0, 0, 0};
+                            for (int i = 0; i < 4; i++)
+                            {
+                                Framework::Vec3<int> neighborPos
+                                    = Framework::Vec3<int>(x, y, z)
+                                    + getDirection(getDirectionFromIndex(i));
+                                if (neighborPos.x < 0 || neighborPos.y < 0
+                                    || neighborPos.x >= CHUNK_SIZE
+                                    || neighborPos.y >= CHUNK_SIZE)
+                                {
+                                    continue;
+                                }
+                                unsigned char* neighborLeight
+                                    = getLightData(neighborPos);
+                                for (int j = 0; j < 3; j++)
+                                {
+                                    newLight[j] = (unsigned char)MAX(
+                                        newLight[j],
+                                        (unsigned char)((float)neighborLeight[j]
+                                                        * 0.8f));
+                                }
+                            }
+                            current->filterPassingLight(newLight);
+                            if (newLight[0] > light[0] || newLight[1] > light[1]
+                                || newLight[2] > light[2])
+                            {
+                                changes = 1;
+                                light[0] = MAX(light[0], newLight[0]);
+                                light[1] = MAX(light[1], newLight[1]);
+                                light[2] = MAX(light[2], newLight[2]);
+                                if (z < WORLD_HEIGHT - 1
+                                    && !(visited[y][z + 1] & (1 << x)))
+                                {
+                                    unsigned char* lightAbove = getLightData(
+                                        Framework::Vec3<int>(x, y, z + 1));
+                                    newLight[0]
+                                        = (unsigned char)(light[0] * 0.8f);
+                                    newLight[1]
+                                        = (unsigned char)(light[1] * 0.8f);
+                                    newLight[2]
+                                        = (unsigned char)(light[2] * 0.8f);
+                                    const Block* above
+                                        = blocks[z + 1] && blocks[z + 1][index]
+                                            ? blocks[z + 1][index]
+                                            : Game::INSTANCE
+                                                  ->zBlockType(
+                                                      blockIds[z + 1]
+                                                          ? blockIds[z + 1]
+                                                                    [index]
+                                                          : 0)
+                                                  ->zDefault();
+                                    above->filterPassingLight(newLight);
+                                    if (newLight[0] > lightAbove[0]
+                                        || newLight[1] > lightAbove[1]
+                                        || newLight[2] > lightAbove[2])
+                                    {
+                                        lightAbove[0]
+                                            = MAX(lightAbove[0], newLight[0]);
+                                        lightAbove[1]
+                                            = MAX(lightAbove[1], newLight[1]);
+                                        lightAbove[2]
+                                            = MAX(lightAbove[2], newLight[2]);
+                                        visited[y][z + 1] |= 1 << x;
+                                        goUp = 1;
+                                    }
+                                }
+                            }
                         }
                     }
                 }
+                if (goUp)
+                {
+                    z++;
+                    goUps++;
+                }
             }
         }
-        if (!changes) break;
+    }
+#ifdef _DEBUG
+    Framework::Logging::debug() << "goUps: " << goUps << " minZ: " << minZ;
+#endif
+}
+
+void Chunk::updateLightSources()
+{
+    Dimension* zDim = Game::INSTANCE->zDimension(dimensionId);
+    for (int i : lightSources)
+    {
+        int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
+        int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
+        int z = i % WORLD_HEIGHT;
+        Framework::Vec3<int> pos = {x, y, z};
+        zDim->updateLightning(
+            Framework::Vec3<int>(x + this->location.x - CHUNK_SIZE / 2,
+                y + this->location.y - CHUNK_SIZE / 2,
+                z));
     }
 }
 
@@ -500,12 +736,12 @@ Framework::Either<Block*, int> Chunk::zBlockAt(
     Framework::Vec3<int> location) const
 {
     if (location.z < 0 || location.z >= WORLD_HEIGHT) return 0;
-    int index = Chunk::index(location);
+    int index = Chunk::index(location.x, location.y);
     assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
-    if (blocks[index])
-        return blocks[index];
+    if (blocks[location.z] && blocks[location.z][index])
+        return blocks[location.z][index];
     else
-        return (int)blockIds[index];
+        return blockIds[location.z] ? (int)blockIds[location.z][index] : 0;
 }
 
 const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
@@ -515,12 +751,13 @@ const Block* Chunk::zBlockConst(Framework::Vec3<int> location) const
     return Game::INSTANCE->zBlockType(b.getB())->zDefault();
 }
 
-const Block* Chunk::zBlockConst(int index) const
+const Block* Chunk::zBlockConst(int z, int index) const
 {
-    if (blocks[index])
-        return blocks[index];
+    if (blocks[z] && blocks[z][index])
+        return blocks[z][index];
     else
-        return Game::INSTANCE->zBlockType(blockIds[index])->zDefault();
+        return Game::INSTANCE->zBlockType(blockIds[z] ? blockIds[z][index] : 0)
+            ->zDefault();
 }
 
 void Chunk::instantiateBlock(Framework::Vec3<int> location)
@@ -541,8 +778,8 @@ void Chunk::instantiateBlock(Framework::Vec3<int> location)
 
 void Chunk::generateBlock(Framework::Vec3<int> location)
 {
-    int index = Chunk::index(location);
-    if (blockIds[index]) return;
+    int index = Chunk::index(location.x, location.y);
+    if (blockIds[location.z] && blockIds[location.z][index]) return;
     auto generated = Game::INSTANCE->zGenerator()->generateSingleBlock(
         {location.x + this->location.x - CHUNK_SIZE / 2,
             location.y + this->location.y - CHUNK_SIZE / 2,
@@ -556,17 +793,17 @@ void Chunk::generateBlock(Framework::Vec3<int> location)
 
 void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
 {
-    int index = Chunk::index(location);
-    assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT && index >= 0);
-    Block* old = blocks[index];
+    int index = Chunk::index(location.x, location.y);
+    assert(index < CHUNK_SIZE * CHUNK_SIZE && index >= 0);
+    Block* old = blocks[location.z] ? blocks[location.z][index] : 0;
     if (old && old->isTickSource() != TickSourceType::NONE)
     { // remove from tick sorces
         if (old->isTickSource() == TickSourceType::EACH_TICK)
         {
             for (Framework::ArrayIterator<Block*> obj
                  = tickSourcesEachTick.begin();
-                 obj;
-                 obj++)
+                obj;
+                obj++)
             {
                 if (obj.val() == old)
                 {
@@ -579,8 +816,8 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
         {
             for (Framework::ArrayIterator<Block*> obj
                  = tickSourcesAfterUpdate.begin();
-                 obj;
-                 obj++)
+                obj;
+                obj++)
             {
                 if (obj.val() == old)
                 {
@@ -590,52 +827,42 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
             }
         }
     }
+    if (!blockIds[location.z])
+    {
+        blockIds[location.z] = new unsigned short[CHUNK_SIZE * CHUNK_SIZE];
+        memset(blockIds[location.z],
+            0,
+            CHUNK_SIZE * CHUNK_SIZE * sizeof(unsigned short));
+    }
+    if (!blocks[location.z])
+    {
+        blocks[location.z] = new Block*[CHUNK_SIZE * CHUNK_SIZE];
+        memset(blocks[location.z], 0, CHUNK_SIZE * CHUNK_SIZE * sizeof(Block*));
+    }
     bool change = 0;
     bool wasLightSource
         = old ? old->zBlockType()->isLightSource()
-              : Game::INSTANCE->zBlockType(blockIds[index])->isLightSource();
+              : Game::INSTANCE->zBlockType(blockIds[location.z][index])
+                    ->isLightSource();
     bool isLightSource = 0;
     if (block)
     {
-        change
-            = blockIds[index] != (unsigned short)block->zBlockType()->getId();
-        blockIds[index] = (unsigned short)block->zBlockType()->getId();
+        change = blockIds[location.z][index]
+              != (unsigned short)block->zBlockType()->getId();
+
+        blockIds[location.z][index]
+            = (unsigned short)block->zBlockType()->getId();
         isLightSource = block->zBlockType()->isLightSource();
     }
     else
     {
         if (old != 0)
         {
-            blockIds[index] = BlockTypeEnum::NO_BLOCK;
+            blockIds[location.z][index] = BlockTypeEnum::NO_BLOCK;
         }
         change = old != 0;
     }
-    blocks[index] = block;
-    for (int i = 0; i < 6; i++)
-    {
-        Direction d = getDirectionFromIndex(i);
-        Chunk* zNeighborChunk = 0;
-        Framework::Either<Block*, int> neighbor
-            = zBlockNeighbor(location + getDirection(d), &zNeighborChunk);
-        if (neighbor.isA())
-        {
-            if (block)
-            {
-                ((Block*)neighbor)
-                    ->setNeighbour(getOppositeDirection(d), block);
-            }
-            else
-            {
-                ((Block*)neighbor)
-                    ->setNeighbour(getOppositeDirection(d), blockIds[index]);
-            }
-        }
-        if (block) block->setNeighbour(d, neighbor);
-        if (zNeighborChunk && zNeighborChunk != this)
-        {
-            zNeighborChunk->worldUpdated = 1;
-        }
-    }
+    blocks[location.z][index] = block;
     if (old) old->release();
     if (block && block->isTickSource() != TickSourceType::NONE)
     { // add to tick sources
@@ -654,9 +881,9 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
         if (isLightSource != wasLightSource)
         {
             if (isLightSource)
-                addLightSource(index);
+                addLightSource(location.z, index);
             else
-                removeLightSource(index);
+                removeLightSource(location.z, index);
         }
         if (added)
         {
@@ -682,34 +909,27 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
 
 void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
 {
-    int index = Chunk::index(location);
-    assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT);
-    bool wasLightSource
-        = Game::INSTANCE->zBlockType(blockIds[index])->isLightSource();
+    int index = Chunk::index(location.x, location.y);
+    assert(index < CHUNK_SIZE * CHUNK_SIZE);
+    int oldType = blockIds[location.z] ? blockIds[location.z][index] : 0;
+    bool wasLightSource = Game::INSTANCE->zBlockType(oldType)->isLightSource();
     bool isLightSource = Game::INSTANCE->zBlockType(type)->isLightSource();
-    if (blockIds[index] != (unsigned short)type)
+    if (oldType != (unsigned short)type)
     {
-        blockIds[index] = (unsigned short)type;
-        for (int i = 0; i < 6; i++)
+        if (!blockIds[location.z])
         {
-            Direction d = getDirectionFromIndex(i);
-            Chunk* zNeighborChunk = 0;
-            Framework::Either<Block*, int> neighbor
-                = zBlockNeighbor(location + getDirection(d), &zNeighborChunk);
-            if (neighbor.isA())
-                ((Block*)neighbor)
-                    ->setNeighbourType(getOppositeDirection(d), type);
-            if (zNeighborChunk && zNeighborChunk != this)
-            {
-                zNeighborChunk->worldUpdated = 1;
-            }
+            blockIds[location.z] = new unsigned short[CHUNK_SIZE * CHUNK_SIZE];
+            memset(blockIds[location.z],
+                0,
+                CHUNK_SIZE * CHUNK_SIZE * sizeof(unsigned short));
         }
+        blockIds[location.z][index] = (unsigned short)type;
         if (isLightSource != wasLightSource)
         {
             if (isLightSource)
-                addLightSource(index);
+                addLightSource(location.z, index);
             else
-                removeLightSource(index);
+                removeLightSource(location.z, index);
         }
         if (added)
         {
@@ -730,18 +950,20 @@ void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
 
 void Chunk::sendBlockInfo(Framework::Vec3<int> location)
 {
-    int index = Chunk::index(location);
+    int index = Chunk::index(location.x, location.y);
     char* msg = new char[14];
     msg[0] = 0; // set block
-    *(unsigned short*)(msg + 1) = blockIds[index];
-    *(int*)(msg + 3) = index;
+    int typeId = blockIds[location.z] ? blockIds[location.z][index] : 0;
+    *(unsigned short*)(msg + 1) = typeId;
+    *(int*)(msg + 3) = index * WORLD_HEIGHT + location.z;
     char state = 0;
-    const BlockType* type = Game::INSTANCE->zBlockType(blockIds[index]);
+    const BlockType* type = Game::INSTANCE->zBlockType(typeId);
     if (type->isFluid())
     {
         state |= 1;
     }
-    if ((blocks[index] && blocks[index]->isPassable())
+    if ((blocks[location.z] && blocks[location.z][index]
+            && blocks[location.z][index]->isPassable())
         || (type->zDefault()->isPassable()))
     {
         state |= 2;
@@ -749,24 +971,25 @@ void Chunk::sendBlockInfo(Framework::Vec3<int> location)
     msg[7] = state;
     if ((state | 1) == state)
     {
-        FluidBlock* fluidBlock = dynamic_cast<FluidBlock*>(blocks[index]);
+        FluidBlock* fluidBlock = dynamic_cast<FluidBlock*>(
+            blocks[location.z] ? blocks[location.z][index] : 0);
         msg[8] = fluidBlock ? fluidBlock->getFlowOptions() : 0;
         msg[9] = fluidBlock ? fluidBlock->getDistanceToSource() : 0;
     }
     if ((state | 2) == state)
     {
-        *(float*)(msg + 10) = blocks[index]
-                                ? blocks[index]->getSpeedModifier()
+        *(float*)(msg + 10) = blocks[location.z] && blocks[location.z][index]
+                                ? blocks[location.z][index]->getSpeedModifier()
                                 : type->zDefault()->getSpeedModifier();
     }
     NetworkMessage* message = new NetworkMessage();
     message->addressChunck(this);
     message->setMessage(msg, 14);
     notifyObservers(message);
-    if (blocks[index])
+    if (blocks[location.z] && blocks[location.z][index])
     {
         NetworkMessage* message = new NetworkMessage();
-        blocks[index]->sendModelInfo(message);
+        blocks[location.z][index]->sendModelInfo(message);
         if (message->isEmpty())
         {
             message->release();
@@ -784,7 +1007,7 @@ void Chunk::sendBlockInfo(Framework::Vec3<int> location)
         if (loc.x >= 0 && loc.x < CHUNK_SIZE && loc.y >= 0 && loc.y < CHUNK_SIZE
             && loc.z >= 0 && loc.z < WORLD_HEIGHT)
         {
-            broadcastLightData(Chunk::index(loc), true);
+            broadcastLightData(loc.z, Chunk::index(loc.x, loc.y), true);
         }
         else if (loc.z >= 0 && loc.z < WORLD_HEIGHT && i < 4 && zNeighbours[i])
         {
@@ -808,87 +1031,15 @@ void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
 {
     cs.lock();
     int dirIndex = getDirectionIndex(dir);
-    Chunk* old = zNeighbours[dirIndex];
     zNeighbours[dirIndex] = zChunk;
-    for (int i = 0; i < CHUNK_SIZE; i++)
-    {
-        for (int z = 0; z < WORLD_HEIGHT; z++)
-        {
-            int index = 0;
-            int j = 0;
-            if (dir == NORTH)
-            {
-                index = i * CHUNK_SIZE * WORLD_HEIGHT + z;
-                j = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
-            }
-            else if (dir == EAST)
-            {
-                index = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
-                j = i * WORLD_HEIGHT + z;
-            }
-            else if (dir == SOUTH)
-            {
-                index = (i * CHUNK_SIZE + CHUNK_SIZE - 1) * WORLD_HEIGHT + z;
-                j = i * CHUNK_SIZE * WORLD_HEIGHT + z;
-            }
-            else if (dir == WEST)
-            {
-                index = i * WORLD_HEIGHT + z;
-                j = ((CHUNK_SIZE - 1) * CHUNK_SIZE + i) * WORLD_HEIGHT + z;
-            }
-            bool needsTransmission = 0;
-            if (blocks[index])
-            {
-                bool visible = blocks[index]->isVisible();
-                if (zChunk && zChunk->blocks[j])
-                    blocks[index]->setNeighbour(dir, zChunk->blocks[j]);
-                else
-                {
-                    blocks[index]->setNeighbour(dir, 0);
-                    blocks[index]->setNeighbourType(
-                        dir, zChunk ? zChunk->blockIds[j] : 0);
-                }
-                if (!visible && blocks[index]->isVisible())
-                {
-                    needsTransmission = 1;
-                }
-            }
-            else
-            {
-                zNeighbours[dirIndex] = old;
-                bool visible = isVisible(index);
-                zNeighbours[dirIndex] = zChunk;
-                if (!visible && isVisible(index))
-                {
-                    needsTransmission = 1;
-                }
-            }
-            if (zChunk)
-            {
-                if (!blocks[index])
-                {
-                    if (zChunk->zBlockConst(j)->isTransparent()
-                        && !blockIds[index])
-                    {
-                        generateBlock(Framework::Vec3<int>(
-                            (index / WORLD_HEIGHT) / CHUNK_SIZE,
-                            (index / WORLD_HEIGHT) % CHUNK_SIZE,
-                            index % WORLD_HEIGHT));
-                    }
-                }
-            }
-            if (needsTransmission && added)
-            {
-                sendBlockInfo(
-                    Framework::Vec3<int>((index / WORLD_HEIGHT) / CHUNK_SIZE,
-                        (index / WORLD_HEIGHT) % CHUNK_SIZE,
-                        index % WORLD_HEIGHT));
-            }
-        }
-    }
     cs.unlock();
 }
 
+Chunk* Chunk::zNeighbor(Direction dir) const
+{
+    return zNeighbours[getDirectionIndex(dir)];
+}
+
 void Chunk::load(Framework::StreamReader* zReader)
 {
     for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
@@ -921,135 +1072,100 @@ void Chunk::load(Framework::StreamReader* zReader)
         }
     }
     initializeLightning();
+    unsigned short entityCount;
+    zReader->lese((char*)&entityCount, 2);
+    lastSavedEntityIds.leeren();
+    entitiesInChunk.leeren();
+    for (int i = 0; i < entityCount; i++)
+    {
+        int type;
+        zReader->lese((char*)&type, 4);
+        Entity* entity = Game::INSTANCE->zEntityType(type)->loadEntity(zReader);
+        entitiesInChunk.add(entity);
+        lastSavedEntityIds.add(entity->getId());
+    }
 }
 
-void Chunk::save(Framework::StreamWriter* zWriter)
+void Chunk::save(Framework::StreamWriter* zWriter,
+    Framework::Array<Framework::Punkt>& otherChunksToSave)
 {
-    for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
+    for (int id : lastSavedEntityIds)
     {
-        unsigned short blockType
-            = blocks[index]
-                ? (unsigned short)blocks[index]->zBlockType()->getId()
-                : blockIds[index];
-        zWriter->schreibe((char*)&blockType, 2);
-        if (blockType)
+        if (!entitiesInChunk.anyMatch(
+                [id](const Entity* e) { return e->getId() == id; }))
         {
-            if (blocks[index])
-            {
-                bool d = 1;
-                zWriter->schreibe((char*)&d, 1);
-                Game::INSTANCE->zBlockType(blockType)->saveBlock(
-                    blocks[index], zWriter);
-            }
-            else
+            Entity* old = Game::INSTANCE->zEntity(id);
+            if (old && old->getDimensionId() == getDimensionId()
+                && !old->isRemoved())
             {
-                bool d = 0;
-                zWriter->schreibe((char*)&d, 1);
+                otherChunksToSave.add(Game::getChunkCenter(
+                    (int)old->getPosition().x, (int)old->getPosition().y));
             }
         }
     }
-}
-
-void Chunk::sendToClient(Framework::StreamWriter* zWriter)
-{
-    for (int x = 0; x < CHUNK_SIZE; x++)
+    for (int index = 0; index < CHUNK_SIZE * CHUNK_SIZE; index++)
     {
-        for (int y = 0; y < CHUNK_SIZE; y++)
+        for (int z = 0; z < WORLD_HEIGHT; z++)
         {
-            for (int z = 0; z < WORLD_HEIGHT; z++)
+            unsigned short blockType = blockIds[z] ? blockIds[z][index] : 0;
+            zWriter->schreibe((char*)&blockType, 2);
+            if (blockType)
             {
-                int index = Chunk::index({x, y, z});
-                const BlockType* type
-                    = Game::INSTANCE->zBlockType(blockIds[index]);
-                if (isVisible(index) && type->doesNeedClientInstance())
+                if (blocks[z] && blocks[z][index])
                 {
-                    zWriter->schreibe((char*)&blockIds[index], 2);
-                    zWriter->schreibe((char*)&index, 4);
-                    char state = 0;
-                    if (type->isFluid())
-                    {
-                        state |= 1;
-                    }
-                    if ((blocks[index] && blocks[index]->isPassable())
-                        || (type->zDefault()->isPassable()))
-                    {
-                        state |= 2;
-                    }
-                    zWriter->schreibe((char*)&state, 1);
-                    if ((state | 1) == state)
-                    {
-                        FluidBlock* fluidBlock
-                            = dynamic_cast<FluidBlock*>(blocks[index]);
-                        char data
-                            = fluidBlock ? fluidBlock->getFlowOptions() : 0;
-                        zWriter->schreibe(&data, 1);
-                        data = fluidBlock ? fluidBlock->getDistanceToSource()
-                                          : 0;
-                        zWriter->schreibe(&data, 1);
-                    }
-                    if ((state | 2) == state)
-                    {
-                        float speedModifier
-                            = blocks[index]
-                                ? blocks[index]->getSpeedModifier()
-                                : type->zDefault()->getSpeedModifier();
-                        zWriter->schreibe((char*)&speedModifier, 4);
-                    }
+                    bool d = 1;
+                    zWriter->schreibe((char*)&d, 1);
+                    Game::INSTANCE->zBlockType(blockType)->saveBlock(
+                        blocks[z][index], zWriter);
+                }
+                else
+                {
+                    bool d = 0;
+                    zWriter->schreibe((char*)&d, 1);
                 }
             }
         }
     }
-    unsigned short end = 0;
-    zWriter->schreibe((char*)&end, 2);
+    unsigned short len = (unsigned short)entitiesInChunk.getEintragAnzahl();
+    zWriter->schreibe((char*)&len, 2);
+    for (Entity* entity : entitiesInChunk)
+    {
+        int type = entity->zType()->getId();
+        zWriter->schreibe((char*)&type, 4);
+        entity->zType()->saveEntity(entity, zWriter);
+        if (lastSavedEntityIds.getWertIndex(entity->getId()) < 0)
+        {
+            entity->getLastSavedChunkCenter().ifPresent(
+                [&otherChunksToSave](
+                    Framework::Punkt p) { otherChunksToSave.add(p); });
+        }
+        entity->setLastSavedChunkCenter(getCenter());
+    }
+    lastSavedEntityIds.leeren();
+    for (Entity* entity : entitiesInChunk)
+    {
+        lastSavedEntityIds.add(entity->getId());
+    }
 }
 
 void Chunk::removeUnusedBlocks()
 {
-    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
+    // no longer needed becaus only used blocks are generated in the first place
+#ifdef _DEBUG
+    int count = 0;
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++)
     {
-        if (!blocks[i] && blockIds[i])
+        for (int z = 0; z < WORLD_HEIGHT; z++)
         {
-            int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
-            int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
-            int z = i % WORLD_HEIGHT;
-            bool visible = 0;
-            if (CONST_BLOCK(0, blockIds[i])->isTransparent()
-                || CONST_BLOCK(0, blockIds[i])->isPassable())
-                visible = 1;
-            else
-            {
-                for (int d = 0; d < 6 && !visible; d++)
-                {
-                    auto n = zBlockNeighbor(
-                        getDirection((Directions)getDirectionFromIndex(d))
-                            + Framework::Vec3<int>(x, y, z),
-                        0);
-                    if (n.isA()
-                        && (((Block*)n)->isPassable()
-                            || ((Block*)n)->isTransparent()))
-                        visible = 1;
-                    if (n.isB()
-                        && (CONST_BLOCK(0, n)->isTransparent()
-                            || CONST_BLOCK(0, n)->isPassable()))
-                        visible = 1;
-                }
-            }
-            if (!visible)
-            {
-                putBlockAt({x, y, z}, 0);
-                putBlockTypeAt({x, y, z}, 0);
-            }
+            if (Game::INSTANCE->zBlockType(blockIds[z] ? blockIds[z][i] : 0)
+                    ->doesNeedClientInstance())
+                count++;
         }
     }
-    int count = 0;
-    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
-    {
-        if (Game::INSTANCE->zBlockType(blockIds[i])->doesNeedClientInstance())
-            count++;
-    }
     Framework::Logging::debug()
         << "chunk " << location.x << ", " << location.y
         << " was generated with " << count << " blocks.";
+#endif
 }
 
 int Chunk::getDimensionId() const
@@ -1059,18 +1175,24 @@ int Chunk::getDimensionId() const
 
 void Chunk::onLoaded()
 {
-    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++)
     {
-        if (blocks[i]) blocks[i]->onLoaded();
+        for (int z = 0; z < WORLD_HEIGHT; z++)
+        {
+            if (blocks[z] && blocks[z][i]) blocks[z][i]->onLoaded();
+        }
     }
     currentlyLoading = 0;
 }
 
 void Chunk::onUnloaded()
 {
-    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++)
+    for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE; i++)
     {
-        if (blocks[i]) blocks[i]->onUnloaded();
+        for (int z = 0; z < WORLD_HEIGHT; z++)
+        {
+            if (blocks[z] && blocks[z][i]) blocks[z][i]->onUnloaded();
+        }
     }
 }
 
@@ -1103,6 +1225,10 @@ void Chunk::prepareRemove()
             zNeighbours[i] = 0;
         }
     }
+    for (Entity* entity : entitiesInChunk)
+    {
+        entity->setRemoved();
+    }
     cs.unlock();
 }
 
@@ -1118,7 +1244,9 @@ bool Chunk::hasObservers() const
 
 unsigned char* Chunk::getLightData(Framework::Vec3<int> location) const
 {
-    int index = Chunk::index(location) * 6;
+    int index
+        = (Chunk::index(location.x, location.y) * WORLD_HEIGHT + location.z)
+        * 6;
     assert(index < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
     return lightData + index;
 }
@@ -1126,8 +1254,8 @@ unsigned char* Chunk::getLightData(Framework::Vec3<int> location) const
 void Chunk::setLightData(
     Framework::Vec3<int> location, unsigned char* data, bool foreground)
 {
-    int index = Chunk::index(location);
-    memcpy(lightData + index * 6, data, 6);
+    int index = Chunk::index(location.x, location.y);
+    memcpy(lightData + (index * WORLD_HEIGHT + location.z) * 6, data, 6);
     // check if neighbor is a visible block and send update to clients
     bool needSend = 0;
     for (int i = 0; i < 6; i++)
@@ -1139,8 +1267,8 @@ void Chunk::setLightData(
             if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
                 && pos.y < CHUNK_SIZE)
             {
-                int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
-                int type = blockIds[bi];
+                int bi = (pos.x * CHUNK_SIZE + pos.y);
+                int type = blockIds[pos.z] ? blockIds[pos.z][bi] : 0;
                 needSend |= Game::INSTANCE->zBlockType(type)
                                 ->doesNeedClientInstance();
                 if (needSend) break;
@@ -1162,11 +1290,88 @@ void Chunk::setLightData(
     }
     if (needSend)
     {
-        broadcastLightData(index, foreground);
+        broadcastLightData(location.z, index, foreground);
     }
 }
 
 int Chunk::getBlockTypeAt(Framework::Vec3<int> location) const
 {
-    return blockIds[index(location)];
-}
+    return blockIds[location.z]
+             ? blockIds[location.z][index(location.x, location.y)]
+             : 0;
+}
+
+int Chunk::getBlockTypeAtWC(int x, int y, int z) const
+{
+    auto pos = Dimension::chunkCoordinates({x, y, z});
+    return blockIds[pos.z] ? blockIds[pos.z][index(pos.x, pos.y)] : 0;
+}
+
+void Chunk::onEntityEnters(Entity* zEntity, Chunk* lastChunk)
+{
+    if (zEntity->zType()->getId() != EntityTypeEnum::PLAYER)
+    {
+        this->entitiesInChunk.add(dynamic_cast<Entity*>(zEntity->getThis()));
+    }
+    NetworkMessage* msg = 0;
+    for (InformationObserver* observer : observers)
+    {
+        if (!lastChunk || !lastChunk->hasObserver(zEntity->getId()))
+        {
+            if (!msg)
+            {
+                msg = new NetworkMessage();
+                msg->addEntityMessage(zEntity);
+                if (msg->isEmpty()) break;
+            }
+            observer->sendMessage(
+                dynamic_cast<NetworkMessage*>(msg->getThis()));
+        }
+    }
+    if (msg) msg->release();
+}
+
+void Chunk::onEntityLeaves(Entity* zEntity, Chunk* zNextChunk)
+{
+    if (zEntity->zType()->getId() != EntityTypeEnum::PLAYER)
+    {
+        this->entitiesInChunk.remove(this->entitiesInChunk.indexOf(zEntity));
+    }
+    NetworkMessage* msg = 0;
+    for (InformationObserver* observer : observers)
+    {
+        if (!zNextChunk || !zNextChunk->hasObserver(zEntity->getId()))
+        {
+            if (!msg)
+            {
+                msg = new NetworkMessage();
+                msg->removeEntityMessage(zEntity);
+                if (msg->isEmpty()) break;
+            }
+            observer->sendMessage(
+                dynamic_cast<NetworkMessage*>(msg->getThis()));
+        }
+    }
+    if (msg) msg->release();
+}
+
+bool Chunk::hasObserver(int entityId) const
+{
+    for (InformationObserver* observer : observers)
+    {
+        if (observer->getEntityId() == entityId) return 1;
+    }
+    return 0;
+}
+
+void Chunk::addGeneratedEntity(Entity* entity)
+{
+    entitiesInChunk.add(entity);
+    lastSavedEntityIds.add(entity->getId());
+    entity->setLastSavedChunkCenter(getCenter());
+}
+
+const Framework::RCArray<Entity>& Chunk::getEntitiesInChunk() const
+{
+    return entitiesInChunk;
+}

+ 24 - 14
FactoryCraft/Chunk.h

@@ -1,7 +1,6 @@
 #pragma once
 
 #include <Array.h>
-#include <Datei.h>
 #include <Either.h>
 #include <Punkt.h>
 #include <Vec3.h>
@@ -9,6 +8,7 @@
 #include "Block.h"
 #include "Constants.h"
 #include "DoLaterHandler.h"
+#include "Entity.h"
 #include "InformationObserver.h"
 #include "Tickable.h"
 
@@ -20,9 +20,9 @@ class Chunk : public virtual Framework::ReferenceCounter,
 private:
     int dimensionId;
     Framework::Punkt location;
-    Block** blocks;
+    Block*** blocks;
     Chunk* zNeighbours[4];
-    unsigned short* blockIds;
+    unsigned short** blockIds;
     Framework::Either<Block*, int> zBlockNeighbor(
         Framework::Vec3<int> location, OUT Chunk** zNeighborChunk);
     bool added;
@@ -34,13 +34,16 @@ private:
     bool worldUpdated;
     unsigned char* lightData;
     bool currentlyLoading;
+    Framework::RCArray<Entity> entitiesInChunk;
+    Framework::Array<int> lastSavedEntityIds;
 
-    void addLightSource(int index);
-    void removeLightSource(int index);
-    void sendLightToClient(Framework::StreamWriter* zWriter);
-    void broadcastLightData(int index, bool foreground);
-    const Block* zBlockConst(int index) const;
-    bool isVisible(int index) const;
+    void addLightSource(int z, int index);
+    void removeLightSource(int z, int index);
+    void sendToClient(Framework::StreamWriter* zWriter, bool* instanceMap);
+    void sendLightToClient(Framework::StreamWriter* zWriter, bool* instanceMap);
+    void broadcastLightData(int z, int index, bool foreground);
+    const Block* zBlockConst(int z, int index) const;
+    bool isVisible(int z, int index) const;
 
 public:
     Chunk(Framework::Punkt location, int dimensionId);
@@ -62,6 +65,7 @@ public:
         Entity* zSource,
         DoLaterHandler& laterHandler);
     void initializeLightning();
+    void updateLightSources();
 
     Framework::Either<Block*, int> zBlockAt(
         Framework::Vec3<int> cLocation) const;
@@ -72,9 +76,10 @@ public:
     void putBlockTypeAt(Framework::Vec3<int> location, int type);
     void sendBlockInfo(Framework::Vec3<int> location);
     void setNeighbor(Direction dir, Chunk* zChunk);
+    Chunk* zNeighbor(Direction dir) const;
     void load(Framework::StreamReader* zReader);
-    void save(Framework::StreamWriter* zWriter);
-    void sendToClient(Framework::StreamWriter* zWriter);
+    void save(Framework::StreamWriter* zWriter,
+        Framework::Array<Framework::Punkt>& otherChunksToSave);
     void removeUnusedBlocks();
     int getDimensionId() const;
     void onLoaded();
@@ -89,11 +94,16 @@ public:
     void setLightData(
         Framework::Vec3<int> location, unsigned char* data, bool foreground);
     int getBlockTypeAt(Framework::Vec3<int> location) const;
+    int getBlockTypeAtWC(int x, int y, int z) const;
+    void onEntityEnters(Entity* zEntity, Chunk* lastChunk);
+    void onEntityLeaves(Entity* zEntity, Chunk* zNextChunk);
+    bool hasObserver(int entityId) const;
+    void addGeneratedEntity(Entity* entity);
+    const Framework::RCArray<Entity>& getEntitiesInChunk() const;
 
-    inline static int index(Framework::Vec3<int> localLocation)
+    inline static int index(int x, int y)
     {
-        return (localLocation.x * CHUNK_SIZE + localLocation.y) * WORLD_HEIGHT
-             + localLocation.z;
+        return x * CHUNK_SIZE + y;
     }
 
     friend ChunkMap;

+ 13 - 6
FactoryCraft/ChunkMap.cpp

@@ -2,7 +2,6 @@
 
 #include "Chunk.h"
 #include "Constants.h"
-#include "Game.h"
 
 ChunkMap::ChunkMap(Framework::Punkt chunkCenter)
     : ReferenceCounter(),
@@ -27,13 +26,21 @@ ChunkMap::ChunkMap(Chunk* zChunk)
             bool visible = 1;
             for (int height = WORLD_HEIGHT / 2 - 1; height >= 0; height--)
             {
-                int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT;
+                int index = x * CHUNK_SIZE + y;
                 const Block* block1
-                    = CONST_BLOCK(zChunk->blocks[index + height * 2],
-                        zChunk->blockIds[index + height * 2]);
+                    = CONST_BLOCK(zChunk->blocks[height * 2]
+                                      ? zChunk->blocks[height * 2][index]
+                                      : 0,
+                        zChunk->blockIds[height * 2]
+                            ? zChunk->blockIds[height * 2][index]
+                            : 0);
                 const Block* block2
-                    = CONST_BLOCK(zChunk->blocks[index + height * 2 + 1],
-                        zChunk->blockIds[index + height * 2 + 1]);
+                    = CONST_BLOCK(zChunk->blocks[height * 2 + 1]
+                                      ? zChunk->blocks[height * 2 + 1][index]
+                                      : 0,
+                        zChunk->blockIds[height * 2 + 1]
+                            ? zChunk->blockIds[height * 2 + 1][index]
+                            : 0);
                 int color1 = 0;
                 int color2 = 0;
                 if (visible) color2 = block2->getMapColor();

+ 19 - 39
FactoryCraft/CraftingStorage.cpp

@@ -5,6 +5,7 @@
 #include "Game.h"
 #include "Inventory.h"
 #include "Item.h"
+#include "ItemType.h"
 #include "RecipieList.h"
 #include "RecipieLoader.h"
 
@@ -42,14 +43,14 @@ BasicShapedCrafter::BasicShapedCrafter(
     zInventory->registerAfterPullStackCall(onChange);
     zInventory->registerAfterPushStackCall(onChange);
     zInventory->registerObserverAddedCall(
-        [this](Entity* zSource, Framework::Text id) {
+        [this](Entity* zSource, Framework::Text id, int processor) {
             Recipie* old = currentRecipie;
             calculateOutputPreview();
             if (old == currentRecipie)
             {
                 NetworkMessage* message = new NetworkMessage();
                 getOutputPreview(message);
-                message->addressUIElement(id);
+                message->addressUIElement(id, processor);
                 Game::INSTANCE->sendMessage(message, zSource);
             }
         });
@@ -144,41 +145,12 @@ bool BasicShapedCrafter::isAllAvailable(
 bool BasicShapedCrafter::isAllAvailable(
     Framework::RCArray<RecipieInput>& inputs)
 {
-    bool* used = new bool[craftingInput.getEintragAnzahl()];
-    memset(used, 0, sizeof(bool) * craftingInput.getEintragAnzahl());
-    for (RecipieInput* input : inputs)
-    {
-        bool found = 0;
-        for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
-        {
-            if (used[i]) continue;
-            ItemSlot* slot = craftingInput.get(i);
-            if (slot && slot->zStack()
-                && slot->zStack()->getSize() >= input->getAmount()
-                && slot->zStack()->zItem()
-                && input->zFilter()->matchItem(slot->zStack()->zItem()))
-            {
-                found = 1;
-                used[i] = 1;
-                break;
-            }
-        }
-        if (!found)
-        {
-            delete[] used;
-            return 0;
-        }
-    }
-    delete[] used;
-    return 1;
+    return zInventory->isAllAvailable(inputs, "CraftingGrid");
 }
 
 bool BasicShapedCrafter::hasFreeSpace(const Item* zItem, int amount)
 {
-    ItemStack* stack
-        = new ItemStack(zItem->zItemType()->cloneItem(zItem), amount);
-    int addable = zInventory->numberOfAddableItems(stack, NO_DIRECTION);
-    stack->release();
+    int addable = zInventory->numberOfAddableItems(zItem, NO_DIRECTION);
     return addable >= amount;
 }
 
@@ -296,7 +268,7 @@ bool BasicShapedCrafter::consume(
     return 1;
 }
 
-bool BasicShapedCrafter::consume(Framework::RCArray<RecipieInput>& inputs)
+void BasicShapedCrafter::consume(Framework::RCArray<RecipieInput>& inputs)
 {
     SourceSlotBlacklistFilter otherSlotsSource;
     TargetSlotBlacklistFilter otherSlotsTarget;
@@ -403,21 +375,19 @@ bool BasicShapedCrafter::consume(Framework::RCArray<RecipieInput>& inputs)
                             0, &tmp, &combinedFilter, 1, NO_DIRECTION, INSIDE);
                     }
                 }
-
                 break;
             }
         }
     }
     delete[] used;
-    return 1;
 }
 
-void BasicShapedCrafter::addCraftingResult(ItemStack* stack)
+void BasicShapedCrafter::addCraftingResult(ItemStack* zStack)
 {
     TargetSlotBlacklistFilter otherSlotsTarget;
     for (int i = 0; i < craftingInput.getEintragAnzahl(); i++)
         otherSlotsTarget.addBlackListSlotId(craftingInput.get(i)->getId());
-    zInventory->unsaveAddItem(stack, NO_DIRECTION, &otherSlotsTarget);
+    zInventory->unsaveAddItem(zStack, NO_DIRECTION, &otherSlotsTarget);
 }
 
 void BasicShapedCrafter::applyCurrentRecipie()
@@ -441,4 +411,14 @@ void BasicShapedCrafter::calculateOutputPreview()
             zInventory->notifyObservers(message);
         }
     }
-}
+}
+
+Framework::Vec3<float> BasicShapedCrafter::getStorageLocation() const
+{
+    return zInventory->getLocation();
+}
+
+int BasicShapedCrafter::getStorageDimensionId() const
+{
+    return zInventory->getDimensionId();
+}

+ 9 - 5
FactoryCraft/CraftingStorage.h

@@ -1,8 +1,8 @@
 #pragma once
 #include <Array.h>
+#include <Vec3.h>
 
 #include "Inventory.h"
-#include "ItemFilter.h"
 #include "ItemSlot.h"
 #include "ItemStack.h"
 #include "Recipie.h"
@@ -12,8 +12,10 @@ class CraftingStorage
 public:
     virtual bool isAllAvailable(Framework::RCArray<RecipieInput>& inputs) = 0;
     virtual bool hasFreeSpace(const Item* zItem, int amount) = 0;
-    virtual bool consume(Framework::RCArray<RecipieInput>& inputs) = 0;
-    virtual void addCraftingResult(ItemStack* stack) = 0;
+    virtual void consume(Framework::RCArray<RecipieInput>& inputs) = 0;
+    virtual void addCraftingResult(ItemStack* zStack) = 0;
+    virtual Framework::Vec3<float> getStorageLocation() const = 0;
+    virtual int getStorageDimensionId() const = 0;
 };
 
 class ShapedCraftingStorage : public CraftingStorage
@@ -53,8 +55,10 @@ public:
     virtual bool consume(Framework::RCArray<RecipieInput>& inputs,
         int width,
         int height) override;
-    virtual bool consume(Framework::RCArray<RecipieInput>& inputs) override;
-    virtual void addCraftingResult(ItemStack* stack) override;
+    virtual void consume(Framework::RCArray<RecipieInput>& inputs) override;
+    virtual void addCraftingResult(ItemStack* zStack) override;
     void applyCurrentRecipie();
     void calculateOutputPreview();
+    virtual Framework::Vec3<float> getStorageLocation() const override;
+    virtual int getStorageDimensionId() const override;
 };

+ 54 - 0
FactoryCraft/DefaultBlockItemDrop.cpp

@@ -0,0 +1,54 @@
+#include "DefaultBlockItemDrop.h"
+
+#include "Block.h"
+#include "BlockType.h"
+
+DefaultBlockItemDrop::DefaultBlockItemDrop()
+    : DropConfig()
+{}
+
+void DefaultBlockItemDrop::doDrop(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject) const
+{
+    if (zDestroyedObject.isA())
+    {
+        Item* blockItem
+            = zDestroyedObject.getA()->zBlockType()->getItemFromBlock(
+                zDestroyedObject.getA());
+        if (blockItem)
+        {
+            Game::INSTANCE->spawnItem(
+                zDestroyedObject.getA()->getLocation()
+                    + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
+                zDestroyedObject.getA()->getDimensionId(),
+                blockItem);
+        }
+    }
+}
+
+DefaultBlockItemDropFactory::DefaultBlockItemDropFactory()
+    : DropConfigFactory()
+{}
+
+JSONObjectValidationBuilder* DefaultBlockItemDropFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return DropConfigFactory::addToValidator(builder);
+}
+
+const char* DefaultBlockItemDropFactory::getTypeToken() const
+{
+    return "blockItem";
+}
+
+DefaultBlockItemDrop* DefaultBlockItemDropFactory::createInstance(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DefaultBlockItemDrop();
+}
+
+void DefaultBlockItemDropFactory::addToJson(
+    Framework::JSON::JSONObject* zJson, DefaultBlockItemDrop* zObject) const
+{}

+ 27 - 0
FactoryCraft/DefaultBlockItemDrop.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "DropConfig.h"
+
+class DefaultBlockItemDrop : public DropConfig
+{
+public:
+    DefaultBlockItemDrop();
+    void doDrop(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) const override;
+};
+
+class DefaultBlockItemDropFactory
+    : public DropConfigFactory<DefaultBlockItemDrop>
+{
+public:
+    DefaultBlockItemDropFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+    DefaultBlockItemDrop* createInstance(
+        Framework::JSON::JSONObject* zJson) const override;
+    void addToJson(Framework::JSON::JSONObject* zJson,
+        DefaultBlockItemDrop* zObject) const override;
+};

+ 67 - 0
FactoryCraft/DefaultInventoryDrop.cpp

@@ -0,0 +1,67 @@
+#include "DefaultInventoryDrop.h"
+
+#include <Block.h>
+#include <Entity.h>
+#include <Inventory.h>
+#include <ItemSlot.h>
+
+DefaultInventoryItemDrop::DefaultInventoryItemDrop()
+    : DropConfig()
+{}
+
+void DefaultInventoryItemDrop::doDrop(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject) const
+{
+    Inventory* inventory;
+    if (zDestroyedObject.isA())
+    {
+        inventory = dynamic_cast<Inventory*>(zDestroyedObject.getA());
+    }
+    else
+    {
+        inventory = dynamic_cast<Inventory*>(zDestroyedObject.getB());
+    }
+    for (ItemSlot* slot : *inventory)
+    {
+        if (!slot->isEmpty())
+        {
+            ItemStack* stack
+                = slot->takeItemsOut(slot->getNumberOfItems(), NO_DIRECTION);
+            if (stack)
+            {
+                Game::INSTANCE->spawnItem(
+                    inventory->getLocation()
+                        + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
+                    inventory->getDimensionId(),
+                    stack);
+            }
+        }
+    }
+}
+
+DefaultInventoryItemDropFactory::DefaultInventoryItemDropFactory()
+    : DropConfigFactory()
+{}
+
+JSONObjectValidationBuilder* DefaultInventoryItemDropFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return DropConfigFactory::addToValidator(builder);
+}
+
+const char* DefaultInventoryItemDropFactory::getTypeToken() const
+{
+    return "inventoryContent";
+}
+
+DefaultInventoryItemDrop* DefaultInventoryItemDropFactory::createInstance(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DefaultInventoryItemDrop();
+}
+
+void DefaultInventoryItemDropFactory::addToJson(
+    Framework::JSON::JSONObject* zJson, DefaultInventoryItemDrop* zObject) const
+{}

+ 27 - 0
FactoryCraft/DefaultInventoryDrop.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "DropConfig.h"
+
+class DefaultInventoryItemDrop : public DropConfig
+{
+public:
+    DefaultInventoryItemDrop();
+    void doDrop(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) const override;
+};
+
+class DefaultInventoryItemDropFactory
+    : public DropConfigFactory<DefaultInventoryItemDrop>
+{
+public:
+    DefaultInventoryItemDropFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+    DefaultInventoryItemDrop* createInstance(
+        Framework::JSON::JSONObject* zJson) const override;
+    void addToJson(Framework::JSON::JSONObject* zJson,
+        DefaultInventoryItemDrop* zObject) const override;
+};

+ 218 - 157
FactoryCraft/Dimension.cpp

@@ -12,16 +12,18 @@
 #include "NoBlock.h"
 #include "Player.h"
 #include "TickOrganizer.h"
+#include "WorldGenerator.h"
 
 using namespace Framework;
 
 Dimension::Dimension(int id)
     : Thread(),
-      nextStructureId(0),
+      nextStructureId(1),
       dimensionId(id),
       gravity(9.8f),
       chunks(new RCTrie<Chunk>()),
       entities(new RCArray<Entity>()),
+      structureManager(new MultiblockStructureManager(id)),
       map(new DimensionMap(id)),
       stop(0),
       currentDayTime(0.0),
@@ -47,6 +49,7 @@ Dimension::~Dimension()
     entities->release();
     chunks->release();
     map->release();
+    delete structureManager;
 }
 
 void Dimension::configureDayNightCyncle(
@@ -102,7 +105,7 @@ void Dimension::api(Framework::InMemoryBuffer* zRequest,
             Framework::Either<Block*, int> block = zBlock(location, 0);
             if (block.isA())
             {
-                block.getA()->api(zRequest, zResponse);
+                block.getA()->api(zRequest, zResponse, zSource);
             }
             break;
         }
@@ -123,6 +126,7 @@ void Dimension::tickEntities()
         this->currentDayTime
             -= dayDuration + nightDuration + nightTransitionDuration * 2;
     }
+    entityCs.lock();
     for (auto entity : *entities)
     {
         if (!entity->isRemoved()
@@ -141,6 +145,7 @@ void Dimension::tickEntities()
             entity->tick(this);
         index++;
     }
+    entityCs.unlock();
 }
 
 void Dimension::thread()
@@ -152,6 +157,7 @@ void Dimension::thread()
     double time = 0;
     bool isForeground = 0;
     Framework::Array<Framework::Vec3<int>> internalLightUpdateQueue;
+    unsigned char tmp[3];
     while (!stop)
     {
         Vec3<int> position;
@@ -167,6 +173,7 @@ void Dimension::thread()
             {
                 Chunk* removedChunk = removedChunks.z(0);
                 removedChunksCs.unlock();
+                Array<Framework::Punkt> chunksToSave;
                 Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/"
                               + getDimensionId() + "/";
                 filePath.appendHex(removedChunk->getCenter().x);
@@ -177,13 +184,34 @@ void Dimension::thread()
                 d.setDatei(filePath);
                 d.erstellen();
                 d.open(Datei::Style::schreiben);
-                removedChunk->save(&d);
+                removedChunk->save(&d, chunksToSave);
                 char addr[8];
                 getAddrOfWorld(removedChunk->getCenter(), addr);
                 map->removeMap(addr, 8);
                 d.close();
                 removedChunksCs.lock();
                 removedChunks.remove(0);
+                while (chunksToSave.getEintragAnzahl() > 0)
+                {
+                    Punkt cPos = chunksToSave.get(0);
+                    chunksToSave.remove(0);
+                    Chunk* c = zChunk(cPos);
+                    if (c)
+                    {
+                        Text filePath = Game::INSTANCE->getWorldDirectory()
+                                      + "/dim/" + getDimensionId() + "/";
+                        filePath.appendHex(cPos.x);
+                        filePath += "_";
+                        filePath.appendHex(cPos.y);
+                        filePath += ".chunk";
+                        Datei d;
+                        d.setDatei(filePath);
+                        d.erstellen();
+                        d.open(Datei::Style::schreiben);
+                        c->save(&d, chunksToSave);
+                        d.close();
+                    }
+                }
             }
             removedChunksCs.unlock();
             if (priorizedLightUpdateQueue.getEintragAnzahl())
@@ -259,9 +287,9 @@ void Dimension::thread()
                 }
                 const Block* current = zBlockOrDefault(position);
                 // add own light emission
+                current->getLightEmisionColor(tmp);
                 for (int j = 3; j < 6; j++)
-                    newLight[j] = (unsigned char)MAX(
-                        newLight[j], current->getLightEmisionColor()[j - 3]);
+                    newLight[j] = (unsigned char)MAX(newLight[j], tmp[j - 3]);
                 current->filterPassingLight(newLight);
                 current->filterPassingLight(newLight + 3);
                 for (int i = 0; i < 6; i++)
@@ -313,25 +341,7 @@ void Dimension::getAddrOfWorld(Punkt wPos, char* addr) const
 
 void Dimension::saveStructure(MultiblockStructure* zStructure) const
 {
-    Datei d;
-    Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
-              + Text(dimensionId) + "/structures/";
-    path.appendHex(zStructure->getStructureId());
-    path += ".str";
-    d.setDatei(path);
-    d.erstellen();
-    d.open(Datei::Style::schreiben);
-    auto uPos = zStructure->getUniquePosition();
-    d.schreibe((char*)&uPos.x, 4);
-    d.schreibe((char*)&uPos.y, 4);
-    d.schreibe((char*)&uPos.z, 4);
-    int typeId = zStructure->getStructureTypeId();
-    d.schreibe((char*)&typeId, 4);
-    __int64 strId = zStructure->getStructureId();
-    d.schreibe((char*)&strId, 8);
-    Game::INSTANCE->zMultiblockStructureType(zStructure->getStructureTypeId())
-        ->saveStructure(zStructure, &d);
-    d.close();
+    structureManager->saveStructure(zStructure);
 }
 
 Chunk* Dimension::zChunk(Punkt wPos) const
@@ -342,7 +352,7 @@ Chunk* Dimension::zChunk(Punkt wPos) const
 }
 
 Framework::Either<Block*, int> Dimension::zBlock(
-    Vec3<int> location, OUT Chunk** zChunk)
+    Vec3<int> location, OUT Chunk** zChunk) const
 {
     Chunk* c
         = this->zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
@@ -358,7 +368,7 @@ Framework::Either<Block*, int> Dimension::zBlock(
     return 0;
 }
 
-Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location)
+Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location) const
 {
     Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
     if (c)
@@ -371,7 +381,7 @@ Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location)
     return 0;
 }
 
-const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location)
+const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location) const
 {
     Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
     if (c)
@@ -382,7 +392,7 @@ const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location)
     return &NoBlock::INSTANCE;
 }
 
-int Dimension::getBlockType(Framework::Vec3<int> location)
+int Dimension::getBlockType(Framework::Vec3<int> location) const
 {
     Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
     if (c)
@@ -425,7 +435,9 @@ void Dimension::sendBlockInfo(Framework::Vec3<int> location)
 
 void Dimension::addEntity(Entity* entity)
 {
+    entityCs.lock();
     entities->add(entity);
+    entityCs.unlock();
 }
 
 void Dimension::setChunk(Chunk* chunk, Punkt center)
@@ -447,12 +459,15 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
                 break;
             }
         }
+        for (Entity* entity : old->getEntitiesInChunk())
+        {
+            removeEntity(entity->getId());
+        }
     }
     chunks->set(addr, 8, chunk);
     if (chunk)
     {
         chunkList.add(chunk);
-        chunk->setAdded();
     }
     getAddrOfWorld(center + Punkt(CHUNK_SIZE, 0), addr);
     Chunk* zChunk = chunks->z(addr, 8);
@@ -462,6 +477,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
         if (chunk)
         {
             chunk->setNeighbor(EAST, zChunk);
+            Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
         }
     }
     getAddrOfWorld(center + Punkt(-CHUNK_SIZE, 0), addr);
@@ -469,29 +485,48 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
     if (zChunk)
     {
         zChunk->setNeighbor(EAST, chunk);
-        if (chunk) chunk->setNeighbor(WEST, zChunk);
+        if (chunk)
+        {
+            chunk->setNeighbor(WEST, zChunk);
+            Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
+        }
     }
     getAddrOfWorld(center + Punkt(0, CHUNK_SIZE), addr);
     zChunk = chunks->z(addr, 8);
     if (zChunk)
     {
         zChunk->setNeighbor(NORTH, chunk);
-        if (chunk) chunk->setNeighbor(SOUTH, zChunk);
+        if (chunk)
+        {
+            chunk->setNeighbor(SOUTH, zChunk);
+            Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
+        }
     }
     getAddrOfWorld(center + Punkt(0, -CHUNK_SIZE), addr);
     zChunk = chunks->z(addr, 8);
     if (zChunk)
     {
         zChunk->setNeighbor(SOUTH, chunk);
-        if (chunk) chunk->setNeighbor(NORTH, zChunk);
+        if (chunk)
+        {
+            chunk->setNeighbor(NORTH, zChunk);
+            Game::INSTANCE->zGenerator()->postprocessChunk(zChunk);
+        }
     }
     DoLaterHandler laterHandler;
     if (chunk)
     {
+        chunkCs.unlock();
+        Game::INSTANCE->zGenerator()->postprocessChunk(chunk);
+        chunk->setAdded();
+        for (Entity* entity : chunk->getEntitiesInChunk())
+        {
+            addEntity(dynamic_cast<Entity*>(entity->getThis()));
+        }
         cs.lock();
         int index = 0;
         for (ArrayIterator<RequestQueue> iterator = waitingRequests.begin();
-             iterator;)
+            iterator;)
         {
             Entity* zE = Game::INSTANCE->zEntity(iterator.val().sourceId);
             if (zE)
@@ -516,7 +551,10 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
         cs.unlock();
         Game::INSTANCE->zTickOrganizer()->addTickSource(chunk);
     }
-    chunkCs.unlock();
+    else
+    {
+        chunkCs.unlock();
+    }
     if (old)
     {
         old->onUnloaded();
@@ -526,7 +564,11 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
     }
     if (chunk) chunk->onLoaded();
     laterHandler.execute();
-    if (chunk) updateLightAtChunkBorders(center);
+    if (chunk)
+    {
+        updateLightAtChunkBorders(chunk);
+        chunk->updateLightSources();
+    }
 }
 
 void Dimension::save(Text worldDir) const
@@ -539,6 +581,7 @@ void Dimension::save(Text worldDir) const
     d.schreibe((char*)&nextStructureId, 8);
     d.schreibe((char*)&currentDayTime, 8);
     d.close();
+    Array<Framework::Punkt> otherChunks;
     for (auto chunk = chunkList.begin(); chunk; chunk++)
     {
         if (!chunk._) continue;
@@ -549,42 +592,33 @@ void Dimension::save(Text worldDir) const
         filePath.appendHex(chunk->getCenter().y);
         filePath += ".chunk";
         file->setDatei(filePath);
-        if (file->open(Datei::Style::schreiben)) chunk->save(file);
+        if (file->open(Datei::Style::schreiben)) chunk->save(file, otherChunks);
         file->close();
         file->release();
         char addr[8];
         getAddrOfWorld(chunk->getCenter(), addr);
         map->saveMap(addr, 8);
     }
-    Text filePath = worldDir + "/dim/" + dimensionId + "/entities";
-    Datei* file = new Datei();
-    file->setDatei(filePath);
-    if (file->open(Datei::Style::schreiben))
+    // since all chunks were saved otherChunks can be ignored
+    entityCs.lock();
+    for (Entity* entity : *entities)
     {
-        for (Entity* entity : *entities)
+        if (entity->zType()->getId() == EntityTypeEnum::PLAYER)
         {
-            if (entity->zType()->getId() != EntityTypeEnum::PLAYER)
+            Datei pFile;
+            pFile.setDatei(
+                worldDir + "/player/"
+                + Game::INSTANCE->getPlayerId(((Player*)entity)->getName()));
+            pFile.erstellen();
+            if (pFile.open(Datei::Style::schreiben))
             {
-                if (!entity->isRemoved())
-                {
-                    int type = entity->zType()->getId();
-                    file->schreibe((char*)&type, 4);
-                    Game::INSTANCE->zEntityType(type)->saveEntity(entity, file);
-                }
-            }
-            else
-            {
-                Datei pFile;
-                pFile.setDatei(worldDir + "/player/"
-                               + Game::INSTANCE->getPlayerId(
-                                   ((Player*)entity)->getName()));
-                if (pFile.open(Datei::Style::schreiben))
-                    Game::INSTANCE->zEntityType(EntityTypeEnum::PLAYER)
-                        ->saveEntity(entity, &pFile);
+                Game::INSTANCE->zEntityType(EntityTypeEnum::PLAYER)
+                    ->saveEntity(entity, &pFile);
+                pFile.close();
             }
         }
-        file->close();
     }
+    entityCs.unlock();
     for (MultiblockStructure* structure : structures)
     {
         saveStructure(structure);
@@ -596,7 +630,7 @@ int Dimension::getDimensionId() const
     return dimensionId;
 }
 
-bool Dimension::hasChunck(int x, int y)
+bool Dimension::hasChunck(int x, int y) const
 {
     if (zChunk(Punkt(x, y))) return 1;
     removedChunksCs.lock();
@@ -674,20 +708,54 @@ void Dimension::removeOldChunks()
     structurCs.unlock();
 }
 
-Entity* Dimension::zEntity(int id)
+Entity* Dimension::zTarget(Framework::Vec3<float> pos,
+    Vec3<float> direction,
+    float maxDistanceSq) const
+{
+    double minDist = 0;
+    Entity* closestEntity = 0;
+    entityCs.lock();
+    for (auto entity : *entities)
+    {
+        if (!entity->isRemoved()
+            && entity->getPosition().abstandSq(pos) <= maxDistanceSq)
+        {
+            double dist = entity->getHitDistance(pos, direction);
+            if (!isnan(dist))
+            {
+                if (!closestEntity || dist < minDist)
+                {
+                    closestEntity = entity;
+                    minDist = dist;
+                }
+            }
+        }
+    }
+    entityCs.unlock();
+    return closestEntity;
+}
+
+Entity* Dimension::zEntity(int id) const
 {
+    entityCs.lock();
     for (auto entity : *entities)
     {
-        if (!entity->isRemoved() && entity->getId() == id) return entity;
+        if (!entity->isRemoved() && entity->getId() == id)
+        {
+            entityCs.unlock();
+            return entity;
+        }
     }
+    entityCs.unlock();
     return 0;
 }
 
 Entity* Dimension::zNearestEntity(
-    Framework::Vec3<float> pos, std::function<bool(Entity*)> filter)
+    Framework::Vec3<float> pos, std::function<bool(Entity*)> filter) const
 {
     Entity* result = 0;
     float sqDist = 0;
+    entityCs.lock();
     for (auto entity : *entities)
     {
         if (!entity->isRemoved() && filter(entity))
@@ -700,21 +768,25 @@ Entity* Dimension::zNearestEntity(
             }
         }
     }
+    entityCs.unlock();
     return result;
 }
 
 void Dimension::removeEntity(int id)
 {
     int index = 0;
+    entityCs.lock();
     for (auto entity : *entities)
     {
         if (entity->getId() == id)
         {
             entities->remove(index);
+            entityCs.unlock();
             return;
         }
         index++;
     }
+    entityCs.unlock();
 }
 
 void Dimension::removeSubscriptions(Entity* zEntity)
@@ -737,41 +809,88 @@ void Dimension::updateLightningWithoutWait(Framework::Vec3<int> location)
     prioLightCs.unlock();
 }
 
-void Dimension::updateLightAtChunkBorders(Punkt chunkCenter)
+void Dimension::updateLightAtChunkBorders(Chunk* zChunk)
 {
     if (lightUpdateQueue.getEintragAnzahl() > 300000)
     {
         Logging::warning()
             << "light calculation queue is over 300000 blocks long";
     }
+    Punkt center = zChunk->getCenter();
+    Chunk* xn = this->zChunk(center - Punkt(CHUNK_SIZE, 0));
+    Chunk* xp = this->zChunk(center + Punkt(CHUNK_SIZE, 0));
+    Chunk* yn = this->zChunk(center - Punkt(0, CHUNK_SIZE));
+    Chunk* yp = this->zChunk(center + Punkt(0, CHUNK_SIZE));
     for (int i = WORLD_HEIGHT - 1; i >= 0; i--)
     {
         for (int j = 0; j < CHUNK_SIZE; j++)
         {
-            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 - 1,
-                chunkCenter.y - CHUNK_SIZE / 2 + j,
-                i));
-            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2,
-                chunkCenter.y - CHUNK_SIZE / 2 + j,
-                i));
-            updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2 - 1,
-                chunkCenter.y - CHUNK_SIZE / 2 + j,
-                i));
-            updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 2,
-                chunkCenter.y - CHUNK_SIZE / 2 + j,
-                i));
-            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
-                chunkCenter.y - CHUNK_SIZE / 2 - 1,
-                i));
-            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
-                chunkCenter.y - CHUNK_SIZE / 2,
-                i));
-            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
-                chunkCenter.y + CHUNK_SIZE / 2 - 1,
-                i));
-            updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 2 + j,
-                chunkCenter.y + CHUNK_SIZE / 2,
-                i));
+            if (xn)
+            {
+                unsigned char* light
+                    = xn->getLightData(Vec3<int>(CHUNK_SIZE - 1, j, i));
+                unsigned char* light2
+                    = zChunk->getLightData(Vec3<int>(0, j, i));
+                if (*(int*)light != *(int*)light2
+                    || *(int*)(light + 2) != *(int*)(light2 + 2))
+                {
+                    updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2 - 1,
+                        center.y - CHUNK_SIZE / 2 + j,
+                        i));
+                    updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2,
+                        center.y - CHUNK_SIZE / 2 + j,
+                        i));
+                }
+            }
+            if (xp)
+            {
+                unsigned char* light = xp->getLightData(Vec3<int>(0, j, i));
+                unsigned char* light2
+                    = zChunk->getLightData(Vec3<int>(CHUNK_SIZE - 1, j, i));
+                if (*(int*)light != *(int*)light2
+                    || *(int*)(light + 2) != *(int*)(light2 + 2))
+                {
+                    updateLightning(Vec3<int>(center.x + CHUNK_SIZE / 2 - 1,
+                        center.y - CHUNK_SIZE / 2 + j,
+                        i));
+                    updateLightning(Vec3<int>(center.x + CHUNK_SIZE / 2,
+                        center.y - CHUNK_SIZE / 2 + j,
+                        i));
+                }
+            }
+            if (yn)
+            {
+                unsigned char* light
+                    = yn->getLightData(Vec3<int>(j, CHUNK_SIZE - 1, i));
+                unsigned char* light2
+                    = zChunk->getLightData(Vec3<int>(j, 0, i));
+                if (*(int*)light != *(int*)light2
+                    || *(int*)(light + 2) != *(int*)(light2 + 2))
+                {
+                    updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2 + j,
+                        center.y - CHUNK_SIZE / 2 - 1,
+                        i));
+                    updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2 + j,
+                        center.y - CHUNK_SIZE / 2,
+                        i));
+                }
+            }
+            if (yp)
+            {
+                unsigned char* light = yp->getLightData(Vec3<int>(j, 0, i));
+                unsigned char* light2
+                    = zChunk->getLightData(Vec3<int>(j, CHUNK_SIZE - 1, i));
+                if (*(int*)light != *(int*)light2
+                    || *(int*)(light + 2) != *(int*)(light2 + 2))
+                {
+                    updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2 + j,
+                        center.y + CHUNK_SIZE / 2 - 1,
+                        i));
+                    updateLightning(Vec3<int>(center.x - CHUNK_SIZE / 2 + j,
+                        center.y + CHUNK_SIZE / 2,
+                        i));
+                }
+            }
         }
     }
 }
@@ -791,52 +910,11 @@ void Dimension::addStructure(MultiblockStructure* structure)
 MultiblockStructure* Dimension::zStructureByPosition(
     Framework::Vec3<int> uniquePosition)
 {
-    structurCs.lock();
-    for (MultiblockStructure* str : structures)
+    __int64 id = structureManager->getStructureId(uniquePosition);
+    if (id > 0)
     {
-        if (str->getUniquePosition() == uniquePosition)
-        {
-            structurCs.unlock();
-            return str;
-        }
+        return zStructureById(id);
     }
-    // search for structure file
-    Datei dir(Game::INSTANCE->getWorldDirectory() + "/dim/" + Text(dimensionId)
-              + "/structures");
-    RCArray<Text>* names = dir.getDateiListe();
-    if (names)
-    {
-        Vec3<int> uPos;
-        for (Text* name : *names)
-        {
-            Datei d(Text(dir.zPfad()->getText()) + "/" + name->getText());
-            if (d.open(Datei::Style::lesen))
-            {
-                d.lese((char*)&uPos.x, 4);
-                d.lese((char*)&uPos.y, 4);
-                d.lese((char*)&uPos.z, 4);
-                if (uPos == uniquePosition)
-                {
-                    int type;
-                    d.lese((char*)&type, 4);
-                    __int64 strId;
-                    d.lese((char*)&strId, 8);
-                    MultiblockStructure* str
-                        = Game::INSTANCE->zMultiblockStructureType(type)
-                              ->loadStructure(
-                                  dimensionId, strId, uniquePosition, &d);
-                    d.close();
-                    structures.add(str);
-                    names->release();
-                    structurCs.unlock();
-                    return str;
-                }
-                d.close();
-            }
-        }
-        names->release();
-    }
-    structurCs.unlock();
     return 0;
 }
 
@@ -851,32 +929,15 @@ MultiblockStructure* Dimension::zStructureById(__int64 id)
             return str;
         }
     }
-    // search for structure file
-    Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
-              + Text(dimensionId) + "/structures/";
-    path.appendHex(id);
-    path += ".str";
-    Datei d(path);
-    Vec3<int> uPos;
-    if (d.open(Datei::Style::lesen))
-    {
-        d.lese((char*)&uPos.x, 4);
-        d.lese((char*)&uPos.y, 4);
-        d.lese((char*)&uPos.z, 4);
-        int type;
-        d.lese((char*)&type, 4);
-        __int64 strId;
-        d.lese((char*)&strId, 8);
-        MultiblockStructure* str
-            = Game::INSTANCE->zMultiblockStructureType(type)->loadStructure(
-                dimensionId, strId, uPos, &d);
-        d.close();
-        structures.add(str);
+    MultiblockStructure* structure = structureManager->loadStructure(id);
+    if (structure)
+    {
+        structures.add(structure);
         structurCs.unlock();
-        return str;
+        return structure;
     }
-    Logging::warning() << "did not find Structure information file '" << path
-                       << "'.";
+    Logging::warning() << "did not find Structure information file '"
+                       << std::hex << id << "'.";
     structurCs.unlock();
     return 0;
 }
@@ -940,7 +1001,7 @@ void Dimension::updateMap(int x, int y, int height)
     chunkCs.unlock();
 }
 
-int Dimension::getChunkCount()
+int Dimension::getChunkCount() const
 {
     return chunkList.getEintragAnzahl();
 }

+ 16 - 10
FactoryCraft/Dimension.h

@@ -10,6 +10,7 @@
 #include "Chunk.h"
 #include "Constants.h"
 #include "MultiblockStructure.h"
+#include "MultiblockStructureManager.h"
 
 class DimensionMap;
 class NetworkMessage;
@@ -38,6 +39,7 @@ private:
     Framework::Array<Chunk*> chunkList;
     Framework::Critical chunkCs;
     Framework::RCArray<Entity>* entities;
+    mutable Framework::Critical entityCs;
     Framework::Array<RequestQueue> waitingRequests;
     Framework::Critical cs;
     Framework::Array<Framework::Vec3<int>> lightUpdateQueue;
@@ -46,8 +48,9 @@ private:
     Framework::Critical prioLightCs;
     Framework::Critical structurCs;
     Framework::RCArray<Chunk> removedChunks;
-    Framework::Critical removedChunksCs;
+    mutable Framework::Critical removedChunksCs;
     Framework::RCArray<MultiblockStructure> structures;
+    MultiblockStructureManager* structureManager;
     DimensionMap* map;
     bool stop;
     double currentDayTime;
@@ -74,10 +77,10 @@ public:
     void thread() override;
 
     Framework::Either<Block*, int> zBlock(
-        Framework::Vec3<int> location, OUT Chunk** zChunk);
-    Block* zRealBlockInstance(Framework::Vec3<int> location);
-    const Block* zBlockOrDefault(Framework::Vec3<int> location);
-    int getBlockType(Framework::Vec3<int> location);
+        Framework::Vec3<int> location, OUT Chunk** zChunk) const;
+    Block* zRealBlockInstance(Framework::Vec3<int> location) const;
+    const Block* zBlockOrDefault(Framework::Vec3<int> location) const;
+    int getBlockType(Framework::Vec3<int> location) const;
     void placeBlock(
         Framework::Vec3<int> location, Framework::Either<Block*, int> block);
     void sendBlockInfo(Framework::Vec3<int> location);
@@ -85,19 +88,22 @@ public:
     void setChunk(Chunk* chunk, Framework::Punkt center);
     void save(Framework::Text worldDir) const;
     int getDimensionId() const;
-    bool hasChunck(int x, int y);
+    bool hasChunck(int x, int y) const;
     bool reviveChunk(int x, int y);
     Chunk* zChunk(Framework::Punkt wPos) const;
     float getGravity() const;
     void removeOldChunks();
-    Entity* zEntity(int id);
+    Entity* zTarget(Framework::Vec3<float> pos,
+        Framework::Vec3<float> direction,
+        float maxDistanceSq) const;
+    Entity* zEntity(int id) const;
     Entity* zNearestEntity(
-        Framework::Vec3<float> pos, std::function<bool(Entity*)> filter);
+        Framework::Vec3<float> pos, std::function<bool(Entity*)> filter) const;
     void removeEntity(int id);
     void removeSubscriptions(Entity* zEntity);
     void updateLightning(Framework::Vec3<int> location);
     void updateLightningWithoutWait(Framework::Vec3<int> location);
-    void updateLightAtChunkBorders(Framework::Punkt chunkCenter);
+    void updateLightAtChunkBorders(Chunk* zChunk);
     __int64 getNextStructureId();
     void addStructure(MultiblockStructure* structure);
     MultiblockStructure* zStructureByPosition(
@@ -105,7 +111,7 @@ public:
     MultiblockStructure* zStructureById(__int64 id);
     void requestStopAndWait();
     void updateMap(int x, int y, int height);
-    int getChunkCount();
+    int getChunkCount() const;
     double getCurrentDayTime() const;
     double getNightDuration() const;
     double getNightTransitionDuration() const;

+ 417 - 110
FactoryCraft/DimensionGenerator.cpp

@@ -1,13 +1,9 @@
 #include "DimensionGenerator.h"
 
-#include <iostream>
-#include <Logging.h>
-#include <Zeit.h>
-
+#include "BiomGenerator.h"
 #include "Constants.h"
 #include "Dimension.h"
 #include "Game.h"
-#include "NoBlock.h"
 #include "Noise.h"
 #include "RandNoise.h"
 #include "WormCaveGenerator.h"
@@ -31,11 +27,13 @@ void WorldHeightLayer::initialize(JExpressionMemory* zMemory)
     if (noise) noise->release();
     noise = JNoise::parseNoise(noiseConfig, zMemory);
     zMemory->setNoise(name, dynamic_cast<Noise*>(noise->getThis()));
+    valueP = zMemory->getFloatVariableP(name);
+    value->compile(zMemory);
 }
 
-void WorldHeightLayer::calculateValue(JExpressionMemory* zMemory)
+void WorldHeightLayer::calculateValue()
 {
-    zMemory->setFloatVariable(name, value->getValue(zMemory));
+    *valueP = value->getValue();
 }
 
 void WorldHeightLayer::setNoiseConfig(Framework::JSON::JSONObject* noiseConfig)
@@ -72,31 +70,29 @@ JFloatExpression* WorldHeightLayer::zValue() const
 
 WorldHeightLayerFactory::WorldHeightLayerFactory() {}
 
-WorldHeightLayer* WorldHeightLayerFactory::createValue(
+WorldHeightLayer* WorldHeightLayerFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new WorldHeightLayer();
-}
-
-void WorldHeightLayerFactory::fromJson(
-    WorldHeightLayer* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setName(zJson->zValue("name")->asString()->getString());
-    zResult->setNoiseConfig(zJson->getValue("noise")->asObject());
-    zResult->setValue(
+    WorldHeightLayer* result = new WorldHeightLayer();
+    result->setName(zJson->zValue("name")->asString()->getString());
+    result->setNoiseConfig(zJson->getValue("noise")->asObject());
+    result->setValue(
         Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
             zJson->zValue("value")));
+    return result;
 }
 
-void WorldHeightLayerFactory::toJson(
-    WorldHeightLayer* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* WorldHeightLayerFactory::toJsonObject(
+    WorldHeightLayer* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "name", new Framework::JSON::JSONString(zObject->getName()));
-    zResult->addValue("noise", zObject->zNoiseConfig());
-    zResult->addValue("value",
+    result->addValue("noise", zObject->zNoiseConfig());
+    result->addValue("value",
         Game::INSTANCE->zTypeRegistry()->toJson<JFloatExpression>(
             zObject->zValue()));
+    return result;
 }
 
 JSONObjectValidationBuilder* WorldHeightLayerFactory::addToValidator(
@@ -131,24 +127,29 @@ void DimensionGenerator::calculateHeightLayers()
 {
     for (WorldHeightLayer* layer : heightLayers)
     {
-        layer->calculateValue(jExpressionMemory);
+        layer->calculateValue();
     }
 }
 
-Dimension* DimensionGenerator::createDimension()
+Dimension* DimensionGenerator::createDimension() const
 {
     return new Dimension(getId());
 }
 
 void DimensionGenerator::initialize(int worldSeed)
 {
-    jExpressionMemory->setFloatVariable("worldSeed", (float)worldSeed);
-    jExpressionMemory->setFloatVariable(
-        "dimensionSeed", seedExpression->getValue(jExpressionMemory));
+    this->worldSeed = jExpressionMemory->getFloatVariableP("worldSeed");
+    *this->worldSeed = (float)worldSeed;
+    this->dimensionSeed = jExpressionMemory->getFloatVariableP("dimensionSeed");
+    seedExpression->compile(jExpressionMemory);
+    *this->dimensionSeed = seedExpression->getValue();
     for (WorldHeightLayer* layer : heightLayers)
     {
         layer->initialize(jExpressionMemory);
     }
+    xPos = jExpressionMemory->getFloatVariableP("x");
+    yPos = jExpressionMemory->getFloatVariableP("y");
+    zPos = jExpressionMemory->getFloatVariableP("z");
 }
 
 int DimensionGenerator::getDimensionId() const
@@ -223,13 +224,15 @@ void BiomedCavedDimensionGenerator::initialize(int worldSeed)
         gen->initialize(zMemory());
     }
     caveGenerator = new WormCaveGenerator(75, 150, 1, 6, 0.1f, worldSeed - 1);
+    terrainHeightP = zMemory()->getFloatVariableP(terrainHeightLayerName);
+    seaFluidBlockTypeId = Game::INSTANCE->getBlockTypeId(seaFluidBlockType);
 }
 
 BiomGenerator* BiomedCavedDimensionGenerator::zBiomGenerator()
 {
     for (BiomGenerator* generator : biomGenerators)
     {
-        if (generator->isApplicable(zMemory())) return generator;
+        if (generator->isApplicable()) return generator;
     }
     return 0;
 }
@@ -250,21 +253,15 @@ BiomedCavedDimensionGenerator::getGeneratedStructoresForArea(
     {
         for (int y = minSearchY; y <= maxSearchY; y++)
         {
-            zMemory()->setFloatVariable("x", (float)x);
-            zMemory()->setFloatVariable("y", (float)y);
+            *xPos = (float)x;
+            *yPos = (float)y;
             calculateHeightLayers();
             BiomGenerator* gen = zBiomGenerator();
             for (int z = minSearchZ; z <= maxSearchZ; z++)
             {
-                zMemory()->setFloatVariable("z", (float)z);
-                gen->generateStructures(x,
-                    y,
-                    z,
-                    getDimensionId(),
-                    zMemory(),
-                    minPos,
-                    maxPos,
-                    result);
+                *zPos = (float)z;
+                gen->generateStructures(
+                    x, y, z, getDimensionId(), minPos, maxPos, result);
             }
         }
     }
@@ -274,20 +271,18 @@ BiomedCavedDimensionGenerator::getGeneratedStructoresForArea(
 Chunk* BiomedCavedDimensionGenerator::generateChunk(int centerX, int centerY)
 {
     zMemory()->lock();
+#ifdef CHUNK_GENERATION_DEBUG_LOG
     Framework::Logging::debug()
         << "generating chunk " << centerX << ", " << centerY;
     double structureTime = 0;
-    double structureTime2 = 0;
-    double structureTime3 = 0;
     double caveTime = 0;
-    double caveTime2 = 0;
     double blockGenTime = 0;
-    double biomTime = 0;
-    double layerTime = 0;
     Framework::ZeitMesser zm;
     Framework::ZeitMesser zmGlobal;
+    Framework::ZeitMesser entityGenTime;
     zm.messungStart();
     zmGlobal.messungStart();
+#endif
     Framework::RCArray<GeneratedStructure>* structures
         = getGeneratedStructoresForArea(
             Framework::Vec3<int>(
@@ -295,13 +290,17 @@ Chunk* BiomedCavedDimensionGenerator::generateChunk(int centerX, int centerY)
             Framework::Vec3<int>(centerX + CHUNK_SIZE / 2,
                 centerY + CHUNK_SIZE / 2,
                 WORLD_HEIGHT - 1));
+#ifdef CHUNK_GENERATION_DEBUG_LOG
     zm.messungEnde();
     structureTime += zm.getSekunden();
     zm.messungStart();
+#endif
     CaveChunkGenerator* caveGen
         = caveGenerator->getGeneratorForChunk(centerX, centerY);
+#ifdef CHUNK_GENERATION_DEBUG_LOG
     zm.messungEnde();
     caveTime += zm.getSekunden();
+#endif
     Chunk* chunk
         = new Chunk(Framework::Punkt(centerX, centerY), getDimensionId());
     zMemory()->setCurrentChunk(dynamic_cast<Chunk*>(chunk->getThis()));
@@ -309,99 +308,359 @@ Chunk* BiomedCavedDimensionGenerator::generateChunk(int centerX, int centerY)
     {
         for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++)
         {
-            zMemory()->setFloatVariable("x", (float)x + (float)centerX);
-            zMemory()->setFloatVariable("y", (float)y + (float)centerY);
+            *xPos = (float)x + (float)centerX;
+            *yPos = (float)y + (float)centerY;
             // calculate height layers
-            zm.messungStart();
             calculateHeightLayers();
-            zm.messungEnde();
-            layerTime += zm.getSekunden();
             // calculate biom
-            zm.messungStart();
             BiomGenerator* biom = zBiomGenerator();
-            zm.messungEnde();
-            biomTime += zm.getSekunden();
+            int terrainHeight = (int)round(*terrainHeightP);
             // generate blocks
             for (int z = 0; z < WORLD_HEIGHT; z++)
             {
-                zMemory()->setFloatVariable("z", (float)z);
+                *zPos = (float)z;
                 Framework::Either<Block*, int> generated = BlockTypeEnum::AIR;
                 bool structureAffected = 0;
                 // check if the block is inside of a structure
-                zm.messungStart();
                 for (auto structure : *structures)
                 {
                     if (structure->isBlockAffected(
                             Framework::Vec3<int>(x + centerX, y + centerY, z)))
                     {
-                        zm.messungEnde();
-                        structureTime2 += zm.getSekunden();
-                        zm.messungStart();
                         generated = structure->generateBlockAt(
                             Framework::Vec3<int>(x + centerX, y + centerY, z),
                             getDimensionId());
                         structureAffected = 1;
-                        zm.messungEnde();
-                        structureTime3 += zm.getSekunden();
-                        zm.messungStart();
                         break;
                     }
                 }
-                zm.messungEnde();
-                structureTime2 += zm.getSekunden();
+                bool inCave = false;
                 if (!structureAffected)
                 {
                     // check if block is a cave block
-                    zm.messungStart();
-                    bool inCave
-                        = caveGen->isInCave(x + centerX, y + centerY, z);
-                    zm.messungEnde();
-                    caveTime2 += zm.getSekunden();
-                    if (!inCave)
+                    inCave = caveGen->isInCave(x + centerX, y + centerY, z);
+                    if (!inCave && z == terrainHeight - 1)
                     {
                         // generate biom block
+#ifdef CHUNK_GENERATION_DEBUG_LOG
                         zm.messungStart();
+#endif
                         generated = biom->generateBlock(x + centerX,
                             y + centerY,
                             z,
                             getDimensionId(),
-                            zMemory(),
                             chunk);
+#ifdef CHUNK_GENERATION_DEBUG_LOG
                         zm.messungEnde();
                         blockGenTime += zm.getSekunden();
+#endif
                     }
                 }
-                if (generated.isA())
-                    chunk->putBlockAt(
-                        Framework::Vec3<int>(
-                            x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z),
-                        generated);
-                else
-                    chunk->putBlockTypeAt(
-                        Framework::Vec3<int>(
-                            x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z),
-                        generated);
+                if (inCave || structureAffected || z >= terrainHeight - 1)
+                {
+                    if (!inCave && !structureAffected && z > terrainHeight - 1
+                        && z < globalSeaLevel)
+                    {
+                        generated = seaFluidBlockTypeId;
+                    }
+                    if (generated.isA())
+                        chunk->putBlockAt(
+                            Framework::Vec3<int>(
+                                x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z),
+                            generated);
+                    else
+                        chunk->putBlockTypeAt(
+                            Framework::Vec3<int>(
+                                x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z),
+                            generated);
+                }
+            }
+        }
+    }
+    // generate cave borders
+    bool generatedMore = true;
+    while (generatedMore)
+    {
+        generatedMore = false;
+        for (int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++)
+        {
+            for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++)
+            {
+                *xPos = (float)x + (float)centerX;
+                *yPos = (float)y + (float)centerY;
+                // calculate height layers
+                calculateHeightLayers();
+                // calculate biom
+                BiomGenerator* biom = zBiomGenerator();
+                // generate blocks
+                for (int z = (int)round(*terrainHeightP) - 1; z >= 0; z--)
+                {
+                    *zPos = (float)z;
+                    int type = chunk->getBlockTypeAt(Framework::Vec3<int>(
+                        x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z));
+                    if (!type)
+                    {
+                        bool needed = false;
+                        for (int i = 0; i < 6; i++)
+                        {
+                            Framework::Vec3<int> pos
+                                = getDirection(
+                                      (Directions)getDirectionFromIndex(i))
+                                + Framework::Vec3<int>(
+                                    x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z);
+                            const Block* neighborBlock = 0;
+                            if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0
+                                && pos.y < CHUNK_SIZE && pos.z >= 0
+                                && pos.z < WORLD_HEIGHT)
+                            {
+                                neighborBlock = chunk->zBlockConst(pos);
+                            }
+                            else if (pos.z >= 0 && pos.z < WORLD_HEIGHT)
+                            {
+                                neighborBlock = Game::INSTANCE->zConstBlock(
+                                    Framework::Vec3<int>(pos.x + centerX,
+                                        pos.y + centerY,
+                                        pos.z),
+                                    getDimensionId());
+                            }
+                            if (neighborBlock && neighborBlock->isTransparent())
+                            {
+                                needed = true;
+                                break;
+                            }
+                        }
+                        if (needed)
+                        {
+                            auto generated = biom->generateBlock(x + centerX,
+                                y + centerY,
+                                z,
+                                getDimensionId(),
+                                chunk);
+                            if (generated.isA())
+                                chunk->putBlockAt(
+                                    Framework::Vec3<int>(x + CHUNK_SIZE / 2,
+                                        y + CHUNK_SIZE / 2,
+                                        z),
+                                    generated);
+                            else
+                                chunk->putBlockTypeAt(
+                                    Framework::Vec3<int>(x + CHUNK_SIZE / 2,
+                                        y + CHUNK_SIZE / 2,
+                                        z),
+                                    generated);
+                            generatedMore = true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    // generate plants
+    for (int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++)
+    {
+        for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++)
+        {
+            *xPos = (float)x + (float)centerX;
+            *yPos = (float)y + (float)centerY;
+            // calculate height layers
+            calculateHeightLayers();
+            // calculate biom
+            BiomGenerator* biom = zBiomGenerator();
+            // generate blocks
+            for (int z = (int)round(*terrainHeightP) + 1; z > 0; z--)
+            {
+                auto current = chunk->getBlockTypeAt(Framework::Vec3<int>(
+                    x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z));
+                auto below = chunk->getBlockTypeAt(Framework::Vec3<int>(
+                    x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z - 1));
+                if ((current == BlockTypeEnum::AIR
+                        || current == seaFluidBlockTypeId)
+                    && below != BlockTypeEnum::AIR
+                    && below != seaFluidBlockTypeId)
+                {
+                    *zPos = (float)z;
+                    bool underwater = current == seaFluidBlockTypeId;
+                    bool underground = z < *terrainHeightP;
+                    biom->generatePlants(x + centerX,
+                        y + centerY,
+                        z,
+                        getDimensionId(),
+                        chunk,
+                        underground,
+                        underwater,
+                        seaFluidBlockTypeId);
+                }
             }
         }
     }
     caveGen->release();
     structures->release();
+#ifdef CHUNK_GENERATION_DEBUG_LOG
+    entityGenTime.messungStart();
+#endif
+    *xPos = (float)chunk->getCenter().x;
+    *yPos = (float)chunk->getCenter().y;
+    calculateHeightLayers();
+    BiomGenerator* biom = zBiomGenerator();
+    for (int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++)
+    {
+        for (int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++)
+        {
+            for (int z = 0; z < WORLD_HEIGHT; z++)
+            {
+                if (chunk->getBlockTypeAt(Framework::Vec3<int>(
+                        x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z))
+                    == BlockTypeEnum::AIR)
+                {
+                    *xPos = (float)x + (float)chunk->getCenter().x;
+                    *yPos = (float)y + (float)chunk->getCenter().y;
+                    *zPos = (float)z;
+                    biom->generateEntities(x + chunk->getCenter().x,
+                        y + chunk->getCenter().y,
+                        z,
+                        getDimensionId(),
+                        chunk);
+                }
+            }
+        }
+    }
+#ifdef CHUNK_GENERATION_DEBUG_LOG
+    entityGenTime.messungEnde();
     zmGlobal.messungEnde();
     Framework::Logging::trace() << "structureGenerationTime: " << structureTime;
-    Framework::Logging::trace()
-        << "structure.isBlockAffected: " << structureTime2;
-    Framework::Logging::trace()
-        << "structure.generateBlockAt: " << structureTime3;
     Framework::Logging::trace() << "caveGenerationTime: " << caveTime;
-    Framework::Logging::trace() << "caveEvaluationTime: " << caveTime2;
     Framework::Logging::trace() << "blockGenTime: " << blockGenTime;
-    Framework::Logging::trace() << "biomTime: " << biomTime;
-    Framework::Logging::trace() << "layerTime: " << layerTime;
     Framework::Logging::debug() << "totalTime: " << zmGlobal.getSekunden();
+#endif
     zMemory()->unlock();
     return chunk;
 }
 
+void BiomedCavedDimensionGenerator::postprocessChunk(Chunk* zChunk)
+{
+    zMemory()->lock();
+    int borderOffset = 1;
+    bool generatedMore = true;
+    while (generatedMore && borderOffset <= CHUNK_SIZE / 2)
+    {
+        int centerX = zChunk->getCenter().x;
+        int centerY = zChunk->getCenter().y;
+        generatedMore = false;
+        for (int d = 0; d < 4; d++)
+        {
+            Direction dir = getDirectionFromIndex(d);
+            Chunk* neighbor = zChunk->zNeighbor(dir);
+            if (!neighbor) continue;
+            int xOffset = 0;
+            int yOffset = 0;
+            int xj = 0;
+            int yj = 0;
+            switch (dir)
+            {
+            case WEST:
+                yj = 1;
+                xOffset = 1;
+                break;
+            case NORTH:
+                xj = 1;
+                yOffset = 1;
+                break;
+            case EAST:
+                yj = 1;
+                xOffset = -1;
+                break;
+            case SOUTH:
+                xj = 1;
+                yOffset = -1;
+                break;
+            }
+            for (int o = 0; o < borderOffset; o++)
+            {
+                for (int j = 0; j < CHUNK_SIZE; j++)
+                {
+                    int x = xOffset * o + xj * j;
+                    if (xOffset < 0)
+                    {
+                        x += CHUNK_SIZE - 1;
+                    }
+                    int y = yOffset * o + yj * j;
+                    if (yOffset < 0)
+                    {
+                        y += CHUNK_SIZE - 1;
+                    }
+                    *xPos = (float)x + (float)centerX - CHUNK_SIZE / 2;
+                    *yPos = (float)y + (float)centerY - CHUNK_SIZE / 2;
+                    // calculate height layers
+                    calculateHeightLayers();
+                    // calculate biom
+                    BiomGenerator* biom = zBiomGenerator();
+                    // generate blocks
+                    for (int z = (int)round(*terrainHeightP) - 1; z >= 0; z--)
+                    {
+                        *zPos = (float)z;
+                        int type = zChunk->getBlockTypeAt(
+                            Framework::Vec3<int>(x, y, z));
+                        if (!type)
+                        {
+                            bool needed = false;
+                            for (int i = 0; i < 6; i++)
+                            {
+                                Framework::Vec3<int> pos
+                                    = getDirection(
+                                          (Directions)getDirectionFromIndex(i))
+                                    + Framework::Vec3<int>(x, y, z);
+                                const Block* neighborBlock = 0;
+                                if (pos.x >= 0 && pos.x < CHUNK_SIZE
+                                    && pos.y >= 0 && pos.y < CHUNK_SIZE
+                                    && pos.z >= 0 && pos.z < WORLD_HEIGHT)
+                                {
+                                    neighborBlock = zChunk->zBlockConst(pos);
+                                }
+                                else if (pos.z >= 0 && pos.z < WORLD_HEIGHT
+                                         && i == d)
+                                {
+                                    neighborBlock = neighbor->zBlockConst(
+                                        {pos.x + centerX
+                                                - neighbor->getCenter().x,
+                                            pos.y + centerY
+                                                - neighbor->getCenter().y,
+                                            pos.z});
+                                }
+                                if (neighborBlock
+                                    && neighborBlock->isTransparent())
+                                {
+                                    needed = true;
+                                    break;
+                                }
+                            }
+                            if (needed)
+                            {
+                                auto generated = biom->generateBlock(
+                                    x + centerX - CHUNK_SIZE / 2,
+                                    y + centerY - CHUNK_SIZE / 2,
+                                    z,
+                                    getDimensionId(),
+                                    zChunk);
+                                if (generated.isA())
+                                    zChunk->putBlockAt(
+                                        Framework::Vec3<int>(x, y, z),
+                                        generated);
+                                else
+                                    zChunk->putBlockTypeAt(
+                                        Framework::Vec3<int>(x, y, z),
+                                        generated);
+                                generatedMore = true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        borderOffset++;
+    }
+    zMemory()->unlock();
+}
+
 Framework::Either<Block*, int> BiomedCavedDimensionGenerator::generateBlock(
     Framework::Vec3<int> location)
 {
@@ -418,13 +677,13 @@ Framework::Either<Block*, int> BiomedCavedDimensionGenerator::generateBlock(
     Framework::RCArray<GeneratedStructure>* structures
         = getGeneratedStructoresForArea(location, location);
 
-    zMemory()->setFloatVariable("x", (float)location.x);
-    zMemory()->setFloatVariable("y", (float)location.y);
+    *xPos = (float)location.x;
+    *yPos = (float)location.y;
 
     calculateHeightLayers();
     BiomGenerator* biom = zBiomGenerator();
 
-    zMemory()->setFloatVariable("z", (float)location.z);
+    *zPos = (float)location.z;
 
     for (auto structure : *structures)
     {
@@ -450,12 +709,8 @@ Framework::Either<Block*, int> BiomedCavedDimensionGenerator::generateBlock(
     }
     caveGen->release();
 
-    auto generated = biom->generateBlock(location.x,
-        location.y,
-        location.z,
-        getDimensionId(),
-        zMemory(),
-        zChunk);
+    auto generated = biom->generateBlock(
+        location.x, location.y, location.z, getDimensionId(), zChunk);
     zMemory()->unlock();
     return generated;
 }
@@ -465,8 +720,8 @@ bool BiomedCavedDimensionGenerator::spawnStructure(
     std::function<bool(GeneratorTemplate* tmpl)> filter)
 {
     zMemory()->lock();
-    zMemory()->setFloatVariable("x", (float)location.x);
-    zMemory()->setFloatVariable("y", (float)location.y);
+    *xPos = (float)location.x;
+    *yPos = (float)location.y;
 
     BiomGenerator* biom = zBiomGenerator();
     zMemory()->unlock();
@@ -561,6 +816,37 @@ BiomedCavedDimensionGenerator::zBiomNoiseConfig() const
     return noiseConfig;
 }
 
+void BiomedCavedDimensionGenerator::setGlobalSeaLevel(int seaLevel)
+{
+    globalSeaLevel = seaLevel;
+}
+
+int BiomedCavedDimensionGenerator::getGlobalSeaLevel() const
+{
+    return globalSeaLevel;
+}
+
+void BiomedCavedDimensionGenerator::setTerrainHeightLayerName(
+    Framework::Text name)
+{
+    terrainHeightLayerName = name;
+}
+
+Framework::Text BiomedCavedDimensionGenerator::getTerrainHeightLayerName() const
+{
+    return terrainHeightLayerName;
+}
+
+void BiomedCavedDimensionGenerator::setSeaFluidBlockType(Framework::Text type)
+{
+    seaFluidBlockType = type;
+}
+
+Framework::Text BiomedCavedDimensionGenerator::getSeaFluidBlockType() const
+{
+    return seaFluidBlockType;
+}
+
 BiomedCavedDimensionGeneratorFactory::BiomedCavedDimensionGeneratorFactory() {}
 
 BiomedCavedDimensionGenerator*
@@ -570,34 +856,48 @@ BiomedCavedDimensionGeneratorFactory::createValue(
     return new BiomedCavedDimensionGenerator();
 }
 
-void BiomedCavedDimensionGeneratorFactory::fromJson(
-    BiomedCavedDimensionGenerator* zResult,
+BiomedCavedDimensionGenerator* BiomedCavedDimensionGeneratorFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setBiomNoiseConfig(zJson->getValue("biomNoise")->asObject());
+    BiomedCavedDimensionGenerator* result
+        = DimensionGeneratorFactory::fromJson(zJson);
+    result->setBiomNoiseConfig(zJson->getValue("biomNoise")->asObject());
     for (Framework::JSON::JSONValue* value : *zJson->zValue("bioms")->asArray())
     {
-        zResult->addBiomGenerator(
+        result->addBiomGenerator(
             Game::INSTANCE->zTypeRegistry()->fromJson<BiomGenerator>(value));
     }
-    DimensionGeneratorFactory::fromJson(zResult, zJson);
+    result->setGlobalSeaLevel(
+        (int)zJson->zValue("globalSeaLevel")->asNumber()->getNumber());
+    result->setTerrainHeightLayerName(
+        zJson->zValue("terrainHeightLeyerName")->asString()->getString());
+    result->setSeaFluidBlockType(
+        zJson->zValue("seaFluidBlockType")->asString()->getString());
+    return result;
 }
 
-void BiomedCavedDimensionGeneratorFactory::toJson(
-    BiomedCavedDimensionGenerator* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BiomedCavedDimensionGeneratorFactory::toJsonObject(
+    BiomedCavedDimensionGenerator* zObject) const
 {
+    Framework::JSON::JSONObject* result
+        = DimensionGeneratorFactory::toJsonObject(zObject);
     Framework::JSON::JSONArray* bioms = new Framework::JSON::JSONArray();
     for (BiomGenerator* biom : zObject->getBiomGenerators())
     {
         bioms->addValue(
             Game::INSTANCE->zTypeRegistry()->toJson<BiomGenerator>(biom));
     }
-    zResult->addValue("bioms", bioms);
-    zResult->addValue("biomNoise",
+    result->addValue("bioms", bioms);
+    result->addValue("biomNoise",
         dynamic_cast<Framework::JSON::JSONValue*>(
             zObject->zBiomNoiseConfig()->getThis()));
-    DimensionGeneratorFactory::toJson(zObject, zResult);
+    result->addValue("globalSeaLevel",
+        new Framework::JSON::JSONNumber(zObject->getGlobalSeaLevel()));
+    result->addValue("terrainHeightLeyerName",
+        new Framework::JSON::JSONString(zObject->getTerrainHeightLayerName()));
+    result->addValue("seaFluidBlockType",
+        new Framework::JSON::JSONString(zObject->getSeaFluidBlockType()));
+    return result;
 }
 
 JSONObjectValidationBuilder*
@@ -609,10 +909,17 @@ BiomedCavedDimensionGeneratorFactory::addToValidator(
             ->addAcceptedTypeInArray(
                 Game::INSTANCE->zTypeRegistry()->getValidator<BiomGenerator>())
             ->finishArray()
-            ->withRequiredAttribute("biomNoise", JNoise::getValidator(false)));
+            ->withRequiredAttribute("biomNoise", JNoise::getValidator(false))
+            ->withRequiredNumber("globalSeaLevel")
+            ->finishNumber()
+            ->withRequiredString("terrainHeightLeyerName")
+            ->finishString()
+            ->withRequiredAttribute("seaFluidBlockType",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    BlockTypeNameFactory::TYPE_ID)));
 }
 
-Framework::Text BiomedCavedDimensionGeneratorFactory::getTypeToken() const
+const char* BiomedCavedDimensionGeneratorFactory::getTypeToken() const
 {
     return "cavedBioms";
 }

+ 50 - 27
FactoryCraft/DimensionGenerator.h

@@ -7,9 +7,11 @@
 #include "BiomGenerator.h"
 #include "CaveGenerator.h"
 #include "Chunk.h"
-#include "JNoise.h"
+#include "GeneratorTemplate.h"
 #include "JsonExpression.h"
 
+// #define CHUNK_GENERATION_DEBUG_LOG to log generation times of chunks
+
 class DimensionGenerator;
 
 class WorldHeightLayer : public virtual Framework::ReferenceCounter
@@ -19,6 +21,7 @@ private:
     Noise* noise;
     Framework::Text name;
     JFloatExpression* value;
+    float* valueP;
 
 public:
     WorldHeightLayer();
@@ -26,7 +29,7 @@ public:
 
     void initialize(JExpressionMemory* zMemory);
 
-    void calculateValue(JExpressionMemory* zMemory);
+    void calculateValue();
 
     void setNoiseConfig(Framework::JSON::JSONObject* noiseConfig);
     Framework::JSON::JSONObject* zNoiseConfig() const;
@@ -36,16 +39,14 @@ public:
     JFloatExpression* zValue() const;
 };
 
-class WorldHeightLayerFactory : public TypeFactory<WorldHeightLayer>
+class WorldHeightLayerFactory : public ObjectTypeFactory<WorldHeightLayer>
 {
 public:
     WorldHeightLayerFactory();
-    WorldHeightLayer* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(WorldHeightLayer* zResult,
+    WorldHeightLayer* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(WorldHeightLayer* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        WorldHeightLayer* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -58,8 +59,11 @@ private:
     Framework::RCArray<WorldHeightLayer> heightLayers;
     Framework::Text name;
     int dimensionId;
+    float* worldSeed;
+    float* dimensionSeed;
 
 protected:
+    float *xPos, *yPos, *zPos;
     DimensionGenerator();
     ~DimensionGenerator();
 
@@ -67,9 +71,10 @@ protected:
     void calculateHeightLayers();
 
 public:
-    Dimension *createDimension();
+    Dimension* createDimension() const;
     virtual void initialize(int worldSeed);
     virtual Chunk* generateChunk(int centerX, int centerY) = 0;
+    virtual void postprocessChunk(Chunk* zChunk) = 0;
     virtual Framework::Either<Block*, int> generateBlock(
         Framework::Vec3<int> location)
         = 0;
@@ -95,10 +100,11 @@ public:
         : SubTypeFactory<DimensionGenerator, S>()
     {}
 
-    void fromJson(S* zResult, Framework::JSON::JSONObject* zJson) const override
+    S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
+        S* result = createValue(zJson);
         DimensionGenerator* zGenerator
-            = dynamic_cast<DimensionGenerator*>(zResult);
+            = dynamic_cast<DimensionGenerator*>(result);
         zGenerator->setName(zJson->zValue("name")->asString()->getString());
         zGenerator->setId((int)zJson->zValue("id")->asNumber()->getNumber());
         zGenerator->setSeed(
@@ -111,17 +117,19 @@ public:
                 Game::INSTANCE->zTypeRegistry()->fromJson<WorldHeightLayer>(
                     layer));
         }
+        return result;
     }
 
-    void toJson(S* zObject, Framework::JSON::JSONObject* zResult) const override
+    Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
         DimensionGenerator* zGenerator
             = dynamic_cast<DimensionGenerator*>(zObject);
-        zResult->addValue(
+        result->addValue(
             "name", new Framework::JSON::JSONString(zGenerator->getName()));
-        zResult->addValue(
+        result->addValue(
             "id", new Framework::JSON::JSONNumber(zGenerator->getId()));
-        zResult->addValue("dimensionSeed",
+        result->addValue("dimensionSeed",
             Game::INSTANCE->zTypeRegistry()->toJson<JFloatExpression>(
                 zGenerator->zSeed()));
         Framework::JSON::JSONArray* hightLayers
@@ -131,7 +139,8 @@ public:
             hightLayers->addValue(
                 Game::INSTANCE->zTypeRegistry()->toJson(layer));
         }
-        zResult->addValue("heightLayers", hightLayers);
+        result->addValue("heightLayers", hightLayers);
+        return result;
     }
 
     JSONObjectValidationBuilder* addToValidator(
@@ -143,16 +152,17 @@ public:
                     ->getValidator<JFloatExpression>())
             ->withRequiredArray("heightLayers")
             ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
-                                         ->getValidator<WorldHeightLayer>())
+                    ->getValidator<WorldHeightLayer>())
             ->finishArray()
             ->withRequiredString("name")
             ->finishString()
             ->withRequiredNumber("id")
             ->finishNumber();
     }
-};
 
-class BiomGenerator;
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
+};
 
 class BiomedCavedDimensionGenerator : public DimensionGenerator
 {
@@ -163,6 +173,11 @@ private:
     Noise* biomNoise;
     Framework::Vec3<int> minStructureOffset;
     Framework::Vec3<int> maxStructureOffset;
+    Framework::Text terrainHeightLayerName;
+    int globalSeaLevel;
+    float* terrainHeightP;
+    Framework::Text seaFluidBlockType;
+    int seaFluidBlockTypeId;
 
     BiomGenerator* zBiomGenerator();
 
@@ -176,15 +191,23 @@ public:
 
     virtual void initialize(int worldSeed) override;
 
-    Chunk* generateChunk(int centerX, int centerY);
-    Framework::Either<Block*, int> generateBlock(Framework::Vec3<int> location);
+    Chunk* generateChunk(int centerX, int centerY) override;
+    void postprocessChunk(Chunk* zChunk) override;
+    Framework::Either<Block*, int> generateBlock(
+        Framework::Vec3<int> location) override;
     bool spawnStructure(Framework::Vec3<int> location,
-        std::function<bool(GeneratorTemplate* tmpl)> filter);
+        std::function<bool(GeneratorTemplate* tmpl)> filter) override;
 
     void addBiomGenerator(BiomGenerator* biomGenerator);
     const Framework::RCArray<BiomGenerator>& getBiomGenerators() const;
     void setBiomNoiseConfig(Framework::JSON::JSONObject* biomNoiseConfig);
     Framework::JSON::JSONObject* zBiomNoiseConfig() const;
+    void setGlobalSeaLevel(int seaLevel);
+    int getGlobalSeaLevel() const;
+    void setTerrainHeightLayerName(Framework::Text name);
+    Framework::Text getTerrainHeightLayerName() const;
+    void setSeaFluidBlockType(Framework::Text type);
+    Framework::Text getSeaFluidBlockType() const;
 };
 
 class BiomedCavedDimensionGeneratorFactory
@@ -193,12 +216,12 @@ class BiomedCavedDimensionGeneratorFactory
 public:
     BiomedCavedDimensionGeneratorFactory();
     BiomedCavedDimensionGenerator* createValue(
-		Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BiomedCavedDimensionGenerator* zResult,
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BiomedCavedDimensionGenerator* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    BiomedCavedDimensionGenerator* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BiomedCavedDimensionGenerator* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 53 - 0
FactoryCraft/DropChanceCondition.cpp

@@ -0,0 +1,53 @@
+#include "DropChanceCondition.h"
+
+DropChanceCondition::DropChanceCondition(double chance)
+    : DropCondition(),
+      chance(chance)
+{}
+
+double DropChanceCondition::getChance() const
+{
+    return chance;
+}
+
+bool DropChanceCondition::evaluate(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject)
+{
+    return (double)std::rand() / RAND_MAX > chance;
+}
+
+DropChanceConditionFactory::DropChanceConditionFactory()
+    : SubTypeFactory()
+{}
+
+JSONObjectValidationBuilder* DropChanceConditionFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder->withRequiredNumber("chance")
+        ->whichIsGreaterThen(0.0)
+        ->whichIsLessOrEqual(1.0)
+        ->finishNumber();
+}
+
+const char* DropChanceConditionFactory::getTypeToken() const
+{
+    return "chance";
+}
+
+DropChanceCondition* DropChanceConditionFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DropChanceCondition(
+        zJson->zValue("chance")->asNumber()->getNumber());
+}
+
+Framework::JSON::JSONObject* DropChanceConditionFactory::toJsonObject(
+    DropChanceCondition* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "chance", new Framework::JSON::JSONNumber(zObject->getChance()));
+    return result;
+}

+ 34 - 0
FactoryCraft/DropChanceCondition.h

@@ -0,0 +1,34 @@
+#pragma once
+
+#include "DropCondition.h"
+#include "TypeRegistry.h"
+
+class DropChanceCondition : public DropCondition
+{
+private:
+    double chance;
+
+public:
+    DropChanceCondition(double chance);
+    double getChance() const;
+    bool evaluate(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) override;
+};
+
+class DropChanceConditionFactory
+    : public SubTypeFactory<DropCondition, DropChanceCondition>
+{
+public:
+    DropChanceConditionFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+
+protected:
+    DropChanceCondition* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DropChanceCondition* zObject) const override;
+};

+ 18 - 0
FactoryCraft/DropCondition.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include <Either.h>
+
+class Entity;
+class Item;
+class ItemSkill;
+class Block;
+
+class DropCondition
+{
+public:
+    virtual bool evaluate(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject)
+        = 0;
+};

+ 218 - 0
FactoryCraft/DropConditionOperator.cpp

@@ -0,0 +1,218 @@
+#include "DropConditionOperator.h"
+
+#include "Game.h"
+
+DropConditionOperator::DropConditionOperator(ConditionalOperator op)
+    : DropCondition(),
+      op(op)
+{}
+
+DropConditionOperator::~DropConditionOperator()
+{
+    for (DropCondition* condition : conditions)
+    {
+        delete condition;
+    }
+}
+
+ConditionalOperator DropConditionOperator::getOperator() const
+{
+    return op;
+}
+
+const Framework::Array<DropCondition*>&
+DropConditionOperator::getConditions() const
+{
+    return conditions;
+}
+
+void DropConditionOperator::addCondition(DropCondition* condition)
+{
+    conditions.add(condition);
+}
+
+bool DropConditionOperator::evaluate(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject)
+{
+    switch (op)
+    {
+    case AND:
+        {
+            bool result = true;
+            for (DropCondition* condition : conditions)
+            {
+                result &= condition->evaluate(
+                    zActor, zItem, zUsedSkill, zDestroyedObject);
+            }
+            return result;
+        }
+    case OR:
+        {
+            bool result = false;
+            for (DropCondition* condition : conditions)
+            {
+                result |= condition->evaluate(
+                    zActor, zItem, zUsedSkill, zDestroyedObject);
+            }
+            return result;
+        }
+    }
+    return false;
+}
+
+DropConditionNegation::DropConditionNegation(DropCondition* condition)
+    : DropCondition(),
+      condition(condition)
+{}
+
+DropConditionNegation::~DropConditionNegation()
+{
+    delete condition;
+}
+
+const DropCondition* DropConditionNegation::zCondition() const
+{
+    return condition;
+}
+
+bool DropConditionNegation::evaluate(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject)
+{
+    return !condition->evaluate(zActor, zItem, zUsedSkill, zDestroyedObject);
+}
+
+DropAllwaysCondition::DropAllwaysCondition()
+    : DropCondition()
+{}
+
+bool DropAllwaysCondition::evaluate(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject)
+{
+    return true;
+}
+
+DropConditionOperatorFactory::DropConditionOperatorFactory()
+    : SubTypeFactory()
+{}
+
+JSONObjectValidationBuilder* DropConditionOperatorFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder->withRequiredString("operator")
+        ->whichIsOneOf({"AND", "OR"})
+        ->finishString()
+        ->withRequiredAttribute("conditions",
+            Framework::Validator::DataValidator::buildForArray()
+                ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                        ->getValidator<DropCondition>())
+                ->finishArray());
+}
+
+const char* DropConditionOperatorFactory::getTypeToken() const
+{
+    return "operator";
+}
+
+DropConditionOperator* DropConditionOperatorFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    DropConditionOperator* result = new DropConditionOperator(
+        zJson->zValue("operator")->asString()->getString().istGleich("AND")
+            ? AND
+            : OR);
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("conditions")->asArray())
+    {
+        result->addCondition(
+            Game::INSTANCE->zTypeRegistry()->fromJson<DropCondition>(value));
+    }
+    return result;
+}
+
+Framework::JSON::JSONObject* DropConditionOperatorFactory::toJsonObject(
+    DropConditionOperator* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    switch (zObject->getOperator())
+    {
+    case AND:
+        result->addValue("operator", new Framework::JSON::JSONString("AND"));
+        break;
+    case OR:
+        result->addValue("operator", new Framework::JSON::JSONString("OR"));
+        break;
+    }
+    Framework::JSON::JSONArray* array = new Framework::JSON::JSONArray();
+    for (DropCondition* condition : zObject->getConditions())
+    {
+        array->addValue(Game::INSTANCE->zTypeRegistry()->toJson(condition));
+    }
+    result->addValue("conditions", array);
+    return nullptr;
+}
+
+DropConditionNegationFactory::DropConditionNegationFactory()
+    : SubTypeFactory()
+{}
+
+JSONObjectValidationBuilder* DropConditionNegationFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder->withRequiredAttribute("condition",
+        Game::INSTANCE->zTypeRegistry()->getValidator<DropCondition>());
+}
+
+const char* DropConditionNegationFactory::getTypeToken() const
+{
+    return "not";
+}
+
+DropConditionNegation* DropConditionNegationFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DropConditionNegation(
+        Game::INSTANCE->zTypeRegistry()->fromJson<DropCondition>(
+            zJson->zValue("condition")));
+}
+
+Framework::JSON::JSONObject* DropConditionNegationFactory::toJsonObject(
+    DropConditionNegation* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("condition",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zCondition()));
+    return result;
+}
+
+DropAllwaysConditionFactory::DropAllwaysConditionFactory()
+    : SubTypeFactory()
+{}
+
+JSONObjectValidationBuilder* DropAllwaysConditionFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder;
+}
+
+const char* DropAllwaysConditionFactory::getTypeToken() const
+{
+    return "allways";
+}
+
+DropAllwaysCondition* DropAllwaysConditionFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DropAllwaysCondition();
+}
+
+Framework::JSON::JSONObject* DropAllwaysConditionFactory::toJsonObject(
+    DropAllwaysCondition* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}

+ 103 - 0
FactoryCraft/DropConditionOperator.h

@@ -0,0 +1,103 @@
+#pragma once
+
+#include <Array.h>
+
+#include "DropCondition.h"
+#include "TypeRegistry.h"
+
+enum ConditionalOperator
+{
+    AND,
+    OR
+};
+
+class DropConditionOperator : public DropCondition
+{
+private:
+    Framework::Array<DropCondition*> conditions;
+    ConditionalOperator op;
+
+public:
+    DropConditionOperator(ConditionalOperator op);
+    ~DropConditionOperator();
+    void addCondition(DropCondition* condition);
+    ConditionalOperator getOperator() const;
+    const Framework::Array<DropCondition*>& getConditions() const;
+    bool evaluate(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) override;
+};
+
+class DropConditionNegation : public DropCondition
+{
+private:
+    DropCondition* condition;
+
+public:
+    DropConditionNegation(DropCondition* condition);
+    ~DropConditionNegation();
+    const DropCondition* zCondition() const;
+    bool evaluate(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) override;
+};
+
+class DropAllwaysCondition : public DropCondition
+{
+public:
+    DropAllwaysCondition();
+    bool evaluate(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) override;
+};
+
+class DropConditionOperatorFactory
+    : public SubTypeFactory<DropCondition, DropConditionOperator>
+{
+public:
+    DropConditionOperatorFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+
+protected:
+    DropConditionOperator* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DropConditionOperator* zObject) const override;
+};
+
+class DropConditionNegationFactory
+    : public SubTypeFactory<DropCondition, DropConditionNegation>
+{
+public:
+    DropConditionNegationFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+
+protected:
+    DropConditionNegation* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DropConditionNegation* zObject) const override;
+};
+
+class DropAllwaysConditionFactory
+    : public SubTypeFactory<DropCondition, DropAllwaysCondition>
+{
+public:
+    DropAllwaysConditionFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+
+protected:
+    DropAllwaysCondition* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DropAllwaysCondition* zObject) const override;
+};

+ 38 - 0
FactoryCraft/DropConfig.cpp

@@ -0,0 +1,38 @@
+#include "DropConfig.h"
+
+DropConfig::DropConfig()
+    : ReferenceCounter(),
+      condition(0)
+{}
+
+DropConfig::~DropConfig()
+{
+    delete condition;
+}
+
+void DropConfig::setCondition(DropCondition* condition)
+{
+    if (this->condition)
+    {
+        delete this->condition;
+    }
+    this->condition = condition;
+}
+
+void DropConfig::initialize() {}
+
+const DropCondition* DropConfig::zCondition() const
+{
+    return condition;
+}
+
+void DropConfig::onObjectDestroyed(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject) const
+{
+    if (condition->evaluate(zActor, zItem, zUsedSkill, zDestroyedObject))
+    {
+        doDrop(zActor, zItem, zUsedSkill, zDestroyedObject);
+    }
+}

+ 71 - 0
FactoryCraft/DropConfig.h

@@ -0,0 +1,71 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+
+#include "DropCondition.h"
+#include "Game.h"
+#include "TypeRegistry.h"
+
+class DropConfig : public virtual Framework::ReferenceCounter
+{
+private:
+    DropCondition* condition;
+
+public:
+    DropConfig();
+    virtual ~DropConfig();
+    void setCondition(DropCondition* condition);
+    virtual void initialize();
+    const DropCondition* zCondition() const;
+    void onObjectDestroyed(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) const;
+
+protected:
+    virtual void doDrop(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) const
+        = 0;
+};
+
+template<typename T> class DropConfigFactory
+    : public SubTypeFactory<DropConfig, T>
+{
+public:
+    DropConfigFactory()
+        : SubTypeFactory<DropConfig, T>()
+    {}
+
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override
+    {
+        return builder->withRequiredAttribute("condition",
+            Game::INSTANCE->zTypeRegistry()->getValidator<DropCondition>());
+    }
+
+    T* fromJson(Framework::JSON::JSONObject* zJson) const
+    {
+        T* result = createInstance(zJson);
+        DropCondition* condition
+            = Game::INSTANCE->zTypeRegistry()->fromJson<DropCondition>(
+                zJson->zValue("condition"));
+        result->setCondition(condition);
+        return result;
+    }
+
+    Framework::JSON::JSONObject* toJsonObject(T* zObject) const override
+    {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+        result->addValue("condition",
+            Game::INSTANCE->zTypeRegistry()->toJson(zObject->zCondition()));
+        addToJson(result, zObject);
+        return result;
+    }
+
+protected:
+    virtual T* createInstance(Framework::JSON::JSONObject* zObject) const = 0;
+    virtual void addToJson(Framework::JSON::JSONObject* zJson, T* zObject) const
+        = 0;
+};

+ 94 - 0
FactoryCraft/DropUsedItemCondition.cpp

@@ -0,0 +1,94 @@
+#include "DropUsedItemCondition.h"
+
+#include "Game.h"
+
+DropUsedItemCondition::DropUsedItemCondition(ItemFilter* filter)
+    : DropCondition(),
+      filter(filter)
+{}
+
+DropUsedItemCondition::~DropUsedItemCondition()
+{
+    filter->release();
+}
+
+const ItemFilter* DropUsedItemCondition::zFilter() const
+{
+    return filter;
+}
+
+bool DropUsedItemCondition::evaluate(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject)
+{
+    return zItem && filter->matchItem(zItem);
+}
+
+bool DropNoUsedItemCondition::evaluate(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject)
+{
+    return !zItem;
+}
+
+DropUsedItemConditionFactory::DropUsedItemConditionFactory()
+    : SubTypeFactory()
+{}
+
+JSONObjectValidationBuilder* DropUsedItemConditionFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder->withRequiredAttribute(
+        "filter", Game::INSTANCE->zTypeRegistry()->getValidator<ItemFilter>());
+}
+
+const char* DropUsedItemConditionFactory::getTypeToken() const
+{
+    return "itemFilter";
+}
+
+DropUsedItemCondition* DropUsedItemConditionFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DropUsedItemCondition(
+        Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
+            zJson->zValue("filter")));
+}
+
+Framework::JSON::JSONObject* DropUsedItemConditionFactory::toJsonObject(
+    DropUsedItemCondition* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
+    return result;
+}
+
+DropNoUsedItemConditionFactory::DropNoUsedItemConditionFactory()
+    : SubTypeFactory()
+{}
+
+JSONObjectValidationBuilder* DropNoUsedItemConditionFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder;
+}
+
+const char* DropNoUsedItemConditionFactory::getTypeToken() const
+{
+    return "noItem";
+}
+
+DropNoUsedItemCondition* DropNoUsedItemConditionFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new DropNoUsedItemCondition();
+}
+
+Framework::JSON::JSONObject* DropNoUsedItemConditionFactory::toJsonObject(
+    DropNoUsedItemCondition* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}

+ 60 - 0
FactoryCraft/DropUsedItemCondition.h

@@ -0,0 +1,60 @@
+#pragma once
+
+#include "DropCondition.h"
+#include "ItemFilter.h"
+
+class DropUsedItemCondition : public DropCondition
+{
+private:
+    ItemFilter* filter;
+
+public:
+    DropUsedItemCondition(ItemFilter* filter);
+    ~DropUsedItemCondition();
+    const ItemFilter* zFilter() const;
+    virtual bool evaluate(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) override;
+};
+
+class DropNoUsedItemCondition : public DropCondition
+{
+public:
+    virtual bool evaluate(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) override;
+};
+
+class DropUsedItemConditionFactory
+    : public SubTypeFactory<DropCondition, DropUsedItemCondition>
+{
+public:
+    DropUsedItemConditionFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+
+protected:
+    DropUsedItemCondition* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DropUsedItemCondition* zObject) const override;
+};
+
+class DropNoUsedItemConditionFactory
+    : public SubTypeFactory<DropCondition, DropNoUsedItemCondition>
+{
+public:
+    DropNoUsedItemConditionFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+
+protected:
+    DropNoUsedItemCondition* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DropNoUsedItemCondition* zObject) const override;
+};

+ 0 - 25
FactoryCraft/Effect.h

@@ -1,25 +0,0 @@
-#pragma once
-
-#include <Text.h>
-
-class Entity;
-class EffectFactory;
-
-class Effect : public virtual Framework::ReferenceCounter
-{
-private:
-	Framework::Text name;
-	float duration;
-
-	Effect(Entity* zTarget);
-
-public:
-	~Effect();
-
-	virtual void tick();
-
-	Framework::Text getName() const;
-	float getDuration() const;
-
-	friend EffectFactory;
-};

+ 0 - 14
FactoryCraft/EffectFactory.h

@@ -1,14 +0,0 @@
-#pragma once
-
-#include "Effect.h"
-
-class EffectFactory : public virtual Framework::ReferenceCounter
-{
-private:
-	Framework::Text effectName;
-
-public:
-	EffectFactory(Framework::Text effectName);
-
-	virtual Effect* createEffectOn(Entity* target) = 0;
-};

+ 271 - 93
FactoryCraft/Entity.cpp

@@ -1,14 +1,15 @@
 #include "Entity.h"
 
+#include <Mat4.h>
 #include <Text.h>
 
 #include "BlockType.h"
 #include "Dimension.h"
-#include "EntityRemovedUpdate.h"
+#include "EntityType.h"
 #include "Game.h"
 #include "ItemSkill.h"
 #include "ItemStack.h"
-#include "NoBlock.h"
+#include "ItemType.h"
 
 ActionTarget::ActionTarget(Framework::Vec3<int> blockPos, Direction blockSide)
     : blockPos(blockPos),
@@ -75,18 +76,20 @@ bool ActionTarget::interactItemSkillOnTarget(
     }
     else
     {
+        bool itemChanged = 0;
         if (entityId >= 0)
         {
             Block* block = Game::INSTANCE->zRealBlockInstance(
                 blockPos, zActor->getDimensionId());
-            if (block) return block->interact(zUsedItem, zActor);
+            if (block) block->interact(zUsedItem, zActor, itemChanged);
         }
         else
         {
             Block* block = Game::INSTANCE->zRealBlockInstance(
                 blockPos, zActor->getDimensionId());
-            if (block) return block->interact(zUsedItem, zActor);
+            if (block) block->interact(zUsedItem, zActor, itemChanged);
         }
+        return itemChanged;
     }
     return 0;
 }
@@ -122,15 +125,34 @@ void ActionTarget::toMessage(
     {
         if (zTarget->entityId >= 0)
         {
-            char* message = new char[6];
-            message[0] = 3;
-            message[1] = 1;
-            *(int*)(message + 2) = zTarget->entityId;
-            zMsg->setMessage(message, 6);
+            Entity* zEntity = Game::INSTANCE->zEntity(zTarget->entityId);
+            if (zEntity)
+            {
+                Framework::XML::Element* targetUIML = zEntity->getTargetUIML();
+                Framework::Text targetUIMLText
+                    = targetUIML ? targetUIML->toString() : Framework::Text();
+                targetUIML->release();
+                char* message = new char[8 + targetUIMLText.getLength()];
+                message[0] = 3;
+                message[1] = 1;
+                *(int*)(message + 2) = zTarget->entityId;
+                *(short*)(message + 6) = (short)targetUIMLText.getLength();
+                memcpy(message + 8,
+                    targetUIMLText.getText(),
+                    targetUIMLText.getLength());
+                zMsg->setMessage(message, 8 + targetUIMLText.getLength());
+            }
+            else
+            {
+                char* message = new char[2];
+                message[0] = 3;
+                message[1] = 0;
+                zMsg->setMessage(message, 2);
+            }
         }
         else
         {
-            Framework::Text targetUIML = "";
+            Framework::XML::Element* targetUIML = 0;
             auto block
                 = Game::INSTANCE->zBlockAt(zTarget->blockPos, dimensionId, 0);
             if (block.isA())
@@ -142,16 +164,18 @@ void ActionTarget::toMessage(
                 targetUIML
                     = Game::INSTANCE->zBlockType(block.getB())->getTargetUIML();
             }
-            char* message = new char[18 + targetUIML.getLength() + 2];
+            Framework::Text targetUIMLText
+                = targetUIML ? targetUIML->toString() : Framework::Text();
+            char* message = new char[18 + targetUIMLText.getLength() + 2];
             message[0] = 3;
             message[1] = 2;
             *(int*)(message + 2) = zTarget->blockPos.x;
             *(int*)(message + 6) = zTarget->blockPos.y;
             *(int*)(message + 10) = zTarget->blockPos.z;
             *(int*)(message + 14) = zTarget->targetBlockSide;
-            short len = (short)targetUIML.getLength();
+            short len = (short)targetUIMLText.getLength();
             *(short*)(message + 18) = len;
-            memcpy(message + 20, targetUIML.getText(), len);
+            memcpy(message + 20, targetUIMLText.getText(), len);
             zMsg->setMessage(message, 18 + len + 2);
         }
     }
@@ -218,6 +242,9 @@ Entity::Entity(
     int typeId, Framework::Vec3<float> location, int dimensionId, int entityId)
     : Inventory(location, dimensionId, true),
       chatSecurityLevel(0),
+      lastChunkCenter(0, 0),
+      lastSavedChunkCenter(Framework::Maybe<Framework::Punkt>::empty()),
+      lastDimensionId(-1),
       speed(0, 0, 0),
       faceDir(1, 0, 0),
       target(0),
@@ -229,12 +256,24 @@ Entity::Entity(
       placeBlockCooldown(0)
 {}
 
-void Entity::onDeath()
+void Entity::onDeath(Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill)
 {
     if (!removed)
     {
-        Game::INSTANCE->requestWorldUpdate(
-            new EntityRemovedUpdate(id, dimensionId, location));
+        for (DropConfig* config : zType()->getDropConfigs())
+        {
+            config->onObjectDestroyed(zActor, zUsedItem, zUsedSkill, this);
+        }
+        Dimension* dim = Game::INSTANCE->zDimension(dimensionId);
+        if (dim)
+        {
+            Chunk* chunk = dim->zChunk(lastChunkCenter);
+            if (chunk)
+            {
+                chunk->onEntityLeaves(this, 0);
+            }
+            dim->removeEntity(id);
+        }
         removed = 1;
     }
 }
@@ -389,22 +428,29 @@ void Entity::addMovementFrame(MovementFrame& frame)
     cs.lock();
     movements.add(frame);
     cs.unlock();
-    NetworkMessage* message = new NetworkMessage();
-    message->addressEntity(this);
-    char* msg = new char[37];
-    msg[0] = 0;
-    *(float*)(msg + 1) = frame.direction.x;
-    *(float*)(msg + 5) = frame.direction.y;
-    *(float*)(msg + 9) = frame.direction.z;
-    *(float*)(msg + 13) = frame.targetPosition.x;
-    *(float*)(msg + 17) = frame.targetPosition.y;
-    *(float*)(msg + 21) = frame.targetPosition.z;
-    *(int*)(msg + 25) = frame.movementFlags;
-    *(double*)(msg + 29) = frame.duration;
-    message->setMessage(msg, 37);
-    Game::INSTANCE->broadcastMessage(message);
+    Dimension* dim = Game::INSTANCE->zDimension(lastDimensionId);
+    if (dim)
+    {
+        Chunk* chunk = dim->zChunk(lastChunkCenter);
+        if (chunk)
+        {
+            NetworkMessage* message = new NetworkMessage();
+            message->addressEntity(this);
+            char* msg = new char[37];
+            msg[0] = 0;
+            *(float*)(msg + 1) = frame.direction.x;
+            *(float*)(msg + 5) = frame.direction.y;
+            *(float*)(msg + 9) = frame.direction.z;
+            *(float*)(msg + 13) = frame.targetPosition.x;
+            *(float*)(msg + 17) = frame.targetPosition.y;
+            *(float*)(msg + 21) = frame.targetPosition.z;
+            *(int*)(msg + 25) = frame.movementFlags;
+            *(double*)(msg + 29) = frame.duration;
+            message->setMessage(msg, 37);
+            chunk->notifyObservers(message);
+        }
+    }
     faceDir = frame.direction;
-    // TODO implement subscription system to notify only interested clients
 }
 
 void Entity::calculateTarget(Framework::Vec3<float> basePos,
@@ -417,6 +463,8 @@ void Entity::calculateTarget(Framework::Vec3<float> basePos,
     int pz = (int)floor(headPosition.z);
     direction.normalize();
     Direction dir = BOTTOM;
+    bool found = false;
+    bool changed = false;
     while (true)
     {
         if (getDefaultBlock(
@@ -424,13 +472,10 @@ void Entity::calculateTarget(Framework::Vec3<float> basePos,
                     Framework::Vec3<int>{px, py, pz}, dimensionId, 0))
                 ->isInteractable(zItem))
         {
+            found = true;
             if (!target || !target->isBlock({px, py, pz}, dir))
             {
-                cs.lock();
-                delete target;
-                target = new ActionTarget({px, py, pz}, dir);
-                cs.unlock();
-                onTargetChange();
+                changed = true;
             }
             break;
         }
@@ -514,72 +559,50 @@ void Entity::calculateTarget(Framework::Vec3<float> basePos,
             }
         }
         if (target)
+        {
+            changed = true;
+        }
+        break;
+    }
+    float distSq = Framework::Vec3<float>((float)px, (float)py, (float)pz)
+                       .abstandSq(headPosition);
+    Entity* zte = Game::INSTANCE->zDimension(dimensionId)
+                      ->zTarget(headPosition, direction, distSq);
+    if (zte)
+    {
+        if (!target || !target->isEntity(zte->getId()))
         {
             cs.lock();
             delete target;
-            target = 0;
+            target = new ActionTarget(zte->getId());
             cs.unlock();
             onTargetChange();
         }
-        break;
     }
-}
-
-void Entity::removeStatusBarObserver(Entity* zSource, Framework::Text id)
-{
-    cs.lock();
-    int index = 0;
-    for (auto observer : statusBarObservers)
+    else if (changed)
     {
-        if (observer.getFirst() == zSource->getId()
-            && observer.getSecond().istGleich(id))
+        if (target && !found)
         {
-            statusBarObservers.remove(index);
-            break;
+            cs.lock();
+            delete target;
+            target = 0;
+            cs.unlock();
+            onTargetChange();
         }
-        index++;
-    }
-    cs.unlock();
-}
-
-void Entity::addStatusBarObserver(Entity* zSource, Framework::Text id)
-{
-    cs.lock();
-    for (auto observer : statusBarObservers)
-    {
-        if (observer.getFirst() == zSource->getId()
-            && observer.getSecond().istGleich(id))
+        else
         {
+            cs.lock();
+            delete target;
+            target = new ActionTarget({px, py, pz}, dir);
             cs.unlock();
-            return;
+            onTargetChange();
         }
     }
-    statusBarObservers.add(
-        Framework::ImmutablePair<int, Framework::Text>(zSource->getId(), id));
-    cs.unlock();
 }
 
 void Entity::notifyStatusBarObservers(NetworkMessage* msg)
 {
-    cs.lock();
-    int index = 0;
-    Framework::Array<int> toDelete;
-    for (auto observer : statusBarObservers)
-    {
-        Entity* e = Game::INSTANCE->zEntity(observer.getFirst());
-        if (e)
-        {
-            msg->addressUIElement(observer.getSecond());
-            Game::INSTANCE->sendMessage(msg->clone(), e);
-        }
-        else
-            toDelete.add(index, 0);
-        index++;
-    }
-    for (int i : toDelete)
-        statusBarObservers.remove(i);
-    cs.unlock();
-    msg->release();
+    statusBarObservable.notifyObservers(msg);
 }
 
 ItemSkill* Entity::zSkill(int itemType)
@@ -598,6 +621,7 @@ void Entity::prepareTick(const Dimension* zDimension) {}
 
 void Entity::tick(const Dimension* zDimension)
 {
+    if (removed) return;
     if (placeBlockCooldown > 0)
     {
         placeBlockCooldown--;
@@ -658,6 +682,32 @@ void Entity::tick(const Dimension* zDimension)
         }
     }
     time.messungStart();
+    Framework::Punkt chunkCenter
+        = Game::INSTANCE->getChunkCenter((int)location.x, (int)location.y);
+    if (dimensionId != lastDimensionId || chunkCenter != lastChunkCenter)
+    {
+        Dimension* lastDimension = Game::INSTANCE->zDimension(lastDimensionId);
+        Dimension* currentDimension = Game::INSTANCE->zDimension(dimensionId);
+        Chunk* zCurrentChunk
+            = currentDimension ? currentDimension->zChunk(chunkCenter) : 0;
+        Chunk* zLastChunk
+            = lastDimension ? lastDimension->zChunk(lastChunkCenter) : 0;
+        if (lastDimensionId != -1)
+        {
+            if (zLastChunk)
+            {
+                zLastChunk->onEntityLeaves(
+                    this, lastDimensionId == dimensionId ? zCurrentChunk : 0);
+            }
+        }
+        if (zCurrentChunk)
+        {
+            zCurrentChunk->onEntityEnters(
+                this, lastDimensionId == dimensionId ? zLastChunk : 0);
+        }
+        lastDimensionId = dimensionId;
+        lastChunkCenter = chunkCenter;
+    }
 }
 
 void Entity::api(Framework::StreamReader* zRequest,
@@ -675,8 +725,10 @@ void Entity::api(Framework::StreamReader* zRequest,
             char* guiId = new char[(int)len + 1];
             zRequest->lese(guiId, len);
             guiId[(int)len] = 0;
-            zResponse->addressUIElement(guiId);
-            addStatusBarObserver(zSource, guiId);
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            zResponse->addressUIElement(guiId, processor);
+            statusBarObservable.addObserver(zSource, guiId, processor);
             char* msg = new char[33];
             msg[0] = 0;
             *(float*)(msg + 1) = getMaxHP();
@@ -698,10 +750,14 @@ void Entity::api(Framework::StreamReader* zRequest,
             char* guiId = new char[(int)len + 1];
             zRequest->lese(guiId, len);
             guiId[(int)len] = 0;
-            removeStatusBarObserver(zSource, guiId);
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            statusBarObservable.removeObserver(zSource, guiId, processor);
             delete[] guiId;
             break;
         }
+    case 2: // TODO: component request
+        break;
     }
 }
 
@@ -709,10 +765,19 @@ void Entity::onFall(float collisionSpeed)
 {
     if (collisionSpeed > 10)
     {
-        setHP(getCurrentHP() - (collisionSpeed - 10.f) / 2.5f);
+        setHP(this, 0, 0, getCurrentHP() - (collisionSpeed - 10.f) / 2.5f);
     }
 }
 
+Framework::XML::Element* Entity::getTargetUIML() const
+{
+    return new Framework::XML::Element(
+        Framework::Text(
+            "<targetInfo><text id=\"type\" width=\"auto\" height=\"auto\">")
+        + Game::INSTANCE->zEntityType(typeId)->getName()
+        + "</text></targetInfo>");
+}
+
 void Entity::setChatSecurityLevel(int level)
 {
     chatSecurityLevel = level;
@@ -723,12 +788,19 @@ void Entity::setPosition(Framework::Vec3<float> pos)
     location = pos;
 }
 
-void Entity::takeDamage(Entity* zSource, float damage)
+void Entity::takeDamage(
+    Entity* zSource, Item* zUsedItem, ItemSkill* zUsedSkill, float damage)
 {
-    // TODO: implement this
+    currentHP -= damage;
+    if (currentHP <= 0)
+    {
+        currentHP = 0;
+        onDeath(zSource, zUsedItem, zUsedSkill);
+    }
 }
 
-void Entity::setHP(float hp)
+void Entity::setHP(
+    Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, float hp)
 {
     currentHP = MIN(MAX(hp, 0), maxHP);
     NetworkMessage* msg = new NetworkMessage();
@@ -740,7 +812,7 @@ void Entity::setHP(float hp)
     notifyStatusBarObservers(msg);
     if (currentHP == 0)
     {
-        onDeath();
+        onDeath(zActor, zUsedItem, zUsedSkill);
     }
 }
 
@@ -898,4 +970,110 @@ bool Entity::isMoving() const
 int Entity::getChatSecurityLevel() const
 {
     return chatSecurityLevel;
-}
+}
+
+Framework::Maybe<Framework::Punkt> Entity::getLastSavedChunkCenter() const
+{
+    return lastSavedChunkCenter;
+}
+
+void Entity::setLastSavedChunkCenter(Framework::Punkt pos)
+{
+    lastSavedChunkCenter = Framework::Maybe<Framework::Punkt>::of(pos);
+}
+
+void Entity::setRemoved()
+{
+    removed = true;
+}
+
+double Entity::getHitDistance(
+    Framework::Vec3<float> rayOrigin, Framework::Vec3<float> rayDirection) const
+{
+    Framework::Mat4<float> rotMat
+        = Framework::Mat4<float>::rotationX(-rotation.x)
+        * Framework::Mat4<float>::rotationY(-rotation.y)
+        * Framework::Mat4<float>::rotationZ(-rotation.z);
+    Framework::Vec3<float> rotatedRayOrigin = rotMat * rayOrigin;
+    Framework::Vec3<float> rotatedRayDirection = rotMat * rayDirection;
+    rotatedRayDirection.normalize();
+    if (rotatedRayDirection.x != 0)
+    {
+        float d;
+        if (rotatedRayDirection.x > 0)
+        {
+            float border = getPosition().x - boundingBox.x;
+            d = (border - rotatedRayOrigin.x) / rotatedRayDirection.x;
+        }
+        else if (rotatedRayDirection.x < 0)
+        {
+            float border = getPosition().x + boundingBox.x;
+            d = (border - rotatedRayOrigin.x) / rotatedRayDirection.x;
+        }
+        if (d > 0)
+        {
+            Framework::Vec3<float> hitPoint
+                = rotatedRayOrigin + rotatedRayDirection * d;
+            if (hitPoint.y >= getPosition().y - boundingBox.y
+                && hitPoint.y <= getPosition().y + boundingBox.y
+                && hitPoint.z >= getPosition().z - boundingBox.z
+                && hitPoint.z <= getPosition().z + boundingBox.z)
+            {
+                return d;
+            }
+        }
+    }
+    if (rotatedRayDirection.y != 0)
+    {
+        float d;
+        if (rotatedRayDirection.y > 0)
+        {
+            float border = getPosition().y - boundingBox.y;
+            d = (border - rotatedRayOrigin.y) / rotatedRayDirection.y;
+        }
+        else if (rotatedRayDirection.y < 0)
+        {
+            float border = getPosition().y + boundingBox.y;
+            d = (border - rotatedRayOrigin.y) / rotatedRayDirection.y;
+        }
+        if (d > 0)
+        {
+            Framework::Vec3<float> hitPoint
+                = rotatedRayOrigin + rotatedRayDirection * d;
+            if (hitPoint.x >= getPosition().x - boundingBox.x
+                && hitPoint.x <= getPosition().x + boundingBox.x
+                && hitPoint.z >= getPosition().z - boundingBox.z
+                && hitPoint.z <= getPosition().z + boundingBox.z)
+            {
+                return d;
+            }
+        }
+    }
+    if (rotatedRayDirection.z != 0)
+    {
+        float d;
+        if (rotatedRayDirection.z > 0)
+        {
+            float border = getPosition().z - boundingBox.z;
+            d = (border - rotatedRayOrigin.z) / rotatedRayDirection.z;
+        }
+        else if (rotatedRayDirection.z < 0)
+        {
+            float border = getPosition().z + boundingBox.z;
+            d = (border - rotatedRayOrigin.z) / rotatedRayDirection.z;
+        }
+        if (d > 0)
+        {
+            Framework::Vec3<float> hitPoint
+                = rotatedRayOrigin + rotatedRayDirection * d;
+            if (hitPoint.x >= getPosition().x - boundingBox.x
+                && hitPoint.x <= getPosition().x + boundingBox.x
+                && hitPoint.y >= getPosition().y - boundingBox.y
+                && hitPoint.y <= getPosition().y + boundingBox.y)
+            {
+                return d;
+            }
+        }
+    }
+    return NAN;
+}

+ 20 - 11
FactoryCraft/Entity.h

@@ -1,16 +1,15 @@
 #pragma once
 
-#include <ReferenceCounter.h>
-#include <Vec2.h>
+#include <Maybe.h>
 #include <Vec3.h>
 #include <Writer.h>
 #include <Zeit.h>
 
-#include "Effect.h"
 #include "Inventory.h"
 #include "ItemSkill.h"
 #include "ModelInfo.h"
 #include "NetworkMessage.h"
+#include "UIObservable.h"
 
 class EntityType;
 class Dimension;
@@ -52,11 +51,15 @@ struct MovementFrame
 class Entity : public Inventory
 {
 private:
+    UIObservable statusBarObservable;
     float stamina;
     float hunger;
     float currentHP;
     float thirst;
     int chatSecurityLevel;
+    Framework::Punkt lastChunkCenter;
+    int lastDimensionId;
+    Framework::Maybe<Framework::Punkt> lastSavedChunkCenter;
 
 protected:
     float maxHP;
@@ -79,10 +82,11 @@ protected:
     Framework::ZeitMesser time;
     Framework::Array<MovementFrame> movements;
     Framework::Critical cs;
-    Framework::Array<Framework::ImmutablePair<int, Framework::Text>>
-        statusBarObservers;
+    Framework::Vec3<float> boundingBox;
+    Framework::Vec3<float> rotation;
 
-    virtual void onDeath();
+    virtual void onDeath(
+        Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill);
     virtual bool useItem(int typeId, ItemStack* zStack, bool left);
     Entity(int typeId,
         Framework::Vec3<float> location,
@@ -92,8 +96,6 @@ protected:
     void calculateTarget(Framework::Vec3<float> basePos,
         Framework::Vec3<float> direction,
         const Item* zItem);
-    void removeStatusBarObserver(Entity* zSource, Framework::Text id);
-    void addStatusBarObserver(Entity* zSource, Framework::Text id);
     void notifyStatusBarObservers(NetworkMessage* msg);
     ItemSkill* zSkill(int itemType);
 
@@ -108,10 +110,13 @@ public:
 
     virtual bool interact(Item* zItem, Entity* zActor);
     virtual void onFall(float collisionSpeed);
+    virtual Framework::XML::Element* getTargetUIML() const;
     void setChatSecurityLevel(int level);
     void setPosition(Framework::Vec3<float> pos);
-    virtual void takeDamage(Entity* zSource, float damage);
-    void setHP(float hp);
+    virtual void takeDamage(
+        Entity* zSource, Item* zUsedItem, ItemSkill* zUsedSkill, float damage);
+    void setHP(
+        Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, float hp);
     void setStamina(float stamina);
     void setHunger(float hunger);
     void setThirst(float thirst);
@@ -139,7 +144,11 @@ public:
     float getMaxSpeed() const;
     bool isMoving() const;
     int getChatSecurityLevel() const;
+    Framework::Maybe<Framework::Punkt> getLastSavedChunkCenter() const;
+    void setLastSavedChunkCenter(Framework::Punkt pos);
+    void setRemoved();
+    double getHitDistance(Framework::Vec3<float> rayOrigin,
+        Framework::Vec3<float> rayDirection) const;
 
-    friend Effect;
     friend EntityType;
 };

+ 129 - 0
FactoryCraft/EntityGenerator.cpp

@@ -0,0 +1,129 @@
+#include "EntityGenerator.h"
+
+#include "EntityType.h"
+#include "Game.h"
+#include "JNoise.h"
+#include "JsonExpression.h"
+
+EntityGenerator::EntityGenerator()
+    : ReferenceCounter(),
+      noise(0),
+      noiseConfig(0),
+      threshold(0.0),
+      zType(0),
+      condition(0)
+{}
+
+EntityGenerator::~EntityGenerator()
+{
+    if (condition)
+    {
+        condition->release();
+    }
+    if (noise)
+    {
+        noise->release();
+    }
+    if (noiseConfig)
+    {
+        noiseConfig->release();
+    }
+}
+
+void EntityGenerator::initialize(JExpressionMemory* zMemory)
+{
+    if (noiseConfig)
+    {
+        if (noise) noise->release();
+        noise = JNoise::parseNoise(noiseConfig, zMemory);
+    }
+    condition->compile(zMemory);
+}
+
+bool EntityGenerator::isGenerated(int x, int y, int z, int dimensionId)
+{
+    return (!noise
+               || noise->getNoise((double)x, (double)y, (double)z) >= threshold)
+        && condition->getValue();
+}
+
+Entity* EntityGenerator::generate(Framework::Vec3<float> pos, int dimesnionId)
+{
+    return zType->createEntityAt(pos, dimesnionId);
+}
+
+EntityGeneratorFactory::EntityGeneratorFactory()
+    : ObjectTypeFactory()
+{}
+
+EntityGenerator* EntityGeneratorFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    EntityGenerator* result = new EntityGenerator();
+    if (zJson->hasValue("noise"))
+    {
+        result->noiseConfig = zJson->getValue("noise")->asObject();
+    }
+    if (zJson->hasValue("threshold"))
+    {
+        result->threshold = zJson->zValue("threshold")->asNumber()->getNumber();
+    }
+    if (zJson->hasValue("type"))
+    {
+        result->zType
+            = Game::INSTANCE->zEntityType(Game::INSTANCE->getEntityTypeId(
+                zJson->zValue("type")->asString()->getString()));
+    }
+    if (zJson->hasValue("condition"))
+    {
+        result->condition
+            = Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(
+                zJson->zValue("condition"));
+    }
+    return result;
+}
+
+Framework::JSON::JSONObject* EntityGeneratorFactory::toJsonObject(
+    EntityGenerator* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    if (zObject->noiseConfig)
+    {
+        result->addValue("noise",
+            dynamic_cast<Framework::JSON::JSONValue*>(
+                zObject->noiseConfig->getThis()));
+    }
+    result->addValue(
+        "threshold", new Framework::JSON::JSONNumber(zObject->threshold));
+    result->addValue(
+        "type", new Framework::JSON::JSONString(zObject->zType->getName()));
+    result->addValue("condition",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->condition));
+    return result;
+}
+
+JSONObjectValidationBuilder* EntityGeneratorFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    Framework::RCArray<Framework::Text> entityTypeNames;
+    for (int i = 0; i < Game::INSTANCE->getEntityTypeCount(); i++)
+    {
+        if (Game::INSTANCE->zEntityType(i))
+        {
+            entityTypeNames.add(
+                new Framework::Text(Game::INSTANCE->zEntityType(i)->getName()));
+        }
+    }
+    // TODO: add EntityTypeNameFactory
+    return builder->withRequiredAttribute("noise", JNoise::getValidator(true))
+        ->withRequiredNumber("threshold")
+        ->whichIsOptional()
+        ->whichIsGreaterOrEqual(0.0)
+        ->whichIsLessOrEqual(1.0)
+        ->finishNumber()
+        ->withRequiredString("type")
+        ->whichIsOneOf(entityTypeNames)
+        ->finishString()
+        ->withRequiredAttribute("condition",
+            Game::INSTANCE->zTypeRegistry()->getValidator<JBoolExpression>());
+}

+ 44 - 0
FactoryCraft/EntityGenerator.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include <Vec3.h>
+
+#include "TypeRegistry.h"
+
+class EntityType;
+class Entity;
+class JBoolExpression;
+class JExpressionMemory;
+class Noise;
+
+class EntityGeneratorFactory;
+
+class EntityGenerator : public Framework::ReferenceCounter
+{
+private:
+    Noise* noise;
+    Framework::JSON::JSONObject* noiseConfig;
+    double threshold;
+    const EntityType* zType;
+    JBoolExpression* condition;
+
+public:
+    EntityGenerator();
+    ~EntityGenerator();
+    void initialize(JExpressionMemory* zMemory);
+    bool isGenerated(int x, int y, int z, int dimensionId);
+    Entity* generate(Framework::Vec3<float> pos, int dimesnionId);
+
+    friend EntityGeneratorFactory;
+};
+
+class EntityGeneratorFactory : public ObjectTypeFactory<EntityGenerator>
+{
+public:
+    EntityGeneratorFactory();
+    EntityGenerator* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        EntityGenerator* zObject) const override;
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+};

+ 0 - 22
FactoryCraft/EntityRemovedUpdate.cpp

@@ -1,22 +0,0 @@
-#include "EntityRemovedUpdate.h"
-#include "Dimension.h"
-
-
-EntityRemovedUpdate::EntityRemovedUpdate(
-    int entityId, int dimensionId, Framework::Vec3<float> pos)
-    : WorldUpdate(WorldUpdateTypeEnum::REMOVE_ENTITY, dimensionId, pos),
-	entityId(entityId)
-{}
-
-EntityRemovedUpdate::~EntityRemovedUpdate()
-{}
-
-void EntityRemovedUpdate::onUpdate(Dimension* zDimension)
-{
-	zDimension->removeEntity(entityId);
-}
-
-void EntityRemovedUpdate::write(Framework::StreamWriter* zWriter)
-{
-	zWriter->schreibe((char*)&entityId, 4);
-}

+ 0 - 19
FactoryCraft/EntityRemovedUpdate.h

@@ -1,19 +0,0 @@
-#pragma once
-
-#include "WorldUpdate.h"
-
-class EntityRemovedUpdate : public WorldUpdate
-{
-private:
-    int entityId;
-
-protected:
-    void write(Framework::StreamWriter* zWriter) override;
-
-public:
-    EntityRemovedUpdate(
-        int entityId, int dimensionId, Framework::Vec3<float> pos);
-    ~EntityRemovedUpdate();
-
-    void onUpdate(Dimension* zDimension) override;
-};

+ 32 - 4
FactoryCraft/EntityType.cpp

@@ -4,10 +4,10 @@
 #include "Game.h"
 #include "ItemType.h"
 
-EntityType::EntityType(Framework::Text name, ModelInfo* model)
+EntityType::EntityType()
     : ReferenceCounter(),
-      name(name),
-      model(model),
+      name(""),
+      model(0),
       id(-1)
 {}
 
@@ -95,13 +95,41 @@ void EntityType::saveSuperEntity(
     }
 }
 
-void EntityType::createSuperEntity(Entity* zEntity) const {}
+void EntityType::createSuperEntity(Entity* zEntity) const
+{
+    zEntity->boundingBox = model->getBoundingBox();
+}
 
 bool EntityType::initialize(Game* zGame)
 {
+    for (DropConfig* config : dropConfigs)
+    {
+        config->initialize();
+    }
     return true;
 }
 
+void EntityType::addDropConfig(DropConfig* config)
+{
+    dropConfigs.add(config);
+}
+
+void EntityType::setName(Framework::Text name)
+{
+    this->name = name;
+}
+
+void EntityType::setModel(ModelInfo* model)
+{
+    if (this->model) this->model->release();
+    this->model = model;
+}
+
+const Framework::RCArray<DropConfig>& EntityType::getDropConfigs() const
+{
+    return dropConfigs;
+}
+
 Entity* EntityType::loadEntity(Framework::StreamReader* zReader) const
 {
     Entity* entity = createEntity(Framework::Vec3<float>(0, 0, 0), 0, 0);

+ 79 - 7
FactoryCraft/EntityType.h

@@ -5,6 +5,7 @@
 #include <Vec3.h>
 #include <Writer.h>
 
+#include "DropConfig.h"
 #include "ModelInfo.h"
 
 class Entity;
@@ -22,10 +23,11 @@ class EntityType : public virtual Framework::ReferenceCounter
 private:
     Framework::Text name;
     int id;
-    ModelInfo *model;
+    ModelInfo* model;
+    Framework::RCArray<DropConfig> dropConfigs;
 
 protected:
-    EntityType(Framework::Text name, ModelInfo* model);
+    EntityType();
     ~EntityType();
 
     virtual void loadSuperEntity(
@@ -35,18 +37,88 @@ protected:
     virtual void createSuperEntity(Entity* zEntity) const;
 
 public:
-    virtual bool initialize(Game *zGame);
+    virtual bool initialize(Game* zGame);
+    void addDropConfig(DropConfig* config);
+    void setName(Framework::Text name);
+    void setModel(ModelInfo* model);
+    const Framework::RCArray<DropConfig>& getDropConfigs() const;
     virtual Entity* loadEntity(Framework::StreamReader* zReader) const;
     virtual void saveEntity(
         Entity* zEntity, Framework::StreamWriter* zWriter) const;
     virtual Entity* createEntityAt(
         Framework::Vec3<float> position, int dimensionId) const;
-    virtual Entity* createEntity(Framework::Vec3<float> position,
-        int dimensionId,
-        int entityId) const = 0;
+    virtual Entity* createEntity(
+        Framework::Vec3<float> position, int dimensionId, int entityId) const
+        = 0;
 
     int getId() const;
     ModelInfo* zModel() const;
     void setTypeId(int id);
     Framework::Text getName() const;
-};
+};
+
+template<typename S> class EntityTypeFactoryBase
+    : public SubTypeFactory<EntityType, S>
+{
+public:
+    EntityTypeFactoryBase()
+        : SubTypeFactory<EntityType, S>()
+    {}
+
+    virtual S* fromJson(Framework::JSON::JSONObject* zJson) const override
+    {
+        S* result = createValue(zJson);
+        EntityType* zType = dynamic_cast<EntityType*>(result);
+        zType->setModel(Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
+            zJson->zValue("model")->asObject()));
+        zType->setName(zJson->zValue("typeName")->asString()->getString());
+        for (Framework::JSON::JSONValue* value :
+            *zJson->zValue("drops")->asArray())
+        {
+            zType->addDropConfig(
+                Game::INSTANCE->zTypeRegistry()->fromJson<DropConfig>(
+                    value->asObject()));
+        }
+        return result;
+    }
+
+    virtual Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
+    {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+        EntityType* zType = dynamic_cast<EntityType*>(zObject);
+        result->addValue("model",
+            Game::INSTANCE->zTypeRegistry()->toJson<ModelInfo>(
+                zType->zModel()));
+        result->addValue(
+            "typeName", new Framework::JSON::JSONString(zType->getName()));
+        Framework::JSON::JSONArray* drops = new Framework::JSON::JSONArray();
+        for (DropConfig* drop : zType->getDropConfigs())
+        {
+            drops->addValue(
+                Game::INSTANCE->zTypeRegistry()->toJson<DropConfig>(drop));
+        }
+        result->addValue("drops", drops);
+        addToJson(result, zObject);
+        return result;
+    }
+
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override
+    {
+        return builder
+            ->withRequiredAttribute("model",
+                Game::INSTANCE->zTypeRegistry()->getValidator<ModelInfo>())
+            ->withRequiredString("typeName")
+            ->finishString()
+            ->withRequiredAttribute("drops",
+                Framework::Validator::DataValidator::buildForArray()
+                    ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                            ->getValidator<DropConfig>())
+                    ->finishArray());
+    }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
+    virtual void addToJson(Framework::JSON::JSONObject* zJson, S* zObject) const
+        = 0;
+};

+ 61 - 10
FactoryCraft/FactoryCraft.vcxproj

@@ -97,19 +97,31 @@
   </PropertyGroup>
   <ItemGroup>
     <ClInclude Include="Animal.h" />
-    <ClInclude Include="AnimalyAI.h" />
+    <ClInclude Include="AnimalAI.h" />
     <ClInclude Include="ArrayUtils.h" />
+    <ClInclude Include="BlockComponent.h" />
     <ClInclude Include="BlockFilter.h" />
     <ClInclude Include="BlockInfoCommand.h" />
     <ClInclude Include="BlockInstanceGeneratorRule.h" />
+    <ClInclude Include="BlockReplacementDrop.h" />
+    <ClInclude Include="BlockTypeNameFactory.h" />
+    <ClInclude Include="DefaultBlockItemDrop.h" />
+    <ClInclude Include="DefaultInventoryDrop.h" />
+    <ClInclude Include="DropChanceCondition.h" />
+    <ClInclude Include="DropCondition.h" />
+    <ClInclude Include="DropConditionOperator.h" />
+    <ClInclude Include="DropConfig.h" />
+    <ClInclude Include="DropUsedItemCondition.h" />
+    <ClInclude Include="EntityGenerator.h" />
     <ClInclude Include="FactorizeNoise.h" />
+    <ClInclude Include="FireBasedProcessingBlockComponent.h" />
     <ClInclude Include="FlattenNoise.h" />
     <ClInclude Include="FluidContainer.h" />
+    <ClInclude Include="GameClient.h" />
     <ClInclude Include="GeneratorRule.h" />
     <ClInclude Include="BlockTypeGeneratorRule.h" />
     <ClInclude Include="Chest.h" />
     <ClInclude Include="ChunkMap.h" />
-    <ClInclude Include="AddEntityUpdate.h" />
     <ClInclude Include="Area.h" />
     <ClInclude Include="BasicBlocks.h" />
     <ClInclude Include="BasicItems.h" />
@@ -127,10 +139,7 @@
     <ClInclude Include="CraftingStorage.h" />
     <ClInclude Include="DimensionGenerator.h" />
     <ClInclude Include="DoLaterHandler.h" />
-    <ClInclude Include="Effect.h" />
-    <ClInclude Include="EffectFactory.h" />
     <ClInclude Include="Entity.h" />
-    <ClInclude Include="EntityRemovedUpdate.h" />
     <ClInclude Include="EntityType.h" />
     <ClInclude Include="FastNoiseLite.h" />
     <ClInclude Include="FastNoiseWrapper.h" />
@@ -142,6 +151,7 @@
     <ClInclude Include="Grass.h" />
     <ClInclude Include="Chat.h" />
     <ClInclude Include="InformationObserver.h" />
+    <ClInclude Include="InteractionConfig.h" />
     <ClInclude Include="Inventory.h" />
     <ClInclude Include="Item.h" />
     <ClInclude Include="ItemEntity.h" />
@@ -151,6 +161,7 @@
     <ClInclude Include="ItemSlot.h" />
     <ClInclude Include="ItemStack.h" />
     <ClInclude Include="ItemType.h" />
+    <ClInclude Include="ItemTypeNameFactory.h" />
     <ClInclude Include="JNoise.h" />
     <ClInclude Include="JsonExpression.h" />
     <ClInclude Include="JsonUtils.h" />
@@ -158,14 +169,18 @@
     <ClInclude Include="DimensionMap.h" />
     <ClInclude Include="ModelInfo.h" />
     <ClInclude Include="MultiblockStructure.h" />
+    <ClInclude Include="MultiblockStructureManager.h" />
     <ClInclude Include="MultiblockTree.h" />
     <ClInclude Include="MultiplyNoise.h" />
     <ClInclude Include="NegateNoise.h" />
     <ClInclude Include="NetworkMessage.h" />
+    <ClInclude Include="NeutralAnimalAI.h" />
     <ClInclude Include="Noise.h" />
     <ClInclude Include="NoBlock.h" />
     <ClInclude Include="NoiseInterpolator.h" />
+    <ClInclude Include="OpenDialogInteractionConfig.h" />
     <ClInclude Include="PlaceableProof.h" />
+    <ClInclude Include="PlantConfig.h" />
     <ClInclude Include="Player.h" />
     <ClInclude Include="PlayerHand.h" />
     <ClInclude Include="PlayerRegister.h" />
@@ -176,6 +191,7 @@
     <ClInclude Include="QuestReward.h" />
     <ClInclude Include="RandNoise.h" />
     <ClInclude Include="Recipie.h" />
+    <ClInclude Include="RecipieGroupConfig.h" />
     <ClInclude Include="RecipieList.h" />
     <ClInclude Include="RecipieLoader.h" />
     <ClInclude Include="SaveCommand.h" />
@@ -194,14 +210,21 @@
     <ClInclude Include="GrowingPlant.h" />
     <ClInclude Include="TypeRegistry.h" />
     <ClInclude Include="UIController.h" />
+    <ClInclude Include="UICraftingGrid.h" />
+    <ClInclude Include="UICraftingProgress.h" />
     <ClInclude Include="UIDialog.h" />
+    <ClInclude Include="UIDialogElement.h" />
+    <ClInclude Include="UIElement.h" />
+    <ClInclude Include="UIFuelState.h" />
+    <ClInclude Include="UIInventory.h" />
+    <ClInclude Include="UIObservable.h" />
+    <ClInclude Include="UIReference.h" />
+    <ClInclude Include="UIText.h" />
     <ClInclude Include="WorldGenerator.h" />
     <ClInclude Include="WorldLoader.h" />
-    <ClInclude Include="WorldUpdate.h" />
     <ClInclude Include="WormCaveGenerator.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="AddEntityUpdate.cpp" />
     <ClCompile Include="Animal.cpp" />
     <ClCompile Include="AnimalAI.cpp" />
     <ClCompile Include="Area.cpp" />
@@ -211,11 +234,13 @@
     <ClCompile Include="BasicTool.cpp" />
     <ClCompile Include="BiomGenerator.cpp" />
     <ClCompile Include="Block.cpp" />
+    <ClCompile Include="BlockComponent.cpp" />
     <ClCompile Include="BlockFilter.cpp" />
     <ClCompile Include="BlockInfoCommand.cpp" />
     <ClCompile Include="BlockInstanceGeneratorRule.cpp" />
     <ClCompile Include="BlockType.cpp" />
     <ClCompile Include="BlockTypeGeneratorRule.cpp" />
+    <ClCompile Include="BlockTypeNameFactory.cpp" />
     <ClCompile Include="CaveGenerator.cpp" />
     <ClCompile Include="Chat.cpp" />
     <ClCompile Include="ChatCommand.cpp" />
@@ -226,25 +251,35 @@
     <ClCompile Include="Chunk.cpp" />
     <ClCompile Include="ChunkMap.cpp" />
     <ClCompile Include="CraftingStorage.cpp" />
+    <ClCompile Include="DefaultBlockItemDrop.cpp" />
+    <ClCompile Include="DefaultInventoryDrop.cpp" />
     <ClCompile Include="Dimension.cpp" />
     <ClCompile Include="DimensionGenerator.cpp" />
     <ClCompile Include="DimensionMap.cpp" />
     <ClCompile Include="DoLaterHandler.cpp" />
+    <ClCompile Include="DropChanceCondition.cpp" />
+    <ClCompile Include="DropConditionOperator.cpp" />
+    <ClCompile Include="DropConfig.cpp" />
+    <ClCompile Include="BlockReplacementDrop.cpp" />
+    <ClCompile Include="DropUsedItemCondition.cpp" />
     <ClCompile Include="Entity.cpp" />
-    <ClCompile Include="EntityRemovedUpdate.cpp" />
+    <ClCompile Include="EntityGenerator.cpp" />
     <ClCompile Include="EntityType.cpp" />
     <ClCompile Include="FactorizeNoise.cpp" />
     <ClCompile Include="FastNoiseWrapper.cpp" />
+    <ClCompile Include="FireBasedProcessingBlockComponent.cpp" />
     <ClCompile Include="FlattenNoise.cpp" />
     <ClCompile Include="FluidBlock.cpp" />
     <ClCompile Include="FluidContainer.cpp" />
     <ClCompile Include="Game.cpp" />
+    <ClCompile Include="GameClient.cpp" />
     <ClCompile Include="GeneratedStructure.cpp" />
     <ClCompile Include="GeneratorTemplate.cpp" />
     <ClCompile Include="GeneratorRule.cpp" />
     <ClCompile Include="GrantCommand.cpp" />
     <ClCompile Include="Grass.cpp" />
     <ClCompile Include="InformationObserver.cpp" />
+    <ClCompile Include="InteractionConfig.cpp" />
     <ClCompile Include="Inventory.cpp" />
     <ClCompile Include="Item.cpp" />
     <ClCompile Include="ItemEntity.cpp" />
@@ -254,20 +289,25 @@
     <ClCompile Include="ItemSlot.cpp" />
     <ClCompile Include="ItemStack.cpp" />
     <ClCompile Include="ItemType.cpp" />
+    <ClCompile Include="ItemTypeNameFactory.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" />
+    <ClCompile Include="MultiblockStructureManager.cpp" />
     <ClCompile Include="MultiblockTree.cpp" />
     <ClCompile Include="MultiplyNoise.cpp" />
     <ClCompile Include="NegateNoise.cpp" />
     <ClCompile Include="NetworkMessage.cpp" />
+    <ClCompile Include="NeutralAnimalAI.cpp" />
     <ClCompile Include="NoBlock.cpp" />
     <ClCompile Include="Noise.cpp" />
     <ClCompile Include="NoiseInterpolator.cpp" />
+    <ClCompile Include="OpenDialogInteractionConfig.cpp" />
     <ClCompile Include="PlaceableProof.cpp" />
+    <ClCompile Include="PlantConfig.cpp" />
     <ClCompile Include="Player.cpp" />
     <ClCompile Include="PlayerHand.cpp" />
     <ClCompile Include="PlayerRegister.cpp" />
@@ -276,6 +316,7 @@
     <ClCompile Include="QuestEvent.cpp" />
     <ClCompile Include="QuestRequirement.cpp" />
     <ClCompile Include="QuestReward.cpp" />
+    <ClCompile Include="RecipieGroupConfig.cpp" />
     <ClCompile Include="RecipieList.cpp" />
     <ClCompile Include="RandNoise.cpp" />
     <ClCompile Include="Recipie.cpp" />
@@ -284,6 +325,8 @@
     <ClCompile Include="ScaleNoise.cpp" />
     <ClCompile Include="Server.cpp" />
     <ClCompile Include="ShapedNoise.cpp" />
+    <ClCompile Include="SpecificItemDrop.cpp" />
+    <ClCompile Include="SpecificItemDrop.h" />
     <ClCompile Include="Start.cpp" />
     <ClCompile Include="StructureCollection.cpp" />
     <ClCompile Include="TickOrganizer.cpp" />
@@ -294,10 +337,18 @@
     <ClCompile Include="GrowingPlant.cpp" />
     <ClCompile Include="TypeRegistry.cpp" />
     <ClCompile Include="UIController.cpp" />
+    <ClCompile Include="UICraftingGrid.cpp" />
+    <ClCompile Include="UICraftingProgress.cpp" />
     <ClCompile Include="UIDialog.cpp" />
+    <ClCompile Include="UIDialogElement.cpp" />
+    <ClCompile Include="UIElement.cpp" />
+    <ClCompile Include="UIFuelState.cpp" />
+    <ClCompile Include="UIInventory.cpp" />
+    <ClCompile Include="UIObservable.cpp" />
+    <ClCompile Include="UIReference.cpp" />
+    <ClCompile Include="UIText.cpp" />
     <ClCompile Include="WorldGenerator.cpp" />
     <ClCompile Include="WorldLoader.cpp" />
-    <ClCompile Include="WorldUpdate.cpp" />
     <ClCompile Include="WormCaveGenerator.cpp" />
   </ItemGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -308,7 +359,7 @@
       <OutputFile>$(RemoteProjectDir)/$(TargetName)$(TargetExt)</OutputFile>
     </Link>
     <ClCompile>
-      <CppLanguageStandard>c++17</CppLanguageStandard>
+      <CppLanguageStandard>c++23</CppLanguageStandard>
       <AdditionalIncludeDirectories>../../../Framework/debug;../../../Network/debug/Network;../../../KsgScript/debug/KsgScript</AdditionalIncludeDirectories>
       <ObjectFileName>%(filename).o</ObjectFileName>
     </ClCompile>

+ 207 - 33
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -7,9 +7,6 @@
     <Filter Include="game">
       <UniqueIdentifier>{26d8996d-452d-4c1f-b52b-82310b4ee42f}</UniqueIdentifier>
     </Filter>
-    <Filter Include="effects">
-      <UniqueIdentifier>{d758dbfd-2172-4c68-bc59-b39c289c28df}</UniqueIdentifier>
-    </Filter>
     <Filter Include="entities">
       <UniqueIdentifier>{56ad694e-70aa-4ef4-b698-7ff7755b3e60}</UniqueIdentifier>
     </Filter>
@@ -28,9 +25,6 @@
     <Filter Include="world\ticking">
       <UniqueIdentifier>{03a72d46-51b8-4f26-b04a-f5f4d4f5af6e}</UniqueIdentifier>
     </Filter>
-    <Filter Include="world\update">
-      <UniqueIdentifier>{05bf4218-e0cd-4d0d-bd7b-eaea87023838}</UniqueIdentifier>
-    </Filter>
     <Filter Include="world\loader">
       <UniqueIdentifier>{12fac988-c4d8-4db8-b4a8-1c025f117866}</UniqueIdentifier>
     </Filter>
@@ -106,6 +100,33 @@
     <Filter Include="entities\animals">
       <UniqueIdentifier>{8c0ab651-350d-42ad-92e8-45899c87420a}</UniqueIdentifier>
     </Filter>
+    <Filter Include="world\generator\biom\entityGenerator">
+      <UniqueIdentifier>{1c0b5b43-9fe2-496d-bcfc-b51005126d2a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="drops">
+      <UniqueIdentifier>{d5d3529a-6b9a-46b4-bb24-beb9ce304151}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="drops\conditions">
+      <UniqueIdentifier>{c8428697-9bc8-457c-8420-5bbb89f629f4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="drops\implementations">
+      <UniqueIdentifier>{591cb52f-39d0-4c28-a756-069e7b868f1c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="UI\UIElements">
+      <UniqueIdentifier>{b000db10-bafc-49f7-b4a3-c4c26e82ca6b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Interaction">
+      <UniqueIdentifier>{ca208791-fa0c-40d2-ad18-ddbef309fa4a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="world\blocks\components">
+      <UniqueIdentifier>{fb4a3a5c-a42f-4674-97eb-825dfcc5d1b6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="UI\Observable">
+      <UniqueIdentifier>{545fce4e-6aa4-4b61-8e95-ece0430bb029}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="world\generator\biom\plants">
+      <UniqueIdentifier>{5e366c8e-008c-4c5b-935e-ea58adcdc94c}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -141,12 +162,6 @@
     <ClInclude Include="ItemSlot.h">
       <Filter>inventory</Filter>
     </ClInclude>
-    <ClInclude Include="Effect.h">
-      <Filter>effects</Filter>
-    </ClInclude>
-    <ClInclude Include="EffectFactory.h">
-      <Filter>effects</Filter>
-    </ClInclude>
     <ClInclude Include="ItemSkill.h">
       <Filter>inventory</Filter>
     </ClInclude>
@@ -174,9 +189,6 @@
     <ClInclude Include="TickOrganizer.h">
       <Filter>world\ticking</Filter>
     </ClInclude>
-    <ClInclude Include="WorldUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="EntityType.h">
       <Filter>entities</Filter>
     </ClInclude>
@@ -204,12 +216,6 @@
     <ClInclude Include="ItemEntity.h">
       <Filter>entities</Filter>
     </ClInclude>
-    <ClInclude Include="AddEntityUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
-    <ClInclude Include="EntityRemovedUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="GeneratorTemplate.h">
       <Filter>world\generator\templates</Filter>
     </ClInclude>
@@ -411,12 +417,99 @@
     <ClInclude Include="Animal.h">
       <Filter>entities\animals</Filter>
     </ClInclude>
-    <ClInclude Include="AnimalyAI.h">
-      <Filter>entities\animals</Filter>
-    </ClInclude>
     <ClInclude Include="TickSourceType.h">
       <Filter>world\ticking</Filter>
     </ClInclude>
+    <ClInclude Include="AnimalAI.h">
+      <Filter>entities\animals</Filter>
+    </ClInclude>
+    <ClInclude Include="EntityGenerator.h">
+      <Filter>world\generator\biom\entityGenerator</Filter>
+    </ClInclude>
+    <ClInclude Include="NeutralAnimalAI.h">
+      <Filter>entities\animals</Filter>
+    </ClInclude>
+    <ClInclude Include="GameClient.h">
+      <Filter>game</Filter>
+    </ClInclude>
+    <ClInclude Include="BlockTypeNameFactory.h">
+      <Filter>server\config</Filter>
+    </ClInclude>
+    <ClInclude Include="ItemTypeNameFactory.h">
+      <Filter>server\config</Filter>
+    </ClInclude>
+    <ClInclude Include="DropCondition.h">
+      <Filter>drops</Filter>
+    </ClInclude>
+    <ClInclude Include="DropConfig.h">
+      <Filter>drops</Filter>
+    </ClInclude>
+    <ClInclude Include="DropUsedItemCondition.h">
+      <Filter>drops\conditions</Filter>
+    </ClInclude>
+    <ClInclude Include="DefaultBlockItemDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="DefaultInventoryDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="DropChanceCondition.h">
+      <Filter>drops\conditions</Filter>
+    </ClInclude>
+    <ClInclude Include="DropConditionOperator.h">
+      <Filter>drops\conditions</Filter>
+    </ClInclude>
+    <ClInclude Include="MultiblockStructureManager.h">
+      <Filter>world\structures</Filter>
+    </ClInclude>
+    <ClInclude Include="BlockReplacementDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="UIText.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="UIInventory.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="UIDialogElement.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="UICraftingGrid.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="UIElement.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="UIReference.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="InteractionConfig.h">
+      <Filter>Interaction</Filter>
+    </ClInclude>
+    <ClInclude Include="OpenDialogInteractionConfig.h">
+      <Filter>Interaction</Filter>
+    </ClInclude>
+    <ClInclude Include="BlockComponent.h">
+      <Filter>world\blocks\components</Filter>
+    </ClInclude>
+    <ClInclude Include="FireBasedProcessingBlockComponent.h">
+      <Filter>world\blocks\components</Filter>
+    </ClInclude>
+    <ClInclude Include="UICraftingProgress.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="UIFuelState.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="UIObservable.h">
+      <Filter>UI\Observable</Filter>
+    </ClInclude>
+    <ClInclude Include="RecipieGroupConfig.h">
+      <Filter>inventory\recipies</Filter>
+    </ClInclude>
+    <ClInclude Include="PlantConfig.h">
+      <Filter>world\generator\biom\plants</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -461,9 +554,6 @@
     <ClCompile Include="WorldLoader.cpp">
       <Filter>world\loader</Filter>
     </ClCompile>
-    <ClCompile Include="WorldUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="Dimension.cpp">
       <Filter>world</Filter>
     </ClCompile>
@@ -509,12 +599,6 @@
     <ClCompile Include="ItemEntity.cpp">
       <Filter>entities</Filter>
     </ClCompile>
-    <ClCompile Include="AddEntityUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
-    <ClCompile Include="EntityRemovedUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="GeneratedStructure.cpp">
       <Filter>world\generator\templates</Filter>
     </ClCompile>
@@ -713,5 +797,95 @@
     <ClCompile Include="Animal.cpp">
       <Filter>entities\animals</Filter>
     </ClCompile>
+    <ClCompile Include="EntityGenerator.cpp">
+      <Filter>world\generator\biom\entityGenerator</Filter>
+    </ClCompile>
+    <ClCompile Include="NeutralAnimalAI.cpp">
+      <Filter>entities\animals</Filter>
+    </ClCompile>
+    <ClCompile Include="GameClient.cpp">
+      <Filter>game</Filter>
+    </ClCompile>
+    <ClCompile Include="BlockTypeNameFactory.cpp">
+      <Filter>server\config</Filter>
+    </ClCompile>
+    <ClCompile Include="ItemTypeNameFactory.cpp">
+      <Filter>server\config</Filter>
+    </ClCompile>
+    <ClCompile Include="SpecificItemDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="DropChanceCondition.cpp">
+      <Filter>drops\conditions</Filter>
+    </ClCompile>
+    <ClCompile Include="DropConditionOperator.cpp">
+      <Filter>drops\conditions</Filter>
+    </ClCompile>
+    <ClCompile Include="DropUsedItemCondition.cpp">
+      <Filter>drops\conditions</Filter>
+    </ClCompile>
+    <ClCompile Include="DropConfig.cpp">
+      <Filter>drops</Filter>
+    </ClCompile>
+    <ClCompile Include="DefaultBlockItemDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="DefaultInventoryDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="SpecificItemDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="MultiblockStructureManager.cpp">
+      <Filter>world\structures</Filter>
+    </ClCompile>
+    <ClCompile Include="BlockReplacementDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="UICraftingGrid.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="UIDialogElement.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="UIInventory.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="UIText.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="UIElement.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="UIReference.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="InteractionConfig.cpp">
+      <Filter>Interaction</Filter>
+    </ClCompile>
+    <ClCompile Include="OpenDialogInteractionConfig.cpp">
+      <Filter>Interaction</Filter>
+    </ClCompile>
+    <ClCompile Include="BlockComponent.cpp">
+      <Filter>world\blocks\components</Filter>
+    </ClCompile>
+    <ClCompile Include="FireBasedProcessingBlockComponent.cpp">
+      <Filter>world\blocks\components</Filter>
+    </ClCompile>
+    <ClCompile Include="UICraftingProgress.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="UIFuelState.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="UIObservable.cpp">
+      <Filter>UI\Observable</Filter>
+    </ClCompile>
+    <ClCompile Include="RecipieGroupConfig.cpp">
+      <Filter>inventory\recipies</Filter>
+    </ClCompile>
+    <ClCompile Include="PlantConfig.cpp">
+      <Filter>world\generator\biom\plants</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 553 - 0
FactoryCraft/FireBasedProcessingBlockComponent.cpp

@@ -0,0 +1,553 @@
+#include "FireBasedProcessingBlockComponent.h"
+
+#include "Block.h"
+#include "ItemFilter.h"
+#include "Recipie.h"
+#include "RecipieList.h"
+#include "RecipieLoader.h"
+
+FireBasedProcessingBlockComponent::FireBasedProcessingBlockComponent()
+    : BlockComponent(),
+      burnLight(0),
+      ticksNeeded(0),
+      currentRecipie(0),
+      maxFuelBuffer(0),
+      fuelBuffer(0),
+      burning(0)
+{}
+
+FireBasedProcessingBlockComponent::~FireBasedProcessingBlockComponent() {}
+
+bool FireBasedProcessingBlockComponent::findRecipie()
+{
+    bool changed = 0;
+    RecipieList* zRecipies
+        = Game::INSTANCE->zRecipies()->zRecipieList(recipieGroup.getText());
+    if (zRecipies)
+    {
+        zBlock->lock();
+        Recipie* recipie = zRecipies->zFirstRecipie(this);
+        if (recipie)
+        {
+            recipie->consumeInputs(this);
+            currentRecipie = recipie;
+            ticksNeeded = recipie->getTicksNeeded();
+            changed = 1;
+        }
+        zBlock->unlock();
+    }
+    return changed;
+}
+
+bool FireBasedProcessingBlockComponent::consumeFuel()
+{
+    bool changed = 0;
+    zBlock->lock();
+    ItemSlot* fireStartingSlot = 0;
+    ItemSlot* fuelSlot = 0;
+    for (ItemSlot* slot : *zBlock)
+    {
+        if (slot->zStack())
+        {
+            if (!burning && !fireStartingSlot
+                && slot->getName().istGleich(fireStartingInventorySlotName)
+                && fireStartingItemFilter->matchItem(slot->zStack()->zItem()))
+            {
+                fireStartingSlot = slot;
+            }
+            if (!fuelSlot && slot->getName().istGleich(fuelInventorySlotName)
+                && fuelItemFilter->matchItem(slot->zStack()->zItem()))
+            {
+                fuelSlot = slot;
+            }
+            if (fuelSlot && fireStartingSlot)
+            {
+                break;
+            }
+        }
+    }
+    if (burning)
+    {
+        if (fuelSlot)
+        {
+            ItemStack* fuelStack
+                = zBlock->takeItemsOut(fuelSlot, 1, Direction::NO_DIRECTION);
+            if (fuelStack)
+            {
+                // TODO: check if item is burnable and how much fuel it provides
+                fuelBuffer += 1000;
+                maxFuelBuffer = fuelBuffer;
+                fuelStack->release();
+                changed = 1;
+            }
+            else
+            {
+                if (fuelBuffer == 0)
+                {
+                    burning = false;
+                }
+            }
+        }
+        else
+        {
+            if (fuelBuffer == 0)
+            {
+                burning = false;
+            }
+        }
+    }
+    else
+    {
+        if (fuelSlot && fireStartingSlot)
+        {
+            ItemStack* fuelStack
+                = zBlock->takeItemsOut(fuelSlot, 1, Direction::NO_DIRECTION);
+            ItemStack* fireStartingStack = zBlock->takeItemsOut(
+                fireStartingSlot, 1, Direction::NO_DIRECTION);
+            if (fuelStack && fireStartingStack)
+            {
+                // TODO: check if item is burnable and how much fuel it provides
+                fuelBuffer += 1000;
+                maxFuelBuffer = fuelBuffer;
+                burning = true;
+                fuelStack->release();
+                fireStartingStack->release();
+                changed = 1;
+            }
+        }
+    }
+    zBlock->unlock();
+    return changed;
+}
+
+void FireBasedProcessingBlockComponent::createProgressMessage(
+    NetworkMessage* message) const
+{
+    char* msg = new char[8];
+    *(int*)msg = currentRecipie ? currentRecipie->getTicksNeeded() : 0;
+    *(int*)(msg + 4)
+        = currentRecipie ? currentRecipie->getTicksNeeded() - ticksNeeded : 0;
+    message->setMessage(msg, 8);
+}
+
+void FireBasedProcessingBlockComponent::createFuelMessage(
+    NetworkMessage* message) const
+{
+    char* msg = new char[8];
+    *(int*)msg = maxFuelBuffer;
+    *(int*)(msg + 4) = fuelBuffer;
+    message->setMessage(msg, 8);
+}
+
+void FireBasedProcessingBlockComponent::initialize(Block* zBlock)
+{
+    this->zBlock = zBlock;
+}
+
+bool FireBasedProcessingBlockComponent::tick(int numTicks)
+{
+    bool active = 0;
+    bool progressChanged = 0;
+    bool fuelChanged = 0;
+    while (numTicks > 0)
+    {
+        if (!fuelBuffer)
+        {
+            fuelChanged |= consumeFuel();
+        }
+        if (!burning)
+        {
+            break;
+        }
+        if (!currentRecipie)
+        {
+            progressChanged |= findRecipie();
+        }
+        bool processed = false;
+        if (currentRecipie)
+        {
+            int possibleTicks
+                = fuelBuffer / currentRecipie->getFuelPerTickNeeded();
+            if (!possibleTicks)
+            {
+                fuelChanged |= consumeFuel();
+                possibleTicks
+                    = fuelBuffer / currentRecipie->getFuelPerTickNeeded();
+            }
+            if (possibleTicks >= numTicks)
+            {
+                if (numTicks >= ticksNeeded)
+                {
+                    numTicks -= ticksNeeded;
+                    fuelBuffer
+                        -= currentRecipie->getFuelPerTickNeeded() * ticksNeeded;
+                    zBlock->lock();
+                    currentRecipie->produceOutputs(this);
+                    zBlock->unlock();
+                    ticksNeeded = 0;
+                    currentRecipie = 0;
+                }
+                else
+                {
+                    ticksNeeded -= numTicks;
+                    fuelBuffer
+                        -= currentRecipie->getFuelPerTickNeeded() * numTicks;
+                    numTicks = 0;
+                }
+                progressChanged = 1;
+                fuelChanged = 1;
+                processed = true;
+            }
+            else
+            {
+                if (possibleTicks >= ticksNeeded)
+                {
+                    numTicks -= ticksNeeded;
+                    fuelBuffer
+                        -= currentRecipie->getFuelPerTickNeeded() * ticksNeeded;
+                    zBlock->lock();
+                    currentRecipie->produceOutputs(this);
+                    zBlock->unlock();
+                    ticksNeeded = 0;
+                    currentRecipie = 0;
+                    processed = true;
+                    fuelChanged = 1;
+                    progressChanged = 1;
+                }
+                else
+                {
+                    numTicks -= possibleTicks;
+                    fuelBuffer -= currentRecipie->getFuelPerTickNeeded()
+                                * possibleTicks;
+                    ticksNeeded -= possibleTicks;
+                    processed = possibleTicks > 0;
+                    progressChanged = possibleTicks > 0;
+                    fuelChanged = possibleTicks > 0;
+                }
+            }
+        }
+        if (!processed)
+        {
+            // burning without recipie
+            if (fuelBuffer >= numTicks)
+            {
+                fuelBuffer -= numTicks;
+                numTicks = 0;
+                fuelChanged = 1;
+            }
+            else
+            {
+                fuelChanged = fuelBuffer > 0;
+                numTicks -= fuelBuffer;
+                fuelBuffer = 0;
+            }
+        }
+        active = 1;
+    }
+    if (fuelChanged)
+    {
+        NetworkMessage* fuelMessage = new NetworkMessage();
+        createFuelMessage(fuelMessage);
+        fuelObservable.notifyObservers(fuelMessage);
+    }
+    if (progressChanged)
+    {
+        NetworkMessage* progressMessage = new NetworkMessage();
+        createProgressMessage(progressMessage);
+        progressObservable.notifyObservers(progressMessage);
+    }
+    return active;
+}
+
+void FireBasedProcessingBlockComponent::api(Framework::StreamReader* zRequest,
+    NetworkMessage* zResponse,
+    Entity* zSource)
+{
+    char type;
+    zRequest->lese(&type, 1);
+    switch (type)
+    {
+    case 0: // subscribe to fuel
+        {
+            char idLen;
+            zRequest->lese(&idLen, 1);
+            char* id = new char[idLen + 1];
+            zRequest->lese(id, idLen);
+            id[(int)idLen] = 0;
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            fuelObservable.addObserver(zSource, id, processor);
+            createFuelMessage(zResponse);
+            zResponse->addressUIElement(id, processor);
+            break;
+        }
+    case 1: // subscribe to progress
+        {
+            char idLen;
+            zRequest->lese(&idLen, 1);
+            char* id = new char[idLen + 1];
+            zRequest->lese(id, idLen);
+            id[(int)idLen] = 0;
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            progressObservable.addObserver(zSource, id, processor);
+            createProgressMessage(zResponse);
+            zResponse->addressUIElement(id, processor);
+            break;
+        }
+    case 2: // unsubscribe to fuel
+        {
+            char idLen;
+            zRequest->lese(&idLen, 1);
+            char* id = new char[idLen + 1];
+            zRequest->lese(id, idLen);
+            id[(int)idLen] = 0;
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            fuelObservable.removeObserver(zSource, id, processor);
+            break;
+        }
+    case 3: // unsubscribe to progress
+        {
+            char idLen;
+            zRequest->lese(&idLen, 1);
+            char* id = new char[idLen + 1];
+            zRequest->lese(id, idLen);
+            id[(int)idLen] = 0;
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            progressObservable.removeObserver(zSource, id, processor);
+            break;
+        }
+    }
+}
+
+Framework::XML::Element*
+FireBasedProcessingBlockComponent::getTooltipUIML() const
+{
+    if (currentRecipie)
+    {
+        Framework::XML::Element* result = new Framework::XML::Element(
+            "<text width=\"auto\" height=\"auto\"></text>");
+        Framework::Text content;
+        content.append() << "Processing: ";
+        int first = 1;
+        for (const ItemInfo& output : currentRecipie->getOutput())
+        {
+            if (!first)
+            {
+                content.append() << ", ";
+            }
+            content.append()
+                << output.count << " "
+                << Game::INSTANCE->zItemType(output.type)->getTooltipUIML();
+            first = 0;
+        }
+        content.append()
+            << " ("
+            << (int)((ticksNeeded / currentRecipie->getTicksNeeded()) * 100)
+            << "%)";
+        result->setText(content);
+    }
+    return 0;
+}
+
+bool FireBasedProcessingBlockComponent::isAllAvailable(
+    Framework::RCArray<RecipieInput>& inputs)
+{
+    return zBlock->isAllAvailable(inputs, inputInventorySlotName);
+}
+
+bool FireBasedProcessingBlockComponent::hasFreeSpace(
+    const Item* zItem, int amount)
+{
+    int addable = zBlock->numberOfAddableItems(
+        zItem, NO_DIRECTION, outputInventorySlotName);
+    return addable >= amount;
+}
+
+void FireBasedProcessingBlockComponent::consume(
+    Framework::RCArray<RecipieInput>& inputs)
+{
+    zBlock->consume(inputs, inputInventorySlotName);
+}
+
+void FireBasedProcessingBlockComponent::addCraftingResult(ItemStack* zStack)
+{
+    TargetSlotNameItemFilter filter(outputInventorySlotName);
+    zBlock->unsaveAddItem(zStack, NO_DIRECTION, &filter);
+}
+
+Framework::Vec3<float>
+FireBasedProcessingBlockComponent::getStorageLocation() const
+{
+    return zBlock->getLocation();
+}
+
+int FireBasedProcessingBlockComponent::getStorageDimensionId() const
+{
+    return zBlock->getDimensionId();
+}
+
+void FireBasedProcessingBlockComponent::loadComponent(
+    Framework::StreamReader* zReader)
+{
+    zReader->lese((char*)&ticksNeeded, 4);
+    zReader->lese((char*)&maxFuelBuffer, 4);
+    zReader->lese((char*)&fuelBuffer, 4);
+    zReader->lese((char*)&burning, 1);
+    int index = 0;
+    zReader->lese((char*)&index, 4);
+    if (index >= 0)
+    {
+        // TODO: add unique recipie ids to enshure correct loading after
+        // recipies were changed, added or removed
+        RecipieList* recipies
+            = Game::INSTANCE->zRecipies()->zRecipieList(recipieGroup);
+        if (recipies && index < recipies->getRecipieCount())
+        {
+            currentRecipie = recipies->zRecipie(index);
+        }
+    }
+}
+
+void FireBasedProcessingBlockComponent::saveComponent(
+    Framework::StreamWriter* zWriter) const
+{
+    zWriter->schreibe((char*)&ticksNeeded, 4);
+    zWriter->schreibe((char*)&maxFuelBuffer, 4);
+    zWriter->schreibe((char*)&fuelBuffer, 4);
+    zWriter->schreibe((char*)&burning, 1);
+    int index = -1;
+    if (currentRecipie)
+    {
+        // TODO: add unique recipie ids to enshure correct loading after
+        // recipies were changed, added or removed
+        RecipieList* recipies
+            = Game::INSTANCE->zRecipies()->zRecipieList(recipieGroup);
+        if (recipies)
+        {
+            index = recipies->getRecipieIndex(currentRecipie);
+        }
+    }
+    zWriter->schreibe((char*)&index, 4);
+}
+
+bool FireBasedProcessingBlockComponent::isLightSource() const
+{
+    return 1;
+}
+
+int FireBasedProcessingBlockComponent::getLightColor() const
+{
+    return burning ? burnLight : 0;
+}
+
+FireBasedProcessingBlockComponentFactory::
+    FireBasedProcessingBlockComponentFactory()
+    : SubTypeFactory()
+{}
+
+FireBasedProcessingBlockComponent*
+FireBasedProcessingBlockComponentFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    FireBasedProcessingBlockComponent* component
+        = new FireBasedProcessingBlockComponent();
+    if (zJson->hasValue("fireStartingItemFilter"))
+    {
+        component->fireStartingItemFilter
+            = Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
+                zJson->zValue("fireStartingItemFilter"));
+    }
+    else
+    {
+        component->fireStartingItemFilter = new AnyItemFilter();
+    }
+    if (zJson->hasValue("fuelItemFilter"))
+    {
+        component->fuelItemFilter
+            = Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
+                zJson->zValue("fuelItemFilter"));
+    }
+    else
+    {
+        component->fuelItemFilter = new AnyItemFilter();
+    }
+    component->recipieGroup
+        = zJson->zValue("recipieGroup")->asString()->getString();
+    component->fuelInventorySlotName
+        = zJson->zValue("fuelInventorySlotName")->asString()->getString();
+    component->fireStartingInventorySlotName
+        = zJson->zValue("fireStartingInventorySlotName")
+              ->asString()
+              ->getString();
+    component->inputInventorySlotName
+        = zJson->zValue("inputInventorySlotName")->asString()->getString();
+    component->outputInventorySlotName
+        = zJson->zValue("outputInventorySlotName")->asString()->getString();
+    component->burnLight
+        = (int)zJson->zValue("lightColor")->asString()->getString();
+    return component;
+}
+
+Framework::JSON::JSONObject*
+FireBasedProcessingBlockComponentFactory::toJsonObject(
+    FireBasedProcessingBlockComponent* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("fireStartingItemFilter",
+        Game::INSTANCE->zTypeRegistry()->toJson(
+            zObject->fireStartingItemFilter));
+    result->addValue("fuelItemFilter",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->fuelItemFilter));
+    result->addValue("recipieGroup",
+        new Framework::JSON::JSONString(zObject->recipieGroup.getText()));
+    result->addValue("fuelInventorySlotName",
+        new Framework::JSON::JSONString(
+            zObject->fuelInventorySlotName.getText()));
+    result->addValue("fireStartingInventorySlotName",
+        new Framework::JSON::JSONString(
+            zObject->fireStartingInventorySlotName.getText()));
+    result->addValue("inputInventorySlotName",
+        new Framework::JSON::JSONString(
+            zObject->inputInventorySlotName.getText()));
+    result->addValue("outputInventorySlotName",
+        new Framework::JSON::JSONString(
+            zObject->outputInventorySlotName.getText()));
+    Framework::Text color = "0x";
+    color.appendHex(zObject->burnLight);
+    result->addValue("lightColor", new Framework::JSON::JSONString(color));
+    return result;
+}
+
+JSONObjectValidationBuilder*
+FireBasedProcessingBlockComponentFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder
+        ->withRequiredAttribute("fireStartingItemFilter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemFilter>())
+        ->withRequiredAttribute("fuelItemFilter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemFilter>())
+        ->withRequiredString("recipieGroup")
+        ->finishString()
+        ->withRequiredString("fuelInventorySlotName")
+        ->finishString()
+        ->withRequiredString("fireStartingInventorySlotName")
+        ->finishString()
+        ->withRequiredString("inputInventorySlotName")
+        ->finishString()
+        ->withRequiredString("outputInventorySlotName")
+        ->finishString()
+        ->withRequiredString("lightColor")
+        ->whichStartsWithMatch("0x")
+        ->withDefault("0x0")
+        ->finishString();
+    return builder;
+}
+
+const char* FireBasedProcessingBlockComponentFactory::getTypeToken() const
+{
+    return "fireBasedProcessing";
+}

+ 75 - 0
FactoryCraft/FireBasedProcessingBlockComponent.h

@@ -0,0 +1,75 @@
+#pragma once
+
+#include "BlockComponent.h"
+#include "CraftingStorage.h"
+#include "TypeRegistry.h"
+#include "UIObservable.h"
+
+class ItemFilter;
+
+class FireBasedProcessingBlockComponent : public BlockComponent,
+                                          public CraftingStorage
+{
+private:
+    UIObservable fuelObservable;
+    UIObservable progressObservable;
+    Block* zBlock;
+    ItemFilter* fireStartingItemFilter;
+    ItemFilter* fuelItemFilter;
+    Framework::Text recipieGroup;
+    Framework::Text fuelInventorySlotName;
+    Framework::Text fireStartingInventorySlotName;
+    Framework::Text inputInventorySlotName;
+    Framework::Text outputInventorySlotName;
+    int burnLight;
+    int ticksNeeded;
+    Recipie* currentRecipie;
+    int maxFuelBuffer;
+    int fuelBuffer;
+    bool burning;
+
+public:
+    FireBasedProcessingBlockComponent();
+    virtual ~FireBasedProcessingBlockComponent();
+
+protected:
+    bool findRecipie();
+    bool consumeFuel();
+    void createProgressMessage(NetworkMessage* message) const;
+    void createFuelMessage(NetworkMessage* message) const;
+
+public:
+    virtual void initialize(Block* zBlock) override;
+    virtual bool tick(int numTicks) override;
+    virtual void api(Framework::StreamReader* zRequest,
+        NetworkMessage* zResponse,
+        Entity* zSource) override;
+    virtual Framework::XML::Element* getTooltipUIML() const override;
+    virtual bool isAllAvailable(
+        Framework::RCArray<RecipieInput>& inputs) override;
+    virtual bool hasFreeSpace(const Item* zItem, int amount) override;
+    virtual void consume(Framework::RCArray<RecipieInput>& inputs) override;
+    virtual void addCraftingResult(ItemStack* zStack) override;
+    virtual Framework::Vec3<float> getStorageLocation() const override;
+    virtual int getStorageDimensionId() const override;
+    virtual void loadComponent(Framework::StreamReader* zReader) override;
+    virtual void saveComponent(Framework::StreamWriter* zWriter) const override;
+    virtual bool isLightSource() const override;
+    virtual int getLightColor() const override;
+
+    friend class FireBasedProcessingBlockComponentFactory;
+};
+
+class FireBasedProcessingBlockComponentFactory
+    : public SubTypeFactory<BlockComponent, FireBasedProcessingBlockComponent>
+{
+public:
+    FireBasedProcessingBlockComponentFactory();
+    FireBasedProcessingBlockComponent* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        FireBasedProcessingBlockComponent* zObject) const override;
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+};

+ 2 - 3
FactoryCraft/FlattenNoise.cpp

@@ -19,7 +19,6 @@ int FlattenNoise::getSeed() const
 
 double FlattenNoise::getNoise(double x, double y, double z)
 {
-    return MAX(
-        MIN((base->getNoise(x, y, z) - 0.5) * factor + 0.5 + minValue, 1.0),
-        0.0);
+    double value = (base->getNoise(x, y, z) - 0.5) * factor + 0.5 + minValue;
+    return MAX(MIN(value, 1.0), 0.0);
 }

+ 53 - 72
FactoryCraft/FluidBlock.cpp

@@ -2,6 +2,7 @@
 
 #include <Logging.h>
 
+#include "BlockType.h"
 #include "Dimension.h"
 #include "FluidContainer.h"
 #include "Game.h"
@@ -12,7 +13,6 @@ FluidBlock::FluidBlock(int typeId,
     Framework::Vec3<float> lightWeights)
     : Block(typeId, pos, dimensionId, 0),
       lightWeights(lightWeights),
-      neighborChanged(1),
       nextFlow(0),
       maxFlowDistance(8)
 {
@@ -31,37 +31,26 @@ FluidBlock::~FluidBlock() {}
 
 bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
 {
-    if (neighborChanged)
+    nextFlow -= numTicks;
+    if (nextFlow <= 0)
     {
-        nextFlow -= numTicks;
-        if (nextFlow <= 0)
+        const FluidBlockType* zType
+            = dynamic_cast<const FluidBlockType*>(zBlockType());
+        if (zType)
         {
-            const FluidBlockType* zType
-                = dynamic_cast<const FluidBlockType*>(zBlockType());
-            if (zType)
-            {
-                nextFlow = zType->getTicktsToFlow();
-            }
-            else
-            {
-                nextFlow = 0;
-            }
-            neighborChanged = 0;
-            doFlow();
+            nextFlow = zType->getTicktsToFlow();
+        }
+        else
+        {
+            nextFlow = 0;
         }
-        return true;
+        doFlow();
     }
-    return false;
+    return true;
 }
 
 void FluidBlock::onPostTick() {}
 
-void FluidBlock::setNeighbourType(Direction dir, int type)
-{
-    Block::setNeighbourType(dir, type);
-    neighborChanged = 1;
-}
-
 void FluidBlock::sendModelInfo(NetworkMessage* zMessage)
 {
     zMessage->addressBlock(this);
@@ -75,12 +64,10 @@ void FluidBlock::sendModelInfo(NetworkMessage* zMessage)
 void FluidBlock::doFlow()
 {
     bool doesFlowSidewards = 1;
-    if (((zNeighbours[getDirectionIndex(Direction::BOTTOM)]
-                 && zNeighbours[getDirectionIndex(Direction::BOTTOM)]
-                            ->zBlockType()
-                        == zBlockType()
-             || neighbourTypes[getDirectionIndex(Direction::BOTTOM)]
-                    == BlockTypeEnum::AIR)
+    Framework::Either<Block*, int> below = Game::INSTANCE->zBlockAt(
+        getPos() + getDirection(Direction::BOTTOM), getDimensionId(), 0);
+    if (((below.isA() && below.getA()->zBlockType() == zBlockType()
+             || below.getB() == BlockTypeEnum::AIR)
             && distanceToSource)
         || distanceToSource >= maxFlowDistance)
     {
@@ -92,23 +79,28 @@ void FluidBlock::doFlow()
     for (int i = 0; i < 6; i++)
     {
         Direction dir = getDirectionFromIndex(i);
+        Framework::Either<Block*, int> neighbor = Game::INSTANCE->zBlockAt(
+            getPos() + getDirection(dir), getDimensionId(), 0);
         if (dir & Direction::TOP)
         {
-            if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType())
+            if (neighbor.isA() && neighbor.getA()->zBlockType() == zBlockType())
             {
                 FluidBlock* neighbour
-                    = dynamic_cast<FluidBlock*>(zNeighbours[i]);
+                    = dynamic_cast<FluidBlock*>(neighbor.getA());
                 minNeighborDistance = 0;
                 nextFlowOptions = (char)getOppositeDirection(dir);
             }
             continue;
         }
-        if (neighbourTypes[i] == BlockTypeEnum::AIR)
+        if (neighbor.isB() && neighbor.getB() == BlockTypeEnum::AIR)
         {
             if (dir & Direction::BOTTOM || doesFlowSidewards)
             {
                 Game::INSTANCE->doLater([this, dir, i]() {
-                    if (neighbourTypes[i] == BlockTypeEnum::AIR)
+                    Framework::Either<Block*, int> neighbor
+                        = Game::INSTANCE->zBlockAt(
+                            getPos() + getDirection(dir), getDimensionId(), 0);
+                    if (neighbor.isB() && neighbor.getB() == BlockTypeEnum::AIR)
                     {
                         Block* belowBlock = zBlockType()->createBlockAt(
                             getPos() + getDirection(dir), getDimensionId(), 0);
@@ -136,10 +128,11 @@ void FluidBlock::doFlow()
                 });
             }
         }
-        else if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType())
+        else if (neighbor.isA()
+                 && neighbor.getA()->zBlockType() == zBlockType())
         {
             if (dir & Direction::BOTTOM) continue;
-            FluidBlock* neighbour = dynamic_cast<FluidBlock*>(zNeighbours[i]);
+            FluidBlock* neighbour = dynamic_cast<FluidBlock*>(neighbor.getA());
             if (neighbour)
             {
                 if (neighbour->distanceToSource < minNeighborDistance)
@@ -166,26 +159,11 @@ void FluidBlock::doFlow()
     if (distanceToSource > maxFlowDistance)
     {
         distanceToSource = maxFlowDistance;
-        Game::INSTANCE->doLater([this]() { setHP(0.f); });
+        Game::INSTANCE->doLater([this]() { setHP(0, 0, 0, 0.f); });
     }
     if (changed)
     {
         broadcastModelInfoChange();
-        neighborChanged = 1;
-        for (int i = 0; i < 6; i++)
-        {
-            Direction dir = getDirectionFromIndex(i);
-            if (dir & (Direction::TOP | Direction::BOTTOM)) continue;
-            if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType())
-            {
-                FluidBlock* neighbour
-                    = dynamic_cast<FluidBlock*>(zNeighbours[i]);
-                if (neighbour)
-                {
-                    neighbour->neighborChanged = 1;
-                }
-            }
-        }
     }
 }
 
@@ -209,7 +187,7 @@ TickSourceType FluidBlock::isTickSource() const
 
 bool FluidBlock::needsTick() const
 {
-    return neighborChanged;
+    return true;
 }
 
 char FluidBlock::getDistanceToSource() const
@@ -347,10 +325,11 @@ FluidBlockType* FluidBlockTypeFactory::createValue(
     return new FluidBlockType();
 }
 
-void FluidBlockTypeFactory::fromJson(
-    FluidBlockType* zResult, Framework::JSON::JSONObject* zJson) const
+FluidBlockType* FluidBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setLightWeights(
+    FluidBlockType* result = BlockTypeFactoryBase::fromJson(zJson);
+    result->setLightWeights(
         Framework::Vec3<float>((float)zJson->zValue("lightWeight")
                                    ->asObject()
                                    ->zValue("red")
@@ -366,21 +345,23 @@ void FluidBlockTypeFactory::fromJson(
                 ->zValue("blue")
                 ->asNumber()
                 ->getNumber()));
-    zResult->setTicktsToFlow(
+    result->setTicktsToFlow(
         (int)zJson->zValue("ticksToFlow")->asNumber()->getNumber());
-    zResult->setFlowDistance(
+    result->setFlowDistance(
         (char)zJson->zValue("flowDistance")->asNumber()->getNumber());
-    zResult->setHungerRecoveryPerL(
+    result->setHungerRecoveryPerL(
         (float)zJson->zValue("hungerRecoveryPerL")->asNumber()->getNumber());
-    zResult->setThirstRecoveryPerL(
+    result->setThirstRecoveryPerL(
         (float)zJson->zValue("thirstRecoveryPerL")->asNumber()->getNumber());
-    zResult->setHeat((float)zJson->zValue("heat")->asNumber()->getNumber());
-    BlockTypeFactoryBase::fromJson(zResult, zJson);
+    result->setHeat((float)zJson->zValue("heat")->asNumber()->getNumber());
+    return result;
 }
 
-void FluidBlockTypeFactory::toJson(
-    FluidBlockType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* FluidBlockTypeFactory::toJsonObject(
+    FluidBlockType* zObject) const
 {
+    Framework::JSON::JSONObject* result
+        = BlockTypeFactoryBase::toJsonObject(zObject);
     Framework::JSON::JSONObject* lightWeight
         = new Framework::JSON::JSONObject();
     lightWeight->addValue(
@@ -389,20 +370,20 @@ void FluidBlockTypeFactory::toJson(
         "green", new Framework::JSON::JSONNumber(zObject->getLightWeights().y));
     lightWeight->addValue(
         "blue", new Framework::JSON::JSONNumber(zObject->getLightWeights().z));
-    zResult->addValue("lightWeight", lightWeight);
-    zResult->addValue("ticksToFlow",
+    result->addValue("lightWeight", lightWeight);
+    result->addValue("ticksToFlow",
         new Framework::JSON::JSONNumber((double)zObject->getTicktsToFlow()));
-    zResult->addValue("flowDistance",
+    result->addValue("flowDistance",
         new Framework::JSON::JSONNumber((double)zObject->getFlowDistance()));
-    zResult->addValue("hungerRecoveryPerL",
+    result->addValue("hungerRecoveryPerL",
         new Framework::JSON::JSONNumber(
             (double)zObject->getHungerRecoveryPerL()));
-    zResult->addValue("thirstRecoveryPerL",
+    result->addValue("thirstRecoveryPerL",
         new Framework::JSON::JSONNumber(
             (double)zObject->getThirstRecoveryPerL()));
-    zResult->addValue(
+    result->addValue(
         "heat", new Framework::JSON::JSONNumber((double)zObject->getHeat()));
-    BlockTypeFactoryBase::toJson(zObject, zResult);
+    return result;
 }
 
 JSONObjectValidationBuilder* FluidBlockTypeFactory::addToValidator(
@@ -442,7 +423,7 @@ JSONObjectValidationBuilder* FluidBlockTypeFactory::addToValidator(
             ->finishNumber());
 }
 
-Framework::Text FluidBlockTypeFactory::getTypeToken() const
+const char* FluidBlockTypeFactory::getTypeToken() const
 {
     return "fluid";
 }

+ 4 - 7
FactoryCraft/FluidBlock.h

@@ -13,7 +13,6 @@ private:
     char distanceToSource;
     int nextFlow;
     Framework::Vec3<float> lightWeights;
-    bool neighborChanged;
     unsigned char maxFlowDistance;
 
 protected:
@@ -29,7 +28,6 @@ public:
         Framework::Vec3<float> lightWeights);
     virtual ~FluidBlock();
 
-    virtual void setNeighbourType(Direction dir, int type) override;
     virtual void sendModelInfo(NetworkMessage* zMessage) override;
 
     virtual bool isInteractable(const Item* zItem) const override;
@@ -89,11 +87,10 @@ public:
     FluidBlockTypeFactory();
     FluidBlockType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(FluidBlockType* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(FluidBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    FluidBlockType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        FluidBlockType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 70 - 72
FactoryCraft/FluidContainer.cpp

@@ -1,8 +1,8 @@
 #include "FluidContainer.h"
 
 #include <Logging.h>
-#include <TextFeld.h>
 
+#include "BlockType.h"
 #include "Dimension.h"
 #include "Entity.h"
 #include "FluidBlock.h"
@@ -232,61 +232,55 @@ float FluidContainerItemSkillConfig::getXpGain() const
 }
 
 FluidContainerItemSkillConfigFactory::FluidContainerItemSkillConfigFactory()
-    : TypeFactory()
+    : ObjectTypeFactory()
 {}
 
-FluidContainerItemSkillConfig*
-FluidContainerItemSkillConfigFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new FluidContainerItemSkillConfig();
-}
-
-void FluidContainerItemSkillConfigFactory::fromJson(
-    FluidContainerItemSkillConfig* zResult,
+FluidContainerItemSkillConfig* FluidContainerItemSkillConfigFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setTargetFilter(
+    FluidContainerItemSkillConfig* result = new FluidContainerItemSkillConfig();
+    result->setTargetFilter(
         Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
             zJson->asObject()->zValue("targetFilter")));
-    zResult->setStaminaCost((float)zJson->asObject()
-                                ->zValue("staminaCost")
-                                ->asNumber()
-                                ->getNumber());
-    zResult->setStaminaCostDevider((float)zJson->asObject()
-                                       ->zValue("staminaCostDevider")
-                                       ->asNumber()
-                                       ->getNumber());
-    zResult->setStaminaCostDeviderPerLevel(
-        (float)zJson->asObject()
+    result->setStaminaCost((float)zJson->asObject()
+            ->zValue("staminaCost")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCostDevider((float)zJson->asObject()
+            ->zValue("staminaCostDevider")
+            ->asNumber()
+            ->getNumber());
+    result->setStaminaCostDeviderPerLevel((float)zJson->asObject()
             ->zValue("staminaCostDeviderPerLevel")
             ->asNumber()
             ->getNumber());
-    zResult->setCooldownTicks((int)zJson->asObject()
-                                  ->zValue("cooldownTicks")
-                                  ->asNumber()
-                                  ->getNumber());
-    zResult->setXpGain(
+    result->setCooldownTicks((int)zJson->asObject()
+            ->zValue("cooldownTicks")
+            ->asNumber()
+            ->getNumber());
+    result->setXpGain(
         (float)zJson->asObject()->zValue("xpGain")->asNumber()->getNumber());
+    return result;
 }
 
-void FluidContainerItemSkillConfigFactory::toJson(
-    FluidContainerItemSkillConfig* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* FluidContainerItemSkillConfigFactory::toJsonObject(
+    FluidContainerItemSkillConfig* zObject) const
 {
-    zResult->addValue("targetFilter",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("targetFilter",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zTargetFilter()));
-    zResult->addValue("staminaCost",
+    result->addValue("staminaCost",
         new Framework::JSON::JSONNumber(zObject->getStaminaCost()));
-    zResult->addValue("staminaCostDevider",
+    result->addValue("staminaCostDevider",
         new Framework::JSON::JSONNumber(zObject->getStaminaCostDevider()));
-    zResult->addValue("staminaCostDeviderPerLevel",
+    result->addValue("staminaCostDeviderPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->getStaminaCostDeviderPerLevel()));
-    zResult->addValue("cooldownTicks",
+    result->addValue("cooldownTicks",
         new Framework::JSON::JSONNumber(zObject->getCooldownTicks()));
-    zResult->addValue(
+    result->addValue(
         "xpGain", new Framework::JSON::JSONNumber(zObject->getXpGain()));
+    return result;
 }
 
 JSONObjectValidationBuilder*
@@ -408,7 +402,7 @@ bool FluidContainerItemSkill::use(
     {
         usedItem->setFluidTypeId(fluidBlock->zBlockType()->getId());
         usedItem->setAmount(usedItem->getAmount() + 1000);
-        zTarget->setHP(0);
+        zTarget->setHP(zActor, zUsedItem, this, 0);
     }
     this->cooldownTicks = usedConfig->getCooldownTicks();
     setXp(getXp() + usedConfig->getXpGain());
@@ -456,15 +450,16 @@ FluidContainerItemSkill* FluidContainerItemSkillFactory::createValue(
     return new FluidContainerItemSkill();
 }
 
-void FluidContainerItemSkillFactory::fromJson(
-    FluidContainerItemSkill* zResult, Framework::JSON::JSONObject* zJson) const
+FluidContainerItemSkill* FluidContainerItemSkillFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
+    FluidContainerItemSkill* result = ItemSkillFactoryBase::fromJson(zJson);
     for (Framework::JSON::JSONValue* configValue :
         *zJson->zValue("configs")->asArray())
     {
-        zResult->addConfig(Game::INSTANCE->zTypeRegistry()
-                               ->fromJson<FluidContainerItemSkillConfig>(
-                                   configValue->asObject()));
+        result->addConfig(Game::INSTANCE->zTypeRegistry()
+                ->fromJson<FluidContainerItemSkillConfig>(
+                    configValue->asObject()));
     }
     FluidContainerItemSkillConfig* invalidConfig
         = new FluidContainerItemSkillConfig();
@@ -480,23 +475,25 @@ void FluidContainerItemSkillFactory::fromJson(
             ->getNumber());
     invalidConfig->setCooldownTicks(
         (int)zJson->zValue("invalidUseCooldownTicks")->asNumber()->getNumber());
-    zResult->setInvalidUseConfig(invalidConfig);
-    ItemSkillFactoryBase::fromJson(zResult, zJson);
+    result->setInvalidUseConfig(invalidConfig);
+    return result;
 }
 
-void FluidContainerItemSkillFactory::toJson(FluidContainerItemSkill* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* FluidContainerItemSkillFactory::toJsonObject(
+    FluidContainerItemSkill* zObject) const
 {
-    zResult->addValue("invalidUseStaminaCost",
+    Framework::JSON::JSONObject* result
+        = ItemSkillFactoryBase::toJsonObject(zObject);
+    result->addValue("invalidUseStaminaCost",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCost()));
-    zResult->addValue("invalidUseStaminaCostDevider",
+    result->addValue("invalidUseStaminaCostDevider",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCostDevider()));
-    zResult->addValue("invalidUseStaminaCostDeviderPerLevel",
+    result->addValue("invalidUseStaminaCostDeviderPerLevel",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getStaminaCostDeviderPerLevel()));
-    zResult->addValue("invalidUseCooldownTicks",
+    result->addValue("invalidUseCooldownTicks",
         new Framework::JSON::JSONNumber(
             zObject->zInvalidUseConfig()->getCooldownTicks()));
     Framework::JSON::JSONArray* configs = new Framework::JSON::JSONArray();
@@ -504,8 +501,8 @@ void FluidContainerItemSkillFactory::toJson(FluidContainerItemSkill* zObject,
     {
         configs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(config));
     }
-    zResult->addValue("configs", configs);
-    ItemSkillFactoryBase::toJson(zObject, zResult);
+    result->addValue("configs", configs);
+    return result;
 }
 
 JSONObjectValidationBuilder* FluidContainerItemSkillFactory::addToValidator(
@@ -529,13 +526,12 @@ JSONObjectValidationBuilder* FluidContainerItemSkillFactory::addToValidator(
         ->withDefault(10)
         ->finishNumber()
         ->withRequiredArray("configs")
-        ->addAcceptedTypeInArray(
-            Game::INSTANCE->zTypeRegistry()
+        ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
                 ->getValidator<FluidContainerItemSkillConfig>())
         ->finishArray();
 }
 
-Framework::Text FluidContainerItemSkillFactory::getTypeToken() const
+const char* FluidContainerItemSkillFactory::getTypeToken() const
 {
     return "fluidGathering";
 }
@@ -618,7 +614,7 @@ void FluidContainerItemType::setItemAttribute(
     }
     if (name.istGleich("fluidType"))
     {
-        if (zValue->getType() == Framework::JSON::JSONType::STRING)
+        if (zValue->getType() == Framework::AbstractType::STRING)
         {
             int id = ItemType::getTypeId(zValue->asString()->getString());
             if (id)
@@ -641,7 +637,7 @@ void FluidContainerItemType::setItemAttribute(
     }
     else if (name.istGleich("fluidAmount"))
     {
-        if (zValue->getType() == Framework::JSON::JSONType::NUMBER)
+        if (zValue->getType() == Framework::AbstractType::NUMBER)
         {
             item->fluidAmount = (int)zValue->asNumber()->getNumber();
         }
@@ -723,36 +719,38 @@ FluidContainerItemType* FluidContainerItemTypeFactory::createValue(
     return new FluidContainerItemType();
 }
 
-void FluidContainerItemTypeFactory::fromJson(
-    FluidContainerItemType* zResult, Framework::JSON::JSONObject* zJson) const
+FluidContainerItemType* FluidContainerItemTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setItemSkillConfig(zJson->getValue("itemSkill")->asObject());
-    zResult->setLevelUpRule(
+    FluidContainerItemType* result = ItemTypeFactoryBase::fromJson(zJson);
+    result->setItemSkillConfig(zJson->getValue("itemSkill")->asObject());
+    result->setLevelUpRule(
         Game::INSTANCE->zTypeRegistry()->fromJson<ItemSkillLevelUpRule>(
             zJson->zValue("levelUpRule")));
-    zResult->setMaxFluidAmount(
+    result->setMaxFluidAmount(
         (int)zJson->zValue("maxFluidAmount")->asNumber()->getNumber());
-    ItemTypeFactoryBase::fromJson(zResult, zJson);
+    return result;
 }
 
-void FluidContainerItemTypeFactory::toJson(
-    FluidContainerItemType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* FluidContainerItemTypeFactory::toJsonObject(
+    FluidContainerItemType* zObject) const
 {
-    zResult->addValue("levelUpRule",
+    Framework::JSON::JSONObject* result
+        = ItemTypeFactoryBase::toJsonObject(zObject);
+    result->addValue("levelUpRule",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zLevelUpRule()));
-    zResult->addValue("itemSkill",
+    result->addValue("itemSkill",
         dynamic_cast<Framework::JSON::JSONObject*>(
             zObject->zItemSkillConfig()->getThis()));
-    zResult->addValue("maxFluidAmount",
+    result->addValue("maxFluidAmount",
         new Framework::JSON::JSONNumber(zObject->getMaxFluidAmount()));
-    ItemTypeFactoryBase::toJson(zObject, zResult);
+    return result;
 }
 
 JSONObjectValidationBuilder* FluidContainerItemTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return ItemTypeFactoryBase::addToValidator(
-        builder
+    return ItemTypeFactoryBase::addToValidator(builder
             ->withRequiredAttribute("levelUpRule",
                 Game::INSTANCE->zTypeRegistry()
                     ->getValidator<ItemSkillLevelUpRule>())
@@ -764,7 +762,7 @@ JSONObjectValidationBuilder* FluidContainerItemTypeFactory::addToValidator(
             ->finishNumber());
 }
 
-Framework::Text FluidContainerItemTypeFactory::getTypeToken() const
+const char* FluidContainerItemTypeFactory::getTypeToken() const
 {
     return "fluidContainer";
 }

+ 13 - 14
FactoryCraft/FluidContainer.h

@@ -5,6 +5,7 @@
 #include "BlockFilter.h"
 #include "Item.h"
 #include "ItemSkill.h"
+#include "ItemType.h"
 
 class FluidContainerItemType;
 
@@ -61,16 +62,14 @@ public:
 };
 
 class FluidContainerItemSkillConfigFactory
-    : public TypeFactory<FluidContainerItemSkillConfig>
+    : public ObjectTypeFactory<FluidContainerItemSkillConfig>
 {
 public:
     FluidContainerItemSkillConfigFactory();
-    FluidContainerItemSkillConfig* createValue(
+    FluidContainerItemSkillConfig* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(FluidContainerItemSkillConfig* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(FluidContainerItemSkillConfig* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        FluidContainerItemSkillConfig* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -100,13 +99,13 @@ public:
     FluidContainerItemSkillFactory();
     FluidContainerItemSkill* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(FluidContainerItemSkill* zResult,
+    FluidContainerItemSkill* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(FluidContainerItemSkill* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        FluidContainerItemSkill* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class FluidContainerItemType : public ItemType
@@ -150,11 +149,11 @@ public:
     FluidContainerItemTypeFactory();
     FluidContainerItemType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(FluidContainerItemType* zResult,
+    FluidContainerItemType* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(FluidContainerItemType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        FluidContainerItemType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 142 - 371
FactoryCraft/Game.cpp

@@ -1,13 +1,11 @@
 #include "Game.h"
 
+#include <Datei.h>
 #include <Logging.h>
 
-#include "AddEntityUpdate.h"
-#include "AsynchronCall.h"
 #include "Chat.h"
 #include "Dimension.h"
 #include "Entity.h"
-#include "EntityRemovedUpdate.h"
 #include "ItemEntity.h"
 #include "JsonUtils.h"
 #include "MultiblockTree.h"
@@ -30,316 +28,13 @@ using namespace Framework;
 Framework::ConsoleHandler* Game::consoleHandler = 0;
 Framework::InputLine* Game::consoleInput = 0;
 
-GameClient::GameClient(Player* zPlayer, FCKlient* client)
-    : Thread(),
-      zPlayer(zPlayer),
-      client(client),
-      viewDistance(DEFAULT_VIEW_DISTANCE),
-      first(1),
-      online(1),
-      finished(0),
-      backgroundFinished(0),
-      foregroundFinished(0)
-{
-    new AsynchronCall("Game Client Updates", [this]() {
-        while (online)
-        {
-            other.lock();
-            if (updateQueue.hat(0))
-            {
-                WorldUpdate* update = updateQueue.get(0);
-                updateQueue.remove(0);
-                other.unlock();
-                background.lock();
-                this->client->zBackgroundWriter()->schreibe(
-                    (char*)&Message::WORLD_UPDATE, 1);
-                update->writeAndCheck(this->client->zBackgroundWriter());
-                background.unlock();
-                update->release();
-            }
-            else
-            {
-                other.unlock();
-                updateSync.wait();
-            }
-        }
-        finished = 1;
-    });
-    start();
-}
-
-GameClient::~GameClient()
-{
-    online = 0;
-    updateSync.notify();
-    emptyForegroundQueueSync.notifyAll();
-    emptyBackgroundQueueSync.notifyAll();
-    foregroundQueueSync.notify();
-    backgroundQueueSync.notify();
-    while (!finished || !foregroundFinished || !backgroundFinished)
-        Sleep(100);
-    client->release();
-}
-
-void GameClient::thread()
-{
-    new AsynchronCall("Game Client Background", [this]() {
-        while (online)
-        {
-            queueCs.lock();
-            if (backgroundQueue.hat(0))
-            {
-                NetworkMessage* message = backgroundQueue.get(0);
-                backgroundQueue.remove(0);
-                queueCs.unlock();
-                background.lock();
-                message->writeTo(client->zBackgroundWriter());
-                background.unlock();
-                message->release();
-            }
-            else
-            {
-                queueCs.unlock();
-                emptyBackgroundQueueSync.notifyAll();
-                while (!backgroundQueueSync.wait(1000))
-                {
-                    emptyBackgroundQueueSync.notifyAll();
-                }
-            }
-        }
-        backgroundFinished = 1;
-    });
-    while (online)
-    {
-        queueCs.lock();
-        if (foregroundQueue.hat(0))
-        {
-            NetworkMessage* message = foregroundQueue.get(0);
-            foregroundQueue.remove(0);
-            queueCs.unlock();
-            foreground.lock();
-            message->writeTo(client->zForegroundWriter());
-            foreground.unlock();
-            message->release();
-        }
-        else
-        {
-            queueCs.unlock();
-            emptyForegroundQueueSync.notifyAll();
-            while (!foregroundQueueSync.wait(1000))
-            {
-                emptyForegroundQueueSync.notifyAll();
-            }
-        }
-    }
-    foregroundFinished = 1;
-}
-
-void GameClient::sendWorldUpdate(WorldUpdate* update)
-{
-    bool add = 0;
-    if (zPlayer->getDimensionId() == update->getAffectedDimension())
-    {
-        auto pos = (Vec3<int>)zPlayer->getPosition();
-        int dist = update->distanceTo(pos.x, pos.y);
-        if (dist < viewDistance * CHUNK_SIZE)
-        {
-            other.lock();
-            updateQueue.add(update);
-            other.unlock();
-            updateSync.notify();
-            add = 1;
-        }
-    }
-    if (!add) update->release();
-}
-
-void GameClient::reply()
-{
-    other.lock();
-    for (auto req : requests)
-        Game::INSTANCE->api(req, this);
-    requests.leeren();
-    other.unlock();
-    if (first)
-    {
-        foreground.lock();
-        int id = zPlayer->getId();
-        client->zForegroundWriter()->schreibe(
-            (char*)&Message::POSITION_UPDATE, 1);
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        id = zPlayer->getDimensionId();
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        client->zForegroundWriter()->schreibe((char*)&Message::API_MESSAGE, 1);
-        int len = 10;
-        client->zForegroundWriter()->schreibe((char*)&len, 4);
-        client->zForegroundWriter()->schreibe("\1", 1);
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        client->zForegroundWriter()->schreibe("\6", 1);
-        float gravity = Game::INSTANCE->zDimension(zPlayer->getDimensionId())
-                            ->getGravity();
-        client->zForegroundWriter()->schreibe((char*)&gravity, 4);
-        foreground.unlock();
-        first = 0;
-    }
-}
-
-void GameClient::logout()
-{
-    online = 0;
-    updateSync.notify();
-    emptyForegroundQueueSync.notifyAll();
-    emptyBackgroundQueueSync.notifyAll();
-    foregroundQueueSync.notify();
-    backgroundQueueSync.notify();
-}
-
-void GameClient::addMessage(StreamReader* reader)
-{
-    short len = 0;
-    reader->lese((char*)&len, 2);
-    InMemoryBuffer* buffer = new InMemoryBuffer();
-    char* tmp = new char[len];
-    reader->lese(tmp, len);
-    buffer->schreibe(tmp, len);
-    delete[] tmp;
-    other.lock();
-    requests.add(buffer);
-    other.unlock();
-}
-
-bool GameClient::isOnline() const
-{
-    return online;
-}
-
-void GameClient::sendResponse(NetworkMessage* response)
-{
-    queueCs.lock();
-    if (response->isUseBackground())
-    {
-        if (backgroundQueue.getEintragAnzahl() > 20)
-        {
-            queueCs.unlock();
-            while (!emptyBackgroundQueueSync.wait(1000))
-            {
-                backgroundQueueSync.notify();
-            }
-            queueCs.lock();
-        }
-        backgroundQueue.add(response);
-        queueCs.unlock();
-        backgroundQueueSync.notify();
-    }
-    else
-    {
-        if (foregroundQueue.getEintragAnzahl() > 100)
-        {
-            queueCs.unlock();
-            Framework::Logging::warning()
-                << "Game paused because nework connection to "
-                << zPlayer->getName() << " is to slow.";
-            ZeitMesser m;
-            m.messungStart();
-            while (foregroundQueue.getEintragAnzahl() > 0)
-            {
-                foregroundQueueSync.notify();
-                emptyForegroundQueueSync.wait(100);
-            }
-            m.messungEnde();
-            Framework::Logging::warning()
-                << "Game resumed after " << m.getSekunden() << " seconds.";
-            queueCs.lock();
-        }
-        foregroundQueue.add(response);
-        queueCs.unlock();
-        foregroundQueueSync.notify();
-    }
-}
-
-Player* GameClient::zEntity() const
-{
-    return zPlayer;
-}
-
-void GameClient::sendTypes()
-{
-    foreground.lock();
-    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 < Game::INSTANCE->getBlockTypeCount(); i++)
-    {
-        const BlockType* t = Game::INSTANCE->zBlockType(i);
-        if (t)
-        {
-            t->writeTypeInfo(client->zForegroundWriter());
-        }
-    }
-    count = 0;
-    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zItemType(i)) count++;
-    }
-    client->zForegroundWriter()->schreibe((char*)&count, 4);
-    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-    {
-        const ItemType* t = Game::INSTANCE->zItemType(i);
-        if (t)
-        {
-            int id = t->getId();
-            client->zForegroundWriter()->schreibe((char*)&id, 4);
-            char len = (char)t->getName().getLength();
-            client->zForegroundWriter()->schreibe((char*)&len, 1);
-            client->zForegroundWriter()->schreibe(t->getName().getText(), len);
-            short tlen = (short)t->getTooltipUIML().getLength();
-            client->zForegroundWriter()->schreibe((char*)&tlen, 2);
-            client->zForegroundWriter()->schreibe(
-                t->getTooltipUIML().getText(), tlen);
-            if (t->zModel())
-            {
-                t->zModel()->writeTo(client->zForegroundWriter());
-            }
-            else
-            {
-                ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
-                    .writeTo(client->zForegroundWriter());
-            }
-        }
-    }
-    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 = Game::INSTANCE->zEntityType(i);
-        int id = t->getId();
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        if (t->zModel())
-        {
-            t->zModel()->writeTo(client->zForegroundWriter());
-        }
-        else
-        {
-            ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
-                .writeTo(client->zForegroundWriter());
-        }
-    }
-    foreground.unlock();
-}
-
 Game::Game(Framework::Text name, Framework::Text worldsDir)
     : Thread(),
       name(name),
       typeRegistry(new TypeRegistry()),
+      blockTypeNameFactory(new BlockTypeNameFactory()),
+      itemTypeNameFactory(new ItemTypeNameFactory()),
       dimensions(new RCArray<Dimension>()),
-      updates(new RCArray<WorldUpdate>()),
       clients(new RCArray<GameClient>()),
       questManager(new QuestManager()),
       ticker(new TickOrganizer()),
@@ -367,6 +62,11 @@ Game::Game(Framework::Text name, Framework::Text worldsDir)
       multiblockStructureTypes(0),
       multiblockStructureTypeCount(0)
 {
+    typeRegistry->registerType(
+        BlockTypeNameFactory::TYPE_ID, blockTypeNameFactory);
+    typeRegistry->registerType(
+        ItemTypeNameFactory::TYPE_ID, itemTypeNameFactory);
+
     if (!DateiExistiert(path)) DateiPfadErstellen(path + "/");
     Datei d;
     d.setDatei(path + "/eid");
@@ -382,7 +82,6 @@ Game::Game(Framework::Text name, Framework::Text worldsDir)
 Game::~Game()
 {
     dimensions->release();
-    updates->release();
     clients->release();
     generator->release();
     loader->release();
@@ -419,19 +118,19 @@ void Game::initialize()
     // load block types
     Framework::Logging::info() << "Loading block types";
     Framework::Array<BlockType*> blockTypeArray;
-    Framework::JSON::Validator::JSONValidator* validator
-        = Framework::JSON::Validator::JSONValidator::buildForArray()
+    Framework::Validator::DataValidator* validator
+        = Framework::Validator::DataValidator::buildForArray()
               ->addAcceptedTypeInArray(typeRegistry->getValidator<BlockType>())
               ->removeInvalidEntries()
               ->finishArray();
     loadAllJsonsFromDirectory("data/blocks",
         [this, &blockTypeArray, validator](
             Framework::JSON::JSONValue* zValue, Framework::Text path) {
-            Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+            Framework::RCArray<Framework::Validator::ValidationResult>
                 validationResults;
             Framework::JSON::JSONValue* validParts
                 = validator->getValidParts(zValue, &validationResults);
-            for (Framework::JSON::Validator::JSONValidationResult* result :
+            for (Framework::Validator::ValidationResult* result :
                 validationResults)
             {
                 Framework::Logging::error() << result->getInvalidInfo();
@@ -454,33 +153,39 @@ void Game::initialize()
     Framework::Logging::info() << "Loaded " << blockTypeArray.getEintragAnzahl()
                                << " block types from data/blocks";
     blockTypes = new BlockType*[2 + blockTypeArray.getEintragAnzahl()];
-    blockTypes[0]
-        = new NoBlockBlockType(&NoBlock::INSTANCE, "__not_yet_generated");
-    blockTypes[1] = new NoBlockBlockType(&AirBlock::INSTANCE, "Air");
+    blockTypes[0] = new NoBlockBlockType(
+        dynamic_cast<Block*>(NoBlock::INSTANCE.getThis()),
+        "__not_yet_generated");
+    blockTypes[1] = new NoBlockBlockType(
+        dynamic_cast<Block*>(AirBlock::INSTANCE.getThis()), "Air");
     blockTypeCount = 2;
     for (BlockType* blockType : blockTypeArray)
     {
         blockTypes[blockTypeCount++] = blockType;
     }
+    Framework::RCArray<Framework::Text>* blockTypeNames
+        = new Framework::RCArray<Framework::Text>();
     for (int i = 0; i < blockTypeCount; i++)
     {
+        blockTypeNames->add(new Framework::Text(blockTypes[i]->getName()));
         blockTypes[i]->setTypeId(i);
     }
+    blockTypeNameFactory->setBlockTypeNames(blockTypeNames);
     Framework::Logging::info() << "Loading item types";
     Framework::Array<ItemType*> itemTypeArray;
     validator
-        = Framework::JSON::Validator::JSONValidator::buildForArray()
+        = Framework::Validator::DataValidator::buildForArray()
               ->addAcceptedTypeInArray(typeRegistry->getValidator<ItemType>())
               ->removeInvalidEntries()
               ->finishArray();
     loadAllJsonsFromDirectory("data/items",
         [this, &itemTypeArray, validator](
             Framework::JSON::JSONValue* zValue, Framework::Text path) {
-            Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+            Framework::RCArray<Framework::Validator::ValidationResult>
                 validationResults;
             Framework::JSON::JSONValue* validParts
                 = validator->getValidParts(zValue, &validationResults);
-            for (Framework::JSON::Validator::JSONValidationResult* result :
+            for (Framework::Validator::ValidationResult* result :
                 validationResults)
             {
                 Framework::Logging::error() << result->getInvalidInfo();
@@ -518,28 +223,32 @@ void Game::initialize()
     {
         itemTypes[itemTypeCount++] = itemType;
     }
+    Framework::RCArray<Framework::Text>* itemTypeNames
+        = new Framework::RCArray<Framework::Text>();
     for (int i = 0; i < itemTypeCount; i++)
     {
         itemTypes[i]->setTypeId(i);
+        itemTypeNames->add(new Framework::Text(itemTypes[i]->getName()));
     }
+    itemTypeNameFactory->setItemTypeNames(itemTypeNames);
     Framework::Logging::info() << "Loading entity types";
     Framework::Array<EntityType*> entityTypeArray;
-    /* validator
-        = Framework::JSON::Validator::JSONValidator::buildForArray()
+    validator
+        = Framework::Validator::DataValidator::buildForArray()
               ->addAcceptedTypeInArray(typeRegistry->getValidator<EntityType>())
               ->removeInvalidEntries()
               ->finishArray();
     loadAllJsonsFromDirectory("data/entities",
         [this, &entityTypeArray, validator](
             Framework::JSON::JSONValue* zValue, Framework::Text path) {
-            Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+            Framework::RCArray<Framework::Validator::ValidationResult>
                 validationResults;
             Framework::JSON::JSONValue* validParts
                 = validator->getValidParts(zValue, &validationResults);
-            for (Framework::JSON::Validator::JSONValidationResult* result :
+            for (Framework::Validator::ValidationResult* result :
                 validationResults)
             {
-                result->printInvalidInfo();
+                Framework::Logging::error() << result->getInvalidInfo();
             }
             if (validParts)
             {
@@ -555,7 +264,7 @@ void Game::initialize()
                 validParts->release();
             }
         });
-    validator->release();*/
+    validator->release();
     Framework::Logging::info()
         << "Loaded " << entityTypeArray.getEintragAnzahl()
         << " entity types from data/entities";
@@ -635,7 +344,47 @@ void Game::initialize()
     multiblockStructureTypeCount = 1;
     // save syntax info
     Framework::DateiRemove("data/syntax");
-    typeRegistry->writeSyntaxInfo("data/syntax");
+    // typeRegistry->writeSyntaxInfo("data/syntax");
+
+    validator
+        = Framework::Validator::DataValidator::buildForArray()
+              ->addAcceptedTypeInArray(typeRegistry->getValidator<BlockType>())
+              ->finishArray();
+    Framework::JSON::JSONObject* schema = validator->getJsonSchema();
+    Framework::Datei syntaxFile;
+    syntaxFile.setDatei("data/syntax/schema/blocks.json");
+    syntaxFile.erstellen();
+    syntaxFile.open(Framework::Datei::Style::schreiben);
+    syntaxFile.schreibe(schema->toString(), schema->toString().getLength());
+    syntaxFile.close();
+    schema->release();
+    validator->release();
+
+    validator
+        = Framework::Validator::DataValidator::buildForArray()
+              ->addAcceptedTypeInArray(typeRegistry->getValidator<ItemType>())
+              ->finishArray();
+    schema = validator->getJsonSchema();
+    syntaxFile.setDatei("data/syntax/schema/items.json");
+    syntaxFile.erstellen();
+    syntaxFile.open(Framework::Datei::Style::schreiben);
+    syntaxFile.schreibe(schema->toString(), schema->toString().getLength());
+    syntaxFile.close();
+    schema->release();
+    validator->release();
+    validator
+        = Framework::Validator::DataValidator::buildForArray()
+              ->addAcceptedTypeInArray(typeRegistry->getValidator<EntityType>())
+              ->finishArray();
+    schema = validator->getJsonSchema();
+    syntaxFile.setDatei("data/syntax/schema/entities.json");
+    syntaxFile.erstellen();
+    syntaxFile.open(Framework::Datei::Style::schreiben);
+    syntaxFile.schreibe(schema->toString(), schema->toString().getLength());
+    syntaxFile.close();
+    schema->release();
+    validator->release();
+
     // initialize world generator and world loader
     int seed = 0;
     int index = 0;
@@ -644,7 +393,7 @@ void Game::initialize()
     generator = new WorldGenerator(seed);
     loader = new WorldLoader();
     // load recipies
-    recipies->loadRecipies("data/recipies");
+    recipies->loadRecipies("data");
     // initialize chat
     chat = new Chat();
     // load quests
@@ -700,17 +449,23 @@ void Game::thread()
                                + getPlayerId(player->zEntity()->getName()));
                 pFile.erstellen();
                 if (pFile.open(Datei::Style::schreiben))
+                {
                     zEntityType(EntityTypeEnum::PLAYER)
                         ->saveEntity(player->zEntity(), &pFile);
+                }
                 pFile.close();
-                removed.add(index, 0);
                 Dimension* dim
                     = zDimension(player->zEntity()->getDimensionId());
+                Chunk* chunk = dim->zChunk(
+                    getChunkCenter((int)player->zEntity()->getLocation().x,
+                        (int)player->zEntity()->getLocation().y));
+                if (chunk)
+                {
+                    chunk->onEntityLeaves(player->zEntity(), 0);
+                }
+                dim->removeEntity(player->zEntity()->getId());
+                removed.add(index, 0);
                 dim->removeSubscriptions(player->zEntity());
-                this->requestWorldUpdate(
-                    new EntityRemovedUpdate(player->zEntity()->getId(),
-                        player->zEntity()->getDimensionId(),
-                        player->zEntity()->getPosition()));
             }
             else
             {
@@ -733,6 +488,7 @@ void Game::thread()
         }
         if (nextTimeSync <= 0)
         {
+            consoleHandler->print();
             nextTimeSync = MAX_TICKS_PER_SECOND;
         }
         for (auto i : removed)
@@ -748,30 +504,6 @@ void Game::thread()
         waitForLock.messungEnde();
         waitTotal += waitForLock.getSekunden();
         worldUpdates.messungStart();
-        while (updates->hat(0))
-        {
-            WorldUpdate* update = updates->z(0);
-            for (auto client : *clients)
-                client->sendWorldUpdate(
-                    dynamic_cast<WorldUpdate*>(update->getThis()));
-            if (!zDimension(update->getAffectedDimension()))
-            {
-                Dimension* dim = generator->createDimension(
-                    update->getAffectedDimension());
-                if (dim)
-                    addDimension(dim);
-                else
-                {
-                    Framework::Logging::error()
-                        << "could not create dimension "
-                        << update->getAffectedDimension()
-                        << ". No Factory was provided.";
-                }
-            }
-            if (zDimension(update->getAffectedDimension()))
-                update->onUpdate(zDimension(update->getAffectedDimension()));
-            updates->remove(0);
-        }
         worldUpdates.messungEnde();
         cs.unlock();
         clientReply.messungStart();
@@ -984,14 +716,6 @@ void Game::sendMessage(NetworkMessage* response, Entity* zTargetPlayer)
     response->release();
 }
 
-bool Game::requestWorldUpdate(WorldUpdate* update)
-{
-    cs.lock();
-    updates->add(update);
-    cs.unlock();
-    return 1;
-}
-
 bool Game::checkPlayer(Framework::Text name, Framework::Text secret)
 {
     if (playerRegister->checkSecret(name, secret))
@@ -1096,7 +820,18 @@ GameClient* Game::addPlayer(FCKlient* client, Framework::Text name)
         player->setPosition(
             {player->getPosition().x, player->getPosition().y, (float)h + 2.f});
     }
-    requestWorldUpdate(new AddEntityUpdate(player, player->getDimensionId()));
+    Dimension* zDim = zDimension(player->getDimensionId());
+    if (zDim)
+    {
+        zDim->addEntity(player);
+    }
+    else
+    {
+        Framework::Logging::error()
+            << "could not add player to dimension "
+            << (int)player->getDimensionId() << ". Dimension not loaded.";
+        player->release();
+    }
     chat->addObserver(gameClient->zEntity()->getId());
     chat->broadcastMessage(name + " joined the game.", Chat::CHANNEL_INFO);
     cs.unlock();
@@ -1158,7 +893,19 @@ void Game::spawnItem(
                   location, dimensionId, Game::INSTANCE->getNextEntityId());
     itemEntity->unsaveAddItem(stack, NO_DIRECTION, 0);
     stack->release();
-    requestWorldUpdate(new AddEntityUpdate(itemEntity, dimensionId));
+    Dimension* dim = zDimension(dimensionId);
+    if (dim)
+    {
+        dim->addEntity(itemEntity);
+    }
+    else
+    {
+        Framework::Logging::error()
+            << "could not spawn item entity in dimension " << dimensionId
+            << ". Dimension not loaded.";
+        itemEntity->release();
+        return;
+    }
 }
 
 Framework::Either<Block*, int> Game::zBlockAt(
@@ -1169,14 +916,23 @@ Framework::Either<Block*, int> Game::zBlockAt(
     return 0;
 }
 
-Block* Game::zRealBlockInstance(Framework::Vec3<int> location, int dimension)
+Block* Game::zRealBlockInstance(
+    Framework::Vec3<int> location, int dimension) const
 {
     Dimension* dim = zDimension(dimension);
     if (dim) return dim->zRealBlockInstance(location);
     return 0;
 }
 
-int Game::getBlockType(Framework::Vec3<int> location, int dimension)
+const Block* Game::zConstBlock(
+    Framework::Vec3<int> location, int dimension) const
+{
+    Dimension* dim = zDimension(dimension);
+    if (dim) return dim->zBlockOrDefault(location);
+    return 0;
+}
+
+int Game::getBlockType(Framework::Vec3<int> location, int dimension) const
 {
     Dimension* dim = zDimension(dimension);
     if (dim) return dim->getBlockType(location);
@@ -1248,9 +1004,9 @@ void Game::addDimension(Dimension* d)
 
 int Game::getNextEntityId()
 {
-    cs.lock();
+    neidl.lock();
     int result = nextEntityId++;
-    cs.unlock();
+    neidl.unlock();
     return result;
 }
 
@@ -1297,7 +1053,7 @@ Entity* Game::zEntity(int id) const
 
 Entity* Game::zNearestEntity(int dimensionId,
     Framework::Vec3<float> pos,
-    std::function<bool(Entity*)> filter)
+    std::function<bool(Entity*)> filter) const
 {
     Dimension* d = zDimension(dimensionId);
     if (!d) return 0;
@@ -1406,6 +1162,21 @@ const EntityType* Game::zEntityType(int id) const
     return entityTypes[id];
 }
 
+int Game::getEntityTypeId(const char* name) const
+{
+    for (int i = 0; i < entityTypeCount; i++)
+    {
+        if (entityTypes[i]
+            && Framework::Text(entityTypes[i]->getName()).istGleich(name))
+        {
+            return i;
+        }
+    }
+    Framework::Logging::warning()
+        << "no entity type with name '" << name << "' found.";
+    return -1;
+}
+
 int Game::getBlockTypeId(const char* name) const
 {
     for (int i = 0; i < blockTypeCount; i++)

+ 13 - 58
FactoryCraft/Game.h

@@ -4,18 +4,17 @@
 #include <Critical.h>
 #include <Either.h>
 #include <InMemoryBuffer.h>
-#include <Network.h>
 #include <Punkt.h>
 #include <Text.h>
 #include <Thread.h>
 
 #include "Area.h"
+#include "BlockTypeNameFactory.h"
+#include "GameClient.h"
+#include "ItemTypeNameFactory.h"
 #include "NetworkMessage.h"
 #include "TypeRegistry.h"
-#include "WorldUpdate.h"
 
-class FCKlient;
-class Player;
 class QuestManager;
 class TickOrganizer;
 class WorldGenerator;
@@ -31,55 +30,6 @@ class BlockType;
 class ItemType;
 class Item;
 
-class GameClient : public Framework::Thread
-{
-private:
-    Player* zPlayer;
-    FCKlient* client;
-    Framework::Critical background;
-    Framework::Critical foreground;
-    Framework::Critical other;
-    Framework::Synchronizer updateSync;
-    Framework::RCArray<Framework::InMemoryBuffer> requests;
-    Framework::RCArray<WorldUpdate> updateQueue;
-    Framework::RCArray<NetworkMessage> backgroundQueue;
-    Framework::RCArray<NetworkMessage> foregroundQueue;
-    Framework::Synchronizer foregroundQueueSync;
-    Framework::Synchronizer backgroundQueueSync;
-    Framework::Critical queueCs;
-    Framework::Synchronizer emptyForegroundQueueSync;
-    Framework::Synchronizer emptyBackgroundQueueSync;
-    int viewDistance;
-    bool first;
-    bool online;
-    bool finished;
-    bool backgroundFinished;
-    bool foregroundFinished;
-
-public:
-    GameClient(Player* zPlayer, FCKlient* client);
-    ~GameClient();
-
-    void thread() override;
-    void sendWorldUpdate(WorldUpdate* update);
-    void reply();
-    void logout();
-    void addMessage(Framework::StreamReader* reader);
-    bool isOnline() const;
-    void sendResponse(NetworkMessage* response);
-    Player* zEntity() const;
-    void sendTypes();
-
-    class Message
-    {
-    public:
-        inline static const unsigned char TERMINATE = 1;
-        inline static const unsigned char WORLD_UPDATE = 2;
-        inline static const unsigned char API_MESSAGE = 3;
-        inline static const unsigned char POSITION_UPDATE = 4;
-    };
-};
-
 class Game : public virtual Framework::Thread
 {
 public:
@@ -89,8 +39,9 @@ public:
 private:
     Framework::Text name;
     TypeRegistry* typeRegistry;
+    BlockTypeNameFactory* blockTypeNameFactory;
+    ItemTypeNameFactory* itemTypeNameFactory;
     Framework::RCArray<Dimension>* dimensions;
-    Framework::RCArray<WorldUpdate>* updates;
     Framework::RCArray<GameClient>* clients;
     Framework::Array<std::function<void()>> actions;
     QuestManager* questManager;
@@ -100,6 +51,7 @@ private:
     bool stop;
     __int64 tickId;
     Framework::Critical cs;
+    Framework::Critical neidl;
     int nextEntityId;
     WorldGenerator* generator;
     WorldLoader* loader;
@@ -134,7 +86,6 @@ public:
         int dimensionId, Framework::Vec3<int> location);
     void broadcastMessage(NetworkMessage* response);
     void sendMessage(NetworkMessage* response, Entity* zTargetPlayer);
-    bool requestWorldUpdate(WorldUpdate* update);
     bool checkPlayer(Framework::Text name, Framework::Text secret);
     bool existsPlayer(Framework::Text name);
     Framework::Text createPlayer(Framework::Text name);
@@ -149,8 +100,11 @@ public:
     bool isChunkLoaded(int x, int y, int dimension) const;
     Framework::Either<Block*, int> zBlockAt(
         Framework::Vec3<int> location, int dimension, OUT Chunk** zChunk) const;
-    Block* zRealBlockInstance(Framework::Vec3<int> location, int dimension);
-    int getBlockType(Framework::Vec3<int> location, int dimension);
+    Block* zRealBlockInstance(
+        Framework::Vec3<int> location, int dimension) const;
+    const Block* zConstBlock(
+        Framework::Vec3<int> location, int dimension) const;
+    int getBlockType(Framework::Vec3<int> location, int dimension) const;
     Dimension* zDimension(int id) const;
     static Framework::Punkt getChunkCenter(int x, int y);
     Area getChunckArea(Framework::Punkt center) const;
@@ -165,7 +119,7 @@ public:
     Entity* zEntity(int id) const;
     Entity* zNearestEntity(int dimensionId,
         Framework::Vec3<float> pos,
-        std::function<bool(Entity*)> filter);
+        std::function<bool(Entity*)> filter) const;
     RecipieLoader* zRecipies() const;
     void doLater(std::function<void()> action);
     TickOrganizer* zTickOrganizer() const;
@@ -185,6 +139,7 @@ public:
     const BlockType* zBlockType(int id) const;
     const ItemType* zItemType(int id) const;
     const EntityType* zEntityType(int id) const;
+    int getEntityTypeId(const char* name) const;
     int getBlockTypeId(const char* name) const;
     int getItemTypeId(const char* name) const;
     int getBlockTypeCount() const;

+ 268 - 0
FactoryCraft/GameClient.cpp

@@ -0,0 +1,268 @@
+#include "GameClient.h"
+
+#include <AsynchronCall.h>
+
+#include "Constants.h"
+#include "Dimension.h"
+#include "Game.h"
+#include "ItemType.h"
+#include "Player.h"
+#include "Server.h"
+
+GameClient::GameClient(Player* zPlayer, FCKlient* client)
+    : Thread(),
+      zPlayer(zPlayer),
+      client(client),
+      viewDistance(DEFAULT_VIEW_DISTANCE),
+      first(1),
+      online(1),
+      backgroundFinished(0),
+      foregroundFinished(0)
+{
+    start();
+}
+
+GameClient::~GameClient()
+{
+    online = 0;
+    emptyForegroundQueueSync.notifyAll();
+    emptyBackgroundQueueSync.notifyAll();
+    foregroundQueueSync.notify();
+    backgroundQueueSync.notify();
+    while (!foregroundFinished || !backgroundFinished)
+        Sleep(100);
+    client->release();
+}
+
+void GameClient::thread()
+{
+    new AsynchronCall("Game Client Background", [this]() {
+        while (online)
+        {
+            queueCs.lock();
+            if (backgroundQueue.hat(0))
+            {
+                NetworkMessage* message = backgroundQueue.get(0);
+                backgroundQueue.remove(0);
+                queueCs.unlock();
+                background.lock();
+                message->writeTo(client->zBackgroundWriter());
+                background.unlock();
+                message->release();
+            }
+            else
+            {
+                queueCs.unlock();
+                emptyBackgroundQueueSync.notifyAll();
+                while (!backgroundQueueSync.wait(1000))
+                {
+                    emptyBackgroundQueueSync.notifyAll();
+                }
+            }
+        }
+        backgroundFinished = 1;
+    });
+    while (online)
+    {
+        queueCs.lock();
+        if (foregroundQueue.hat(0))
+        {
+            NetworkMessage* message = foregroundQueue.get(0);
+            foregroundQueue.remove(0);
+            queueCs.unlock();
+            foreground.lock();
+            message->writeTo(client->zForegroundWriter());
+            foreground.unlock();
+            message->release();
+        }
+        else
+        {
+            queueCs.unlock();
+            emptyForegroundQueueSync.notifyAll();
+            while (!foregroundQueueSync.wait(1000))
+            {
+                emptyForegroundQueueSync.notifyAll();
+            }
+        }
+    }
+    foregroundFinished = 1;
+}
+
+void GameClient::reply()
+{
+    other.lock();
+    for (auto req : requests)
+        Game::INSTANCE->api(req, this);
+    requests.leeren();
+    other.unlock();
+    if (first)
+    {
+        foreground.lock();
+        int id = zPlayer->getId();
+        client->zForegroundWriter()->schreibe(
+            (char*)&Message::POSITION_UPDATE, 1);
+        client->zForegroundWriter()->schreibe((char*)&id, 4);
+        id = zPlayer->getDimensionId();
+        client->zForegroundWriter()->schreibe((char*)&id, 4);
+        client->zForegroundWriter()->schreibe((char*)&Message::API_MESSAGE, 1);
+        int len = 10;
+        client->zForegroundWriter()->schreibe((char*)&len, 4);
+        client->zForegroundWriter()->schreibe("\1", 1);
+        client->zForegroundWriter()->schreibe((char*)&id, 4);
+        client->zForegroundWriter()->schreibe("\6", 1);
+        float gravity = Game::INSTANCE->zDimension(zPlayer->getDimensionId())
+                            ->getGravity();
+        client->zForegroundWriter()->schreibe((char*)&gravity, 4);
+        foreground.unlock();
+        first = 0;
+    }
+}
+
+void GameClient::logout()
+{
+    online = 0;
+    emptyForegroundQueueSync.notifyAll();
+    emptyBackgroundQueueSync.notifyAll();
+    foregroundQueueSync.notify();
+    backgroundQueueSync.notify();
+}
+
+void GameClient::addMessage(StreamReader* reader)
+{
+    short len = 0;
+    reader->lese((char*)&len, 2);
+    InMemoryBuffer* buffer = new InMemoryBuffer();
+    char* tmp = new char[len];
+    reader->lese(tmp, len);
+    buffer->schreibe(tmp, len);
+    delete[] tmp;
+    other.lock();
+    requests.add(buffer);
+    other.unlock();
+}
+
+bool GameClient::isOnline() const
+{
+    return online;
+}
+
+void GameClient::sendResponse(NetworkMessage* response)
+{
+    queueCs.lock();
+    if (response->isUseBackground())
+    {
+        if (backgroundQueue.getEintragAnzahl() > 20)
+        {
+            queueCs.unlock();
+            while (!emptyBackgroundQueueSync.wait(1000))
+            {
+                backgroundQueueSync.notify();
+            }
+            queueCs.lock();
+        }
+        backgroundQueue.add(response);
+        queueCs.unlock();
+        backgroundQueueSync.notify();
+    }
+    else
+    {
+        if (foregroundQueue.getEintragAnzahl() > 100)
+        {
+            queueCs.unlock();
+            Framework::Logging::warning()
+                << "Game paused because nework connection to "
+                << zPlayer->getName() << " is to slow.";
+            ZeitMesser m;
+            m.messungStart();
+            while (foregroundQueue.getEintragAnzahl() > 0)
+            {
+                foregroundQueueSync.notify();
+                emptyForegroundQueueSync.wait(100);
+            }
+            m.messungEnde();
+            Framework::Logging::warning()
+                << "Game resumed after " << m.getSekunden() << " seconds.";
+            queueCs.lock();
+        }
+        foregroundQueue.add(response);
+        queueCs.unlock();
+        foregroundQueueSync.notify();
+    }
+}
+
+Player* GameClient::zEntity() const
+{
+    return zPlayer;
+}
+
+void GameClient::sendTypes()
+{
+    foreground.lock();
+    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 < Game::INSTANCE->getBlockTypeCount(); i++)
+    {
+        const BlockType* t = Game::INSTANCE->zBlockType(i);
+        if (t)
+        {
+            t->writeTypeInfo(client->zForegroundWriter());
+        }
+    }
+    count = 0;
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
+    {
+        if (Game::INSTANCE->zItemType(i)) count++;
+    }
+    client->zForegroundWriter()->schreibe((char*)&count, 4);
+    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
+    {
+        const ItemType* t = Game::INSTANCE->zItemType(i);
+        if (t)
+        {
+            int id = t->getId();
+            client->zForegroundWriter()->schreibe((char*)&id, 4);
+            char len = (char)t->getName().getLength();
+            client->zForegroundWriter()->schreibe((char*)&len, 1);
+            client->zForegroundWriter()->schreibe(t->getName().getText(), len);
+            short tlen = (short)t->getTooltipUIML().getLength();
+            client->zForegroundWriter()->schreibe((char*)&tlen, 2);
+            client->zForegroundWriter()->schreibe(
+                t->getTooltipUIML().getText(), tlen);
+            if (t->zModel())
+            {
+                t->zModel()->writeTo(client->zForegroundWriter());
+            }
+            else
+            {
+                ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
+                    .writeTo(client->zForegroundWriter());
+            }
+        }
+    }
+    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 = Game::INSTANCE->zEntityType(i);
+        int id = t->getId();
+        client->zForegroundWriter()->schreibe((char*)&id, 4);
+        if (t->zModel())
+        {
+            t->zModel()->writeTo(client->zForegroundWriter());
+        }
+        else
+        {
+            ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
+                .writeTo(client->zForegroundWriter());
+        }
+    }
+    foreground.unlock();
+}

+ 55 - 0
FactoryCraft/GameClient.h

@@ -0,0 +1,55 @@
+#pragma once
+
+#include <Array.h>
+#include <Critical.h>
+#include <InMemoryBuffer.h>
+#include <Thread.h>
+
+class Player;
+class FCKlient;
+class NetworkMessage;
+
+class GameClient : public Framework::Thread
+{
+private:
+    Player* zPlayer;
+    FCKlient* client;
+    Framework::Critical background;
+    Framework::Critical foreground;
+    Framework::Critical other;
+    Framework::RCArray<Framework::InMemoryBuffer> requests;
+    Framework::RCArray<NetworkMessage> backgroundQueue;
+    Framework::RCArray<NetworkMessage> foregroundQueue;
+    Framework::Synchronizer foregroundQueueSync;
+    Framework::Synchronizer backgroundQueueSync;
+    Framework::Critical queueCs;
+    Framework::Synchronizer emptyForegroundQueueSync;
+    Framework::Synchronizer emptyBackgroundQueueSync;
+    int viewDistance;
+    bool first;
+    bool online;
+    bool backgroundFinished;
+    bool foregroundFinished;
+
+public:
+    GameClient(Player* zPlayer, FCKlient* client);
+    ~GameClient();
+
+    void thread() override;
+    void reply();
+    void logout();
+    void addMessage(Framework::StreamReader* reader);
+    bool isOnline() const;
+    void sendResponse(NetworkMessage* response);
+    Player* zEntity() const;
+    void sendTypes();
+
+    class Message
+    {
+    public:
+        inline static const unsigned char TERMINATE = 1;
+        inline static const unsigned char WORLD_UPDATE = 2;
+        inline static const unsigned char API_MESSAGE = 3;
+        inline static const unsigned char POSITION_UPDATE = 4;
+    };
+};

+ 1 - 2
FactoryCraft/GeneratedStructure.cpp

@@ -1,9 +1,8 @@
 #include "GeneratedStructure.h"
 
+#include "Game.h"
 #include "GeneratorTemplate.h"
 #include "MultiblockStructure.h"
-#include "NoBlock.h"
-#include "Game.h"
 
 using namespace Framework;
 

+ 55 - 13
FactoryCraft/GeneratorRule.cpp

@@ -7,7 +7,11 @@ GeneratorRule::GeneratorRule()
       noiseConfig(0),
       noise(0),
       threshold(0.f),
-      condition(0)
+      condition(0),
+      bottomLayer(""),
+      topLayer(""),
+      topLayerF(0),
+      botomLayerF(0)
 {}
 
 GeneratorRule::~GeneratorRule()
@@ -24,14 +28,29 @@ void GeneratorRule::initialize(JExpressionMemory* zMemory)
         if (noise) noise->release();
         noise = JNoise::parseNoise(noiseConfig, zMemory);
     }
+    if (topLayer.getLength())
+    {
+        topLayerF = zMemory->getFloatVariableP(topLayer);
+    }
+    if (bottomLayer.getLength())
+    {
+        botomLayerF = zMemory->getFloatVariableP(bottomLayer);
+    }
+    if (condition)
+    {
+        condition->compile(zMemory);
+    }
 }
 
-bool GeneratorRule::checkCondition(
-    int x, int y, int z, JExpressionMemory* zMemory)
+bool GeneratorRule::checkCondition(int x, int y, int z)
 {
-    return (!noise
-               || noise->getNoise((double)x, (double)y, (double)z) <= threshold)
-        && condition->getValue(zMemory);
+    if ((topLayerF && z > *topLayerF) || (botomLayerF && z < *botomLayerF))
+    {
+        return false;
+    }
+    return (!condition || condition->getValue())
+        && (!noise
+            || noise->getNoise((double)x, (double)y, (double)z) <= threshold);
 }
 
 Framework::Either<Block*, int> GeneratorRule::generateBlock(
@@ -40,9 +59,10 @@ Framework::Either<Block*, int> GeneratorRule::generateBlock(
     return createBlock(x, y, z, dimensionId);
 }
 
-void GeneratorRule::setNoiseConfig(Framework::JSON::JSONObject* noiseConfig) {
+void GeneratorRule::setNoiseConfig(Framework::JSON::JSONObject* noiseConfig)
+{
     if (this->noiseConfig) this->noiseConfig->release();
-	this->noiseConfig = noiseConfig;
+    this->noiseConfig = noiseConfig;
 }
 
 Framework::JSON::JSONObject* GeneratorRule::zNoiseConfig() const
@@ -50,7 +70,8 @@ Framework::JSON::JSONObject* GeneratorRule::zNoiseConfig() const
     return noiseConfig;
 }
 
-void GeneratorRule::setThreshold(float threshold) {
+void GeneratorRule::setThreshold(float threshold)
+{
     this->threshold = threshold;
 }
 
@@ -59,12 +80,33 @@ float GeneratorRule::getThreshold() const
     return threshold;
 }
 
-void GeneratorRule::setCondition(JBoolExpression* condition) {
-	if (this->condition) this->condition->release();
-	this->condition = condition;
+void GeneratorRule::setCondition(JBoolExpression* condition)
+{
+    if (this->condition) this->condition->release();
+    this->condition = condition;
 }
 
 JBoolExpression* GeneratorRule::zCondition() const
 {
     return condition;
-}
+}
+
+void GeneratorRule::setBottomLayer(Framework::Text bottomLayer)
+{
+    this->bottomLayer = bottomLayer;
+}
+
+Framework::Text GeneratorRule::getBottomLayer() const
+{
+    return bottomLayer;
+}
+
+void GeneratorRule::setTopLayer(Framework::Text topLayer)
+{
+    this->topLayer = topLayer;
+}
+
+Framework::Text GeneratorRule::getTopLayer() const
+{
+    return topLayer;
+}

+ 62 - 17
FactoryCraft/GeneratorRule.h

@@ -15,6 +15,10 @@ private:
     Noise* noise;
     float threshold;
     JBoolExpression* condition;
+    Framework::Text bottomLayer;
+    Framework::Text topLayer;
+    float* topLayerF;
+    float* botomLayerF;
 
 protected:
     virtual Framework::Either<Block*, int> createBlock(
@@ -27,16 +31,19 @@ public:
 
     void initialize(JExpressionMemory* zMemory);
 
-    bool checkCondition(int x, int y, int z, JExpressionMemory* zMemory);
+    bool checkCondition(int x, int y, int z);
     Framework::Either<Block*, int> generateBlock(
         int x, int y, int z, int dimensionId);
-
     void setNoiseConfig(Framework::JSON::JSONObject* noiseConfig);
     Framework::JSON::JSONObject* zNoiseConfig() const;
     void setThreshold(float threshold);
     float getThreshold() const;
     void setCondition(JBoolExpression* condition);
     JBoolExpression* zCondition() const;
+    void setBottomLayer(Framework::Text bottomLayer);
+    Framework::Text getBottomLayer() const;
+    void setTopLayer(Framework::Text topLayer);
+    Framework::Text getTopLayer() const;
 };
 
 template<typename S> class GeneratorRuleFactory
@@ -47,9 +54,10 @@ public:
         : SubTypeFactory<GeneratorRule, S>()
     {}
 
-    void fromJson(S* zResult, Framework::JSON::JSONObject* zJson) const override
+    S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
-        GeneratorRule* zRule = dynamic_cast<GeneratorRule*>(zResult);
+        S* result = createValue(zJson);
+        GeneratorRule* zRule = dynamic_cast<GeneratorRule*>(result);
         if (zJson->hasValue("noise"))
         {
             zRule->setNoiseConfig(zJson->getValue("noise")->asObject());
@@ -59,40 +67,77 @@ public:
             zRule->setThreshold(
                 (float)zJson->zValue("threshold")->asNumber()->getNumber());
         }
-        zRule->setCondition(
-            Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(
-                zJson->zValue("condition")));
+        if (zJson->hasValue("condition"))
+        {
+            zRule->setCondition(
+                Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(
+                    zJson->zValue("condition")));
+        }
+        if (zJson->hasValue("bottomLayer"))
+        {
+            zRule->setBottomLayer(
+                zJson->zValue("bottomLayer")->asString()->getString());
+        }
+        if (zJson->hasValue("topLayer"))
+        {
+            zRule->setTopLayer(
+                zJson->zValue("topLayer")->asString()->getString());
+        }
+        return result;
     }
 
-    void toJson(S* zObject, Framework::JSON::JSONObject* zResult) const override
+    Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
         GeneratorRule* zRule = dynamic_cast<GeneratorRule*>(zObject);
         if (zRule->zNoiseConfig())
         {
-            zResult->addValue("noise",
+            result->addValue("noise",
                 dynamic_cast<Framework::JSON::JSONValue*>(
                     zRule->zNoiseConfig()->getThis()));
         }
-        zResult->addValue("threshold",
+        result->addValue("threshold",
             new Framework::JSON::JSONNumber(zRule->getThreshold()));
-        zResult->addValue("condition",
-            Game::INSTANCE->zTypeRegistry()->toJson(
-                dynamic_cast<Framework::JSON::JSONValue*>(
-                    zRule->zCondition()->getThis())));
+        if (zRule->zCondition())
+        {
+            result->addValue("condition",
+                Game::INSTANCE->zTypeRegistry()->toJson(
+                    dynamic_cast<Framework::JSON::JSONValue*>(
+                        zRule->zCondition()->getThis())));
+        }
+
+        result->addValue("bottomLayer",
+            new Framework::JSON::JSONString(zRule->getBottomLayer()));
+        result->addValue(
+            "topLayer", new Framework::JSON::JSONString(zRule->getTopLayer()));
+        return result;
     }
 
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override
+
     {
         return builder
-            ->withRequiredAttribute("noise", JNoise::getValidator(true))
+            ->withRequiredAttribute(
+                "noise", JNoise::getValidator(true), false, true)
             ->withRequiredAttribute("condition",
                 Game::INSTANCE->zTypeRegistry()
-                    ->getValidator<JBoolExpression>())
+                    ->getValidator<JBoolExpression>(),
+                false,
+                true)
             ->withRequiredNumber("threshold")
             ->whichIsOptional()
             ->whichIsGreaterOrEqual(0.0)
             ->whichIsLessOrEqual(1.0)
-            ->finishNumber();
+            ->finishNumber()
+            ->withRequiredString("topLayer")
+            ->whichIsOptional()
+            ->finishString()
+            ->withRequiredString("bottomLayer")
+            ->whichIsOptional()
+            ->finishString();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };

+ 15 - 6
FactoryCraft/GeneratorTemplate.h

@@ -41,23 +41,32 @@ public:
         : SubTypeFactory<GeneratorTemplate, S>()
     {}
 
-    void fromJson(S* zResult, Framework::JSON::JSONObject* zJson) const override
+    S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
-        GeneratorTemplate* zRecipie = dynamic_cast<GeneratorTemplate*>(zResult);
+        S* result = createValue(zJson);
+        GeneratorTemplate* zRecipie = dynamic_cast<GeneratorTemplate*>(result);
         zRecipie->setPropability(
             (float)zJson->zValue("propability")->asNumber()->getNumber());
+        return result;
     }
 
-    void toJson(S* zObject, Framework::JSON::JSONObject* zResult) const override
+    Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
-        GeneratorTemplate* zRecipie = dynamic_cast<GeneratorTemplate*>(zResult);
-        zResult->addValue("propability",
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+        GeneratorTemplate* zRecipie = dynamic_cast<GeneratorTemplate*>(result);
+        result->addValue("propability",
             new Framework::JSON::JSONNumber(zRecipie->getPropability()));
+        return result;
     };
 
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override
     {
-        return builder->withRequiredNumber("propability")->finishNumber();
+        return builder->withRequiredNumber("propability")
+            ->whichIsGreaterThen(0)
+            ->finishNumber();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };

+ 19 - 19
FactoryCraft/Grass.cpp

@@ -1,11 +1,7 @@
 #include "Grass.h"
 
-#include "AddEntityUpdate.h"
-#include "Game.h"
-#include "ItemEntity.h"
-
 GrassBlock::GrassBlock(int typeId, Framework::Vec3<int> pos, int dimensionId)
-    : AdditionalItemSpawningBlock(typeId, pos, dimensionId)
+    : BasicBlock(typeId, pos, dimensionId)
 {
     transparent = 1;
 }
@@ -31,7 +27,7 @@ TickSourceType GrassBlock::isTickSource() const
 }
 
 GrassBlockType::GrassBlockType()
-    : AdditionalItemSpawningBlockType()
+    : BasicBlockType()
 {}
 
 ItemType* GrassBlockType::createItemType() const
@@ -41,20 +37,19 @@ ItemType* GrassBlockType::createItemType() const
 
 void GrassBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
 {
-    AdditionalItemSpawningBlockType::createSuperBlock(zBlock, zItem);
+    BasicBlockType::createSuperBlock(zBlock, zItem);
 }
 
 void GrassBlockType::loadSuperBlock(
     Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
 {
-    AdditionalItemSpawningBlockType::loadSuperBlock(
-        zBlock, zReader, dimensionId);
+    BasicBlockType::loadSuperBlock(zBlock, zReader, dimensionId);
 }
 
 void GrassBlockType::saveSuperBlock(
     Block* zBlock, Framework::StreamWriter* zWriter) const
 {
-    AdditionalItemSpawningBlockType::saveSuperBlock(zBlock, zWriter);
+    BasicBlockType::saveSuperBlock(zBlock, zWriter);
 }
 
 Item* GrassBlockType::createItem() const
@@ -69,7 +64,7 @@ Block* GrassBlockType::createBlock(
 }
 
 GrassBlockTypeFactory::GrassBlockTypeFactory()
-    : SubTypeFactory()
+    : BasicBlockTypeFactory()
 {}
 
 GrassBlockType* GrassBlockTypeFactory::createValue(
@@ -78,25 +73,30 @@ GrassBlockType* GrassBlockTypeFactory::createValue(
     return new GrassBlockType();
 }
 
-void GrassBlockTypeFactory::fromJson(
-    GrassBlockType* zResult, Framework::JSON::JSONObject* zJson) const
+GrassBlockType* GrassBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    super.fromJson(zResult, zJson);
+    return BasicBlockTypeFactory::fromJson(zJson);
 }
 
-void GrassBlockTypeFactory::toJson(
-    GrassBlockType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* GrassBlockTypeFactory::toJsonObject(
+    GrassBlockType* zObject) const
 {
-    super.toJson(zObject, zResult);
+    return BasicBlockTypeFactory::toJsonObject(zObject);
 }
 
 JSONObjectValidationBuilder* GrassBlockTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return super.addToValidator(builder);
+    return BasicBlockTypeFactory::addToValidator(builder);
 }
 
-Framework::Text GrassBlockTypeFactory::getTypeToken() const
+const char* GrassBlockTypeFactory::getTypeToken() const
 {
     return "grass";
 }
+
+const char* GrassBlockTypeFactory::getTypeName() const
+{
+    return typeid(GrassBlockType).name();
+}

+ 8 - 11
FactoryCraft/Grass.h

@@ -5,7 +5,7 @@
 
 class GrassBlockType;
 
-class GrassBlock : public AdditionalItemSpawningBlock
+class GrassBlock : public BasicBlock
 {
 public:
     GrassBlock(int typeId, Framework::Vec3<int> pos, int dimensionId);
@@ -18,7 +18,7 @@ public:
     friend GrassBlockType;
 };
 
-class GrassBlockType : public AdditionalItemSpawningBlockType
+class GrassBlockType : public BasicBlockType
 {
 public:
     GrassBlockType();
@@ -38,20 +38,17 @@ public:
     virtual ItemType* createItemType() const override;
 };
 
-class GrassBlockTypeFactory : public SubTypeFactory<BlockType, GrassBlockType>
+class GrassBlockTypeFactory : public BasicBlockTypeFactory<GrassBlockType>
 {
-private:
-    AdditionalItemSpawningBlockTypeFactory super;
-
 public:
     GrassBlockTypeFactory();
     GrassBlockType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(GrassBlockType* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(GrassBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    GrassBlockType* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        GrassBlockType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
+    const char* getTypeName() const override;
 };

+ 49 - 36
FactoryCraft/GrowingPlant.cpp

@@ -110,12 +110,13 @@ TickSourceType GrowingPlantBlock::isTickSource() const
     return TickSourceType::EACH_TICK;
 }
 
-Framework::Text GrowingPlantBlock::getTargetUIML()
+Framework::XML::Element* GrowingPlantBlock::getTargetUIML() const
 {
-    return Framework::Text("<targetInfo><text width=\"auto\" height=\"auto\">")
-         + name + "\n" + "Growth: "
-         + Framework::Text((int)(seblingTicks / (float)seblingTicksMax * 100.f))
-         + "%</text></targetInfo>";
+    return new Framework::XML::Element(
+        Framework::Text("<targetInfo><text width=\"auto\" height=\"auto\">")
+        + name + "\n" + "Growth: "
+        + Framework::Text((int)(seblingTicks / (float)seblingTicksMax * 100.f))
+        + "%</text></targetInfo>");
 }
 
 GrowingPlantBlock* GrowingPlantBlock::addGrowthState(GrowthState* state)
@@ -269,8 +270,16 @@ const Framework::RCArray<GrowthState>& GrowingPlantBlockType::getStates() const
 }
 
 void GrowingPlantBlockType::setBlockTypeNameAfterGrowth(
-    Framework::Text blockTypeIdAfterGrowth)
-{}
+    Framework::Text blockTypeNameAfterGrowth)
+{
+    this->blockTypeNameAfterGrowth = blockTypeNameAfterGrowth;
+}
+
+bool GrowingPlantBlockType::initialize(Game* zGame)
+{
+    blockTypeIdAfterGrowth = zGame->getBlockTypeId(blockTypeNameAfterGrowth);
+    return blockTypeIdAfterGrowth >= 0 && BlockType::initialize(zGame);
+}
 
 ItemType* GrowingPlantBlockType::createItemType() const
 {
@@ -287,51 +296,53 @@ GrowingPlantBlockType* GrowingPlantBlockTypeFactory::createValue(
     return new GrowingPlantBlockType();
 }
 
-void GrowingPlantBlockTypeFactory::fromJson(
-    GrowingPlantBlockType* zResult, Framework::JSON::JSONObject* zJson) const
+GrowingPlantBlockType* GrowingPlantBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setBlockTypeNameAfterGrowth(
+    GrowingPlantBlockType* result = BlockTypeFactoryBase::fromJson(zJson);
+    result->setBlockTypeNameAfterGrowth(
         zJson->zValue("blockTypeAfterGrowth")->asString()->getString());
-    zResult->setReadableName(
+    result->setReadableName(
         zJson->zValue("readableName")->asString()->getString());
-    zResult->setTicksNeeded(
+    result->setTicksNeeded(
         (int)zJson->zValue("ticksNeeded")->asNumber()->getNumber());
-    zResult->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
-    zResult->setPassable(zJson->zValue("passable")->asBool()->getBool());
-    zResult->setSpeedModifier(
+    result->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
+    result->setPassable(zJson->zValue("passable")->asBool()->getBool());
+    result->setSpeedModifier(
         (float)zJson->zValue("speedModifier")->asNumber()->getNumber());
-    zResult->setInteractable(
-        zJson->zValue("interactable")->asBool()->getBool());
+    result->setInteractable(zJson->zValue("interactable")->asBool()->getBool());
     for (Framework::JSON::JSONValue* state :
         *zJson->zValue("states")->asArray())
     {
-        zResult->addGrowthState((float)state->asObject()
-                                    ->zValue("percentage")
-                                    ->asNumber()
-                                    ->getNumber(),
+        result->addGrowthState((float)state->asObject()
+                                   ->zValue("percentage")
+                                   ->asNumber()
+                                   ->getNumber(),
             Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
                 state->asObject()->zValue("model")));
     }
-    BlockTypeFactoryBase::fromJson(zResult, zJson);
+    return result;
 }
 
-void GrowingPlantBlockTypeFactory::toJson(
-    GrowingPlantBlockType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* GrowingPlantBlockTypeFactory::toJsonObject(
+    GrowingPlantBlockType* zObject) const
 {
-    zResult->addValue("readableName",
+    Framework::JSON::JSONObject* result
+        = BlockTypeFactoryBase::toJsonObject(zObject);
+    result->addValue("readableName",
         new Framework::JSON::JSONString(zObject->getReadableName()));
-    zResult->addValue(
+    result->addValue(
         "model", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModel()));
-    zResult->addValue(
+    result->addValue(
         "name", new Framework::JSON::JSONString(zObject->getName()));
-    zResult->addValue(
+    result->addValue(
         "hardness", new Framework::JSON::JSONNumber(zObject->getHardness()));
-    zResult->addValue(
+    result->addValue(
         "mapColor", new Framework::JSON::JSONString(zObject->getMapColor()));
-    zResult->addValue("blockTypeAfterGrowth",
+    result->addValue("blockTypeAfterGrowth",
         new Framework::JSON::JSONString(
             zObject->getBlockTypeNameAfterGrowth()));
-    zResult->addValue("ticksNeeded",
+    result->addValue("ticksNeeded",
         new Framework::JSON::JSONNumber((double)zObject->getTicksNeeded()));
     Framework::JSON::JSONArray* states = new Framework::JSON::JSONArray();
     for (GrowthState* state : zObject->getStates())
@@ -344,13 +355,14 @@ void GrowingPlantBlockTypeFactory::toJson(
             new Framework::JSON::JSONNumber(state->getPercentage()));
         states->addValue(stateObj);
     }
-    zResult->addValue("states", states);
+    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));
     }
-    zResult->addValue("groupNames", groupNames);
+    result->addValue("groupNames", groupNames);
+    return result;
 }
 
 JSONObjectValidationBuilder* GrowingPlantBlockTypeFactory::addToValidator(
@@ -361,8 +373,9 @@ JSONObjectValidationBuilder* GrowingPlantBlockTypeFactory::addToValidator(
             ->finishString()
             ->withRequiredNumber("ticksNeeded")
             ->finishNumber()
-            ->withRequiredString("blockTypeAfterGrowth")
-            ->finishString()
+            ->withRequiredAttribute("blockTypeAfterGrowth",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    BlockTypeNameFactory::TYPE_ID))
             ->withRequiredArray("states")
             ->addAcceptedObjectInArray()
             ->withRequiredNumber("percentage")
@@ -387,7 +400,7 @@ JSONObjectValidationBuilder* GrowingPlantBlockTypeFactory::addToValidator(
             ->finishBool());
 }
 
-Framework::Text GrowingPlantBlockTypeFactory::getTypeToken() const
+const char* GrowingPlantBlockTypeFactory::getTypeToken() const
 {
     return "growingPlant";
 }

+ 7 - 5
FactoryCraft/GrowingPlant.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "Block.h"
+#include "BlockType.h"
 
 class GrowingPlantBlockType;
 
@@ -41,7 +42,7 @@ public:
     virtual void onPostTick() override;
     virtual void sendModelInfo(NetworkMessage* zMessage) override;
     virtual TickSourceType isTickSource() const override;
-    virtual Framework::Text getTargetUIML();
+    virtual Framework::XML::Element* getTargetUIML() const override;
     GrowingPlantBlock* addGrowthState(GrowthState* state);
 
     friend GrowingPlantBlockType;
@@ -75,6 +76,7 @@ protected:
         Framework::Vec3<int> position, int dimensionId) const override;
 
 public:
+    virtual bool initialize(Game* zGame) override;
     virtual ItemType* createItemType() const override;
 
     GrowingPlantBlockType* addGrowthState(
@@ -103,11 +105,11 @@ public:
     GrowingPlantBlockTypeFactory();
     GrowingPlantBlockType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(GrowingPlantBlockType* zResult,
+    GrowingPlantBlockType* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(GrowingPlantBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        GrowingPlantBlockType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 40 - 0
FactoryCraft/InteractionConfig.cpp

@@ -0,0 +1,40 @@
+#include "InteractionConfig.h"
+
+InteractionConfig::InteractionConfig()
+    : Framework::ReferenceCounter(),
+      filter(0)
+{}
+
+InteractionConfig::~InteractionConfig()
+{
+    if (filter)
+    {
+        filter->release();
+    }
+}
+
+void InteractionConfig::setItemFilter(ItemFilter* filter)
+{
+    if (this->filter)
+    {
+        this->filter->release();
+    }
+    this->filter = filter;
+}
+
+ItemFilter* InteractionConfig::zItemFilter() const
+{
+    return filter;
+}
+
+bool InteractionConfig::doInteraction(Framework::Either<Block*, Entity*> target,
+    Item* zItem,
+    Entity* actor,
+    bool& itemChanged)
+{
+    if (!filter || (zItem && filter->matchItem(zItem)))
+    {
+        return onInteraction(target, zItem, actor, itemChanged);
+    }
+    return false;
+}

+ 77 - 0
FactoryCraft/InteractionConfig.h

@@ -0,0 +1,77 @@
+#pragma once
+
+#include <Either.h>
+#include <ReferenceCounter.h>
+
+#include "Game.h"
+#include "ItemFilter.h"
+#include "TypeRegistry.h"
+
+class Block;
+class Entity;
+class Item;
+
+class InteractionConfig : public virtual Framework::ReferenceCounter
+{
+private:
+    ItemFilter* filter;
+
+public:
+    InteractionConfig();
+    ~InteractionConfig();
+    void setItemFilter(ItemFilter* filter);
+    ItemFilter* zItemFilter() const;
+    bool doInteraction(Framework::Either<Block*, Entity*> target,
+        Item* zItem,
+        Entity* actor,
+        bool& itemChanged);
+
+protected:
+    virtual bool onInteraction(Framework::Either<Block*, Entity*> target,
+        Item* zItem,
+        Entity* actor,
+        bool& itemChanged)
+        = 0;
+};
+
+template<class T> class InteractionConfigFactory
+    : public SubTypeFactory<InteractionConfig, T>
+{
+public:
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const
+    {
+        return builder->withRequiredAttribute("itemFilter",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemFilter>(),
+            false,
+            true);
+    }
+
+    virtual T* fromJson(Framework::JSON::JSONObject* zJson) const
+    {
+        T* result = createValue(zJson);
+        if (zJson->hasValue("itemFilter"))
+        {
+            ItemFilter* itemFilter
+                = Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
+                    zJson->zValue("itemFilter"));
+            result->setItemFilter(itemFilter);
+        }
+        return result;
+    }
+
+    virtual Framework::JSON::JSONObject* toJsonObject(T* zObject) const
+    {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+        if (zObject->zItemFilter())
+        {
+            result->addValue("itemFilter",
+                Game::INSTANCE->zTypeRegistry()->toJson(
+                    zObject->zItemFilter()));
+        }
+        return result;
+    }
+
+protected:
+    virtual T* createValue(Framework::JSON::JSONObject* zJson) const = 0;
+};

+ 121 - 78
FactoryCraft/Inventory.cpp

@@ -9,6 +9,7 @@
 #include "ItemFilter.h"
 #include "ItemSlot.h"
 #include "ItemStack.h"
+#include "ItemType.h"
 #include "NetworkMessage.h"
 
 using namespace Framework;
@@ -25,7 +26,7 @@ InventoryInteraction::InventoryInteraction(
 InventoryInteraction::InventoryInteraction(
     const InventoryInteraction& interaction)
     : InventoryInteraction(
-        interaction.current, interaction.other, interaction.dir)
+          interaction.current, interaction.other, interaction.dir)
 {}
 
 InventoryInteraction::~InventoryInteraction()
@@ -435,60 +436,7 @@ void Inventory::saveInventory(Framework::StreamWriter* zWriter)
 
 void Inventory::notifyObservers(NetworkMessage* msg)
 {
-    cs.lock();
-    int index = 0;
-    Array<int> toDelete;
-    for (auto observer : observers)
-    {
-        Entity* e = Game::INSTANCE->zEntity(observer.getFirst());
-        if (e)
-        {
-            msg->addressUIElement(observer.getSecond());
-            Game::INSTANCE->sendMessage(msg->clone(), e);
-        }
-        else
-            toDelete.add(index, 0);
-        index++;
-    }
-    for (int i : toDelete)
-        observers.remove(i);
-    cs.unlock();
-    msg->release();
-}
-
-void Inventory::removeObserver(Entity* zSource, Framework::Text id)
-{
-    cs.lock();
-    int index = 0;
-    for (auto observer : observers)
-    {
-        if (observer.getFirst() == zSource->getId()
-            && observer.getSecond().istGleich(id))
-        {
-            observers.remove(index);
-            break;
-        }
-        index++;
-    }
-    cs.unlock();
-}
-
-void Inventory::addObserver(Entity* zSource, Framework::Text id)
-{
-    cs.lock();
-    for (auto observer : observers)
-    {
-        if (observer.getFirst() == zSource->getId()
-            && observer.getSecond().istGleich(id))
-        {
-            cs.unlock();
-            return;
-        }
-    }
-    observers.add(ImmutablePair<int, Text>(zSource->getId(), id));
-    cs.unlock();
-    for (auto call : observerAddedCalls)
-        call(zSource, id);
+    observable.notifyObservers(msg);
 }
 
 void Inventory::lock()
@@ -566,7 +514,7 @@ void Inventory::addItems(ItemStack* zItems, Direction dir, ItemFilter* zFilter)
     {
         cs.lock();
         for (auto targetSlot = pushSlotsOrder->begin(); targetSlot;
-             targetSlot++)
+            targetSlot++)
         {
             if (!targetSlot->isFull()
                 && (!zFilter || zFilter->matchTargetSlot(targetSlot)))
@@ -576,9 +524,9 @@ void Inventory::addItems(ItemStack* zItems, Direction dir, ItemFilter* zFilter)
                     if (targetSlot->zStack()->zItem()->canBeStackedWith(
                             zItems->zItem()))
                     {
-                        int number
-                            = MIN(targetSlot->numberOfAddableItems(zItems, dir),
-                                zItems->getSize());
+                        int number = MIN(targetSlot->numberOfAddableItems(
+                                             zItems->zItem(), dir),
+                            zItems->getSize());
                         int tmp = number;
                         if (number > 0
                             && allowPushStack(
@@ -602,9 +550,9 @@ void Inventory::addItems(ItemStack* zItems, Direction dir, ItemFilter* zFilter)
                 }
                 else
                 {
-                    int number
-                        = MIN(targetSlot->numberOfAddableItems(zItems, dir),
-                            zItems->getSize());
+                    int number = MIN(
+                        targetSlot->numberOfAddableItems(zItems->zItem(), dir),
+                        zItems->getSize());
                     int tmp = number;
                     if (number > 0
                         && allowPushStack(
@@ -638,8 +586,8 @@ void Inventory::addItems(ItemSlot* zSlot, ItemStack* zItems, Direction dir)
         && !zSlot->zStack()->zItem()->canBeStackedWith(zItems->zItem()))
         return;
     bool needUpdate = !zSlot->zStack();
-    int number
-        = MIN(zSlot->numberOfAddableItems(zItems, dir), zItems->getSize());
+    int number = MIN(
+        zSlot->numberOfAddableItems(zItems->zItem(), dir), zItems->getSize());
     int tmp = number;
     if (number > 0 && allowPushStack(zSlot, dir, zItems->zItem(), tmp))
     {
@@ -684,20 +632,108 @@ void Inventory::unsaveAddItem(
     addItems(zStack, dir, zFilter);
 }
 
-int Inventory::numberOfAddableItems(
-    const ItemStack* zStack, Direction dir) const
+int Inventory::numberOfAddableItems(const Item* zItem, Direction dir) const
 {
     int count = 0;
     for (auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++)
     {
-        int maxCount = targetSlot->numberOfAddableItems(zStack, dir);
+        int maxCount = targetSlot->numberOfAddableItems(zItem, dir);
         int allowed = maxCount;
-        if (allowPushStack(targetSlot, dir, zStack->zItem(), allowed))
+        if (allowPushStack(targetSlot, dir, zItem, allowed))
             count += MIN(maxCount, allowed);
     }
     return count;
 }
 
+int Inventory::numberOfAddableItems(
+    const Item* zItem, Direction dir, const Framework::Text& slotName) const
+{
+    int count = 0;
+    for (auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++)
+    {
+        if (targetSlot->getName().istGleich(slotName))
+        {
+            int maxCount = targetSlot->numberOfAddableItems(zItem, dir);
+            int allowed = maxCount;
+            if (allowPushStack(targetSlot, dir, zItem, allowed))
+                count += MIN(maxCount, allowed);
+        }
+    }
+    return count;
+}
+
+bool Inventory::isAllAvailable(Framework::RCArray<RecipieInput>& inputs,
+    const Framework::Text& slotName) const
+{
+    int* used = new int[pullSlotsOrder->getEintragAnzahl()];
+    memset(used, 0, sizeof(int) * pullSlotsOrder->getEintragAnzahl());
+    for (RecipieInput* input : inputs)
+    {
+        int found = 0;
+        for (int i = 0; i < pullSlotsOrder->getEintragAnzahl(); i++)
+        {
+            ItemSlot* slot = pullSlotsOrder->get(i);
+            if (slot && slot->zStack() && slot->zStack()->zItem()
+                && slot->getNumberOfItems() > used[i]
+                && slot->getName().istGleich(slotName)
+                && input->zFilter()->matchItem(slot->zStack()->zItem()))
+            {
+                int usable = slot->getNumberOfItems() - used[i];
+                if (found + usable >= input->getAmount())
+                {
+                    used[i] += input->getAmount() - found;
+                    found = input->getAmount();
+                    break;
+                }
+                else
+                {
+                    used[i] += usable;
+                    found += usable;
+                }
+            }
+        }
+        if (found < input->getAmount())
+        {
+            delete[] used;
+            return 0;
+        }
+    }
+    delete[] used;
+    return 1;
+}
+
+void Inventory::consume(
+    Framework::RCArray<RecipieInput>& inputs, const Framework::Text& slotName)
+{
+    for (RecipieInput* input : inputs)
+    {
+        int consumed = 0;
+        for (int i = 0; i < pullSlotsOrder->getEintragAnzahl(); i++)
+        {
+            ItemSlot* slot = pullSlotsOrder->get(i);
+            if (slot && slot->zStack() && slot->zStack()->zItem()
+                && slot->getName().istGleich(slotName)
+                && input->zFilter()->matchItem(slot->zStack()->zItem()))
+            {
+                if (consumed + slot->getNumberOfItems() >= input->getAmount())
+                {
+                    takeItemsOut(
+                        slot, input->getAmount() - consumed, NO_DIRECTION)
+                        ->release();
+                    consumed = input->getAmount();
+                    break;
+                }
+                else
+                {
+                    consumed += slot->getNumberOfItems();
+                    takeItemsOut(slot, slot->getNumberOfItems(), NO_DIRECTION)
+                        ->release();
+                }
+            }
+        }
+    }
+}
+
 Framework::ArrayIterator<ItemSlot*> Inventory::begin()
 {
     return pullSlotsOrder->begin();
@@ -723,8 +759,10 @@ void Inventory::inventoryApi(Framework::StreamReader* zRequest,
             char* id = new char[idLen + 1];
             zRequest->lese(id, idLen);
             id[(int)idLen] = 0;
-            zResponse->addressUIElement(id);
-            addObserver(zSource, id);
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            zResponse->addressUIElement(id, processor);
+            observable.addObserver(zSource, id, processor);
             delete[] id;
             char filterLen;
             zRequest->lese(&filterLen, 1);
@@ -780,7 +818,9 @@ void Inventory::inventoryApi(Framework::StreamReader* zRequest,
             char* id = new char[idLen + 1];
             zRequest->lese(id, idLen);
             id[(int)idLen] = 0;
-            removeObserver(zSource, id);
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            observable.removeObserver(zSource, id, processor);
             delete[] id;
             break;
         }
@@ -791,7 +831,9 @@ void Inventory::inventoryApi(Framework::StreamReader* zRequest,
             char* id = new char[idLen + 1];
             zRequest->lese(id, idLen);
             id[(int)idLen] = 0;
-            zResponse->addressUIElement(id);
+            int processor;
+            zRequest->lese((char*)&processor, 4);
+            zResponse->addressUIElement(id, processor);
             delete[] id;
             int slotId;
             zRequest->lese((char*)&slotId, 4);
@@ -829,9 +871,10 @@ void Inventory::registerAfterPushStackCall(std::function<void(
 }
 
 void Inventory::registerObserverAddedCall(
-    std::function<void(Entity* zSource, Framework::Text id)> call)
+    std::function<void(Entity* zSource, Framework::Text id, int processor)>
+        call)
 {
-    observerAddedCalls.add(call);
+    observable.registerOnObserverAddedCall(call);
 }
 
 int Inventory::getDimensionId() const
@@ -857,8 +900,8 @@ bool Inventory::unsafeMove(Inventory* zSource,
         if (sourceSlot->zStack()->zItem()->canBeStackedWith(
                 targetSlot->zStack()->zItem()))
         {
-            int number = MIN(
-                targetSlot->numberOfAddableItems(sourceSlot->zStack(), outDir),
+            int number = MIN(targetSlot->numberOfAddableItems(
+                                 sourceSlot->zStack()->zItem(), outDir),
                 count);
             int tmp = number;
             if (number > 0 && zSource->allowPullStack(sourceSlot, outDir)
@@ -896,8 +939,8 @@ bool Inventory::unsafeMove(Inventory* zSource,
     }
     else
     {
-        int number = MIN(
-            targetSlot->numberOfAddableItems(sourceSlot->zStack(), outDir),
+        int number = MIN(targetSlot->numberOfAddableItems(
+                             sourceSlot->zStack()->zItem(), outDir),
             count);
         int tmp = number;
         if (number > 0 && zSource->allowPullStack(sourceSlot, outDir)

+ 30 - 15
FactoryCraft/Inventory.h

@@ -2,18 +2,19 @@
 
 #include <Critical.h>
 #include <HashMap.h>
-#include <ImmutablePair.h>
 #include <ReferenceCounter.h>
 #include <Vec3.h>
 #include <Writer.h>
 
 #include "Area.h"
+#include "ItemSlot.h"
+#include "Recipie.h"
+#include "UIObservable.h"
 
 class ItemFilter;
 class Inventory;
 class NetworkMessage;
 class Entity;
-class ItemSlot;
 class Item;
 class ItemStack;
 
@@ -57,10 +58,17 @@ public:
     void lock();
 };
 
+struct InventoryObserver
+{
+    int entityId;
+    Framework::Text uimlId;
+    int processorId;
+};
+
 class Inventory : public virtual Framework::ReferenceCounter
 {
 private:
-    Framework::Array<Framework::ImmutablePair<int, Framework::Text>> observers;
+    UIObservable observable;
     Framework::RCArray<ItemSlot>* pullSlotsOrder;
     Framework::RCArray<ItemSlot>* pushSlotsOrder;
     Framework::HashMap<int, Framework::Array<ItemSlot*>*>* itemCache;
@@ -71,10 +79,15 @@ private:
     Framework::Array<std::function<void(
         ItemSlot* zSlot, Direction dir, const Item* zItem, int count)>>
         afterPushStackCalls;
-    Framework::Array<std::function<void(Entity* zSource, Framework::Text id)>>
-        observerAddedCalls;
     int nextSlotId;
 
+public:
+    Inventory(const Framework::Vec3<float> location,
+        int dimensionId,
+        bool hasInventory);
+    virtual ~Inventory();
+
+private:
     void updateCache(ItemSlot* zSlot, int beforeKey);
 
 protected:
@@ -91,18 +104,12 @@ protected:
     virtual void updateSlot(ItemSlot* zSlot);
     virtual void loadInventory(Framework::StreamReader* zReader);
     virtual void saveInventory(Framework::StreamWriter* zWriter);
-    void removeObserver(Entity* zSource, Framework::Text id);
-    void addObserver(Entity* zSource, Framework::Text id);
     virtual void addItems(
         ItemStack* zItems, Direction dir, ItemFilter* zFilter);
-    void lock();
-    void unlock();
 
 public:
-    Inventory(const Framework::Vec3<float> location,
-        int dimensionId,
-        bool hasInventory);
-    virtual ~Inventory();
+    void lock();
+    void unlock();
     void notifyObservers(NetworkMessage* msg);
     const ItemSlot* zSlot(int id) const;
     void addSlot(ItemSlot* slot);
@@ -116,7 +123,14 @@ public:
     virtual void addItems(ItemSlot* zSlot, ItemStack* zItems, Direction dir);
     InventoryInteraction interactWith(Inventory* zInventory, Direction dir);
     void unsaveAddItem(ItemStack* zStack, Direction dir, ItemFilter* zFilter);
-    int numberOfAddableItems(const ItemStack* zStack, Direction dir) const;
+    int numberOfAddableItems(const Item* zItem, Direction dir) const;
+    int numberOfAddableItems(const Item* zItem,
+        Direction dir,
+        const Framework::Text& slotName) const;
+    bool isAllAvailable(Framework::RCArray<RecipieInput>& inputs,
+        const Framework::Text& slotName) const;
+    void consume(Framework::RCArray<RecipieInput>& inputs,
+        const Framework::Text& slotName);
     Framework::ArrayIterator<ItemSlot*> begin();
     Framework::ArrayIterator<ItemSlot*> end();
     void inventoryApi(Framework::StreamReader* zRequest,
@@ -129,7 +143,8 @@ public:
             ItemSlot* zSlot, Direction dir, const Item* zItem, int count)>
             call);
     void registerObserverAddedCall(
-        std::function<void(Entity* zSource, Framework::Text id)> call);
+        std::function<void(Entity* zSource, Framework::Text id, int processor)>
+            call);
     int getDimensionId() const;
     Framework::Vec3<float> getLocation() const;
 

+ 14 - 27
FactoryCraft/Item.cpp

@@ -171,52 +171,39 @@ bool Item::canApplyFoodEffectsFully(Entity* zTarget) const
 }
 
 ItemJsonType::ItemJsonType()
-    : TypeFactory()
+    : ObjectTypeFactory()
 {}
 
-Item* ItemJsonType::createValue(Framework::JSON::JSONObject* zJson) const
-{
-    const ItemType* type = ItemType::zByName(
-        zJson->asObject()->zValue("type")->asString()->getString());
-    return type->createItem();
-}
-
-void ItemJsonType::fromJson(
-    Item* zResult, Framework::JSON::JSONObject* zJson) const
+Item* ItemJsonType::fromJson(Framework::JSON::JSONObject* zJson) const
 {
     const ItemType* type = ItemType::zByName(
         zJson->asObject()->zValue("type")->asString()->getString());
+    Item* result = type->createItem();
     for (auto attribute = zJson->asObject()->getFields(); attribute;
          attribute++)
     {
         if (attribute.val().istGleich("type")) continue;
         type->setItemAttribute(
-            zResult, attribute, zJson->asObject()->zValue(attribute));
+            result, attribute, zJson->asObject()->zValue(attribute));
     }
+    return result;
 }
 
-void ItemJsonType::toJson(
-    Item* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* ItemJsonType::toJsonObject(Item* zObject) const
 {
-    zResult->addValue("type",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("type",
         new Framework::JSON::JSONString(zObject->zItemType()->getName()));
-    zObject->zItemType()->addItemAttributes(zObject, zResult);
+    zObject->zItemType()->addItemAttributes(zObject, result);
+    return result;
 }
 
 JSONObjectValidationBuilder* ItemJsonType::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    Framework::RCArray<Framework::Text> itemTypes;
-    for (int index = 0; index < Game::INSTANCE->getItemTypeCount(); index++)
-    {
-        if (Game::INSTANCE->zItemType(index))
-        {
-            itemTypes.add(new Framework::Text(
-                Game::INSTANCE->zItemType(index)->getName()));
-        }
-    }
-    return builder->withRequiredString("type")
-        ->whichIsOneOf(itemTypes)
-        ->finishString()
+    return builder
+        ->withRequiredAttribute("type",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                ItemTypeNameFactory::TYPE_ID))
         ->allowAdditionalAttriutes();
 }

+ 6 - 8
FactoryCraft/Item.h

@@ -1,12 +1,13 @@
 #pragma once
 
-#include "ItemType.h"
-#include "Reader.h"
+#include <Vec3.h>
+
 #include "TypeRegistry.h"
 
 class ItemType;
 class BlockType;
 class StoneToolItemType;
+class Entity;
 
 class Item : public virtual Framework::ReferenceCounter
 {
@@ -66,15 +67,12 @@ public:
     friend ItemType;
 };
 
-class ItemJsonType : public TypeFactory<Item>
+class ItemJsonType : public ObjectTypeFactory<Item>
 {
 public:
     ItemJsonType();
-    Item* createValue(Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(
-        Item* zResult, Framework::JSON::JSONObject* zJson) const override;
-    void toJson(
-        Item* zObject, Framework::JSON::JSONObject* zResult) const override;
+    Item* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(Item* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };

+ 11 - 7
FactoryCraft/ItemEntity.cpp

@@ -3,6 +3,7 @@
 #include "Game.h"
 #include "ItemSlot.h"
 #include "ItemStack.h"
+#include "ItemType.h"
 
 #ifdef _WINDOWS
 #    define __INT32_MAX__ 0x7FFFFFFF
@@ -19,7 +20,7 @@ ItemEntity::ItemEntity(
     maxStamina = 10;
     maxHunger = 10;
     maxThirst = 10;
-    setHP(10);
+    setHP(0, 0, 0, 10.f);
     setStamina(10);
     setHunger(10);
     setThirst(10);
@@ -36,7 +37,7 @@ void ItemEntity::prepareTick(const Dimension* zDimension)
             dimensionId, location, [this](Entity* zOther) {
                 return zOther != this
                     && zOther->numberOfAddableItems(
-                        slot->zStack(), NO_DIRECTION)
+                        slot->zStack()->zItem(), NO_DIRECTION)
                     && (!this->slot->isFull()
                         || zOther->zType()->getId() != EntityTypeEnum::ITEM);
             });
@@ -59,7 +60,8 @@ void ItemEntity::tick(const Dimension* zDimension)
     Entity* zOther = Game::INSTANCE->zNearestEntity(
         dimensionId, location, [this](Entity* zOther) {
             return zOther != this
-                && zOther->numberOfAddableItems(slot->zStack(), NO_DIRECTION)
+                && zOther->numberOfAddableItems(
+                    slot->zStack()->zItem(), NO_DIRECTION)
                 && (!this->slot->isFull()
                     || zOther->zType()->getId() != EntityTypeEnum::ITEM);
         });
@@ -71,7 +73,7 @@ void ItemEntity::tick(const Dimension* zDimension)
             // add items of this entity to the other entity
             zOther->interactWith(this, NO_DIRECTION)
                 .pullItems(slot->getNumberOfItems(), 0);
-            if (slot->getNumberOfItems() == 0) onDeath();
+            if (slot->getNumberOfItems() == 0) onDeath(0, 0, 0);
         }
     }
     Entity::tick(zDimension);
@@ -79,7 +81,7 @@ void ItemEntity::tick(const Dimension* zDimension)
 
 void ItemEntity::onFall(float collisionSpeed)
 {
-    if (collisionSpeed >= 50.f) this->setHP(0);
+    if (collisionSpeed >= 50.f) this->setHP(0, 0, 0, 0.f);
 }
 
 bool ItemEntity::hasDefaultModel() const
@@ -95,8 +97,10 @@ ModelInfo* ItemEntity::zSpecialModel() const
 }
 
 ItemEntityType::ItemEntityType()
-    : EntityType("Item", 0)
-{}
+    : EntityType()
+{
+    setName("Item");
+}
 
 Entity* ItemEntityType::createEntity(
     Framework::Vec3<float> position, int dimensionId, int entityId) const

+ 86 - 62
FactoryCraft/ItemFilter.cpp

@@ -137,15 +137,10 @@ CombinedItemFilterFactory::CombinedItemFilterFactory()
     : SubTypeFactory()
 {}
 
-CombinedItemFilter* CombinedItemFilterFactory::createValue(
+CombinedItemFilter* CombinedItemFilterFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new CombinedItemFilter();
-}
-
-void CombinedItemFilterFactory::fromJson(
-    CombinedItemFilter* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    CombinedItemFilter* result = new CombinedItemFilter();
     std::function<bool(bool, bool)> func;
     Framework::Text op = zJson->zValue("operator")->asString()->getString();
     if (op.istGleich("or"))
@@ -212,19 +207,21 @@ void CombinedItemFilterFactory::fromJson(
     {
         func = [](bool a, bool b) { return false; };
     }
-    zResult->setOp(func);
+    result->setOp(func);
     Framework::RCArray<ItemFilter> filters;
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("filters")->asArray())
     {
-        zResult->addFilter(
+        result->addFilter(
             Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(value));
     }
+    return result;
 }
 
-void CombinedItemFilterFactory::toJson(
-    CombinedItemFilter* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* CombinedItemFilterFactory::toJsonObject(
+    CombinedItemFilter* zObject) const
 {
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
     Framework::Text op;
     std::function<bool(bool, bool)> func = zObject->getOp();
     if (func(0, 0))
@@ -333,14 +330,14 @@ void CombinedItemFilterFactory::toJson(
             }
         }
     }
-    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
-    zResult->addValue("operator", new Framework::JSON::JSONString(op));
+    result->addValue("operator", new Framework::JSON::JSONString(op));
     Framework::JSON::JSONArray* filters = new Framework::JSON::JSONArray();
     for (ItemFilter* filter : zObject->getFilters())
     {
         filters->addValue(Game::INSTANCE->zTypeRegistry()->toJson(filter));
     }
-    zResult->addValue("filters", filters);
+    result->addValue("filters", filters);
+    return result;
 }
 
 JSONObjectValidationBuilder* CombinedItemFilterFactory::addToValidator(
@@ -370,7 +367,7 @@ JSONObjectValidationBuilder* CombinedItemFilterFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text CombinedItemFilterFactory::getTypeToken() const
+const char* CombinedItemFilterFactory::getTypeToken() const
 {
     return "operator";
 }
@@ -393,19 +390,17 @@ AnyItemFilterFactory::AnyItemFilterFactory()
     : SubTypeFactory()
 {}
 
-AnyItemFilter* AnyItemFilterFactory::createValue(
+AnyItemFilter* AnyItemFilterFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
     return new AnyItemFilter();
 }
 
-void AnyItemFilterFactory::fromJson(
-    AnyItemFilter* zResult, Framework::JSON::JSONObject* zJson) const
-{}
-
-void AnyItemFilterFactory::toJson(
-    AnyItemFilter* zObject, Framework::JSON::JSONObject* zResult) const
-{}
+Framework::JSON::JSONObject* AnyItemFilterFactory::toJsonObject(
+    AnyItemFilter* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
 
 JSONObjectValidationBuilder* AnyItemFilterFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
@@ -413,7 +408,7 @@ JSONObjectValidationBuilder* AnyItemFilterFactory::addToValidator(
     return builder;
 }
 
-Framework::Text AnyItemFilterFactory::getTypeToken() const
+const char* AnyItemFilterFactory::getTypeToken() const
 {
     return "anyItem";
 }
@@ -449,44 +444,33 @@ TypeItemFilterFactory::TypeItemFilterFactory()
     : SubTypeFactory()
 {}
 
-TypeItemFilter* TypeItemFilterFactory::createValue(
+TypeItemFilter* TypeItemFilterFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new TypeItemFilter();
-}
-
-void TypeItemFilterFactory::fromJson(
-    TypeItemFilter* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setType(Game::INSTANCE->zItemType(Game::INSTANCE->getItemTypeId(
+    TypeItemFilter* result = new TypeItemFilter();
+    result->setType(Game::INSTANCE->zItemType(Game::INSTANCE->getItemTypeId(
         zJson->zValue("itemType")->asString()->getString())));
+    return result;
 }
 
-void TypeItemFilterFactory::toJson(
-    TypeItemFilter* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* TypeItemFilterFactory::toJsonObject(
+    TypeItemFilter* zObject) const
 {
-    zResult->addValue("itemType",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
         new Framework::JSON::JSONString(zObject->zType()->getName()));
+    return result;
 }
 
 JSONObjectValidationBuilder* TypeItemFilterFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    Framework::RCArray<Framework::Text> types;
-    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zItemType(i))
-        {
-            types.add(
-                new Framework::Text(Game::INSTANCE->zItemType(i)->getName()));
-        }
-    }
-    return builder->withRequiredString("itemType")
-        ->whichIsOneOf(types)
-        ->finishString();
+    return builder->withRequiredAttribute("itemType",
+        Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+            ItemTypeNameFactory::TYPE_ID));
 }
 
-Framework::Text TypeItemFilterFactory::getTypeToken() const
+const char* TypeItemFilterFactory::getTypeToken() const
 {
     return "type";
 }
@@ -578,7 +562,7 @@ bool GroupItemFilter::matchItem(const Item* zItem) const
     {
         for (Framework::Text* typeGroup : zItem->zItemType()->getGroups())
         {
-            if (typeGroup->istGleich(group)) return true;
+            if (typeGroup->istGleich(*group)) return true;
         }
     }
     return false;
@@ -597,7 +581,7 @@ Framework::Text GroupItemFilter::getLogicUIML() const
                 for (Framework::Text* typeGroup :
                     Game::INSTANCE->zItemType(i)->getGroups())
                 {
-                    if (typeGroup->istGleich(group))
+                    if (typeGroup->istGleich(*group))
                     {
                         found = true;
                         break;
@@ -631,31 +615,29 @@ GroupItemFilterFactory::GroupItemFilterFactory()
     : SubTypeFactory()
 {}
 
-GroupItemFilter* GroupItemFilterFactory::createValue(
+GroupItemFilter* GroupItemFilterFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new GroupItemFilter();
-}
-
-void GroupItemFilterFactory::fromJson(
-    GroupItemFilter* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    GroupItemFilter* result = new GroupItemFilter();
     for (Framework::JSON::JSONValue* group :
         *zJson->zValue("groupNames")->asArray())
     {
-        zResult->addGroup(group->asString()->getString());
+        result->addGroup(group->asString()->getString());
     }
+    return result;
 }
 
-void GroupItemFilterFactory::toJson(
-    GroupItemFilter* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* GroupItemFilterFactory::toJsonObject(
+    GroupItemFilter* zObject) const
 {
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
     Framework::JSON::JSONArray* groups = new Framework::JSON::JSONArray();
     for (Framework::Text* group : zObject->getGroups())
     {
         groups->addValue(new Framework::JSON::JSONString(group->getText()));
     }
-    zResult->addValue("groupNames", groups);
+    result->addValue("groupNames", groups);
+    return result;
 }
 
 JSONObjectValidationBuilder* GroupItemFilterFactory::addToValidator(
@@ -667,7 +649,49 @@ JSONObjectValidationBuilder* GroupItemFilterFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text GroupItemFilterFactory::getTypeToken() const
+const char* GroupItemFilterFactory::getTypeToken() const
 {
     return "groups";
 }
+
+TargetSlotNameItemFilter::TargetSlotNameItemFilter(
+    const Framework::Text& slotName)
+    : ItemFilter(),
+      slotName(slotName)
+{}
+
+bool TargetSlotNameItemFilter::matchSourceSlot(ItemSlot* zSlot) const
+{
+    return 1;
+}
+
+bool TargetSlotNameItemFilter::matchTargetSlot(ItemSlot* zSlot) const
+{
+    return zSlot->getName().istGleich(slotName);
+}
+
+Framework::Text TargetSlotNameItemFilter::getLogicUIML() const
+{
+    return "<anyItem/>";
+}
+
+SourceSlotNameItemFilter::SourceSlotNameItemFilter(
+    const Framework::Text& slotName)
+    : ItemFilter(),
+      slotName(slotName)
+{}
+
+bool SourceSlotNameItemFilter::matchSourceSlot(ItemSlot* zSlot) const
+{
+    return zSlot->getName().istGleich(slotName);
+}
+
+bool SourceSlotNameItemFilter::matchTargetSlot(ItemSlot* zSlot) const
+{
+    return 1;
+}
+
+Framework::Text SourceSlotNameItemFilter::getLogicUIML() const
+{
+    return "<anyItem/>";
+}

+ 41 - 27
FactoryCraft/ItemFilter.h

@@ -44,15 +44,13 @@ class CombinedItemFilterFactory
 {
 public:
     CombinedItemFilterFactory();
-    CombinedItemFilter* createValue(
+    CombinedItemFilter* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(CombinedItemFilter* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(CombinedItemFilter* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        CombinedItemFilter* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class AnyItemFilter : public ItemFilter
@@ -67,15 +65,12 @@ class AnyItemFilterFactory : public SubTypeFactory<ItemFilter, AnyItemFilter>
 {
 public:
     AnyItemFilterFactory();
-    AnyItemFilter* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(AnyItemFilter* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(AnyItemFilter* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    AnyItemFilter* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        AnyItemFilter* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class TypeItemFilter : public ItemFilter
@@ -95,15 +90,12 @@ class TypeItemFilterFactory : public SubTypeFactory<ItemFilter, TypeItemFilter>
 {
 public:
     TypeItemFilterFactory();
-    TypeItemFilter* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(TypeItemFilter* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(TypeItemFilter* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    TypeItemFilter* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        TypeItemFilter* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class SpecificSlotFilter : public ItemFilter
@@ -163,13 +155,35 @@ class GroupItemFilterFactory
 {
 public:
     GroupItemFilterFactory();
-    GroupItemFilter* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(GroupItemFilter* zResult,
+    GroupItemFilter* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(GroupItemFilter* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        GroupItemFilter* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
-};
+    const char* getTypeToken() const override;
+};
+
+class TargetSlotNameItemFilter : public ItemFilter
+{
+private:
+    Framework::Text slotName;
+
+public:
+    TargetSlotNameItemFilter(const Framework::Text& slotName);
+    bool matchSourceSlot(ItemSlot* zSlot) const override;
+    bool matchTargetSlot(ItemSlot* zSlot) const override;
+    Framework::Text getLogicUIML() const override;
+};
+
+class SourceSlotNameItemFilter : public ItemFilter
+{
+private:
+    Framework::Text slotName;
+
+public:
+    SourceSlotNameItemFilter(const Framework::Text& slotName);
+    bool matchSourceSlot(ItemSlot* zSlot) const override;
+    bool matchTargetSlot(ItemSlot* zSlot) const override;
+    Framework::Text getLogicUIML() const override;
+};

+ 35 - 42
FactoryCraft/ItemModifier.cpp

@@ -1,6 +1,7 @@
 #include "ItemModifier.h"
 
 #include "Game.h"
+#include "ItemType.h"
 
 using namespace Framework;
 
@@ -21,19 +22,17 @@ ConsumeItemModifierFactory::ConsumeItemModifierFactory()
     : SubTypeFactory()
 {}
 
-ConsumeItemModifier* ConsumeItemModifierFactory::createValue(
+ConsumeItemModifier* ConsumeItemModifierFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
     return new ConsumeItemModifier();
 }
 
-void ConsumeItemModifierFactory::fromJson(
-    ConsumeItemModifier* zResult, Framework::JSON::JSONObject* zJson) const
-{}
-
-void ConsumeItemModifierFactory::toJson(
-    ConsumeItemModifier* zObject, Framework::JSON::JSONObject* zResult) const
-{}
+Framework::JSON::JSONObject* ConsumeItemModifierFactory::toJsonObject(
+    ConsumeItemModifier* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
 
 JSONObjectValidationBuilder* ConsumeItemModifierFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
@@ -41,7 +40,7 @@ JSONObjectValidationBuilder* ConsumeItemModifierFactory::addToValidator(
     return builder;
 }
 
-Framework::Text ConsumeItemModifierFactory::getTypeToken() const
+const char* ConsumeItemModifierFactory::getTypeToken() const
 {
     return "consume";
 }
@@ -59,19 +58,17 @@ DoNothingModifierFactory::DoNothingModifierFactory()
     : SubTypeFactory()
 {}
 
-DoNothingModifier* DoNothingModifierFactory::createValue(
+DoNothingModifier* DoNothingModifierFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
     return new DoNothingModifier();
 }
 
-void DoNothingModifierFactory::fromJson(
-    DoNothingModifier* zResult, Framework::JSON::JSONObject* zJson) const
-{}
-
-void DoNothingModifierFactory::toJson(
-    DoNothingModifier* zObject, Framework::JSON::JSONObject* zResult) const
-{}
+Framework::JSON::JSONObject* DoNothingModifierFactory::toJsonObject(
+    DoNothingModifier* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
 
 JSONObjectValidationBuilder* DoNothingModifierFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
@@ -79,7 +76,7 @@ JSONObjectValidationBuilder* DoNothingModifierFactory::addToValidator(
     return builder;
 }
 
-Framework::Text DoNothingModifierFactory::getTypeToken() const
+const char* DoNothingModifierFactory::getTypeToken() const
 {
     return "doNothing";
 }
@@ -124,40 +121,38 @@ AttributeItemModifierFactory::AttributeItemModifierFactory()
     : SubTypeFactory()
 {}
 
-AttributeItemModifier* AttributeItemModifierFactory::createValue(
+AttributeItemModifier* AttributeItemModifierFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new AttributeItemModifier();
-}
-
-void AttributeItemModifierFactory::fromJson(
-    AttributeItemModifier* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    AttributeItemModifier* result = new AttributeItemModifier();
     auto attribute = zJson->getFields();
     auto value = zJson->getValues();
     while (attribute, value)
     {
         if (!attribute.val().istGleich("type"))
         {
-            zResult->addAttribute(attribute.val(), value);
+            result->addAttribute(attribute.val(), value);
         }
         attribute++;
         value++;
     }
+    return result;
 }
 
-void AttributeItemModifierFactory::toJson(
-    AttributeItemModifier* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* AttributeItemModifierFactory::toJsonObject(
+    AttributeItemModifier* zObject) const
 {
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
     auto attribute = zObject->getAttributes().begin();
     auto value = zObject->getValues().begin();
     while (attribute && value)
     {
-        zResult->addValue(attribute->getText(),
+        result->addValue(attribute->getText(),
             dynamic_cast<Framework::JSON::JSONObject*>(value->getThis()));
         attribute++;
         value++;
     }
+    return result;
 }
 
 JSONObjectValidationBuilder* AttributeItemModifierFactory::addToValidator(
@@ -166,7 +161,7 @@ JSONObjectValidationBuilder* AttributeItemModifierFactory::addToValidator(
     return builder->allowAdditionalAttriutes();
 }
 
-Framework::Text AttributeItemModifierFactory::getTypeToken() const
+const char* AttributeItemModifierFactory::getTypeToken() const
 {
     return "attributes";
 }
@@ -198,32 +193,30 @@ CombinedItemModifierFactory::CombinedItemModifierFactory()
     : SubTypeFactory()
 {}
 
-CombinedItemModifier* CombinedItemModifierFactory::createValue(
+CombinedItemModifier* CombinedItemModifierFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new CombinedItemModifier();
-}
-
-void CombinedItemModifierFactory::fromJson(
-    CombinedItemModifier* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    CombinedItemModifier* result = new CombinedItemModifier();
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("modifiers")->asArray())
     {
-        zResult->addModifier(
+        result->addModifier(
             Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(value));
     }
+    return result;
 }
 
-void CombinedItemModifierFactory::toJson(
-    CombinedItemModifier* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* CombinedItemModifierFactory::toJsonObject(
+    CombinedItemModifier* zObject) const
 {
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
     Framework::JSON::JSONArray* modifiers = new Framework::JSON::JSONArray();
     for (ItemModifier* modifier : zObject->getModifiers())
     {
         modifiers->addValue(Game::INSTANCE->zTypeRegistry()->toJson(modifier));
     }
-    zResult->addValue("modifiers", modifiers);
+    result->addValue("modifiers", modifiers);
+    return result;
 }
 
 JSONObjectValidationBuilder* CombinedItemModifierFactory::addToValidator(
@@ -235,7 +228,7 @@ JSONObjectValidationBuilder* CombinedItemModifierFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text CombinedItemModifierFactory::getTypeToken() const
+const char* CombinedItemModifierFactory::getTypeToken() const
 {
     return "combined";
 }

+ 16 - 24
FactoryCraft/ItemModifier.h

@@ -24,15 +24,13 @@ class ConsumeItemModifierFactory
 {
 public:
     ConsumeItemModifierFactory();
-    ConsumeItemModifier* createValue(
+    ConsumeItemModifier* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(ConsumeItemModifier* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(ConsumeItemModifier* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        ConsumeItemModifier* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class DoNothingModifier : public ItemModifier
@@ -47,15 +45,13 @@ class DoNothingModifierFactory
 {
 public:
     DoNothingModifierFactory();
-    DoNothingModifier* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(DoNothingModifier* zResult,
+    DoNothingModifier* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(DoNothingModifier* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        DoNothingModifier* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class AttributeItemModifier : public ItemModifier
@@ -77,15 +73,13 @@ class AttributeItemModifierFactory
 {
 public:
     AttributeItemModifierFactory();
-    AttributeItemModifier* createValue(
+    AttributeItemModifier* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(AttributeItemModifier* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(AttributeItemModifier* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        AttributeItemModifier* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class CombinedItemModifier : public ItemModifier
@@ -104,13 +98,11 @@ class CombinedItemModifierFactory
 {
 public:
     CombinedItemModifierFactory();
-    CombinedItemModifier* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(CombinedItemModifier* zResult,
+    CombinedItemModifier* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(CombinedItemModifier* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        CombinedItemModifier* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 3 - 2
FactoryCraft/ItemSkill.cpp

@@ -2,7 +2,6 @@
 
 #include "Block.h"
 #include "Entity.h"
-#include "ItemType.h"
 
 ItemSkill::ItemSkill()
     : Framework::ReferenceCounter(),
@@ -30,7 +29,9 @@ void ItemSkill::save(Framework::StreamWriter* zWriter)
 
 bool ItemSkill::interact(Entity* zActor, Item* zUsedItem, Block* zTarget)
 {
-    return zTarget->interact(zUsedItem, zActor);
+    bool itemChanged = 0;
+    zTarget->interact(zUsedItem, zActor, itemChanged);
+    return itemChanged;
 }
 
 bool ItemSkill::interact(Entity* zActor, Item* zUsedItem, Entity* zTarget)

+ 14 - 8
FactoryCraft/ItemSkill.h

@@ -3,6 +3,7 @@
 #include <JSON.h>
 #include <Reader.h>
 #include <ReferenceCounter.h>
+#include <Writer.h>
 
 #include "TypeRegistry.h"
 
@@ -50,26 +51,28 @@ template<typename S> class ItemSkillFactoryBase
 {
 public:
     ItemSkillFactoryBase()
-        : SubTypeFactory<ItemSkill, S>(){};
+        : SubTypeFactory<ItemSkill, S>() {};
 
-    virtual void fromJson(
-        S* zResult, Framework::JSON::JSONObject* zJson) const override
+    virtual S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
-        ItemSkill* zSkill = dynamic_cast<ItemSkill*>(zResult);
+        S* result = createValue(zJson);
+        ItemSkill* zSkill = dynamic_cast<ItemSkill*>(result);
         zSkill->setMaxXp(
             (float)zJson->zValue("maxXp")->asNumber()->getNumber());
         zSkill->setLevel(
             (float)zJson->zValue("level")->asNumber()->getNumber());
+        return result;
     }
 
-    virtual void toJson(
-        S* zObject, Framework::JSON::JSONObject* zResult) const override
+    virtual Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
         ItemSkill* zSkill = dynamic_cast<ItemSkill*>(zObject);
-        zResult->addValue(
+        result->addValue(
             "maxXp", new Framework::JSON::JSONNumber(zSkill->getMaxXp()));
-        zResult->addValue(
+        result->addValue(
             "level", new Framework::JSON::JSONNumber(zSkill->getLevel()));
+        return result;
     }
 
     virtual JSONObjectValidationBuilder* addToValidator(
@@ -82,4 +85,7 @@ public:
             ->withDefault(1.f)
             ->finishNumber();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };

+ 185 - 10
FactoryCraft/ItemSlot.cpp

@@ -71,28 +71,30 @@ void ItemSlot::addItems(ItemStack* zStack, Direction dir)
     }
 }
 
-void ItemSlot::update() {
+void ItemSlot::update()
+{
     if (items && items->getSize() == 0)
     {
-		items->release();
-		items = 0;
-	}
+        items->release();
+        items = 0;
+    }
 }
 
-int ItemSlot::numberOfAddableItems(const ItemStack* zStack, Direction dir) const
+int ItemSlot::numberOfAddableItems(const Item* zItem, Direction dir) const
 {
     if ((dir | allowedPushSides) == allowedPushSides)
     {
-        if (!items)
+        if (!items || !items->zItem())
         {
             if (allowHigherStackSize)
                 return maxSize;
             else
-                return MIN(maxSize, zStack->zItem()->getMaxStackSize());
+                return MIN(maxSize, zItem->getMaxStackSize());
         }
-        else if (zStack->zItem()
-                 && items->zItem()->canBeStackedWith(zStack->zItem()))
+        else if (zItem && items->zItem()->canBeStackedWith(zItem))
+        {
             return items->getMaxSize() - items->getSize();
+        }
     }
     return 0;
 }
@@ -140,4 +142,177 @@ const Framework::Text& ItemSlot::getName() const
 int ItemSlot::getId() const
 {
     return id;
-}
+}
+
+ItemSlotFactory::ItemSlotFactory()
+    : ObjectTypeFactory()
+{}
+
+JSONObjectValidationBuilder* ItemSlotFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    Framework::JSON::JSONArray* defaultSides = new Framework::JSON::JSONArray();
+    defaultSides->addValue(new Framework::JSON::JSONString("TOP"));
+    defaultSides->addValue(new Framework::JSON::JSONString("BOTTOM"));
+    defaultSides->addValue(new Framework::JSON::JSONString("NORTH"));
+    defaultSides->addValue(new Framework::JSON::JSONString("EAST"));
+    defaultSides->addValue(new Framework::JSON::JSONString("SOUTH"));
+    defaultSides->addValue(new Framework::JSON::JSONString("WEST"));
+    return builder->withRequiredString("category")
+        ->withDefault("Inventory")
+        ->finishString()
+        ->withRequiredNumber("maxSize")
+        ->withDefault(50.0)
+        ->finishNumber()
+        ->withRequiredNumber("pullPriority")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("pushPriority")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredArray("allowedPullSides")
+        ->withDefault(
+            dynamic_cast<Framework::JSON::JSONArray*>(defaultSides->getThis()))
+        ->addAcceptedStringInArray()
+        ->whichIsOneOf({"TOP", "BOTTOM", "NORTH", "EAST", "SOUTH", "WEST"})
+        ->finishString()
+        ->finishArray()
+        ->withRequiredArray("allowedPushSides")
+        ->withDefault(defaultSides)
+        ->addAcceptedStringInArray()
+        ->whichIsOneOf({"TOP", "BOTTOM", "NORTH", "EAST", "SOUTH", "WEST"})
+        ->finishString()
+        ->finishArray()
+        ->withRequiredBool("allowHigherStackSize")
+        ->withDefault(false)
+        ->finishBool();
+}
+
+ItemSlot* ItemSlotFactory::fromJson(Framework::JSON::JSONObject* zJson) const
+{
+    Framework::Text category
+        = zJson->zValue("category")->asString()->getString();
+    int maxSize = (int)zJson->zValue("maxSize")->asNumber()->getNumber();
+    int pullPriority
+        = (int)zJson->zValue("pullPriority")->asNumber()->getNumber();
+    int pushPriority
+        = (int)zJson->zValue("pushPriority")->asNumber()->getNumber();
+    int allowedPullSides = 0;
+    int allowedPushSides = 0;
+    for (Framework::JSON::JSONValue* side :
+        *zJson->zValue("allowedPullSides")->asArray())
+    {
+        Framework::Text sideText = side->asString()->getString();
+        if (sideText.istGleich("TOP"))
+        {
+            allowedPullSides |= TOP;
+        }
+        else if (sideText.istGleich("BOTTOM"))
+        {
+            allowedPullSides |= BOTTOM;
+        }
+        else if (sideText.istGleich("NORTH"))
+        {
+            allowedPullSides |= NORTH;
+        }
+        else if (sideText.istGleich("EAST"))
+        {
+            allowedPullSides |= EAST;
+        }
+        else if (sideText.istGleich("SOUTH"))
+        {
+            allowedPullSides |= SOUTH;
+        }
+        else if (sideText.istGleich("WEST"))
+        {
+            allowedPullSides |= WEST;
+        }
+    }
+    for (Framework::JSON::JSONValue* side :
+        *zJson->zValue("allowedPushSides")->asArray())
+    {
+        Framework::Text sideText = side->asString()->getString();
+        if (sideText.istGleich("TOP"))
+        {
+            allowedPushSides |= TOP;
+        }
+        else if (sideText.istGleich("BOTTOM"))
+        {
+            allowedPushSides |= BOTTOM;
+        }
+        else if (sideText.istGleich("NORTH"))
+        {
+            allowedPushSides |= NORTH;
+        }
+        else if (sideText.istGleich("EAST"))
+        {
+            allowedPushSides |= EAST;
+        }
+        else if (sideText.istGleich("SOUTH"))
+        {
+            allowedPushSides |= SOUTH;
+        }
+        else if (sideText.istGleich("WEST"))
+        {
+            allowedPushSides |= WEST;
+        }
+    }
+    bool allowHigherStackSize
+        = zJson->zValue("allowHigherStackSize")->asBool()->getBool();
+    return new ItemSlot(category,
+        maxSize,
+        pullPriority,
+        pushPriority,
+        allowedPullSides,
+        allowedPushSides,
+        allowHigherStackSize);
+}
+
+Framework::JSON::JSONObject* ItemSlotFactory::toJsonObject(
+    ItemSlot* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
+        "category", new Framework::JSON::JSONString(zObject->getName()));
+    result->addValue(
+        "maxSize", new Framework::JSON::JSONNumber((double)zObject->maxSize));
+    result->addValue("pullPriority",
+        new Framework::JSON::JSONNumber((double)zObject->getPullPriority()));
+    result->addValue("pushPriority",
+        new Framework::JSON::JSONNumber((double)zObject->getPushPriority()));
+    Framework::JSON::JSONArray* allowedPullSides
+        = new Framework::JSON::JSONArray();
+    if (zObject->allowedPullSide & TOP)
+        allowedPullSides->addValue(new Framework::JSON::JSONString("TOP"));
+    if (zObject->allowedPullSide & BOTTOM)
+        allowedPullSides->addValue(new Framework::JSON::JSONString("BOTTOM"));
+    if (zObject->allowedPullSide & NORTH)
+        allowedPullSides->addValue(new Framework::JSON::JSONString("NORTH"));
+    if (zObject->allowedPullSide & EAST)
+        allowedPullSides->addValue(new Framework::JSON::JSONString("EAST"));
+    if (zObject->allowedPullSide & SOUTH)
+        allowedPullSides->addValue(new Framework::JSON::JSONString("SOUTH"));
+    if (zObject->allowedPullSide & WEST)
+        allowedPullSides->addValue(new Framework::JSON::JSONString("WEST"));
+    result->addValue("allowedPullSides", allowedPullSides);
+    Framework::JSON::JSONArray* allowedPushSides
+        = new Framework::JSON::JSONArray();
+    if (zObject->allowedPushSides & TOP)
+        allowedPushSides->addValue(new Framework::JSON::JSONString("TOP"));
+    if (zObject->allowedPushSides & BOTTOM)
+        allowedPullSides->addValue(new Framework::JSON::JSONString("BOTTOM"));
+    if (zObject->allowedPushSides & NORTH)
+        allowedPushSides->addValue(new Framework::JSON::JSONString("NORTH"));
+    if (zObject->allowedPushSides & EAST)
+        allowedPushSides->addValue(new Framework::JSON::JSONString("EAST"));
+    if (zObject->allowedPushSides & SOUTH)
+        allowedPushSides->addValue(new Framework::JSON::JSONString("SOUTH"));
+    if (zObject->allowedPushSides & WEST)
+        allowedPushSides->addValue(new Framework::JSON::JSONString("WEST"));
+    result->addValue("allowedPushSides", allowedPushSides);
+    result->addValue("allowHigherStackSize",
+        new Framework::JSON::JSONBool(zObject->allowHigherStackSize));
+    return result;
+}

+ 17 - 3
FactoryCraft/ItemSlot.h

@@ -3,9 +3,11 @@
 #include <Text.h>
 
 #include "Area.h"
+#include "TypeRegistry.h"
 
 class Inventory;
 class ItemStack;
+class Item;
 
 class ItemSlotIDSetter
 {
@@ -36,7 +38,7 @@ public:
         int maxSize,
         int pullPriority,
         int pushPriority,
-        int allowedPullSide,
+        int allowedPullSides,
         int allowedPushSides,
         bool allowHigherStackSize);
     ~ItemSlot();
@@ -45,7 +47,7 @@ public:
     void addItems(ItemStack* zStack, Direction dir);
     void update();
 
-    int numberOfAddableItems(const ItemStack* zStack, Direction dir) const;
+    int numberOfAddableItems(const Item* zItem, Direction dir) const;
     const ItemStack* zStack() const;
     int getPullPriority() const;
     int getPushPriority() const;
@@ -55,4 +57,16 @@ public:
     int getNumberOfItems() const;
     const Framework::Text& getName() const;
     int getId() const;
-};
+
+    friend class ItemSlotFactory;
+};
+
+class ItemSlotFactory : public ObjectTypeFactory<ItemSlot>
+{
+public:
+    ItemSlotFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    ItemSlot* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(ItemSlot* zObject) const override;
+};

+ 2 - 1
FactoryCraft/ItemStack.cpp

@@ -1,6 +1,7 @@
 #include "ItemStack.h"
 
 #include "Item.h"
+#include "ItemType.h"
 
 ItemStack::ItemStack(Item* item, int currentSize, int maxSize)
     : ReferenceCounter(),
@@ -27,7 +28,7 @@ ItemStack* ItemStack::split(int size)
 {
     size = MIN(size, this->size);
     this->size -= size;
-    ItemStack *result = new ItemStack(
+    ItemStack* result = new ItemStack(
         dynamic_cast<Item*>(item->getThis()), size, item->getMaxStackSize());
     if (size == 0)
     {

+ 2 - 2
FactoryCraft/ItemType.cpp

@@ -112,7 +112,7 @@ void ItemType::setItemAttribute(
     Item* zItem, Framework::Text name, Framework::JSON::JSONValue* zValue) const
 {
     bool ok = true;
-    if (zValue->getType() == Framework::JSON::JSONType::NUMBER)
+    if (zValue->getType() == Framework::AbstractType::NUMBER)
     {
         if (name.istGleich("hp"))
             zItem->hp = (float)zValue->asNumber()->getNumber();
@@ -125,7 +125,7 @@ void ItemType::setItemAttribute(
         else
             ok = false;
     }
-    else if (zValue->getType() == Framework::JSON::JSONType::STRING)
+    else if (zValue->getType() == Framework::AbstractType::STRING)
     {
         if (name.istGleich("name"))
             zItem->name = zValue->asString()->getString();

+ 13 - 9
FactoryCraft/ItemType.h

@@ -2,11 +2,9 @@
 
 #include <JSON.h>
 #include <Text.h>
-#include <Trie.h>
 #include <Writer.h>
 
 #include "BlockType.h"
-#include "Effect.h"
 #include "Game.h"
 #include "ModelInfo.h"
 
@@ -33,7 +31,7 @@ protected:
 
 public:
     ItemType();
-    ~ItemType();
+    virtual ~ItemType();
 
 protected:
     virtual void loadSuperItem(
@@ -99,10 +97,10 @@ public:
         : SubTypeFactory<ItemType, S>()
     {}
 
-    virtual void fromJson(
-        S* zResult, Framework::JSON::JSONObject* zJson) const override
+    virtual S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
-        ItemType* zType = dynamic_cast<ItemType*>(zResult);
+        S* result = createValue(zJson);
+        ItemType* zType = dynamic_cast<ItemType*>(result);
         zType->setModel(Game::INSTANCE->zTypeRegistry()->fromJson<ModelInfo>(
             zJson->zValue("model")->asObject()));
         zType->setName(zJson->zValue("name")->asString()->getString());
@@ -118,12 +116,14 @@ public:
         {
             zType->addGroup(value->asString()->getString());
         }
+        return result;
     }
 
-    virtual void toJson(
-        S* zObject, Framework::JSON::JSONObject* zResult) const override
+    virtual Framework::JSON::JSONObject* toJsonObject(S* zObject) const
     {
-        ItemType* zType = dynamic_cast<ItemType*>(zResult);
+        Framework::JSON::JSONObject* zResult
+            = new Framework::JSON::JSONObject();
+        ItemType* zType = dynamic_cast<ItemType*>(zObject);
         zResult->addValue("model",
             Game::INSTANCE->zTypeRegistry()->toJson<ModelInfo>(
                 zType->zModel()));
@@ -140,6 +140,7 @@ public:
             groupNames->addValue(new Framework::JSON::JSONString(*groupName));
         }
         zResult->addValue("groupNames", groupNames);
+        return zResult;
     }
 
     virtual JSONObjectValidationBuilder* addToValidator(
@@ -162,4 +163,7 @@ public:
             ->finishString()
             ->finishArray();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };

+ 49 - 0
FactoryCraft/ItemTypeNameFactory.cpp

@@ -0,0 +1,49 @@
+#include "ItemTypeNameFactory.h"
+
+const Framework::Text ItemTypeNameFactory::TYPE_ID = "ItemTypeName";
+
+ItemTypeNameFactory::ItemTypeNameFactory()
+    : SimpleTypeFactory<Framework::Text*>(),
+      itemTypeNames(0)
+{}
+
+ItemTypeNameFactory::~ItemTypeNameFactory()
+{
+    if (itemTypeNames)
+    {
+        itemTypeNames->release();
+    }
+}
+
+void ItemTypeNameFactory::setItemTypeNames(
+    Framework::RCArray<Framework::Text>* itemTypeNames)
+{
+    this->itemTypeNames = itemTypeNames;
+}
+
+Framework::Text* ItemTypeNameFactory::fromJson(
+    Framework::JSON::JSONValue* zJson) const
+{
+    return new Framework::Text(zJson->asString()->getString());
+}
+
+Framework::JSON::JSONValue* ItemTypeNameFactory::toJson(
+    Framework::Text* value) const
+{
+    return new Framework::JSON::JSONString(value->getText());
+}
+
+Framework::Validator::DataValidator* ItemTypeNameFactory::getValidator() const
+{
+    if (!itemTypeNames)
+    {
+        return Framework::Validator::DataValidator::buildForString()
+            ->finishString();
+    }
+    else
+    {
+        return Framework::Validator::DataValidator::buildForString()
+            ->whichIsOneOf(*itemTypeNames)
+            ->finishString();
+    }
+}

+ 20 - 0
FactoryCraft/ItemTypeNameFactory.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "TypeRegistry.h"
+
+class ItemTypeNameFactory : public SimpleTypeFactory<Framework::Text*>
+{
+public:
+    static const Framework::Text TYPE_ID;
+
+private:
+    Framework::RCArray<Framework::Text>* itemTypeNames;
+
+public:
+    ItemTypeNameFactory();
+    ~ItemTypeNameFactory();
+    void setItemTypeNames(Framework::RCArray<Framework::Text>* itemTypeNames);
+    Framework::Text* fromJson(Framework::JSON::JSONValue* zJson) const override;
+    Framework::JSON::JSONValue* toJson(Framework::Text* value) const override;
+    Framework::Validator::DataValidator* getValidator() const override;
+};

+ 106 - 117
FactoryCraft/JNoise.cpp

@@ -19,7 +19,9 @@ Noise* JNoise::parseNoise(JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
         JFloatExpression* seedExpression
             = Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
                 zConfig->asObject()->zValue("seed"));
-        float seed = seedExpression->getValue(zMemory);
+        seedExpression->compile(zMemory);
+        float seed = seedExpression->getValue();
+        seedExpression->release();
         return new RandNoise((int)(round(seed)));
     }
     else if (type.istGleich("factorize"))
@@ -63,7 +65,9 @@ Noise* JNoise::parseNoise(JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
         JFloatExpression* seedExpression
             = Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
                 zConfig->asObject()->zValue("seed"));
-        float seed = seedExpression->getValue(zMemory);
+        seedExpression->compile(zMemory);
+        float seed = seedExpression->getValue();
+        seedExpression->release();
         FastNoiseLite* noise = new FastNoiseLite((int)(round(seed)));
         if (type.istGleich("Cellular"))
             noise->SetNoiseType(FastNoiseLite::NoiseType::NoiseType_Cellular);
@@ -104,9 +108,9 @@ Noise* JNoise::parseNoise(JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
         if (zConfig->asObject()->hasValue("frequency"))
         {
             noise->SetFrequency((float)zConfig->asObject()
-                                    ->zValue("frequency")
-                                    ->asNumber()
-                                    ->getNumber());
+                    ->zValue("frequency")
+                    ->asNumber()
+                    ->getNumber());
         }
         if (zConfig->asObject()->hasValue("fractalType"))
         {
@@ -148,23 +152,23 @@ Noise* JNoise::parseNoise(JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
         if (zConfig->asObject()->hasValue("fractalOctaves"))
         {
             noise->SetFractalOctaves((int)round(zConfig->asObject()
-                                                    ->zValue("fractalOctaves")
-                                                    ->asNumber()
-                                                    ->getNumber()));
+                    ->zValue("fractalOctaves")
+                    ->asNumber()
+                    ->getNumber()));
         }
         if (zConfig->asObject()->hasValue("fractalLacunarity"))
         {
             noise->SetFractalLacunarity((float)zConfig->asObject()
-                                            ->zValue("fractalLacunarity")
-                                            ->asNumber()
-                                            ->getNumber());
+                    ->zValue("fractalLacunarity")
+                    ->asNumber()
+                    ->getNumber());
         }
         if (zConfig->asObject()->hasValue("fractalGain"))
         {
             noise->SetFractalGain((float)zConfig->asObject()
-                                      ->zValue("fractalGain")
-                                      ->asNumber()
-                                      ->getNumber());
+                    ->zValue("fractalGain")
+                    ->asNumber()
+                    ->getNumber());
         }
         if (zConfig->asObject()->hasValue("cellularDistanceFunction"))
         {
@@ -242,9 +246,9 @@ Noise* JNoise::parseNoise(JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
         if (zConfig->asObject()->hasValue("cellularJitter"))
         {
             noise->SetCellularJitter((float)zConfig->asObject()
-                                         ->zValue("cellularJitter")
-                                         ->asNumber()
-                                         ->getNumber());
+                    ->zValue("cellularJitter")
+                    ->asNumber()
+                    ->getNumber());
         }
         if (zConfig->asObject()->hasValue("domainWarpType"))
         {
@@ -271,33 +275,33 @@ Noise* JNoise::parseNoise(JSON::JSONValue* zConfig, JExpressionMemory* zMemory)
         if (zConfig->asObject()->hasValue("domainWarpAmp"))
         {
             noise->SetDomainWarpAmp((float)zConfig->asObject()
-                                        ->zValue("domainWarpAmp")
-                                        ->asNumber()
-                                        ->getNumber());
+                    ->zValue("domainWarpAmp")
+                    ->asNumber()
+                    ->getNumber());
         }
         FastNoiseWrapper* result
             = new FastNoiseWrapper(noise, (int)(round(seed)));
         if (zConfig->asObject()->hasValue("multiplier"))
         {
             result->setMultiplier((float)zConfig->asObject()
-                                      ->zValue("multiplier")
-                                      ->asNumber()
-                                      ->getNumber());
+                    ->zValue("multiplier")
+                    ->asNumber()
+                    ->getNumber());
         }
         return result;
     }
     return 0;
 }
 
-JSON::Validator::JSONValidator* JNoise::getValidator(bool optional)
+Validator::DataValidator* JNoise::getValidator(bool optional)
 {
-    auto validator1 = JSON::Validator::JSONValidator::buildForObject();
-    auto validator2 = JSON::Validator::JSONValidator::buildForObject();
-    auto validator3 = JSON::Validator::JSONValidator::buildForObject();
-    auto validator4 = JSON::Validator::JSONValidator::buildForObject();
-    auto validator5 = JSON::Validator::JSONValidator::buildForObject();
-    auto validator6 = JSON::Validator::JSONValidator::buildForObject();
-    auto validator7 = JSON::Validator::JSONValidator::buildForObject();
+    auto validator1 = Validator::DataValidator::buildForObject();
+    auto validator2 = Validator::DataValidator::buildForObject();
+    auto validator3 = Validator::DataValidator::buildForObject();
+    auto validator4 = Validator::DataValidator::buildForObject();
+    auto validator5 = Validator::DataValidator::buildForObject();
+    auto validator6 = Validator::DataValidator::buildForObject();
+    auto validator7 = Validator::DataValidator::buildForObject();
     if (optional)
     {
         validator1 = validator1->whichIsOptional();
@@ -308,101 +312,86 @@ JSON::Validator::JSONValidator* JNoise::getValidator(bool optional)
         validator6 = validator6->whichIsOptional();
         validator7 = validator7->whichIsOptional();
     }
-    JSON::Validator::JSONValidator* refs
-        = JSON::Validator::JSONValidator::buildForOneOf()
+    Validator::DataValidator* refs
+        = Validator::DataValidator::buildForOneOf()
               ->typeSpecifiedByAttribute("type")
               ->addAcceptedType(
-                  JSON::Validator::JSONValidator::buildForObjectReference(
-                      "jn_random"))
+                  Validator::DataValidator::buildForReference("jn_random"))
               ->addAcceptedType(
-                  JSON::Validator::JSONValidator::buildForObjectReference(
-                      "jn_factorize"))
+                  Validator::DataValidator::buildForReference("jn_factorize"))
               ->addAcceptedType(
-                  JSON::Validator::JSONValidator::buildForObjectReference(
-                      "jn_multiply"))
+                  Validator::DataValidator::buildForReference("jn_multiply"))
               ->addAcceptedType(
-                  JSON::Validator::JSONValidator::buildForObjectReference(
-                      "jn_negate"))
+                  Validator::DataValidator::buildForReference("jn_negate"))
               ->addAcceptedType(
-                  JSON::Validator::JSONValidator::buildForObjectReference(
-                      "jn_flatten"))
+                  Validator::DataValidator::buildForReference("jn_flatten"))
               ->addAcceptedType(
-                  JSON::Validator::JSONValidator::buildForObjectReference(
-                      "jn_scale"))
-              ->addAcceptedType(
-                  JSON::Validator::JSONValidator::buildForObjectReference(
-                      "jn_fastNoiseLite"))
+                  Validator::DataValidator::buildForReference("jn_scale"))
+              ->addAcceptedType(Validator::DataValidator::buildForReference(
+                  "jn_fastNoiseLite"))
               ->finishOneOf();
-    return JSON::Validator::JSONValidator::buildForOneOf()
+    return Validator::DataValidator::buildForOneOf()
         ->typeSpecifiedByAttribute("type")
-        ->addAcceptedType(validator1->setObjectReferenceId("jn_random")
-                              ->withRequiredString("type")
-                              ->withExactMatch("random")
-                              ->finishString()
-                              ->withRequiredAttribute("seed",
-                                  Game::INSTANCE->zTypeRegistry()
-                                      ->getValidator<JFloatExpression>())
-                              ->finishObject())
-        ->addAcceptedType(validator2->setObjectReferenceId("jn_factorize")
-                              ->withRequiredString("type")
-                              ->withExactMatch("factorize")
-                              ->finishString()
-                              ->withRequiredNumber("factorA")
-                              ->whichIsGreaterThen(0)
-                              ->whichIsLessThen(1)
-                              ->finishNumber()
-                              ->withRequiredAttribute("noiseA",
-                                  dynamic_cast<JSON::Validator::JSONValidator*>(
-                                      refs->getThis()))
-                              ->withRequiredAttribute("noiseB",
-                                  dynamic_cast<JSON::Validator::JSONValidator*>(
-                                      refs->getThis()))
-                              ->finishObject())
-        ->addAcceptedType(validator3->setObjectReferenceId("jn_multiply")
-                              ->withRequiredString("type")
-                              ->withExactMatch("multiply")
-                              ->finishString()
-                              ->withRequiredAttribute("base",
-                                  dynamic_cast<JSON::Validator::JSONValidator*>(
-                                      refs->getThis()))
-                              ->withRequiredAttribute("multiplier",
-                                  dynamic_cast<JSON::Validator::JSONValidator*>(
-                                      refs->getThis()))
-                              ->finishObject())
-        ->addAcceptedType(validator4->setObjectReferenceId("jn_negate")
-                              ->withRequiredString("type")
-                              ->withExactMatch("negate")
-                              ->finishString()
-                              ->withRequiredAttribute("noise",
-                                  dynamic_cast<JSON::Validator::JSONValidator*>(
-                                      refs->getThis()))
-                              ->finishObject())
-        ->addAcceptedType(validator5->setObjectReferenceId("jn_flatten")
-                              ->withRequiredString("type")
-                              ->withExactMatch("flatten")
-                              ->finishString()
-                              ->withRequiredAttribute("noise",
-                                  dynamic_cast<JSON::Validator::JSONValidator*>(
-                                      refs->getThis()))
-                              ->withRequiredNumber("factor")
-                              ->withDefault(1.0)
-                              ->finishNumber()
-                              ->withRequiredNumber("addition")
-                              ->withDefault(0.0)
-                              ->finishNumber()
-                              ->finishObject())
-        ->addAcceptedType(validator6->setObjectReferenceId("jn_scale")
-                              ->withRequiredString("type")
-                              ->withExactMatch("scale")
-                              ->finishString()
-                              ->withRequiredAttribute("noise",
-                                  dynamic_cast<JSON::Validator::JSONValidator*>(
-                                      refs->getThis()))
-                              ->withRequiredNumber("factor")
-                              ->finishNumber()
-                              ->finishObject())
-        ->addAcceptedType(
-            validator7->setObjectReferenceId("jn_fastNoiseLite")
+        ->addAcceptedType(validator1->setReferenceId("jn_random")
+                ->withRequiredString("type")
+                ->withExactMatch("random")
+                ->finishString()
+                ->withRequiredAttribute("seed",
+                    Game::INSTANCE->zTypeRegistry()
+                        ->getValidator<JFloatExpression>())
+                ->finishObject())
+        ->addAcceptedType(validator2->setReferenceId("jn_factorize")
+                ->withRequiredString("type")
+                ->withExactMatch("factorize")
+                ->finishString()
+                ->withRequiredNumber("factorA")
+                ->whichIsGreaterThen(0)
+                ->whichIsLessThen(1)
+                ->finishNumber()
+                ->withRequiredAttribute("noiseA",
+                    dynamic_cast<Validator::DataValidator*>(refs->getThis()))
+                ->withRequiredAttribute("noiseB",
+                    dynamic_cast<Validator::DataValidator*>(refs->getThis()))
+                ->finishObject())
+        ->addAcceptedType(validator3->setReferenceId("jn_multiply")
+                ->withRequiredString("type")
+                ->withExactMatch("multiply")
+                ->finishString()
+                ->withRequiredAttribute("base",
+                    dynamic_cast<Validator::DataValidator*>(refs->getThis()))
+                ->withRequiredAttribute("multiplier",
+                    dynamic_cast<Validator::DataValidator*>(refs->getThis()))
+                ->finishObject())
+        ->addAcceptedType(validator4->setReferenceId("jn_negate")
+                ->withRequiredString("type")
+                ->withExactMatch("negate")
+                ->finishString()
+                ->withRequiredAttribute("noise",
+                    dynamic_cast<Validator::DataValidator*>(refs->getThis()))
+                ->finishObject())
+        ->addAcceptedType(validator5->setReferenceId("jn_flatten")
+                ->withRequiredString("type")
+                ->withExactMatch("flatten")
+                ->finishString()
+                ->withRequiredAttribute("noise",
+                    dynamic_cast<Validator::DataValidator*>(refs->getThis()))
+                ->withRequiredNumber("factor")
+                ->withDefault(1.0)
+                ->finishNumber()
+                ->withRequiredNumber("addition")
+                ->withDefault(0.0)
+                ->finishNumber()
+                ->finishObject())
+        ->addAcceptedType(validator6->setReferenceId("jn_scale")
+                ->withRequiredString("type")
+                ->withExactMatch("scale")
+                ->finishString()
+                ->withRequiredAttribute("noise",
+                    dynamic_cast<Validator::DataValidator*>(refs->getThis()))
+                ->withRequiredNumber("factor")
+                ->finishNumber()
+                ->finishObject())
+        ->addAcceptedType(validator7->setReferenceId("jn_fastNoiseLite")
                 ->withRequiredString("type")
                 ->whichIsOneOf({"Cellular",
                     "ValueCubic",

+ 3 - 3
FactoryCraft/JNoise.h

@@ -2,12 +2,12 @@
 
 #include <JSON.h>
 
-#include "Noise.h"
 #include "JsonExpression.h"
+#include "Noise.h"
 
 namespace JNoise
 {
     Noise* parseNoise(
         Framework::JSON::JSONValue* zConfig, JExpressionMemory* zMemory);
-    Framework::JSON::Validator::JSONValidator* getValidator(bool optional);
-}
+    Framework::Validator::DataValidator* getValidator(bool optional);
+} // namespace JNoise

+ 590 - 297
FactoryCraft/JsonExpression.cpp

@@ -1,7 +1,6 @@
 #include "JsonExpression.h"
 
-#include "Dimension.h"
-#include "DimensionGenerator.h"
+#include "Chunk.h"
 #include "Game.h"
 
 JExpressionMemory::JExpressionMemory()
@@ -24,13 +23,9 @@ void JExpressionMemory::unlock()
     cs.unlock();
 }
 
-float JExpressionMemory::getNoise(
-    Framework::Text name, float x, float y, float z) const
+Noise* JExpressionMemory::zNoiseP(Framework::Text name)
 {
-    Noise* currentNoise = noises.z(name, name.getLength());
-    if (currentNoise)
-        return (float)currentNoise->getNoise((double)x, (double)y, (double)z);
-    return 0.f;
+    return noises.z(name, name.getLength());
 }
 
 void JExpressionMemory::setNoise(Framework::Text name, Noise* noise)
@@ -44,46 +39,88 @@ void JExpressionMemory::setCurrentChunk(Chunk* chunk)
     currentChunk = chunk;
 }
 
-float JExpressionMemory::getFloatVariable(Framework::Text name) const
+float* JExpressionMemory::getFloatVariableP(const Framework::Text& name)
 {
-    return floatVariables.get(name, name.getLength());
+    if (!floatVariables.contains(name, name.getLength()))
+    {
+        floatVariables.set(name, name.getLength(), 0.f);
+    }
+    return floatVariables.getP(name, name.getLength());
 }
 
-void JExpressionMemory::setFloatVariable(Framework::Text name, float value)
+bool* JExpressionMemory::getBoolVariableP(const Framework::Text& name)
 {
-    floatVariables.set(name, name.getLength(), value);
+    if (!boolVariables.contains(name, name.getLength()))
+    {
+        boolVariables.set(name, name.getLength(), 0);
+    }
+    return boolVariables.getP(name, name.getLength());
 }
 
-bool JExpressionMemory::getBoolVariable(Framework::Text name) const
+Chunk** JExpressionMemory::zzCurrentChunk()
 {
-    return boolVariables.get(name, name.getLength());
+    return &currentChunk;
 }
 
-void JExpressionMemory::setBoolVariable(Framework::Text name, bool value)
+JFloatExpression::JFloatExpression()
+    : ReferenceCounter(),
+      compiled(0)
+{}
+
+float JFloatExpression::getValue()
 {
-    return boolVariables.set(name, name.getLength(), value);
+    return compiled();
 }
 
-Chunk* JExpressionMemory::zCurrentChunk()
+FloatFunc JFloatExpression::compile(JExpressionMemory* zMemory)
 {
-    return currentChunk;
+    if (compiled)
+    {
+        if (zMemory != memory)
+        {
+            throw "Cannot compile the same expression for different memories";
+        }
+        return compiled;
+    }
+    memory = zMemory;
+    return compiled = buildAssembly(zMemory).compileToFunction<FloatFunc>();
 }
 
-JFloatExpression::JFloatExpression()
-    : ReferenceCounter()
-{}
-
 JBoolExpression::JBoolExpression()
-    : ReferenceCounter()
+    : ReferenceCounter(),
+      compiled(0)
 {}
 
+bool JBoolExpression::getValue()
+{
+    return compiled();
+}
+
+BoolFunc JBoolExpression::compile(JExpressionMemory* zMemory)
+{
+    if (compiled)
+    {
+        if (zMemory != memory)
+        {
+            throw "Cannot compile the same expression for different "
+                  "memories";
+        }
+        return compiled;
+    }
+    memory = zMemory;
+    return compiled = buildAssembly(zMemory).compileToFunction<BoolFunc>();
+}
+
 JVariableFloatExpression::JVariableFloatExpression()
     : JFloatExpression()
 {}
 
-float JVariableFloatExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JVariableFloatExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
-    return zMemory->getFloatVariable(name);
+    codeBlock.addLoadValue(
+        zMemory->getFloatVariableP(name), Framework::Assembly::MM0);
+    return codeBlock;
 }
 
 void JVariableFloatExpression::setName(Framework::Text name)
@@ -100,23 +137,21 @@ JVariableFloatExpressionFactory::JVariableFloatExpressionFactory()
     : SubTypeFactory()
 {}
 
-JVariableFloatExpression* JVariableFloatExpressionFactory::createValue(
+JVariableFloatExpression* JVariableFloatExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JVariableFloatExpression();
-}
-
-void JVariableFloatExpressionFactory::fromJson(
-    JVariableFloatExpression* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setName(zJson->zValue("name")->asString()->getString());
+    JVariableFloatExpression* result = new JVariableFloatExpression();
+    result->setName(zJson->zValue("name")->asString()->getString());
+    return result;
 }
 
-void JVariableFloatExpressionFactory::toJson(JVariableFloatExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JVariableFloatExpressionFactory::toJsonObject(
+    JVariableFloatExpression* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "name", new Framework::JSON::JSONString(zObject->getName()));
+    return result;
 }
 
 JSONObjectValidationBuilder* JVariableFloatExpressionFactory::addToValidator(
@@ -125,7 +160,7 @@ JSONObjectValidationBuilder* JVariableFloatExpressionFactory::addToValidator(
     return builder->withRequiredString("name")->finishString();
 }
 
-Framework::Text JVariableFloatExpressionFactory::getTypeToken() const
+const char* JVariableFloatExpressionFactory::getTypeToken() const
 {
     return "variable";
 }
@@ -134,9 +169,12 @@ JVariableBoolExpression::JVariableBoolExpression()
     : JBoolExpression()
 {}
 
-bool JVariableBoolExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JVariableBoolExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
-    return zMemory->getBoolVariable(name);
+    codeBlock.addLoadValue(
+        (char*)zMemory->getBoolVariableP(name), Framework::Assembly::RAX);
+    return codeBlock;
 }
 
 void JVariableBoolExpression::setName(Framework::Text name)
@@ -153,23 +191,21 @@ JVariableBoolExpressionFactory::JVariableBoolExpressionFactory()
     : SubTypeFactory()
 {}
 
-JVariableBoolExpression* JVariableBoolExpressionFactory::createValue(
+JVariableBoolExpression* JVariableBoolExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JVariableBoolExpression();
-}
-
-void JVariableBoolExpressionFactory::fromJson(
-    JVariableBoolExpression* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setName(zJson->zValue("name")->asString()->getString());
+    JVariableBoolExpression* result = new JVariableBoolExpression();
+    result->setName(zJson->zValue("name")->asString()->getString());
+    return result;
 }
 
-void JVariableBoolExpressionFactory::toJson(JVariableBoolExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JVariableBoolExpressionFactory::toJsonObject(
+    JVariableBoolExpression* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "name", new Framework::JSON::JSONString(zObject->getName()));
+    return result;
 }
 
 JSONObjectValidationBuilder* JVariableBoolExpressionFactory::addToValidator(
@@ -178,7 +214,7 @@ JSONObjectValidationBuilder* JVariableBoolExpressionFactory::addToValidator(
     return builder->withRequiredString("name")->finishString();
 }
 
-Framework::Text JVariableBoolExpressionFactory::getTypeToken() const
+const char* JVariableBoolExpressionFactory::getTypeToken() const
 {
     return "variable";
 }
@@ -188,9 +224,11 @@ JConstantFloatExpression::JConstantFloatExpression()
       value(0)
 {}
 
-float JConstantFloatExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JConstantFloatExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
-    return value;
+    codeBlock.addLoadValue(&value, Framework::Assembly::MM0);
+    return codeBlock;
 }
 
 void JConstantFloatExpression::setValue(float value)
@@ -207,23 +245,21 @@ JConstantFloatExpressionFactory::JConstantFloatExpressionFactory()
     : SubTypeFactory()
 {}
 
-JConstantFloatExpression* JConstantFloatExpressionFactory::createValue(
+JConstantFloatExpression* JConstantFloatExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JConstantFloatExpression();
-}
-
-void JConstantFloatExpressionFactory::fromJson(
-    JConstantFloatExpression* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setValue((float)zJson->zValue("value")->asNumber()->getNumber());
+    JConstantFloatExpression* result = new JConstantFloatExpression();
+    result->setValue((float)zJson->zValue("value")->asNumber()->getNumber());
+    return result;
 }
 
-void JConstantFloatExpressionFactory::toJson(JConstantFloatExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JConstantFloatExpressionFactory::toJsonObject(
+    JConstantFloatExpression* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "value", new Framework::JSON::JSONNumber(zObject->getValue()));
+    return result;
 }
 
 JSONObjectValidationBuilder* JConstantFloatExpressionFactory::addToValidator(
@@ -232,7 +268,7 @@ JSONObjectValidationBuilder* JConstantFloatExpressionFactory::addToValidator(
     return builder->withRequiredNumber("value")->finishNumber();
 }
 
-Framework::Text JConstantFloatExpressionFactory::getTypeToken() const
+const char* JConstantFloatExpressionFactory::getTypeToken() const
 {
     return "constant";
 }
@@ -241,9 +277,11 @@ JConstantBoolExpression::JConstantBoolExpression()
     : JBoolExpression()
 {}
 
-bool JConstantBoolExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JConstantBoolExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
-    return value;
+    codeBlock.addMoveValue(Framework::Assembly::RAX, (char)(value ? 1 : 0));
+    return codeBlock;
 }
 
 void JConstantBoolExpression::setValue(bool value)
@@ -260,23 +298,21 @@ JConstantBoolExpressionFactory::JConstantBoolExpressionFactory()
     : SubTypeFactory()
 {}
 
-JConstantBoolExpression* JConstantBoolExpressionFactory::createValue(
+JConstantBoolExpression* JConstantBoolExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JConstantBoolExpression();
-}
-
-void JConstantBoolExpressionFactory::fromJson(
-    JConstantBoolExpression* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setValue(zJson->zValue("value")->asBool()->getBool());
+    JConstantBoolExpression* result = new JConstantBoolExpression();
+    result->setValue(zJson->zValue("value")->asBool()->getBool());
+    return result;
 }
 
-void JConstantBoolExpressionFactory::toJson(JConstantBoolExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JConstantBoolExpressionFactory::toJsonObject(
+    JConstantBoolExpression* zObject) const
 {
+    Framework::JSON::JSONObject* zResult = new Framework::JSON::JSONObject();
     zResult->addValue(
         "value", new Framework::JSON::JSONBool(zObject->getValue()));
+    return zResult;
 }
 
 JSONObjectValidationBuilder* JConstantBoolExpressionFactory::addToValidator(
@@ -285,7 +321,7 @@ JSONObjectValidationBuilder* JConstantBoolExpressionFactory::addToValidator(
     return builder->withRequiredBool("value")->finishBool();
 }
 
-Framework::Text JConstantBoolExpressionFactory::getTypeToken() const
+const char* JConstantBoolExpressionFactory::getTypeToken() const
 {
     return "constant";
 }
@@ -304,10 +340,86 @@ JNoiseFloatExpression::~JNoiseFloatExpression()
     if (z) z->release();
 }
 
-float JNoiseFloatExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JNoiseFloatExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
-    return zMemory->getNoise(
-        name, x->getValue(zMemory), y->getValue(zMemory), z->getValue(zMemory));
+    Noise* noise = zMemory->zNoiseP(name);
+    if (!noise)
+    {
+        Framework::Logging::error() << "no noise with name '" << name.getText()
+                                    << "' found, behavior is undefined\n";
+        return codeBlock;
+    }
+    Framework::Assembly::AssemblyBlock& xBlock = x->buildAssembly(zMemory);
+    Framework::Assembly::AssemblyBlock& yBlock = y->buildAssembly(zMemory);
+    Framework::Assembly::AssemblyBlock& zBlock = z->buildAssembly(zMemory);
+    Framework::Assembly::FPRegister xTarget = Framework::Assembly::MM0;
+    if (xBlock.isReplacementPossible(
+            Framework::Assembly::MM0, Framework::Assembly::MM1))
+    {
+        xBlock.replaceRegister(
+            Framework::Assembly::MM0, Framework::Assembly::MM1);
+        xTarget = Framework::Assembly::MM1;
+    }
+    Framework::Assembly::FPRegister yTarget = Framework::Assembly::MM0;
+    if (yBlock.isReplacementPossible(
+            Framework::Assembly::MM0, Framework::Assembly::MM2))
+    {
+        yBlock.replaceRegister(
+            Framework::Assembly::MM0, Framework::Assembly::MM2);
+        yTarget = Framework::Assembly::MM2;
+    }
+    Framework::Assembly::FPRegister zTarget = Framework::Assembly::MM0;
+    if (zBlock.isReplacementPossible(
+            Framework::Assembly::MM0, Framework::Assembly::MM3))
+    {
+        zBlock.replaceRegister(
+            Framework::Assembly::MM0, Framework::Assembly::MM3);
+        zTarget = Framework::Assembly::MM3;
+    }
+    codeBlock.addBlock(&zBlock, {}, {}, {}, 0, &zTarget);
+    if (zTarget != Framework::Assembly::MM3)
+    {
+        codeBlock.addMoveValue(Framework::Assembly::MM3,
+            zTarget,
+            Framework::Assembly::SINGLE_FLOAT,
+            Framework::Assembly::X);
+    }
+    codeBlock.addBlock(&yBlock,
+        {},
+        {Framework::Assembly::MM3},
+        {Framework::Assembly::SINGLE_FLOAT},
+        0,
+        &yTarget);
+    if (yTarget != Framework::Assembly::MM2)
+    {
+        codeBlock.addMoveValue(Framework::Assembly::MM2,
+            yTarget,
+            Framework::Assembly::SINGLE_FLOAT,
+            Framework::Assembly::X);
+    }
+    codeBlock.addBlock(&xBlock,
+        {},
+        {Framework::Assembly::MM2, Framework::Assembly::MM3},
+        {Framework::Assembly::SINGLE_FLOAT, Framework::Assembly::SINGLE_FLOAT},
+        0,
+        &xTarget);
+    if (xTarget != Framework::Assembly::MM1)
+    {
+        codeBlock.addMoveValue(Framework::Assembly::MM1,
+            xTarget,
+            Framework::Assembly::SINGLE_FLOAT,
+            Framework::Assembly::X);
+    }
+    codeBlock.addLoadAddress(noise, Framework::Assembly::RCX);
+    codeBlock.addMemberCall<float (Noise::*)(float, float, float)>(
+        &Noise::getNoise,
+        Framework::Assembly::FLOAT_VALUE,
+        {Framework::Assembly::RCX},
+        {Framework::Assembly::MM1,
+            Framework::Assembly::MM2,
+            Framework::Assembly::MM3});
+    return codeBlock;
 }
 
 void JNoiseFloatExpression::setName(Framework::Text name)
@@ -357,35 +469,33 @@ JNoiseFloatExpressionFactory::JNoiseFloatExpressionFactory()
     : SubTypeFactory()
 {}
 
-JNoiseFloatExpression* JNoiseFloatExpressionFactory::createValue(
+JNoiseFloatExpression* JNoiseFloatExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JNoiseFloatExpression();
-}
-
-void JNoiseFloatExpressionFactory::fromJson(
-    JNoiseFloatExpression* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setName(zJson->zValue("name")->asString()->getString());
-    zResult->setX(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
+    JNoiseFloatExpression* result = new JNoiseFloatExpression();
+    result->setName(zJson->zValue("name")->asString()->getString());
+    result->setX(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
         zJson->zValue("x")));
-    zResult->setY(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
+    result->setY(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
         zJson->zValue("y")));
-    zResult->setZ(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
+    result->setZ(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
         zJson->zValue("z")));
+    return result;
 }
 
-void JNoiseFloatExpressionFactory::toJson(
-    JNoiseFloatExpression* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JNoiseFloatExpressionFactory::toJsonObject(
+    JNoiseFloatExpression* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "name", new Framework::JSON::JSONString(zObject->getName()));
-    zResult->addValue(
+    result->addValue(
         "x", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zX()));
-    zResult->addValue(
+    result->addValue(
         "y", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zY()));
-    zResult->addValue(
+    result->addValue(
         "z", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zZ()));
+    return result;
 }
 
 JSONObjectValidationBuilder* JNoiseFloatExpressionFactory::addToValidator(
@@ -401,40 +511,90 @@ JSONObjectValidationBuilder* JNoiseFloatExpressionFactory::addToValidator(
             Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>());
 }
 
-Framework::Text JNoiseFloatExpressionFactory::getTypeToken() const
+const char* JNoiseFloatExpressionFactory::getTypeToken() const
 {
     return "noise";
 }
 
 JOperatorFloatExpression::JOperatorFloatExpression()
-    : JFloatExpression(),
-      accumulator([](float a, float b) { return 0.f; })
+    : JFloatExpression()
 {}
 
-float JOperatorFloatExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JOperatorFloatExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
     bool first = 1;
-    float val = 0.f;
+    if (!values.getEintragAnzahl())
+    {
+        codeBlock.addMoveValue(Framework::Assembly::MM0, 0.f);
+    }
     for (JFloatExpression* expression : values)
     {
         if (first)
         {
             first = 0;
-            val = expression->getValue(zMemory);
+            codeBlock.addBlock(
+                &expression->buildAssembly(zMemory), {}, {}, {}, 0, 0);
         }
         else
         {
-            val = accumulator(val, expression->getValue(zMemory));
+            Framework::Assembly::AssemblyBlock& exprBlock
+                = expression->buildAssembly(zMemory);
+            if (exprBlock.isReplacementPossible(
+                    Framework::Assembly::MM0, Framework::Assembly::MM1))
+            {
+                exprBlock.replaceRegister(
+                    Framework::Assembly::MM0, Framework::Assembly::MM1);
+            }
+            else
+            {
+                exprBlock.addMoveValue(Framework::Assembly::MM1,
+                    Framework::Assembly::MM0,
+                    Framework::Assembly::SINGLE_FLOAT,
+                    Framework::Assembly::X);
+            }
+            codeBlock.addBlock(&exprBlock,
+                {},
+                {Framework::Assembly::MM0},
+                {Framework::Assembly::SINGLE_FLOAT},
+                0,
+                0);
+            if (op.istGleich("+"))
+            {
+                codeBlock.addAddition(Framework::Assembly::MM0,
+                    Framework::Assembly::MM1,
+                    Framework::Assembly::SINGLE_FLOAT,
+                    Framework::Assembly::X);
+            }
+            else if (op.istGleich("-"))
+            {
+                codeBlock.addSubtraction(Framework::Assembly::MM0,
+                    Framework::Assembly::MM1,
+                    Framework::Assembly::SINGLE_FLOAT,
+                    Framework::Assembly::X);
+            }
+            else if (op.istGleich("*"))
+            {
+                codeBlock.addMultiplication(Framework::Assembly::MM0,
+                    Framework::Assembly::MM1,
+                    Framework::Assembly::SINGLE_FLOAT,
+                    Framework::Assembly::X);
+            }
+            else if (op.istGleich("/"))
+            {
+                codeBlock.addDivision(Framework::Assembly::MM0,
+                    Framework::Assembly::MM1,
+                    Framework::Assembly::SINGLE_FLOAT,
+                    Framework::Assembly::X);
+            }
         }
     }
-    return val;
+    return codeBlock;
 }
 
-void JOperatorFloatExpression::setOperator(
-    Framework::Text op, std::function<float(float a, float b)> accumulator)
+void JOperatorFloatExpression::setOperator(Framework::Text op)
 {
     this->op = op;
-    this->accumulator = accumulator;
 }
 
 Framework::Text JOperatorFloatExpression::getOperator()
@@ -457,44 +617,25 @@ JOperatorFloatExpressionFactory::JOperatorFloatExpressionFactory()
     : SubTypeFactory()
 {}
 
-JOperatorFloatExpression* JOperatorFloatExpressionFactory::createValue(
+JOperatorFloatExpression* JOperatorFloatExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JOperatorFloatExpression();
-}
-
-void JOperatorFloatExpressionFactory::fromJson(
-    JOperatorFloatExpression* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    Framework::Text op = zJson->zValue("operator")->asString()->getString();
-    if (op.istGleich("+"))
-    {
-        zResult->setOperator("+", [](float a, float b) { return a + b; });
-    }
-    else if (op.istGleich("-"))
-    {
-        zResult->setOperator("-", [](float a, float b) { return a - b; });
-    }
-    else if (op.istGleich("*"))
-    {
-        zResult->setOperator("*", [](float a, float b) { return a * b; });
-    }
-    else if (op.istGleich("/"))
-    {
-        zResult->setOperator("/", [](float a, float b) { return a / b; });
-    }
+    JOperatorFloatExpression* result = new JOperatorFloatExpression();
+    result->setOperator(zJson->zValue("operator")->asString()->getString());
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("values")->asArray())
     {
-        zResult->addValue(
+        result->addValue(
             Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(value));
     }
+    return result;
 }
 
-void JOperatorFloatExpressionFactory::toJson(JOperatorFloatExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JOperatorFloatExpressionFactory::toJsonObject(
+    JOperatorFloatExpression* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "operator", new Framework::JSON::JSONString(zObject->getOperator()));
     Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray();
     for (JFloatExpression* expression : zObject->getValues())
@@ -503,7 +644,8 @@ void JOperatorFloatExpressionFactory::toJson(JOperatorFloatExpression* zObject,
             Game::INSTANCE->zTypeRegistry()->toJson<JFloatExpression>(
                 expression));
     }
-    zResult->addValue("values", values);
+    result->addValue("values", values);
+    return result;
 }
 
 JSONObjectValidationBuilder* JOperatorFloatExpressionFactory::addToValidator(
@@ -518,7 +660,7 @@ JSONObjectValidationBuilder* JOperatorFloatExpressionFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text JOperatorFloatExpressionFactory::getTypeToken() const
+const char* JOperatorFloatExpressionFactory::getTypeToken() const
 {
     return "operator";
 }
@@ -527,30 +669,60 @@ JBoolOperatorBoolExpression::JBoolOperatorBoolExpression()
     : JBoolExpression()
 {}
 
-bool JBoolOperatorBoolExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JBoolOperatorBoolExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
     bool first = 1;
-    bool val = 0;
+    if (!values.getEintragAnzahl())
+    {
+        codeBlock.addMoveValue(Framework::Assembly::RAX, (char)0);
+    }
     for (JBoolExpression* expression : values)
     {
         if (first)
         {
             first = 0;
-            val = expression->getValue(zMemory);
+            codeBlock.addBlock(
+                &expression->buildAssembly(zMemory), {}, {}, {}, 0, 0);
         }
         else
         {
-            val = accumulator(val, expression->getValue(zMemory));
+            Framework::Assembly::AssemblyBlock& exprBlock
+                = expression->buildAssembly(zMemory);
+            if (exprBlock.isReplacementPossible(
+                    Framework::Assembly::RAX, Framework::Assembly::RCX))
+            {
+                exprBlock.replaceRegister(
+                    Framework::Assembly::RAX, Framework::Assembly::RCX);
+            }
+            else
+            {
+                exprBlock.addMoveValue(Framework::Assembly::RCX,
+                    Framework::Assembly::RAX,
+                    Framework::Assembly::LOWER8);
+            }
+            codeBlock.addBlock(
+                &exprBlock, {Framework::Assembly::RAX}, {}, {}, 0, 0);
+            if (op.istGleich("&&"))
+            {
+                codeBlock.addAnd(Framework::Assembly::RAX,
+                    Framework::Assembly::RCX,
+                    Framework::Assembly::LOWER8);
+            }
+            else if (op.istGleich("||"))
+            {
+                codeBlock.addOr(Framework::Assembly::RAX,
+                    Framework::Assembly::RCX,
+                    Framework::Assembly::LOWER8);
+            }
         }
     }
-    return val;
+    return codeBlock;
 }
 
-void JBoolOperatorBoolExpression::setOperator(
-    Framework::Text op, std::function<float(float a, float b)> accumulator)
+void JBoolOperatorBoolExpression::setOperator(Framework::Text op)
 {
     this->op = op;
-    this->accumulator = accumulator;
 }
 
 Framework::Text JBoolOperatorBoolExpression::getOperator()
@@ -573,36 +745,24 @@ JBoolOperatorBoolExpressionFactory::JBoolOperatorBoolExpressionFactory()
     : SubTypeFactory()
 {}
 
-JBoolOperatorBoolExpression* JBoolOperatorBoolExpressionFactory::createValue(
+JBoolOperatorBoolExpression* JBoolOperatorBoolExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JBoolOperatorBoolExpression();
-}
-
-void JBoolOperatorBoolExpressionFactory::fromJson(
-    JBoolOperatorBoolExpression* zResult,
-    Framework::JSON::JSONObject* zJson) const
-{
-    for (Framework::JSON::JSONValue* value : *zJson->zValue("values")->asArray())
+    JBoolOperatorBoolExpression* result = new JBoolOperatorBoolExpression();
+    for (Framework::JSON::JSONValue* value :
+        *zJson->zValue("values")->asArray())
     {
-        zResult->addValue(
+        result->addValue(
             Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(value));
     }
-    Framework::Text op = zJson->zValue("operator")->asString()->getString();
-    if (op.istGleich("&&"))
-    {
-        zResult->setOperator("&&", [](bool a, bool b) { return a && b; });
-    }
-    else if (op.istGleich("||"))
-    {
-        zResult->setOperator("||", [](bool a, bool b) { return a || b; });
-    }
+    result->setOperator(zJson->zValue("operator")->asString()->getString());
+    return result;
 }
 
-void JBoolOperatorBoolExpressionFactory::toJson(
-    JBoolOperatorBoolExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JBoolOperatorBoolExpressionFactory::toJsonObject(
+    JBoolOperatorBoolExpression* zObject) const
 {
+    Framework::JSON::JSONObject* zResult = new Framework::JSON::JSONObject();
     Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray();
     for (JBoolExpression* expression : zObject->getValues())
     {
@@ -613,6 +773,7 @@ void JBoolOperatorBoolExpressionFactory::toJson(
     zResult->addValue("values", values);
     zResult->addValue(
         "operator", new Framework::JSON::JSONString(zObject->getOperator()));
+    return zResult;
 }
 
 JSONObjectValidationBuilder* JBoolOperatorBoolExpressionFactory::addToValidator(
@@ -627,7 +788,7 @@ JSONObjectValidationBuilder* JBoolOperatorBoolExpressionFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text JBoolOperatorBoolExpressionFactory::getTypeToken() const
+const char* JBoolOperatorBoolExpressionFactory::getTypeToken() const
 {
     return "operator";
 }
@@ -636,26 +797,139 @@ JFloatOperatorBoolExpression::JFloatOperatorBoolExpression()
     : JBoolExpression()
 {}
 
-bool JFloatOperatorBoolExpression::getValue(JExpressionMemory* zMemory)
+Framework::Assembly::AssemblyBlock& JFloatOperatorBoolExpression::buildAssembly(
+    JExpressionMemory* zMemory)
 {
     bool first = 1;
-    bool val = 1;
-    float last = 0.f;
+    Framework::Assembly::FPRegister lastResultSorage = Framework::Assembly::MM0;
     for (JFloatExpression* expression : values)
     {
-        float current = expression->getValue(zMemory);
-        if (!first) val &= accumulator(last, current);
-        first = 0;
-        last = current;
+        if (first)
+        {
+            first = 0;
+            codeBlock.addBlock(
+                &expression->buildAssembly(zMemory), {}, {}, {}, 0, 0);
+        }
+        else
+        {
+            Framework::Assembly::FPRegister currentResultSorage
+                = lastResultSorage == Framework::Assembly::MM0
+                    ? Framework::Assembly::MM1
+                    : Framework::Assembly::MM0;
+            Framework::Assembly::AssemblyBlock& exprBlock
+                = expression->buildAssembly(zMemory);
+            if (currentResultSorage != Framework::Assembly::MM0)
+            {
+                if (exprBlock.isReplacementPossible(
+                        Framework::Assembly::MM0, currentResultSorage))
+                {
+                    exprBlock.replaceRegister(
+                        Framework::Assembly::MM0, currentResultSorage);
+                }
+                else
+                {
+                    exprBlock.addMoveValue(currentResultSorage,
+                        Framework::Assembly::MM0,
+                        Framework::Assembly::SINGLE_FLOAT,
+                        Framework::Assembly::X);
+                }
+            }
+            codeBlock.addBlock(&exprBlock,
+                {},
+                {lastResultSorage},
+                {Framework::Assembly::SINGLE_FLOAT},
+                0,
+                0);
+            Framework::Assembly::Operation jumpOp = Framework::Assembly::NOP;
+            bool needConversion = false;
+            if (op.istGleich(">"))
+            {
+                jumpOp = Framework::Assembly::JBE; // jump if below or equal
+            }
+            else if (op.istGleich("<"))
+            {
+                jumpOp = Framework::Assembly::JNB; // jump if not below
+            }
+            else if (op.istGleich(">="))
+            {
+                jumpOp = Framework::Assembly::JB; // jump if below
+            }
+            else if (op.istGleich("<="))
+            {
+                jumpOp = Framework::Assembly::JA; // jump if above
+            }
+            else if (op.istGleich("=="))
+            {
+                jumpOp = Framework::Assembly::JNE; // jump if not equal
+            }
+            else if (op.istGleich("!="))
+            {
+                jumpOp = Framework::Assembly::JE; // jump if equal
+            }
+            else
+            {
+                needConversion = true;
+                if (op.istGleich(">i"))
+                {
+                    jumpOp = Framework::Assembly::JLE; // jump if less or equal
+                }
+                else if (op.istGleich("<i"))
+                {
+                    jumpOp = Framework::Assembly::JGE; // jump if greater or
+                                                       // equal
+                }
+                else if (op.istGleich(">=i"))
+                {
+                    jumpOp = Framework::Assembly::JL; // jump if less
+                }
+                else if (op.istGleich("<=i"))
+                {
+                    jumpOp = Framework::Assembly::JG; // jump if greater
+                }
+                else if (op.istGleich("==i"))
+                {
+                    jumpOp = Framework::Assembly::JNE; // jump if not equal
+                }
+                else if (op.istGleich("!=i"))
+                {
+                    jumpOp = Framework::Assembly::JE; // jump if equal
+                }
+            }
+            if (needConversion)
+            {
+                codeBlock.addConversion(Framework::Assembly::RAX,
+                    lastResultSorage,
+                    Framework::Assembly::SINGLE_FLOAT,
+                    Framework::Assembly::LOWER32);
+                codeBlock.addConversion(Framework::Assembly::RCX,
+                    currentResultSorage,
+                    Framework::Assembly::SINGLE_FLOAT,
+                    Framework::Assembly::LOWER32);
+                codeBlock.addCompare(Framework::Assembly::RAX,
+                    Framework::Assembly::RCX,
+                    Framework::Assembly::LOWER32);
+            }
+            else
+            {
+                codeBlock.addCompare(lastResultSorage,
+                    currentResultSorage,
+                    Framework::Assembly::SINGLE_FLOAT);
+            }
+            codeBlock.addJump(jumpOp, "end_false");
+            lastResultSorage = currentResultSorage;
+        }
     }
-    return val;
+    codeBlock.addMoveValue(Framework::Assembly::RAX, (char)1);
+    codeBlock.addJump(Framework::Assembly::JMP, "end");
+    codeBlock.defineJumpTarget("end_false");
+    codeBlock.addMoveValue(Framework::Assembly::RAX, (char)0);
+    codeBlock.defineJumpTarget("end");
+    return codeBlock;
 }
 
-void JFloatOperatorBoolExpression::setOperator(
-    Framework::Text op, std::function<bool(float a, float b)> accumulator)
+void JFloatOperatorBoolExpression::setOperator(Framework::Text op)
 {
     this->op = op;
-    this->accumulator = accumulator;
 }
 
 Framework::Text JFloatOperatorBoolExpression::getOperator()
@@ -678,90 +952,25 @@ JFloatOperatorBoolExpressionFactory::JFloatOperatorBoolExpressionFactory()
     : SubTypeFactory()
 {}
 
-JFloatOperatorBoolExpression* JFloatOperatorBoolExpressionFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new JFloatOperatorBoolExpression();
-}
-
-void JFloatOperatorBoolExpressionFactory::fromJson(
-    JFloatOperatorBoolExpression* zResult,
+JFloatOperatorBoolExpression* JFloatOperatorBoolExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    Framework::Text op = zJson->zValue("operator")->asString()->getString();
-    if (op.istGleich(">"))
-    {
-        zResult->setOperator(
-            ">", [](float a, float b) { return a > b; });
-    }
-    else if (op.istGleich("<"))
-    {
-        zResult->setOperator(
-            "<", [](float a, float b) { return a < b; });
-    }
-    else if (op.istGleich(">="))
-    {
-        zResult->setOperator(
-            ">=", [](float a, float b) { return a >= b; });
-    }
-    else if (op.istGleich("<="))
-    {
-        zResult->setOperator(
-            "<=", [](float a, float b) { return a <= b; });
-    }
-    else if (op.istGleich("=="))
-    {
-        zResult->setOperator(
-            "==", [](float a, float b) { return a == b; });
-    }
-    else if (op.istGleich("!="))
-    {
-        zResult->setOperator(
-            "!=", [](float a, float b) { return a != b; });
-    }
-    else if (op.istGleich(">i"))
-    {
-        zResult->setOperator(
-            ">i", [](float a, float b) { return (int)a > (int)b; });
-    }
-    else if (op.istGleich("<i"))
-    {
-        zResult->setOperator(
-            "<i", [](float a, float b) { return (int)a < (int)b; });
-    }
-    else if (op.istGleich(">=i"))
-    {
-        zResult->setOperator(
-            ">=i", [](float a, float b) { return (int)a >= (int)b; });
-    }
-    else if (op.istGleich("<=i"))
-    {
-        zResult->setOperator(
-            "<=i", [](float a, float b) { return (int)a <= (int)b; });
-    }
-    else if (op.istGleich("==i"))
-    {
-        zResult->setOperator(
-            "==i", [](float a, float b) { return (int)a == (int)b; });
-    }
-    else if (op.istGleich("!=i"))
-    {
-        zResult->setOperator(
-            "!=i", [](float a, float b) { return (int)a != (int)b; });
-    }
+    JFloatOperatorBoolExpression* result = new JFloatOperatorBoolExpression();
+    result->setOperator(zJson->zValue("operator")->asString()->getString());
     for (Framework::JSON::JSONValue* value :
         *zJson->zValue("values")->asArray())
     {
-        zResult->addValue(
+        result->addValue(
             Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(value));
     }
+    return result;
 }
 
-void JFloatOperatorBoolExpressionFactory::toJson(
-    JFloatOperatorBoolExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JFloatOperatorBoolExpressionFactory::toJsonObject(
+    JFloatOperatorBoolExpression* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "operator", new Framework::JSON::JSONString(zObject->getOperator()));
     Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray();
     for (JFloatExpression* expression : zObject->getValues())
@@ -770,7 +979,8 @@ void JFloatOperatorBoolExpressionFactory::toJson(
             Game::INSTANCE->zTypeRegistry()->toJson<JFloatExpression>(
                 expression));
     }
-    zResult->addValue("values", values);
+    result->addValue("values", values);
+    return result;
 }
 
 JSONObjectValidationBuilder*
@@ -797,7 +1007,7 @@ JFloatOperatorBoolExpressionFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text JFloatOperatorBoolExpressionFactory::getTypeToken() const
+const char* JFloatOperatorBoolExpressionFactory::getTypeToken() const
 {
     return "comparsion";
 }
@@ -817,19 +1027,112 @@ JBlockTypeBoolExpression ::~JBlockTypeBoolExpression()
     if (z) z->release();
 }
 
-bool JBlockTypeBoolExpression::getValue(JExpressionMemory* zMemory)
+bool JBlockTypeBoolExpression::isValidPosition(
+    int x, int y, Chunk* currentChunk)
 {
-    int x = (int)(round(this->x->getValue(zMemory)));
-    int y = (int)(round(this->y->getValue(zMemory)));
-    int z = (int)(round(this->z->getValue(zMemory)));
-    if (z < 0 || z >= WORLD_HEIGHT || !zMemory->zCurrentChunk()
-        || Game::getChunkCenter(x, y) != zMemory->zCurrentChunk()->getCenter())
+    return currentChunk
+        && Game::getChunkCenter(x, y) == currentChunk->getCenter();
+}
+
+Framework::Assembly::AssemblyBlock& JBlockTypeBoolExpression::buildAssembly(
+    JExpressionMemory* zMemory)
+{
+    Framework::Assembly::AssemblyBlock& xBlock = x->buildAssembly(zMemory);
+    Framework::Assembly::AssemblyBlock& yBlock = y->buildAssembly(zMemory);
+    Framework::Assembly::AssemblyBlock& zBlock = z->buildAssembly(zMemory);
+    Framework::Assembly::FPRegister xTarget = Framework::Assembly::MM0;
+    if (xBlock.isReplacementPossible(
+            Framework::Assembly::MM0, Framework::Assembly::MM1))
+    {
+        xBlock.replaceRegister(
+            Framework::Assembly::MM0, Framework::Assembly::MM1);
+        xTarget = Framework::Assembly::MM1;
+    }
+    Framework::Assembly::FPRegister yTarget = Framework::Assembly::MM0;
+    if (yBlock.isReplacementPossible(
+            Framework::Assembly::MM0, Framework::Assembly::MM2))
     {
-        return 0;
+        yBlock.replaceRegister(
+            Framework::Assembly::MM0, Framework::Assembly::MM2);
+        yTarget = Framework::Assembly::MM2;
     }
-    return zMemory->zCurrentChunk()->getBlockTypeAt(
-               Dimension::chunkCoordinates({x, y, z}))
-        == typeId;
+    Framework::Assembly::FPRegister zTarget = Framework::Assembly::MM0;
+    if (zBlock.isReplacementPossible(
+            Framework::Assembly::MM0, Framework::Assembly::MM3))
+    {
+        zBlock.replaceRegister(
+            Framework::Assembly::MM0, Framework::Assembly::MM3);
+        zTarget = Framework::Assembly::MM3;
+    }
+    codeBlock.addBlock(&zBlock, {}, {}, {}, 0, &zTarget);
+    codeBlock.addConversion(Framework::Assembly::R9,
+        zTarget,
+        Framework::Assembly::SINGLE_FLOAT,
+        Framework::Assembly::LOWER32,
+        1);
+    codeBlock.addTest(Framework::Assembly::R9,
+        Framework::Assembly::R9,
+        Framework::Assembly::LOWER32);
+    codeBlock.addJump(Framework::Assembly::JL, "end_false");
+    codeBlock.addCompare(Framework::Assembly::R9, WORLD_HEIGHT);
+    codeBlock.addJump(Framework::Assembly::JGE, "end_false");
+    codeBlock.addBlock(&yBlock, {Framework::Assembly::R9}, {}, {}, 0, &yTarget);
+    codeBlock.addConversion(Framework::Assembly::R8,
+        yTarget,
+        Framework::Assembly::SINGLE_FLOAT,
+        Framework::Assembly::LOWER32,
+        1);
+    codeBlock.addBlock(&xBlock,
+        {Framework::Assembly::R8, Framework::Assembly::R9},
+        {},
+        {},
+        0,
+        &xTarget);
+    codeBlock.addConversion(Framework::Assembly::RDX,
+        xTarget,
+        Framework::Assembly::SINGLE_FLOAT,
+        Framework::Assembly::LOWER32,
+        1);
+    codeBlock.addLoadAddress(this, Framework::Assembly::RCX);
+    codeBlock.addPush(Framework::Assembly::RDX, Framework::Assembly::LOWER32);
+    codeBlock.addPush(Framework::Assembly::R8, Framework::Assembly::LOWER32);
+    codeBlock.addPush(Framework::Assembly::R9, Framework::Assembly::LOWER32);
+    codeBlock.addLoadValue(
+        (__int64*)zMemory->zzCurrentChunk(), Framework::Assembly::R9);
+    codeBlock
+        .addMemberCall<bool (JBlockTypeBoolExpression::*)(int, int, Chunk*)>(
+            &JBlockTypeBoolExpression::isValidPosition,
+            Framework::Assembly::INT_VALUE,
+            {Framework::Assembly::R9},
+            {});
+    codeBlock.addPop(Framework::Assembly::R9, Framework::Assembly::LOWER32);
+    codeBlock.addPop(Framework::Assembly::R8, Framework::Assembly::LOWER32);
+    codeBlock.addPop(Framework::Assembly::RDX, Framework::Assembly::LOWER32);
+    codeBlock.addTest(Framework::Assembly::RAX,
+        Framework::Assembly::RAX,
+        Framework::Assembly::LOWER8);
+    codeBlock.addJump(Framework::Assembly::JZ, "end");
+    codeBlock.addLoadValue(
+        (__int64*)zMemory->zzCurrentChunk(), Framework::Assembly::RCX);
+    codeBlock.addMemberCall<int (Chunk::*)(int, int, int) const>(
+        &Chunk::getBlockTypeAtWC,
+        Framework::Assembly::INT_VALUE,
+        {Framework::Assembly::RCX,
+            Framework::Assembly::RDX,
+            Framework::Assembly::R8,
+            Framework::Assembly::R9},
+        {});
+    codeBlock.addLoadValue(&typeId, Framework::Assembly::RCX);
+    codeBlock.addCompare(Framework::Assembly::RAX,
+        Framework::Assembly::RCX,
+        Framework::Assembly::LOWER32);
+    codeBlock.addJump(Framework::Assembly::JNE, "end_false");
+    codeBlock.addMoveValue(Framework::Assembly::RAX, (char)1);
+    codeBlock.addJump(Framework::Assembly::JMP, "end");
+    codeBlock.defineJumpTarget("end_false");
+    codeBlock.addMoveValue(Framework::Assembly::RAX, (char)0);
+    codeBlock.defineJumpTarget("end");
+    return codeBlock;
 }
 
 void JBlockTypeBoolExpression::setTypeId(int typeId)
@@ -879,54 +1182,44 @@ JBlockTypeBoolExpressionFactory::JBlockTypeBoolExpressionFactory()
     : SubTypeFactory()
 {}
 
-JBlockTypeBoolExpression* JBlockTypeBoolExpressionFactory::createValue(
+JBlockTypeBoolExpression* JBlockTypeBoolExpressionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new JBlockTypeBoolExpression();
-}
-
-void JBlockTypeBoolExpressionFactory::fromJson(
-    JBlockTypeBoolExpression* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setTypeId(Game::INSTANCE->getBlockTypeId(
+    JBlockTypeBoolExpression* result = new JBlockTypeBoolExpression();
+    result->setTypeId(Game::INSTANCE->getBlockTypeId(
         zJson->zValue("blockType")->asString()->getString()));
-    zResult->setX(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
+    result->setX(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
         zJson->zValue("x")));
-    zResult->setY(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
+    result->setY(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
         zJson->zValue("y")));
-    zResult->setZ(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
+    result->setZ(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
         zJson->zValue("z")));
+    return result;
 }
 
-void JBlockTypeBoolExpressionFactory::toJson(JBlockTypeBoolExpression* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* JBlockTypeBoolExpressionFactory::toJsonObject(
+    JBlockTypeBoolExpression* zObject) const
 {
-    zResult->addValue("blockType",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("blockType",
         new Framework::JSON::JSONString(
             Game::INSTANCE->zBlockType(zObject->getTypeId())->getName()));
-    zResult->addValue(
+    result->addValue(
         "x", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zX()));
-    zResult->addValue(
+    result->addValue(
         "y", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zY()));
-    zResult->addValue(
+    result->addValue(
         "z", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zZ()));
+    return result;
 }
 
 JSONObjectValidationBuilder* JBlockTypeBoolExpressionFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zBlockType(i))
-        {
-            blockTypeNames.add(
-                new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
-        }
-    }
-    return builder->withRequiredString("blockType")
-        ->whichIsOneOf(blockTypeNames)
-        ->finishString()
+    return builder
+        ->withRequiredAttribute("blockType",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                BlockTypeNameFactory::TYPE_ID))
         ->withRequiredAttribute("x",
             Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>())
         ->withRequiredAttribute("y",
@@ -935,7 +1228,7 @@ JSONObjectValidationBuilder* JBlockTypeBoolExpressionFactory::addToValidator(
             Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>());
 }
 
-Framework::Text JBlockTypeBoolExpressionFactory::getTypeToken() const
+const char* JBlockTypeBoolExpressionFactory::getTypeToken() const
 {
     return "blockType";
 }

+ 91 - 81
FactoryCraft/JsonExpression.h

@@ -1,8 +1,8 @@
 #pragma once
 
 #include <Array.h>
+#include <Assembly.h>
 #include <Critical.h>
-#include <functional>
 #include <JSON.h>
 #include <Text.h>
 #include <Trie.h>
@@ -30,33 +30,53 @@ public:
     void lock();
     void unlock();
 
-    float getNoise(Framework::Text name, float x, float y, float z) const;
+    Noise* zNoiseP(Framework::Text name);
     void setNoise(Framework::Text name, Noise* noise);
     void setCurrentChunk(Chunk* chunk);
 
-    float getFloatVariable(Framework::Text name) const;
-    void setFloatVariable(Framework::Text name, float value);
-    bool getBoolVariable(Framework::Text name) const;
-    void setBoolVariable(Framework::Text name, bool value);
-    Chunk* zCurrentChunk();
+    float* getFloatVariableP(const Framework::Text& name);
+    bool* getBoolVariableP(const Framework::Text& name);
+    Chunk** zzCurrentChunk();
 };
 
+typedef float (*FloatFunc)();
+
 class JFloatExpression : public virtual Framework::ReferenceCounter
 {
 private:
+    FloatFunc compiled;
+    JExpressionMemory* memory;
+
+protected:
+    Framework::Assembly::AssemblyBlock codeBlock;
 
 public:
     JFloatExpression();
-    virtual float getValue(JExpressionMemory* zMemory) = 0;
+    virtual Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory)
+        = 0;
+    float getValue();
+    FloatFunc compile(JExpressionMemory* zMemory);
 };
 
+typedef bool (*BoolFunc)();
+
 class JBoolExpression : public virtual Framework::ReferenceCounter
 {
 private:
+    BoolFunc compiled;
+    JExpressionMemory* memory;
+
+protected:
+    Framework::Assembly::AssemblyBlock codeBlock;
 
 public:
     JBoolExpression();
-    virtual bool getValue(JExpressionMemory* zMemory) = 0;
+    virtual Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory)
+        = 0;
+    bool getValue();
+    BoolFunc compile(JExpressionMemory* zMemory);
 };
 
 class JVariableFloatExpression : public JFloatExpression
@@ -66,7 +86,8 @@ private:
 
 public:
     JVariableFloatExpression();
-    float getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
     void setName(Framework::Text name);
     Framework::Text getName() const;
@@ -77,15 +98,13 @@ class JVariableFloatExpressionFactory
 {
 public:
     JVariableFloatExpressionFactory();
-    JVariableFloatExpression* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JVariableFloatExpression* zResult,
+    JVariableFloatExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JVariableFloatExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JVariableFloatExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JVariableBoolExpression : public JBoolExpression
@@ -95,7 +114,8 @@ private:
 
 public:
     JVariableBoolExpression();
-    bool getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
     void setName(Framework::Text name);
     Framework::Text getName() const;
@@ -106,15 +126,13 @@ class JVariableBoolExpressionFactory
 {
 public:
     JVariableBoolExpressionFactory();
-    JVariableBoolExpression* createValue(
+    JVariableBoolExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JVariableBoolExpression* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JVariableBoolExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JVariableBoolExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JConstantFloatExpression : public JFloatExpression
@@ -124,7 +142,8 @@ private:
 
 public:
     JConstantFloatExpression();
-    float getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
     void setValue(float value);
     float getValue() const;
@@ -135,15 +154,13 @@ class JConstantFloatExpressionFactory
 {
 public:
     JConstantFloatExpressionFactory();
-    JConstantFloatExpression* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JConstantFloatExpression* zResult,
+    JConstantFloatExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JConstantFloatExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JConstantFloatExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JConstantBoolExpression : public JBoolExpression
@@ -153,7 +170,8 @@ private:
 
 public:
     JConstantBoolExpression();
-    bool getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
     void setValue(bool value);
     bool getValue() const;
@@ -164,15 +182,13 @@ class JConstantBoolExpressionFactory
 {
 public:
     JConstantBoolExpressionFactory();
-    JConstantBoolExpression* createValue(
+    JConstantBoolExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JConstantBoolExpression* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JConstantBoolExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JConstantBoolExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JNoiseFloatExpression : public JFloatExpression
@@ -186,7 +202,8 @@ private:
 public:
     JNoiseFloatExpression();
     ~JNoiseFloatExpression();
-    float getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
     void setName(Framework::Text name);
     Framework::Text getName() const;
@@ -203,30 +220,27 @@ class JNoiseFloatExpressionFactory
 {
 public:
     JNoiseFloatExpressionFactory();
-    JNoiseFloatExpression* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JNoiseFloatExpression* zResult,
+    JNoiseFloatExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JNoiseFloatExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JNoiseFloatExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JOperatorFloatExpression : public JFloatExpression
 {
 private:
     Framework::Text op;
-    std::function<float(float a, float b)> accumulator;
     Framework::RCArray<JFloatExpression> values;
 
 public:
     JOperatorFloatExpression();
-    float getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
-    void setOperator(
-        Framework::Text op, std::function<float(float a, float b)> accumulator);
+    void setOperator(Framework::Text op);
     Framework::Text getOperator();
     void addValue(JFloatExpression* value);
     const Framework::RCArray<JFloatExpression>& getValues() const;
@@ -237,30 +251,27 @@ class JOperatorFloatExpressionFactory
 {
 public:
     JOperatorFloatExpressionFactory();
-    JOperatorFloatExpression* createValue(
+    JOperatorFloatExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JOperatorFloatExpression* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JOperatorFloatExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JOperatorFloatExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JBoolOperatorBoolExpression : public JBoolExpression
 {
 private:
     Framework::Text op;
-    std::function<bool(bool a, bool b)> accumulator;
     Framework::RCArray<JBoolExpression> values;
 
 public:
     JBoolOperatorBoolExpression();
-    bool getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
-    void setOperator(
-        Framework::Text op, std::function<float(float a, float b)> accumulator);
+    void setOperator(Framework::Text op);
     Framework::Text getOperator();
     void addValue(JBoolExpression* value);
     const Framework::RCArray<JBoolExpression>& getValues() const;
@@ -271,30 +282,27 @@ class JBoolOperatorBoolExpressionFactory
 {
 public:
     JBoolOperatorBoolExpressionFactory();
-    JBoolOperatorBoolExpression* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JBoolOperatorBoolExpression* zResult,
+    JBoolOperatorBoolExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JBoolOperatorBoolExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JBoolOperatorBoolExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JFloatOperatorBoolExpression : public JBoolExpression
 {
 private:
     Framework::Text op;
-    std::function<bool(float a, float b)> accumulator;
     Framework::RCArray<JFloatExpression> values;
 
 public:
     JFloatOperatorBoolExpression();
-    bool getValue(JExpressionMemory* zMemory) override;
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
-    void setOperator(
-        Framework::Text op, std::function<bool(float a, float b)> accumulator);
+    void setOperator(Framework::Text op);
     Framework::Text getOperator();
     void addValue(JFloatExpression* value);
     const Framework::RCArray<JFloatExpression>& getValues() const;
@@ -305,15 +313,13 @@ class JFloatOperatorBoolExpressionFactory
 {
 public:
     JFloatOperatorBoolExpressionFactory();
-    JFloatOperatorBoolExpression* createValue(
+    JFloatOperatorBoolExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JFloatOperatorBoolExpression* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JFloatOperatorBoolExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JFloatOperatorBoolExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class JBlockTypeBoolExpression : public JBoolExpression
@@ -327,7 +333,13 @@ private:
 public:
     JBlockTypeBoolExpression();
     ~JBlockTypeBoolExpression();
-    bool getValue(JExpressionMemory* zMemory) override;
+
+private:
+    bool isValidPosition(int x, int y, Chunk* currentChunk);
+
+public:
+    Framework::Assembly::AssemblyBlock& buildAssembly(
+        JExpressionMemory* zMemory) override;
 
     void setTypeId(int typeId);
     int getTypeId() const;
@@ -344,13 +356,11 @@ class JBlockTypeBoolExpressionFactory
 {
 public:
     JBlockTypeBoolExpressionFactory();
-    JBlockTypeBoolExpression* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(JBlockTypeBoolExpression* zResult,
+    JBlockTypeBoolExpression* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(JBlockTypeBoolExpression* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        JBlockTypeBoolExpression* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 36 - 33
FactoryCraft/LightSources.cpp

@@ -20,15 +20,15 @@ LightSourceItemType::LightSourceItemType(Framework::Text name,
     int maxStackSize,
     Framework::RCArray<Framework::Text> groups)
     : BasicBlockItemType(name,
-        model,
-        true,
-        true,
-        0.f,
-        1.f,
-        blockTypeName,
-        0,
-        maxStackSize,
-        groups)
+          model,
+          true,
+          true,
+          0.f,
+          1.f,
+          blockTypeName,
+          0,
+          maxStackSize,
+          groups)
 {}
 
 void LightSourceItemType::loadSuperItem(
@@ -63,7 +63,9 @@ LightSourceItemType* LightSourceItemType::setColor(int color)
 BasicLightSource::BasicLightSource(
     int typeId, Framework::Vec3<int> pos, int dimensionId)
     : Block(typeId, pos, dimensionId, false)
-{}
+{
+    transparent = true;
+}
 
 void BasicLightSource::setLight(int light)
 {
@@ -165,7 +167,7 @@ ItemType* BasicLightSourceBlockType::createItemType() const
                 getName(),
                 50,
                 getGroupNames()))
-        ->setColor(0x00F69A54);
+        ->setColor(lightColor);
 }
 
 void BasicLightSourceBlockType::setItemTypeName(Framework::Text itemTypeName)
@@ -228,43 +230,44 @@ BasicLightSourceBlockType* BasicLightSourceBlockTypeFactory::createValue(
     return new BasicLightSourceBlockType();
 }
 
-void BasicLightSourceBlockTypeFactory::fromJson(
-    BasicLightSourceBlockType* zResult,
+BasicLightSourceBlockType* BasicLightSourceBlockTypeFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setItemTypeName(zJson->zValue("itemType")->asString()->getString());
-    zResult->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
-    zResult->setPassable(zJson->zValue("passable")->asBool()->getBool());
-    zResult->setInteractable(
-        zJson->zValue("interactable")->asBool()->getBool());
-    zResult->setLightColor(
+    BasicLightSourceBlockType* result = BlockTypeFactoryBase::fromJson(zJson);
+    result->setItemTypeName(zJson->zValue("itemType")->asString()->getString());
+    result->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
+    result->setPassable(zJson->zValue("passable")->asBool()->getBool());
+    result->setInteractable(zJson->zValue("interactable")->asBool()->getBool());
+    result->setLightColor(
         (int)zJson->zValue("lightColor")->asString()->getString());
-    BlockTypeFactoryBase::fromJson(zResult, zJson);
+    return result;
 }
 
-void BasicLightSourceBlockTypeFactory::toJson(
-    BasicLightSourceBlockType* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* BasicLightSourceBlockTypeFactory::toJsonObject(
+    BasicLightSourceBlockType* zObject) const
 {
-    zResult->addValue("itemType",
+    Framework::JSON::JSONObject* result
+        = BlockTypeFactoryBase::toJsonObject(zObject);
+    result->addValue("itemType",
         new Framework::JSON::JSONString(zObject->getItemTypeName()));
-    zResult->addValue(
+    result->addValue(
         "transparent", new Framework::JSON::JSONBool(zObject->isTransparent()));
-    zResult->addValue(
+    result->addValue(
         "passable", new Framework::JSON::JSONBool(zObject->isPassable()));
-    zResult->addValue("interactable",
+    result->addValue("interactable",
         new Framework::JSON::JSONBool(zObject->isInteractable()));
-    zResult->addValue("lightColor",
+    result->addValue("lightColor",
         new Framework::JSON::JSONString(zObject->getLightColor()));
-    BlockTypeFactoryBase::toJson(zObject, zResult);
+    return result;
 }
 
 JSONObjectValidationBuilder* BasicLightSourceBlockTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return BlockTypeFactoryBase::addToValidator(
-        builder->withRequiredString("itemType")
-            ->finishString()
+    return BlockTypeFactoryBase::addToValidator(builder
+            ->withRequiredAttribute("itemType",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    ItemTypeNameFactory::TYPE_ID))
             ->withRequiredBool("transparent")
             ->withDefault(true)
             ->finishBool()
@@ -278,7 +281,7 @@ JSONObjectValidationBuilder* BasicLightSourceBlockTypeFactory::addToValidator(
             ->finishString());
 }
 
-Framework::Text BasicLightSourceBlockTypeFactory::getTypeToken() const
+const char* BasicLightSourceBlockTypeFactory::getTypeToken() const
 {
     return "lightSource";
 }

+ 4 - 5
FactoryCraft/LightSources.h

@@ -1,6 +1,5 @@
 #pragma once
 
-#include "BasicBlocks.h"
 #include "Block.h"
 #include "BlockType.h"
 
@@ -107,11 +106,11 @@ public:
     BasicLightSourceBlockTypeFactory();
     BasicLightSourceBlockType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(BasicLightSourceBlockType* zResult,
+    BasicLightSourceBlockType* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(BasicLightSourceBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        BasicLightSourceBlockType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 81 - 20
FactoryCraft/ModelInfo.cpp

@@ -1,5 +1,8 @@
 #include "ModelInfo.h"
 
+#include <M3Datei.h>
+#include <Model3D.h>
+
 using namespace Framework;
 
 ModelInfo::ModelInfo()
@@ -82,46 +85,98 @@ float ModelInfo::getSize() const
     return size;
 }
 
-ModelInfoFactory::ModelInfoFactory()
-    : TypeFactory()
-{}
-
-ModelInfo* ModelInfoFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
+Framework::Vec3<float> ModelInfo::getBoundingBox() const
 {
-    return new ModelInfo();
+    return boundingBox;
 }
 
-void ModelInfoFactory::fromJson(
-    ModelInfo* zResult, Framework::JSON::JSONObject* zJson) const
+ModelInfoFactory::ModelInfoFactory()
+    : ObjectTypeFactory()
+{}
+
+ModelInfo* ModelInfoFactory::fromJson(Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setModelPath(
+    ModelInfo* result = new ModelInfo();
+    result->setModelPath(
         zJson->asObject()->zValue("modelPath")->asString()->getString());
     for (Framework::JSON::JSONValue* v :
         *zJson->asObject()->zValue("texturePaths")->asArray())
     {
-        zResult->addTexturePath(v->asString()->getString());
+        result->addTexturePath(v->asString()->getString());
     }
-    zResult->setTransparent(
+    result->setTransparent(
         zJson->asObject()->zValue("transparent")->asBool()->getBool());
-    zResult->setSize(
+    result->setSize(
         (float)zJson->asObject()->zValue("size")->asNumber()->getNumber());
+    if (zJson->asObject()->hasValue("boundingBox"))
+    {
+        Framework::JSON::JSONArray* bbArr
+            = zJson->asObject()->zValue("boundingBox")->asArray();
+        result->boundingBox.x
+            = (float)bbArr->getValue(0)->asNumber()->getNumber();
+        result->boundingBox.y
+            = (float)bbArr->getValue(1)->asNumber()->getNumber();
+        result->boundingBox.z
+            = (float)bbArr->getValue(2)->asNumber()->getNumber();
+    }
+    else
+    {
+        Text path = "data/models/";
+        path += result->getModelPath();
+        bool loades = 0;
+        if (path.positionVon(".m3/") > 0)
+        {
+            int pos = path.positionVon(".m3/", path.anzahlVon(".m3/") - 1) + 3;
+            Framework::M3Datei m3File(path.getTeilText(0, pos));
+            m3File.leseDaten();
+            Model3DData* data
+                = m3File.ladeModel(path.getTeilText(pos + 1), 0, new Text());
+            if (data)
+            {
+                auto tmp = data->getMaxPos();
+                result->boundingBox.x = abs(tmp.x);
+                result->boundingBox.y = abs(tmp.y);
+                result->boundingBox.z = abs(tmp.z);
+                tmp = data->getMinPos();
+                result->boundingBox.x = max(result->boundingBox.x, abs(tmp.x));
+                result->boundingBox.y = max(result->boundingBox.y, abs(tmp.y));
+                result->boundingBox.z = max(result->boundingBox.z, abs(tmp.z));
+                data->release();
+                loades = 1;
+            }
+        }
+        if (!loades)
+        {
+            result->boundingBox.x = 0.5f;
+            result->boundingBox.y = 0.5f;
+            result->boundingBox.z = 0.5f;
+        }
+    }
+
+    return result;
 }
 
-void ModelInfoFactory::toJson(
-    ModelInfo* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* ModelInfoFactory::toJsonObject(
+    ModelInfo* zObject) const
 {
+    Framework::JSON::JSONObject* result = 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()));
     }
-    zResult->addValue("texturePaths", arr);
-    zResult->addValue(
+    result->addValue("texturePaths", arr);
+    result->addValue(
         "modelPath", new Framework::JSON::JSONString(zObject->modelPath));
-    zResult->addValue(
+    result->addValue(
         "transparent", new Framework::JSON::JSONBool(zObject->transparent));
-    zResult->addValue("size", new Framework::JSON::JSONNumber(zObject->size));
+    result->addValue("size", new Framework::JSON::JSONNumber(zObject->size));
+    Framework::JSON::JSONArray* bbArr = new Framework::JSON::JSONArray();
+    bbArr->addValue(new Framework::JSON::JSONNumber(zObject->boundingBox.x));
+    bbArr->addValue(new Framework::JSON::JSONNumber(zObject->boundingBox.y));
+    bbArr->addValue(new Framework::JSON::JSONNumber(zObject->boundingBox.z));
+    result->addValue("boundingBox", bbArr);
+    return result;
 }
 
 JSONObjectValidationBuilder* ModelInfoFactory::addToValidator(
@@ -139,5 +194,11 @@ JSONObjectValidationBuilder* ModelInfoFactory::addToValidator(
         ->withRequiredNumber("size")
         ->whichIsGreaterThen(0)
         ->withDefault(1.0)
-        ->finishNumber();
+        ->finishNumber()
+        ->withRequiredArray("boundingBox")
+        ->whichIsOptional()
+        ->withRequiredSize(3)
+        ->addAcceptedNumberInArray()
+        ->finishNumber()
+        ->finishArray();
 }

+ 7 - 6
FactoryCraft/ModelInfo.h

@@ -2,6 +2,7 @@
 
 #include <Array.h>
 #include <Text.h>
+#include <Vec3.h>
 #include <Writer.h>
 
 #include "TypeRegistry.h"
@@ -15,6 +16,7 @@ private:
     Framework::RCArray<Framework::Text> texturePaths;
     bool transparent;
     float size;
+    Framework::Vec3<float> boundingBox;
 
 public:
     ModelInfo();
@@ -32,19 +34,18 @@ public:
     Framework::RCArray<Framework::Text> getTexturePaths() const;
     bool isTransparent() const;
     float getSize() const;
+    Framework::Vec3<float> getBoundingBox() const;
 
     friend ModelInfoFactory;
 };
 
-class ModelInfoFactory : public TypeFactory<ModelInfo>
+class ModelInfoFactory : public ObjectTypeFactory<ModelInfo>
 {
 public:
     ModelInfoFactory();
-    ModelInfo* createValue(Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(
-        ModelInfo* zResult, Framework::JSON::JSONObject* zJson) const override;
-    void toJson(ModelInfo* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    ModelInfo* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        ModelInfo* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };

+ 16 - 1
FactoryCraft/MultiblockStructure.cpp

@@ -53,7 +53,8 @@ void MultiblockStructure::addMemberPosition(Framework::Vec3<int> blockPos)
     affectedChunks.add(center);
 }
 
-void MultiblockStructure::onBlockRemoved(Block* zBlock)
+void MultiblockStructure::onBlockRemoved(
+    Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, Block* zBlock)
 {
     for (auto i = memberBlockPositions.begin(); i; ++i)
     {
@@ -78,6 +79,15 @@ void MultiblockStructure::onBlockRemoved(Block* zBlock)
     }
 }
 
+void MultiblockStructure::onBlockReplaced(Entity* zActor,
+    Item* zUsedItem,
+    ItemSkill* zUsedSkill,
+    Block* zOldBlock,
+    Block* zNewBlock)
+{
+    // do nothing
+}
+
 bool MultiblockStructure::isEmpty() const
 {
     return memberBlockPositions.getEintragAnzahl() == 0 && !isLoading;
@@ -183,4 +193,9 @@ void MultiblockStructureType::saveStructure(
 int MultiblockStructureType::getId() const
 {
     return id;
+}
+
+int MultiblockStructure::getDimensionId() const
+{
+    return dimensionId;
 }

+ 11 - 1
FactoryCraft/MultiblockStructure.h

@@ -7,6 +7,9 @@
 #include <Writer.h>
 
 class MultiblockStructureType;
+class Entity;
+class Item;
+class ItemSkill;
 class Block;
 
 class MultiblockStructureEnum
@@ -38,7 +41,13 @@ public:
     void onBlockLoaded(Block* block);
     void onBlockUnloaded(Block* zBlock);
     void addMemberPosition(Framework::Vec3<int> blockPos);
-    virtual void onBlockRemoved(Block* zBlock);
+    virtual void onBlockRemoved(
+        Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, Block* zBlock);
+    virtual void onBlockReplaced(Entity* zActor,
+        Item* zUsedItem,
+        ItemSkill* zUsedSkill,
+        Block* zOldBlock,
+        Block* zNewBlock);
 
     bool isEmpty() const;
     bool isFullyLoaded() const;
@@ -47,6 +56,7 @@ public:
     __int64 getStructureId() const;
     Framework::Vec3<int> getUniquePosition() const;
     int getStructureTypeId() const;
+    int getDimensionId() const;
 
     friend MultiblockStructureType;
 };

+ 107 - 0
FactoryCraft/MultiblockStructureManager.cpp

@@ -0,0 +1,107 @@
+#include "MultiblockStructureManager.h"
+
+#include <Datei.h>
+#include <Logging.h>
+
+#include "Block.h"
+#include "Game.h"
+
+MultiblockStructureManager::MultiblockStructureManager(int dimensionId)
+    : dimensionId(dimensionId)
+{
+    Framework::Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                         + Framework::Text(dimensionId) + "/structures";
+    Framework::Datei folder(path);
+    Framework::RCArray<Framework::Text>* files = folder.getDateiListe();
+    if (files)
+    {
+        Framework::Logging::info() << "Loading Multiblock Position Cache";
+        Framework::ConsoleProgressBar* progressBar
+            = new Framework::ConsoleProgressBar();
+        Game::consoleHandler->addContent(
+            progressBar, Framework::ConsoleContentPosition::Top);
+        progressBar->setMaxProgress(files->getEintragAnzahl());
+        progressBar->triggerUpdate();
+        char addr[12];
+        for (Framework::Text* name : *files)
+        {
+            Framework::Datei d(Framework::Text(folder.zPfad()->getText()) + "/"
+                               + name->getText());
+            if (d.open(Framework::Datei::Style::lesen))
+            {
+                d.lese(addr, 4);
+                d.lese(addr + 4, 4);
+                d.lese(addr + 8, 4);
+                __int64 id;
+                d.lese((char*)&id, 8);
+                idCache.set(addr, 12, id);
+                d.close();
+            }
+            progressBar->setProgress(progressBar->getProgress() + 1);
+            progressBar->triggerUpdate();
+        }
+        files->release();
+        Game::consoleHandler->removeContent(progressBar);
+    }
+}
+
+MultiblockStructure* MultiblockStructureManager::loadStructure(__int64 id) const
+{
+    Framework::Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                         + Framework::Text(dimensionId) + "/structures/";
+    path.appendHex(id);
+    path += ".str";
+    Framework::Datei d(path);
+    Framework::Vec3<int> uPos;
+    if (d.open(Framework::Datei::Style::lesen))
+    {
+        d.lese((char*)&uPos.x, 4);
+        d.lese((char*)&uPos.y, 4);
+        d.lese((char*)&uPos.z, 4);
+        __int64 strId;
+        d.lese((char*)&strId, 8);
+        int type;
+        d.lese((char*)&type, 4);
+        MultiblockStructure* str
+            = Game::INSTANCE->zMultiblockStructureType(type)->loadStructure(
+                dimensionId, strId, uPos, &d);
+        d.close();
+        return str;
+    }
+    return 0;
+}
+
+__int64 MultiblockStructureManager::getStructureId(
+    Framework::Vec3<int> pos) const
+{
+    char addr[12];
+    *(int*)addr = pos.x;
+    *(int*)(addr + 4) = pos.y;
+    *(int*)(addr + 8) = pos.z;
+    idCache.get(addr, 12);
+    return 0;
+}
+
+void MultiblockStructureManager::saveStructure(
+    MultiblockStructure* zStructure) const
+{
+    Framework::Datei d;
+    Framework::Text path = Game::INSTANCE->getWorldDirectory() + "/dim/"
+                         + Framework::Text(dimensionId) + "/structures/";
+    path.appendHex(zStructure->getStructureId());
+    path += ".str";
+    d.setDatei(path);
+    d.erstellen();
+    d.open(Framework::Datei::Style::schreiben);
+    auto uPos = zStructure->getUniquePosition();
+    d.schreibe((char*)&uPos.x, 4);
+    d.schreibe((char*)&uPos.y, 4);
+    d.schreibe((char*)&uPos.z, 4);
+    __int64 strId = zStructure->getStructureId();
+    d.schreibe((char*)&strId, 8);
+    int typeId = zStructure->getStructureTypeId();
+    d.schreibe((char*)&typeId, 4);
+    Game::INSTANCE->zMultiblockStructureType(zStructure->getStructureTypeId())
+        ->saveStructure(zStructure, &d);
+    d.close();
+}

+ 19 - 0
FactoryCraft/MultiblockStructureManager.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include <Trie.h>
+
+#include "MultiblockStructure.h"
+
+class MultiblockStructureManager
+{
+private:
+    int dimensionId;
+    Framework::Trie<__int64> idCache;
+
+public:
+    MultiblockStructureManager(int dimensionId);
+
+    MultiblockStructure* loadStructure(__int64 id) const;
+    __int64 getStructureId(Framework::Vec3<int> pos) const;
+    void saveStructure(MultiblockStructure* zStructure) const;
+};

+ 27 - 9
FactoryCraft/MultiblockTree.cpp

@@ -6,27 +6,40 @@ using namespace Framework;
 
 MultiblockTree::MultiblockTree(
     int dimensionId, __int64 structureId, Framework::Vec3<int> uniquePosition)
-    : MultiblockStructure(
-        dimensionId, structureId, uniquePosition, MultiblockStructureEnum::TREE)
+    : MultiblockStructure(dimensionId,
+          structureId,
+          uniquePosition,
+          MultiblockStructureEnum::TREE)
 {}
 
-void MultiblockTree::onBlockRemoved(Block* zBlock)
+void MultiblockTree::onBlockRemoved(
+    Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill, Block* zBlock)
 {
     if (isBlockMember(zBlock))
     {
-        MultiblockStructure::onBlockRemoved(zBlock);
+        MultiblockStructure::onBlockRemoved(
+            zActor, zUsedItem, zUsedSkill, zBlock);
         for (int d = 4; d >= 0; d--)
         {
             bool foundStablizer = 0;
             Array<Block*> checked;
             Array<Block*> queue;
-            Block* current = zBlock->zNeighbor(getDirectionFromIndex(d));
+            Either<Block*, int> tmp = Game::INSTANCE->zBlockAt(
+                zBlock->getPos() + getDirection(getDirectionFromIndex(d)),
+                getDimensionId(),
+                0);
+            Block* current = tmp.isA() ? tmp.getA() : 0;
             if (current && isBlockMember(current)) queue.add(current);
             while (queue.getEintragAnzahl() > 0)
             {
                 current = queue.get(0);
                 queue.remove(0);
-                Block* bottom = current->zNeighbor(BOTTOM);
+                tmp = Game::INSTANCE->zBlockAt(
+                    zBlock->getPos()
+                        + getDirection(getDirectionFromIndex(d) | BOTTOM),
+                    getDimensionId(),
+                    0);
+                Block* bottom = tmp.isA() ? tmp.getA() : 0;
                 if (bottom && isBlockMember(bottom))
                 {
                     foundStablizer = 1;
@@ -35,8 +48,13 @@ void MultiblockTree::onBlockRemoved(Block* zBlock)
                 checked.add(current);
                 for (int i = 0; i < 4; i++)
                 {
-                    Block* neighbor
-                        = current->zNeighbor(getDirectionFromIndex(i));
+                    tmp = Game::INSTANCE->zBlockAt(
+                        zBlock->getPos()
+                            + getDirection(getDirectionFromIndex(d)
+                                           | getDirectionFromIndex(i)),
+                        getDimensionId(),
+                        0);
+                    Block* neighbor = tmp.isA() ? tmp.getA() : 0;
                     if (neighbor && isBlockMember(neighbor))
                     {
                         bool found = 0;
@@ -66,7 +84,7 @@ void MultiblockTree::onBlockRemoved(Block* zBlock)
             if (!foundStablizer)
             {
                 for (Block* b : checked)
-                    b->setHP(0);
+                    b->setHP(zActor, zUsedItem, zUsedSkill, 0);
             }
         }
     }

+ 4 - 1
FactoryCraft/MultiblockTree.h

@@ -8,7 +8,10 @@ public:
     MultiblockTree(int dimensionId,
         __int64 structureId,
         Framework::Vec3<int> uniquePosition);
-    virtual void onBlockRemoved(Block* zBlock) override;
+    virtual void onBlockRemoved(Entity* zActor,
+        Item* zUsedItem,
+        ItemSkill* zUsedSkill,
+        Block* zBlock) override;
 };
 
 class MultiblockTreeStructureType : public MultiblockStructureType

+ 49 - 2
FactoryCraft/NetworkMessage.cpp

@@ -8,6 +8,7 @@
 #include "ChunkMap.h"
 #include "Dimension.h"
 #include "Entity.h"
+#include "EntityType.h"
 #include "Game.h"
 
 NetworkMessage::NetworkMessage()
@@ -116,15 +117,17 @@ void NetworkMessage::updateDialog(
     setMessage(msg, msgSize);
 }
 
-void NetworkMessage::addressUIElement(Framework::Text elementId)
+void NetworkMessage::addressUIElement(
+    Framework::Text elementId, int processorId)
 {
     delete[] address;
-    addressLength = (char)(4 + elementId.getLength());
+    addressLength = (char)(8 + elementId.getLength());
     address = new char[addressLength];
     address[0] = 2;                                        // gui message
     address[1] = 1;                                        // element message
     *(short*)(address + 2) = (short)elementId.getLength(); // element id
     memcpy(address + 4, elementId.getText(), elementId.getLength());
+    *(int*)(address + 4 + elementId.getLength()) = processorId; // processor id
 }
 
 void NetworkMessage::setMessage(char* msg, int length)
@@ -238,6 +241,50 @@ void NetworkMessage::syncTime(
     *(double*)(message + 24) = dayLength;
 }
 
+void NetworkMessage::addEntityMessage(const Entity* zEntity)
+{
+    Dimension* dim = Game::INSTANCE->zDimension(zEntity->getDimensionId());
+    if (dim)
+    {
+        addressDimension(dim);
+        Framework::InMemoryBuffer buffer;
+        int id = zEntity->zType()->getId();
+        buffer.schreibe("\x7", 1); // add entity
+        buffer.schreibe((char*)&id, 4);
+        id = zEntity->getId();
+        buffer.schreibe((char*)&id, 4);
+        Framework::Vec3<float> pos = zEntity->getPosition();
+        buffer.schreibe((char*)&pos.x, 4);
+        buffer.schreibe((char*)&pos.y, 4);
+        buffer.schreibe((char*)&pos.z, 4);
+        float maxSpeed = zEntity->getMaxSpeed();
+        buffer.schreibe((char*)&maxSpeed, 4);
+        float gravityMultiplier = zEntity->getGravityMultiplier();
+        buffer.schreibe((char*)&gravityMultiplier, 4);
+        float jumpSpeed = zEntity->getJumpSpeed();
+        buffer.schreibe((char*)&jumpSpeed, 4);
+        bool special = !zEntity->hasDefaultModel();
+        buffer.schreibe((char*)&special, 1);
+        if (special) zEntity->zSpecialModel()->writeTo(&buffer);
+        msgLength = (int)buffer.getSize();
+        message = new char[msgLength];
+        buffer.lese(message, (int)buffer.getSize());
+    }
+}
+
+void NetworkMessage::removeEntityMessage(const Entity* zEntity)
+{
+    Dimension* dim = Game::INSTANCE->zDimension(zEntity->getDimensionId());
+    if (dim)
+    {
+        addressDimension(dim);
+        msgLength = 5;
+        message = new char[5];
+        message[0] = '\x8';
+        *(int*)(message + 1) = zEntity->getId();
+    }
+}
+
 void NetworkMessage::writeTo(Framework::StreamWriter* zWriter) const
 {
     int total = msgLength + addressLength;

+ 3 - 1
FactoryCraft/NetworkMessage.h

@@ -36,7 +36,7 @@ public:
     void addressDimension(const Dimension* zDim);
     void openDialog(Framework::Text dialogName, Framework::Text uiml);
     void updateDialog(Framework::Text dialogName, Framework::Text uiml);
-    void addressUIElement(Framework::Text elementId);
+    void addressUIElement(Framework::Text elementId, int processorId);
     void setMessage(char* msg, int length);
     void sendChatMessage(ChatMessage* zMsg);
     void sendChatOptions(ChatObserver* zOptions);
@@ -55,6 +55,8 @@ public:
         double nightLength,
         double transitionLength,
         double dayLength);
+    void addEntityMessage(const Entity* zEntity);
+    void removeEntityMessage(const Entity* zEntity);
 
     void writeTo(Framework::StreamWriter* zWriter) const;
     bool isBroadcast() const;

+ 0 - 0
FactoryCraft/NeutralAnimalAI.cpp


+ 6 - 0
FactoryCraft/NeutralAnimalAI.h

@@ -0,0 +1,6 @@
+#pragma once
+
+#include "AnimalAI.h"
+
+class NeutralAnimalAI : public AnimalAI
+{};

+ 5 - 10
FactoryCraft/NoBlock.cpp

@@ -1,8 +1,7 @@
 #include "NoBlock.h"
 
-NoBlockBlockType::NoBlockBlockType(const Block* defaultB, Framework::Text name)
-    : BlockType(),
-      defaultB(defaultB)
+NoBlockBlockType::NoBlockBlockType(Block* defaultB, Framework::Text name)
+    : BlockType()
 {
     setModel(new ModelInfo("", Framework::RCArray<Framework::Text>(), 0, 1.f));
     setNeedModelSubscription(false);
@@ -12,6 +11,7 @@ NoBlockBlockType::NoBlockBlockType(const Block* defaultB, Framework::Text name)
     setNeedsClientInstance(false);
     setMapColor(0);
     setHardness(0.f);
+    defaultBlock = defaultB;
 }
 
 ItemType* NoBlockBlockType::createItemType() const
@@ -52,11 +52,6 @@ Block* NoBlockBlockType::createBlockAt(
     return 0;
 }
 
-const Block* NoBlockBlockType::zDefault() const
-{
-    return defaultB;
-}
-
 NoBlock::NoBlock()
     : Block(BlockTypeEnum::NO_BLOCK, {0, 0, 0}, 0, false)
 {
@@ -74,7 +69,7 @@ bool NoBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
 
 void NoBlock::onPostTick() {}
 
-const NoBlock NoBlock::INSTANCE;
+NoBlock NoBlock::INSTANCE;
 
 AirBlock::AirBlock()
     : Block(BlockTypeEnum::AIR, {0, 0, 0}, 0, false)
@@ -93,4 +88,4 @@ bool AirBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
 
 void AirBlock::onPostTick() {}
 
-const AirBlock AirBlock::INSTANCE;
+AirBlock AirBlock::INSTANCE;

+ 3 - 7
FactoryCraft/NoBlock.h

@@ -5,9 +5,6 @@
 
 class NoBlockBlockType : public BlockType
 {
-private:
-    const Block* defaultB;
-
 protected:
     virtual Block* createBlock(
         Framework::Vec3<int> position, int dimensionId) const override;
@@ -21,17 +18,16 @@ protected:
     virtual Block* createBlockAt(Framework::Vec3<int> position,
         int dimensionId,
         Item* zUsedItem) const override;
-    virtual const Block* zDefault() const override;
 
 public:
-    NoBlockBlockType(const Block* defaultB, Framework::Text name);
+    NoBlockBlockType(Block* defaultB, Framework::Text name);
     virtual ItemType* createItemType() const override;
 };
 
 class NoBlock : public Block
 {
 public:
-    static const NoBlock INSTANCE;
+    static NoBlock INSTANCE;
 
 protected:
     NoBlock();
@@ -44,7 +40,7 @@ protected:
 class AirBlock : public Block
 {
 public:
-    static const AirBlock INSTANCE;
+    static AirBlock INSTANCE;
 
 protected:
     AirBlock();

+ 6 - 1
FactoryCraft/Noise.cpp

@@ -7,4 +7,9 @@ Noise::Noise()
 double Noise::getNoise(Framework::Vec3<double>& pos)
 {
     return getNoise(pos.x, pos.y, pos.z);
-}
+}
+
+float Noise::getNoise(float x, float y, float z)
+{
+    return (float)getNoise((double)x, (double)y, (double)z);
+}

+ 1 - 0
FactoryCraft/Noise.h

@@ -17,4 +17,5 @@ public:
     /// <returns>the noise value scaled to a range from 0 to 1</returns>
     virtual double getNoise(double x, double y, double z) = 0;
     double getNoise(Framework::Vec3<double>& pos);
+    float getNoise(float x, float y, float z);
 };

+ 95 - 0
FactoryCraft/OpenDialogInteractionConfig.cpp

@@ -0,0 +1,95 @@
+#include "OpenDialogInteractionConfig.h"
+
+#include <XML.h>
+
+#include "Entity.h"
+#include "UIController.h"
+#include "UIDialog.h"
+#include "UIDialogElement.h"
+
+OpenDialogInteractionConfig::OpenDialogInteractionConfig()
+    : InteractionConfig(),
+      dialogElement(0)
+{}
+
+OpenDialogInteractionConfig::~OpenDialogInteractionConfig()
+{
+    if (dialogElement)
+    {
+        dialogElement->release();
+    }
+}
+
+void OpenDialogInteractionConfig::setDialogElement(
+    UIDialogElement* dialogElement)
+{
+    if (this->dialogElement)
+    {
+        this->dialogElement->release();
+    }
+    this->dialogElement = dialogElement;
+}
+
+UIDialogElement* OpenDialogInteractionConfig::zDialogElement() const
+{
+    return dialogElement;
+}
+
+bool OpenDialogInteractionConfig::onInteraction(
+    Framework::Either<Block*, Entity*> target,
+    Item* zItem,
+    Entity* actor,
+    bool& itemChanged)
+{
+    Framework::XML::Element* uiml = dialogElement->toUIML(target, actor);
+    Game::INSTANCE->zUIController()->addDialog(
+        new UIDialog(uiml->getAttributeValue("id"), actor->getId(), uiml));
+    return true;
+}
+
+OpenDialogInteractionConfigFactory::OpenDialogInteractionConfigFactory()
+    : InteractionConfigFactory<OpenDialogInteractionConfig>()
+{}
+
+JSONObjectValidationBuilder* OpenDialogInteractionConfigFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return InteractionConfigFactory<
+        OpenDialogInteractionConfig>::addToValidator(builder)
+        ->withRequiredAttribute("dialogElement",
+            Game::INSTANCE->zTypeRegistry()->getValidator<UIDialogElement>());
+}
+
+OpenDialogInteractionConfig* OpenDialogInteractionConfigFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    OpenDialogInteractionConfig* result
+        = InteractionConfigFactory<OpenDialogInteractionConfig>::fromJson(
+            zJson);
+    result->setDialogElement(
+        Game::INSTANCE->zTypeRegistry()->fromJson<UIDialogElement>(
+            zJson->zValue("dialogElement")));
+    return result;
+}
+
+Framework::JSON::JSONObject* OpenDialogInteractionConfigFactory::toJsonObject(
+    OpenDialogInteractionConfig* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = InteractionConfigFactory<OpenDialogInteractionConfig>::toJsonObject(
+            zObject);
+    result->addValue("dialogElement",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zDialogElement()));
+    return result;
+}
+
+const char* OpenDialogInteractionConfigFactory::getTypeToken() const
+{
+    return "OpenDialogInteractionConfig";
+}
+
+OpenDialogInteractionConfig* OpenDialogInteractionConfigFactory::createValue(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new OpenDialogInteractionConfig();
+}

+ 41 - 0
FactoryCraft/OpenDialogInteractionConfig.h

@@ -0,0 +1,41 @@
+#pragma once
+
+#include "InteractionConfig.h"
+
+class UIDialogElement;
+
+class OpenDialogInteractionConfig : public InteractionConfig
+{
+private:
+    UIDialogElement* dialogElement;
+
+public:
+    OpenDialogInteractionConfig();
+    ~OpenDialogInteractionConfig();
+    void setDialogElement(UIDialogElement* dialogElement);
+    UIDialogElement* zDialogElement() const;
+
+protected:
+    virtual bool onInteraction(Framework::Either<Block*, Entity*> target,
+        Item* zItem,
+        Entity* actor,
+        bool& itemChanged) override;
+};
+
+class OpenDialogInteractionConfigFactory
+    : public InteractionConfigFactory<OpenDialogInteractionConfig>
+{
+public:
+    OpenDialogInteractionConfigFactory();
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    virtual OpenDialogInteractionConfig* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    virtual Framework::JSON::JSONObject* toJsonObject(
+        OpenDialogInteractionConfig* zObject) const override;
+    virtual const char* getTypeToken() const override;
+
+protected:
+    virtual OpenDialogInteractionConfig* createValue(
+        Framework::JSON::JSONObject* zJson) const override;
+};

+ 43 - 53
FactoryCraft/PlaceableProof.cpp

@@ -39,32 +39,30 @@ PlaceableProofAndFactory::PlaceableProofAndFactory()
     : SubTypeFactory()
 {}
 
-PlaceableProofAnd* PlaceableProofAndFactory::createValue(
+PlaceableProofAnd* PlaceableProofAndFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new PlaceableProofAnd();
-}
-
-void PlaceableProofAndFactory::fromJson(
-    PlaceableProofAnd* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    PlaceableProofAnd* result = new PlaceableProofAnd();
     for (Framework::JSON::JSONValue* zProof :
         *zJson->zValue("proofs")->asArray())
     {
-        zResult->addProof(
+        result->addProof(
             Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(zProof));
     }
+    return result;
 }
 
-void PlaceableProofAndFactory::toJson(
-    PlaceableProofAnd* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* PlaceableProofAndFactory::toJsonObject(
+    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));
     }
-    zResult->addValue("proofs", proofs);
+    result->addValue("proofs", proofs);
+    return result;
 }
 
 JSONObjectValidationBuilder* PlaceableProofAndFactory::addToValidator(
@@ -76,7 +74,7 @@ JSONObjectValidationBuilder* PlaceableProofAndFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text PlaceableProofAndFactory::getTypeToken() const
+const char* PlaceableProofAndFactory::getTypeToken() const
 {
     return "and";
 }
@@ -112,32 +110,30 @@ PlaceableProofOrFactory::PlaceableProofOrFactory()
     : SubTypeFactory()
 {}
 
-PlaceableProofOr* PlaceableProofOrFactory::createValue(
+PlaceableProofOr* PlaceableProofOrFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new PlaceableProofOr();
-}
-
-void PlaceableProofOrFactory::fromJson(
-    PlaceableProofOr* zResult, Framework::JSON::JSONObject* zJson) const
-{
+    PlaceableProofOr* result = new PlaceableProofOr();
     for (Framework::JSON::JSONValue* zProof :
         *zJson->zValue("proofs")->asArray())
     {
-        zResult->addProof(
+        result->addProof(
             Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(zProof));
     }
+    return result;
 }
 
-void PlaceableProofOrFactory::toJson(
-    PlaceableProofOr* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* PlaceableProofOrFactory::toJsonObject(
+    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));
     }
-    zResult->addValue("proofs", proofs);
+    result->addValue("proofs", proofs);
+    return result;
 }
 
 JSONObjectValidationBuilder* PlaceableProofOrFactory::addToValidator(
@@ -149,7 +145,7 @@ JSONObjectValidationBuilder* PlaceableProofOrFactory::addToValidator(
         ->finishArray();
 }
 
-Framework::Text PlaceableProofOrFactory::getTypeToken() const
+const char* PlaceableProofOrFactory::getTypeToken() const
 {
     return "or";
 }
@@ -181,24 +177,22 @@ PlaceableProofNotFactory::PlaceableProofNotFactory()
     : SubTypeFactory()
 {}
 
-PlaceableProofNot* PlaceableProofNotFactory::createValue(
+PlaceableProofNot* PlaceableProofNotFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new PlaceableProofNot();
-}
-
-void PlaceableProofNotFactory::fromJson(
-    PlaceableProofNot* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setProof(Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
+    PlaceableProofNot* result = new PlaceableProofNot();
+    result->setProof(Game::INSTANCE->zTypeRegistry()->fromJson<PlaceableProof>(
         zJson->zValue("proof")));
+    return result;
 }
 
-void PlaceableProofNotFactory::toJson(
-    PlaceableProofNot* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* PlaceableProofNotFactory::toJsonObject(
+    PlaceableProofNot* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "proof", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zProof()));
+    return result;
 }
 
 JSONObjectValidationBuilder* PlaceableProofNotFactory::addToValidator(
@@ -208,7 +202,7 @@ JSONObjectValidationBuilder* PlaceableProofNotFactory::addToValidator(
         Game::INSTANCE->zTypeRegistry()->getValidator<PlaceableProof>());
 }
 
-Framework::Text PlaceableProofNotFactory::getTypeToken() const
+const char* PlaceableProofNotFactory::getTypeToken() const
 {
     return "not";
 }
@@ -268,16 +262,10 @@ PlaceableProofBlockFilterFactory::PlaceableProofBlockFilterFactory()
     : SubTypeFactory()
 {}
 
-PlaceableProofBlockFilter* PlaceableProofBlockFilterFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new PlaceableProofBlockFilter();
-}
-
-void PlaceableProofBlockFilterFactory::fromJson(
-    PlaceableProofBlockFilter* zResult,
+PlaceableProofBlockFilter* PlaceableProofBlockFilterFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
+    PlaceableProofBlockFilter* result = new PlaceableProofBlockFilter();
     Direction dir = NO_DIRECTION;
     if (zJson->zValue("direction")->asString()->getString().istGleich("top"))
     {
@@ -318,15 +306,16 @@ void PlaceableProofBlockFilterFactory::fromJson(
     {
         dir = WEST;
     }
-    zResult->setDirection(dir);
-    zResult->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
+    result->setDirection(dir);
+    result->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson<BlockFilter>(
         zJson->zValue("filter")));
+    return result;
 }
 
-void PlaceableProofBlockFilterFactory::toJson(
-    PlaceableProofBlockFilter* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* PlaceableProofBlockFilterFactory::toJsonObject(
+    PlaceableProofBlockFilter* zObject) const
 {
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
     Framework::Text dir = "";
     if (zObject->getDirection() == NORTH)
     {
@@ -352,11 +341,12 @@ void PlaceableProofBlockFilterFactory::toJson(
     {
         dir = "bottom";
     }
-    zResult->addValue("direction", new Framework::JSON::JSONString(dir));
-    zResult->addValue(
+    result->addValue("direction", new Framework::JSON::JSONString(dir));
+    result->addValue(
         "distance", new Framework::JSON::JSONNumber(zObject->getDistance()));
-    zResult->addValue(
+    result->addValue(
         "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
+    return result;
 }
 
 JSONObjectValidationBuilder* PlaceableProofBlockFilterFactory::addToValidator(
@@ -373,7 +363,7 @@ JSONObjectValidationBuilder* PlaceableProofBlockFilterFactory::addToValidator(
             Game::INSTANCE->zTypeRegistry()->getValidator<BlockFilter>());
 }
 
-Framework::Text PlaceableProofBlockFilterFactory::getTypeToken() const
+const char* PlaceableProofBlockFilterFactory::getTypeToken() const
 {
     return "blockFilter";
 }

+ 16 - 24
FactoryCraft/PlaceableProof.h

@@ -36,15 +36,13 @@ class PlaceableProofAndFactory
 {
 public:
     PlaceableProofAndFactory();
-    PlaceableProofAnd* createValue(
+    PlaceableProofAnd* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(PlaceableProofAnd* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(PlaceableProofAnd* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        PlaceableProofAnd* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class PlaceableProofOr : public PlaceableProof
@@ -65,15 +63,13 @@ class PlaceableProofOrFactory
 {
 public:
     PlaceableProofOrFactory();
-    PlaceableProofOr* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(PlaceableProofOr* zResult,
+    PlaceableProofOr* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(PlaceableProofOr* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        PlaceableProofOr* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class PlaceableProofNot : public PlaceableProof
@@ -95,15 +91,13 @@ class PlaceableProofNotFactory
 {
 public:
     PlaceableProofNotFactory();
-    PlaceableProofNot* createValue(
+    PlaceableProofNot* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(PlaceableProofNot* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(PlaceableProofNot* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        PlaceableProofNot* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class PlaceableProofBlockFilter : public PlaceableProof
@@ -131,15 +125,13 @@ class PlaceableProofBlockFilterFactory
 {
 public:
     PlaceableProofBlockFilterFactory();
-    PlaceableProofBlockFilter* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(PlaceableProofBlockFilter* zResult,
+    PlaceableProofBlockFilter* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(PlaceableProofBlockFilter* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        PlaceableProofBlockFilter* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 // TODO: add item Filter

+ 269 - 0
FactoryCraft/PlantConfig.cpp

@@ -0,0 +1,269 @@
+#include "PlantConfig.h"
+
+#include "Chunk.h"
+#include "Dimension.h"
+#include "Game.h"
+#include "JNoise.h"
+
+PlantConfig::PlantConfig()
+    : Framework::ReferenceCounter(),
+      condition(0),
+      noise(0),
+      noiseConfig(0),
+      threshold(0.0),
+      locations(0),
+      plantBlockTypeName(""),
+      plantblockTypeId(0),
+      plantHeight(0)
+{}
+
+PlantConfig::~PlantConfig()
+{
+    if (condition)
+    {
+        condition->release();
+    }
+    if (noise)
+    {
+        noise->release();
+    }
+    if (noiseConfig)
+    {
+        noiseConfig->release();
+    }
+}
+
+void PlantConfig::initialize(JExpressionMemory* zMemory)
+{
+    condition->compile(zMemory);
+    if (noise)
+    {
+        noise->release();
+    }
+    noise = JNoise::parseNoise(noiseConfig, zMemory);
+    plantblockTypeId = Game::INSTANCE->getBlockTypeId(plantBlockTypeName);
+}
+
+double PlantConfig::doesGeneratePlant(int x,
+    int y,
+    int z,
+    int dimensionId,
+    Chunk* zChunk,
+    bool underground,
+    bool underwater,
+    int seaFluidBlockTypeId)
+{
+    if (underwater && !(locations & PlantLocation::UNDERWATER))
+    {
+        return 0.0;
+    }
+    if (!underwater && underground && !(locations & PlantLocation::CAVE))
+    {
+        return 0.0;
+    }
+    if (!underwater && !underground && !(locations & PlantLocation::SURFACE))
+    {
+        return 0.0;
+    }
+    if (z + plantHeight > WORLD_HEIGHT)
+    {
+        return 0.0;
+    }
+    for (int i = 0; i < plantHeight; i++)
+    {
+        int result = zChunk->getBlockTypeAt(
+            Dimension::chunkCoordinates({x, y, z + i}));
+        if (result != BlockTypeEnum::AIR && result != seaFluidBlockTypeId)
+        {
+            return 0.0;
+        }
+    }
+    if (!condition->getValue())
+    {
+        return 0.0;
+    }
+    if (!noise)
+    {
+        return 0.0;
+    }
+    return noise->getNoise((double)x, (double)y, (double)z) - threshold;
+}
+
+void PlantConfig::generatePlantAt(
+    int x, int y, int z, int dimensionId, Chunk* zChunk)
+{
+    for (int i = 0; i < plantHeight; i++)
+    {
+        zChunk->putBlockTypeAt(
+            Dimension::chunkCoordinates({x, y, z + i}), plantblockTypeId);
+    }
+}
+
+void PlantConfig::setCondition(JBoolExpression* condition)
+{
+    if (this->condition)
+    {
+        this->condition->release();
+    }
+    this->condition = condition;
+}
+
+JBoolExpression* PlantConfig::zCondition() const
+{
+    return condition;
+}
+
+void PlantConfig::setNoiseConfig(Framework::JSON::JSONObject* noiseConfig)
+{
+    if (this->noiseConfig)
+    {
+        this->noiseConfig->release();
+    }
+    this->noiseConfig = noiseConfig;
+}
+
+Framework::JSON::JSONObject* PlantConfig::zNoiseConfig() const
+{
+    return noiseConfig;
+}
+
+void PlantConfig::setThreshold(double threshold)
+{
+    this->threshold = threshold;
+}
+
+double PlantConfig::getThreshold() const
+{
+    return threshold;
+}
+
+void PlantConfig::setLocations(int locations)
+{
+    this->locations = locations;
+}
+
+int PlantConfig::getLocations() const
+{
+    return locations;
+}
+
+void PlantConfig::setPlantBlockTypeName(Framework::Text name)
+{
+    this->plantBlockTypeName = name;
+}
+
+Framework::Text PlantConfig::getPlantBlockTypeName() const
+{
+    return plantBlockTypeName;
+}
+
+void PlantConfig::setPlantHeight(int height)
+{
+    this->plantHeight = height;
+}
+
+int PlantConfig::getPlantHeight() const
+{
+    return plantHeight;
+}
+
+PlantConfigFactory::PlantConfigFactory()
+    : ObjectTypeFactory<PlantConfig>()
+{}
+
+PlantConfig* PlantConfigFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    PlantConfig* config = new PlantConfig();
+    config->setCondition(
+        Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(
+            zJson->zValue("condition")));
+    config->setNoiseConfig(zJson->getValue("noise")->asObject());
+    config->setThreshold(zJson->zValue("threshold")->asNumber()->getNumber());
+    config->setLocations(0);
+    Framework::JSON::JSONArray* zLocationsArray
+        = zJson->zValue("locations")->asArray();
+    for (int i = 0; i < zLocationsArray->getLength(); i++)
+    {
+        Framework::Text locationStr
+            = zLocationsArray->zValue(i)->asString()->getString();
+        if (locationStr.istGleich("CAVE"))
+        {
+            config->setLocations(config->getLocations() | PlantLocation::CAVE);
+        }
+        else if (locationStr.istGleich("UNDERWATER"))
+        {
+            config->setLocations(
+                config->getLocations() | PlantLocation::UNDERWATER);
+        }
+        else if (locationStr.istGleich("SURFACE"))
+        {
+            config->setLocations(
+                config->getLocations() | PlantLocation::SURFACE);
+        }
+    }
+    config->setPlantBlockTypeName(
+        zJson->zValue("plantBlock")->asString()->getString());
+    config->setPlantHeight(
+        (int)zJson->zValue("plantHeight")->asNumber()->getNumber());
+    return config;
+}
+
+Framework::JSON::JSONObject* PlantConfigFactory::toJsonObject(
+    PlantConfig* zObject) const
+{
+    Framework::JSON::JSONObject* zJson = new Framework::JSON::JSONObject();
+    zJson->addValue("condition",
+        Game::INSTANCE->zTypeRegistry()->toJson<JBoolExpression>(
+            zObject->zCondition()));
+    zJson->addValue("noise",
+        dynamic_cast<Framework::JSON::JSONObject*>(
+            zObject->zNoiseConfig()->getThis()));
+    zJson->addValue(
+        "threshold", new Framework::JSON::JSONNumber(zObject->getThreshold()));
+    Framework::JSON::JSONArray* zLocationsArray
+        = new Framework::JSON::JSONArray();
+    int locations = zObject->getLocations();
+    if (locations & PlantLocation::CAVE)
+    {
+        zLocationsArray->addValue(new Framework::JSON::JSONString("CAVE"));
+    }
+    if (locations & PlantLocation::UNDERWATER)
+    {
+        zLocationsArray->addValue(
+            new Framework::JSON::JSONString("UNDERWATER"));
+    }
+    if (locations & PlantLocation::SURFACE)
+    {
+        zLocationsArray->addValue(new Framework::JSON::JSONString("SURFACE"));
+    }
+    zJson->addValue("locations", zLocationsArray);
+    zJson->addValue("plantBlock",
+        new Framework::JSON::JSONString(zObject->getPlantBlockTypeName()));
+    zJson->addValue("plantHeight",
+        new Framework::JSON::JSONNumber(zObject->getPlantHeight()));
+    return zJson;
+}
+
+JSONObjectValidationBuilder* PlantConfigFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder
+        ->withRequiredAttribute("condition",
+            Game::INSTANCE->zTypeRegistry()->getValidator<JBoolExpression>())
+        ->withRequiredAttribute("noise", JNoise::getValidator(false))
+        ->withRequiredNumber("threshold")
+        ->withDefault(0.5)
+        ->finishNumber()
+        ->withRequiredArray("locations")
+        ->addAcceptedStringInArray()
+        ->whichIsOneOf({"CAVE", "UNDERWATER", "SURFACE"})
+        ->finishString()
+        ->finishArray()
+        ->withRequiredAttribute("plantBlock",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                BlockTypeNameFactory::TYPE_ID))
+        ->withRequiredNumber("plantHeight")
+        ->whichIsGreaterOrEqual(1)
+        ->finishNumber();
+}

+ 63 - 0
FactoryCraft/PlantConfig.h

@@ -0,0 +1,63 @@
+#pragma once
+
+#include "JsonExpression.h"
+#include "TypeRegistry.h"
+
+class PlantLocation
+{
+public:
+    static const int CAVE = 1;
+    static const int UNDERWATER = 2;
+    static const int SURFACE = 4;
+};
+
+class PlantConfig : public virtual Framework::ReferenceCounter
+{
+private:
+    JBoolExpression* condition;
+    Noise* noise;
+    Framework::JSON::JSONObject* noiseConfig;
+    double threshold;
+    int locations;
+    Framework::Text plantBlockTypeName;
+    int plantblockTypeId;
+    int plantHeight;
+
+public:
+    PlantConfig();
+    ~PlantConfig();
+    void initialize(JExpressionMemory* zMemory);
+    double doesGeneratePlant(int x,
+        int y,
+        int z,
+        int dimensionId,
+        Chunk* zChunk,
+        bool underground,
+        bool underwater,
+        int seaFluidBlockTypeId);
+    void generatePlantAt(int x, int y, int z, int dimensionId, Chunk* zChunk);
+
+    void setCondition(JBoolExpression* condition);
+    JBoolExpression* zCondition() const;
+    void setNoiseConfig(Framework::JSON::JSONObject* noiseConfig);
+    Framework::JSON::JSONObject* zNoiseConfig() const;
+    void setThreshold(double threshold);
+    double getThreshold() const;
+    void setLocations(int locations);
+    int getLocations() const;
+    void setPlantBlockTypeName(Framework::Text name);
+    Framework::Text getPlantBlockTypeName() const;
+    void setPlantHeight(int height);
+    int getPlantHeight() const;
+};
+
+class PlantConfigFactory : public ObjectTypeFactory<PlantConfig>
+{
+public:
+    PlantConfigFactory();
+    PlantConfig* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        PlantConfig* zObject) const override;
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+};

+ 12 - 12
FactoryCraft/Player.cpp

@@ -6,7 +6,7 @@
 #include "Game.h"
 #include "ItemFilter.h"
 #include "ItemStack.h"
-#include "PlayerHand.h"
+#include "ItemType.h"
 #include "QuestDialog.h"
 #include "UIController.h"
 
@@ -31,7 +31,7 @@ Player::Player(Framework::Vec3<float> location, int dimensionId, int entityId)
     maxStamina = 10;
     maxHunger = 10;
     maxThirst = 10;
-    setHP(10);
+    setHP(0, 0, 0, 10.f);
     setStamina(10);
     setHunger(10);
     setThirst(10);
@@ -227,7 +227,7 @@ void Player::playerApi(
             zRequest->lese((char*)&leftHandPosition, 4);
             leftHandPosition = leftHandPosition % itemBar.getEintragAnzahl();
             NetworkMessage* msg = new NetworkMessage();
-            msg->addressUIElement("gui_item_bar");
+            msg->addressUIElement("gui_item_bar", -1);
             char* message = new char[5];
             message[0] = 3; // set selected slot
             *(int*)(message + 1) = leftHandPosition;
@@ -337,7 +337,7 @@ void Player::playerApi(
     case 8: // request left hand position
         {
             NetworkMessage* msg = new NetworkMessage();
-            msg->addressUIElement("gui_item_bar");
+            msg->addressUIElement("gui_item_bar", -1);
             char* message = new char[5];
             message[0] = 3; // set selected slot
             *(int*)(message + 1) = leftHandPosition;
@@ -367,21 +367,21 @@ void Player::onFall(float collisionSpeed)
     // TODO: check validity
 }
 
-void Player::onDeath()
+void Player::onDeath(Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill)
 {
-    this->setHP(this->getMaxHP());
+    this->setHP(zActor, zUsedItem, zUsedSkill, this->getMaxHP());
     Game::INSTANCE->zChat()->broadcastMessage(
         name + " died!", Chat::CHANNEL_INFO);
     // TODO: respown
 }
 
 PlayerEntityType::PlayerEntityType()
-    : EntityType("Player",
-        new ModelInfo("entities.m3/player",
-            toArray("entities.ltdb/player.png", 6),
-            0,
-            1.f))
-{}
+    : EntityType()
+{
+    setName("Player");
+    setModel(new ModelInfo(
+        "entities.m3/player", toArray("entities.ltdb/player.png", 6), 0, 1.f));
+}
 
 void PlayerEntityType::loadSuperEntity(
     Entity* zEntity, Framework::StreamReader* zReader) const

+ 2 - 1
FactoryCraft/Player.h

@@ -42,7 +42,8 @@ public:
     void playerApi(
         Framework::StreamReader* zRequest, NetworkMessage* zResponse);
     void onFall(float collisionSpeed) override;
-    void onDeath() override;
+    void onDeath(
+        Entity* zActor, Item* zUsedItem, ItemSkill* zUsedSkill) override;
 
     friend PlayerEntityType;
 };

+ 7 - 3
FactoryCraft/PlayerHand.cpp

@@ -34,15 +34,19 @@ bool PlayerHandSkill::use(Entity* zActor, Item* zUsedItem, Block* zTarget)
 {
     if (zActor->getStamina() > 0.001f)
     {
-        if (zTarget && zTarget->getHardness() <= 1)
+        if (zTarget && zTarget->zBlockType()->isDamagableByHand())
         {
             zActor->setStamina(zActor->getStamina() - 0.001f);
-            zTarget->setHP(zTarget->getHP() - 1 / (zTarget->getHardness() + 1));
+            zTarget->setHP(zActor,
+                zUsedItem,
+                this,
+                zTarget->getHP() - 1 / (zTarget->getHardness() + 1));
         }
         else
         {
             zActor->setStamina(zActor->getStamina() - 0.001f);
-            zActor->setHP(zActor->getCurrentHP() - 0.01f);
+            zActor->setHP(
+                zActor, zUsedItem, this, zActor->getCurrentHP() - 0.01f);
         }
     }
     return false; // item was not changed

+ 98 - 106
FactoryCraft/Quest.cpp

@@ -1,9 +1,7 @@
 #include "Quest.h"
 
 #include <Datei.h>
-#include <Fenster.h>
 #include <Logging.h>
-#include <TextFeld.h>
 
 #include "Game.h"
 
@@ -33,31 +31,29 @@ const Framework::Text& QuestRequirementStorage::getRequirementId() const
 }
 
 QuestRequirementStorageType::QuestRequirementStorageType()
-    : TypeFactory<QuestRequirementStorage>()
+    : ObjectTypeFactory<QuestRequirementStorage>()
 {}
 
-QuestRequirementStorage* QuestRequirementStorageType::createValue(
+QuestRequirementStorage* QuestRequirementStorageType::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new QuestRequirementStorage();
-}
-
-void QuestRequirementStorageType::fromJson(
-    QuestRequirementStorage* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setRequirementId(
+    QuestRequirementStorage* result = new QuestRequirementStorage();
+    result->setRequirementId(
         zJson->asObject()->zValue("requirementId")->asString()->getString());
-    zResult->setFullfilled(
+    result->setFullfilled(
         zJson->asObject()->zValue("fulfilled")->asBool()->getBool());
+    return result;
 }
 
-void QuestRequirementStorageType::toJson(QuestRequirementStorage* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* QuestRequirementStorageType::toJsonObject(
+    QuestRequirementStorage* zObject) const
 {
-    zResult->addValue("requirementId",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("requirementId",
         new Framework::JSON::JSONString(zObject->getRequirementId()));
-    zResult->addValue(
+    result->addValue(
         "fulfilled", new Framework::JSON::JSONBool(zObject->isFullfilled()));
+    return result;
 }
 
 JSONObjectValidationBuilder* QuestRequirementStorageType::addToValidator(
@@ -159,44 +155,41 @@ bool QuestStorage::containsKey(Framework::Text key) const
 }
 
 QuestStorageType::QuestStorageType()
-    : TypeFactory<QuestStorage>()
+    : ObjectTypeFactory<QuestStorage>()
 {}
 
-QuestStorage* QuestStorageType::createValue(
+QuestStorage* QuestStorageType::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new QuestStorage();
-}
-
-void QuestStorageType::fromJson(
-    QuestStorage* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setQuestId(
+    QuestStorage* result = new QuestStorage();
+    result->setQuestId(
         zJson->asObject()->zValue("questId")->asString()->getString());
-    zResult->setQuestFinished(
+    result->setQuestFinished(
         zJson->asObject()->zValue("finished")->asBool()->getBool());
-    zResult->setQuestRewarded(
+    result->setQuestRewarded(
         zJson->asObject()->zValue("rewarded")->asBool()->getBool());
     Framework::JSON::JSONArray* rewardsArray
         = zJson->asObject()->zValue("requirements")->asArray();
     for (int i = 0; i < rewardsArray->getLength(); i++)
     {
-        zResult->requirements.add(
+        result->requirements.add(
             Game::INSTANCE->zTypeRegistry()->fromJson<QuestRequirementStorage>(
                 rewardsArray->zValue(i)->asObject()));
     }
-    zResult->data->release();
-    zResult->data = zJson->asObject()->getValue("data")->asObject();
+    result->data->release();
+    result->data = zJson->asObject()->getValue("data")->asObject();
+    return result;
 }
 
-void QuestStorageType::toJson(
-    QuestStorage* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* QuestStorageType::toJsonObject(
+    QuestStorage* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "questId", new Framework::JSON::JSONString(zObject->questId));
-    zResult->addValue(
+    result->addValue(
         "finished", new Framework::JSON::JSONBool(zObject->finished));
-    zResult->addValue(
+    result->addValue(
         "rewarded", new Framework::JSON::JSONBool(zObject->rewarded));
     Framework::JSON::JSONArray* rewardsArray = new Framework::JSON::JSONArray();
     for (QuestRequirementStorage* storage : zObject->requirements)
@@ -204,9 +197,10 @@ void QuestStorageType::toJson(
         rewardsArray->addValue(
             Game::INSTANCE->zTypeRegistry()->toJson(storage));
     }
-    zResult->addValue("requirements", rewardsArray);
+    result->addValue("requirements", rewardsArray);
     Framework::Text dataString = zObject->data->toString();
-    zResult->addValue("data", Framework::JSON::Parser::getValue(dataString));
+    result->addValue("data", Framework::JSON::Parser::getValue(dataString));
+    return result;
 }
 
 JSONObjectValidationBuilder* QuestStorageType::addToValidator(
@@ -222,7 +216,7 @@ JSONObjectValidationBuilder* QuestStorageType::addToValidator(
         ->finishBool()
         ->withRequiredArray("requirements")
         ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
-                                     ->getValidator<QuestRequirementStorage>())
+                ->getValidator<QuestRequirementStorage>())
         ->finishArray()
         ->withRequiredObject("data")
         ->allowAdditionalAttriutes()
@@ -283,44 +277,40 @@ QuestParty* QuestParty::clone() const
 }
 
 QuestPartyType::QuestPartyType()
-    : TypeFactory<QuestParty>()
+    : ObjectTypeFactory<QuestParty>()
 {}
 
-QuestParty* QuestPartyType::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new QuestParty();
-}
-
-void QuestPartyType::fromJson(
-    QuestParty* zResult, Framework::JSON::JSONObject* zJson) const
+QuestParty* QuestPartyType::fromJson(Framework::JSON::JSONObject* zJson) const
 {
+    QuestParty* result = new QuestParty();
     Framework::JSON::JSONArray* membersArray
         = zJson->asObject()->zValue("members")->asArray();
     for (int i = 0; i < membersArray->getLength(); i++)
     {
-        zResult->memberEntityIds.add(
+        result->memberEntityIds.add(
             (int)membersArray->zValue(i)->asNumber()->getNumber());
     }
     Framework::JSON::JSONArray* storagesArray
         = zJson->asObject()->zValue("quests")->asArray();
     for (int i = 0; i < storagesArray->getLength(); i++)
     {
-        zResult->questStorage.add(
+        result->questStorage.add(
             Game::INSTANCE->zTypeRegistry()->fromJson<QuestStorage>(
                 storagesArray->zValue(i)->asObject()));
     }
+    return result;
 }
 
-void QuestPartyType::toJson(
-    QuestParty* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* QuestPartyType::toJsonObject(
+    QuestParty* zObject) const
 {
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
     Framework::JSON::JSONArray* membersArray = new Framework::JSON::JSONArray();
     for (int memberEntityId : zObject->memberEntityIds)
     {
         membersArray->addValue(new Framework::JSON::JSONNumber(memberEntityId));
     }
-    zResult->addValue("members", membersArray);
+    result->addValue("members", membersArray);
     Framework::JSON::JSONArray* storagesArray
         = new Framework::JSON::JSONArray();
     for (QuestStorage* storage : zObject->questStorage)
@@ -328,7 +318,8 @@ void QuestPartyType::toJson(
         storagesArray->addValue(
             Game::INSTANCE->zTypeRegistry()->toJson(storage));
     }
-    zResult->addValue("quests", storagesArray);
+    result->addValue("quests", storagesArray);
+    return result;
 }
 
 JSONObjectValidationBuilder* QuestPartyType::addToValidator(
@@ -429,22 +420,17 @@ void Quest::setVisible(bool visible, QuestParty* zParty, QuestManager* zManager)
 }
 
 QuestType::QuestType()
-    : TypeFactory<Quest>()
+    : ObjectTypeFactory<Quest>()
 {}
 
-Quest* QuestType::createValue(Framework::JSON::JSONObject* zJson) const
+Quest* QuestType::fromJson(Framework::JSON::JSONObject* zJson) const
 {
-    return new Quest();
-}
-
-void QuestType::fromJson(
-    Quest* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setQuestId(
+    Quest* result = new Quest();
+    result->setQuestId(
         zJson->asObject()->zValue("questId")->asString()->getString());
-    zResult->questName
+    result->questName
         = zJson->asObject()->zValue("questName")->asString()->getString();
-    zResult->description
+    result->description
         = zJson->asObject()->zValue("description")->asString()->getString();
     Framework::JSON::JSONArray* requiredQuestGroups
         = zJson->asObject()->zValue("requiredQuestIds")->asArray();
@@ -454,16 +440,16 @@ void QuestType::fromJson(
             = requiredQuestGroups->zValue(i)->asArray();
         for (int j = 0; j < requiredQuestIdsArray->getLength(); j++)
         {
-            zResult->requiredQuestsIds.add(new Framework::Text(
+            result->requiredQuestsIds.add(new Framework::Text(
                 requiredQuestIdsArray->zValue(j)->asString()->getString()));
-            zResult->requiredQuestsGroups.add(i);
+            result->requiredQuestsGroups.add(i);
         }
     }
     Framework::JSON::JSONArray* requirementsArray
         = zJson->asObject()->zValue("requirements")->asArray();
     for (int i = 0; i < requirementsArray->getLength(); i++)
     {
-        zResult->requirements.add(
+        result->requirements.add(
             Game::INSTANCE->zTypeRegistry()->fromJson<QuestRequirement>(
                 requirementsArray->zValue(i)));
     }
@@ -471,22 +457,23 @@ void QuestType::fromJson(
         = zJson->asObject()->zValue("rewards")->asArray();
     for (int i = 0; i < rewardsArray->getLength(); i++)
     {
-        zResult->rewards.add(
+        result->rewards.add(
             Game::INSTANCE->zTypeRegistry()->fromJson<QuestReward>(
                 rewardsArray->zValue(i)));
     }
-    zResult->imagePath
+    result->imagePath
         = zJson->asObject()->zValue("imagePath")->asString()->getString();
+    return result;
 }
 
-void QuestType::toJson(
-    Quest* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* QuestType::toJsonObject(Quest* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "questId", new Framework::JSON::JSONString(zObject->questId));
-    zResult->addValue(
+    result->addValue(
         "questName", new Framework::JSON::JSONString(zObject->questName));
-    zResult->addValue(
+    result->addValue(
         "description", new Framework::JSON::JSONString(zObject->description));
     Framework::JSON::JSONArray* requiredQuestGroupArray
         = new Framework::JSON::JSONArray();
@@ -515,7 +502,7 @@ void QuestType::toJson(
         requiredQuestGroupArray->addValue(requiredQuestIdsArray);
         requiredQuestIdsArray = new Framework::JSON::JSONArray();
     }
-    zResult->addValue("requiredQuestIds", requiredQuestGroupArray);
+    result->addValue("requiredQuestIds", requiredQuestGroupArray);
     Framework::JSON::JSONArray* requirementsArray
         = new Framework::JSON::JSONArray();
     for (QuestRequirement* requirement : zObject->requirements)
@@ -523,15 +510,16 @@ void QuestType::toJson(
         requirementsArray->addValue(
             Game::INSTANCE->zTypeRegistry()->toJson(requirement));
     }
-    zResult->addValue("requirements", requirementsArray);
+    result->addValue("requirements", requirementsArray);
     Framework::JSON::JSONArray* rewardsArray = new Framework::JSON::JSONArray();
     for (QuestReward* reward : zObject->rewards)
     {
         rewardsArray->addValue(Game::INSTANCE->zTypeRegistry()->toJson(reward));
     }
-    zResult->addValue("rewards", rewardsArray);
-    zResult->addValue(
+    result->addValue("rewards", rewardsArray);
+    result->addValue(
         "imagePath", new Framework::JSON::JSONString(zObject->imagePath));
+    return result;
 }
 
 JSONObjectValidationBuilder* QuestType::addToValidator(
@@ -618,39 +606,36 @@ void QuestCollection::setQuestVisible(bool visible,
 }
 
 QuestCollectionType::QuestCollectionType()
-    : TypeFactory<QuestCollection>()
+    : ObjectTypeFactory<QuestCollection>()
 {}
 
-QuestCollection* QuestCollectionType::createValue(
+QuestCollection* QuestCollectionType::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new QuestCollection();
-}
-
-void QuestCollectionType::fromJson(
-    QuestCollection* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setName(
-        zJson->asObject()->zValue("name")->asString()->getString());
+    QuestCollection* result = new QuestCollection();
+    result->setName(zJson->asObject()->zValue("name")->asString()->getString());
     Framework::JSON::JSONArray* questsArray
         = zJson->asObject()->zValue("quests")->asArray();
     for (int i = 0; i < questsArray->getLength(); i++)
     {
-        zResult->quests.add(Game::INSTANCE->zTypeRegistry()->fromJson<Quest>(
+        result->quests.add(Game::INSTANCE->zTypeRegistry()->fromJson<Quest>(
             questsArray->zValue(i)->asObject()));
     }
+    return result;
 }
 
-void QuestCollectionType::toJson(
-    QuestCollection* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* QuestCollectionType::toJsonObject(
+    QuestCollection* zObject) const
 {
-    zResult->addValue("name", new Framework::JSON::JSONString(zObject->name));
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("name", new Framework::JSON::JSONString(zObject->name));
     Framework::JSON::JSONArray* questsArray = new Framework::JSON::JSONArray();
     for (Quest* quest : zObject->quests)
     {
         questsArray->addValue(Game::INSTANCE->zTypeRegistry()->toJson(quest));
     }
-    zResult->addValue("quests", questsArray);
+    result->addValue("quests", questsArray);
+    return result;
 }
 
 JSONObjectValidationBuilder* QuestCollectionType::addToValidator(
@@ -708,7 +693,7 @@ void QuestManager::loadQuests()
     }
     Framework::JSON::JSONValue* value
         = Framework::JSON::loadJSONFromFile(questDir + "/quests.json");
-    if (!value || value->getType() == Framework::JSON::JSONType::NULL_)
+    if (!value || value->getType() == Framework::AbstractType::NULL_)
     {
         Framework::Logging::warning()
             << "No valid quests.json found in " << questDir;
@@ -720,18 +705,17 @@ void QuestManager::loadQuests()
     else
     {
         Framework::Logging::info() << "loading quests ...";
-        Framework::JSON::Validator::JSONValidator* validator
-            = Framework::JSON::Validator::JSONValidator::buildForArray()
-                  ->addAcceptedTypeInArray(
-                      Game::INSTANCE->zTypeRegistry()
+        Framework::Validator::DataValidator* validator
+            = Framework::Validator::DataValidator::buildForArray()
+                  ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
                           ->getValidator<QuestCollection>())
                   ->removeInvalidEntries()
                   ->finishArray();
-        Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+        Framework::RCArray<Framework::Validator::ValidationResult>
             validationResult;
         Framework::JSON::JSONArray* valid
             = validator->getValidParts(value, &validationResult)->asArray();
-        for (Framework::JSON::Validator::JSONValidationResult* invalidPart :
+        for (Framework::Validator::ValidationResult* invalidPart :
             validationResult)
         {
             Framework::Logging::error() << invalidPart->getInvalidInfo();
@@ -744,10 +728,18 @@ void QuestManager::loadQuests()
                     validPart->asObject()));
         }
         valid->release();
+        Framework::JSON::JSONObject* schema = validator->getJsonSchema();
+        Framework::Datei syntaxFile;
+        syntaxFile.setDatei("data/syntax/schema/quests.json");
+        syntaxFile.erstellen();
+        syntaxFile.open(Framework::Datei::Style::schreiben);
+        syntaxFile.schreibe(schema->toString(), schema->toString().getLength());
+        syntaxFile.close();
+        schema->release();
         validator->release();
     }
     value = Framework::JSON::loadJSONFromFile(questDir + "/parties.json");
-    if (!value || value->getType() == Framework::JSON::JSONType::NULL_)
+    if (!value || value->getType() == Framework::AbstractType::NULL_)
     {
         if (value)
         {
@@ -757,17 +749,17 @@ void QuestManager::loadQuests()
     else
     {
         Framework::Logging::info() << "loading quest parties ...";
-        Framework::JSON::Validator::JSONValidator* validator
-            = Framework::JSON::Validator::JSONValidator::buildForArray()
+        Framework::Validator::DataValidator* validator
+            = Framework::Validator::DataValidator::buildForArray()
                   ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
-                                               ->getValidator<QuestParty>())
+                          ->getValidator<QuestParty>())
                   ->removeInvalidEntries()
                   ->finishArray();
-        Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
+        Framework::RCArray<Framework::Validator::ValidationResult>
             validationResult;
         Framework::JSON::JSONArray* valid
             = validator->getValidParts(value, &validationResult)->asArray();
-        for (Framework::JSON::Validator::JSONValidationResult* invalidPart :
+        for (Framework::Validator::ValidationResult* invalidPart :
             validationResult)
         {
             Framework::Logging::error() << invalidPart->getInvalidInfo();

+ 20 - 32
FactoryCraft/Quest.h

@@ -26,16 +26,15 @@ public:
     friend QuestRequirementStorageType;
 };
 
-class QuestRequirementStorageType : public TypeFactory<QuestRequirementStorage>
+class QuestRequirementStorageType
+    : public ObjectTypeFactory<QuestRequirementStorage>
 {
 public:
     QuestRequirementStorageType();
-    QuestRequirementStorage* createValue(
+    QuestRequirementStorage* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(QuestRequirementStorage* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(QuestRequirementStorage* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        QuestRequirementStorage* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -73,16 +72,13 @@ public:
     friend QuestStorageType;
 };
 
-class QuestStorageType : public TypeFactory<QuestStorage>
+class QuestStorageType : public ObjectTypeFactory<QuestStorage>
 {
 public:
     QuestStorageType();
-    QuestStorage* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(QuestStorage* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(QuestStorage* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    QuestStorage* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        QuestStorage* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -108,16 +104,13 @@ public:
     friend QuestPartyType;
 };
 
-class QuestPartyType : public TypeFactory<QuestParty>
+class QuestPartyType : public ObjectTypeFactory<QuestParty>
 {
 public:
     QuestPartyType();
-    QuestParty* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(
-        QuestParty* zResult, Framework::JSON::JSONObject* zJson) const override;
-    void toJson(QuestParty* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    QuestParty* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        QuestParty* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -153,15 +146,12 @@ public:
     friend QuestDialog;
 };
 
-class QuestType : public TypeFactory<Quest>
+class QuestType : public ObjectTypeFactory<Quest>
 {
 public:
     QuestType();
-    Quest* createValue(Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(
-        Quest* zResult, Framework::JSON::JSONObject* zJson) const override;
-    void toJson(
-        Quest* zObject, Framework::JSON::JSONObject* zResult) const override;
+    Quest* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(Quest* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -192,16 +182,14 @@ public:
     friend QuestDialog;
 };
 
-class QuestCollectionType : public TypeFactory<QuestCollection>
+class QuestCollectionType : public ObjectTypeFactory<QuestCollection>
 {
 public:
     QuestCollectionType();
-    QuestCollection* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(QuestCollection* zResult,
+    QuestCollection* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(QuestCollection* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        QuestCollection* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };

+ 13 - 15
FactoryCraft/QuestRequirement.cpp

@@ -108,35 +108,33 @@ QuestRequirementOpenDialog* QuestRequirementOpenDialogType::createValue(
     return new QuestRequirementOpenDialog();
 }
 
-void QuestRequirementOpenDialogType::fromJson(
-    QuestRequirementOpenDialog* zResult,
+QuestRequirementOpenDialog* QuestRequirementOpenDialogType::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setDialogId(zJson->zValue("dialogId")->asString()->getString());
-    QuestRequirementFactoryBase::fromJson(zResult, zJson);
+    QuestRequirementOpenDialog* result
+        = QuestRequirementFactoryBase::fromJson(zJson);
+    result->setDialogId(zJson->zValue("dialogId")->asString()->getString());
+    return result;
 }
 
-void QuestRequirementOpenDialogType::toJson(QuestRequirementOpenDialog* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* QuestRequirementOpenDialogType::toJsonObject(
+    QuestRequirementOpenDialog* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result
+        = QuestRequirementFactoryBase::toJsonObject(zObject);
+    result->addValue(
         "dialogId", new Framework::JSON::JSONString(zObject->dialogId));
-    QuestRequirementFactoryBase::toJson(zObject, zResult);
+    return result;
 }
 
 JSONObjectValidationBuilder* QuestRequirementOpenDialogType::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
     return QuestRequirementFactoryBase::addToValidator(
-        builder->withRequiredString("id")
-            ->finishString()
-            ->withRequiredString("description")
-            ->finishString()
-            ->withRequiredString("dialogId")
-            ->finishString());
+        builder->withRequiredString("dialogId")->finishString());
 }
 
-Framework::Text QuestRequirementOpenDialogType::getTypeToken() const
+const char* QuestRequirementOpenDialogType::getTypeToken() const
 {
     return "open_dialog";
 }

+ 16 - 9
FactoryCraft/QuestRequirement.h

@@ -35,24 +35,28 @@ public:
         : SubTypeFactory<QuestRequirement, S>()
     {}
 
-    void fromJson(S* zResult, Framework::JSON::JSONObject* zJson) const override
+    S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
+        S* result = createValue(zJson);
         QuestRequirement* zRequirement
-            = dynamic_cast<QuestRequirement*>(zResult);
+            = dynamic_cast<QuestRequirement*>(result);
         zRequirement->setRequirementId(
             zJson->zValue("id")->asString()->getString());
         zRequirement->setDescription(
             zJson->zValue("description")->asString()->getString());
+        return result;
     }
 
-    void toJson(S* zObject, Framework::JSON::JSONObject* zResult) const override
+    Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
         QuestRequirement* zRequirement
             = dynamic_cast<QuestRequirement*>(zObject);
-        zResult->addValue("id",
+        result->addValue("id",
             new Framework::JSON::JSONString(zRequirement->getRequirementId()));
-        zResult->addValue("description",
+        result->addValue("description",
             new Framework::JSON::JSONString(zRequirement->getDescription()));
+        return result;
     }
 
     JSONObjectValidationBuilder* addToValidator(
@@ -63,6 +67,9 @@ public:
             ->withRequiredString("description")
             ->finishString();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };
 
 class QuestRequirementOpenDialogType;
@@ -91,13 +98,13 @@ public:
     QuestRequirementOpenDialogType();
     QuestRequirementOpenDialog* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(QuestRequirementOpenDialog* zResult,
+    QuestRequirementOpenDialog* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(QuestRequirementOpenDialog* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        QuestRequirementOpenDialog* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };
 
 class QuestRequirementBlockBreak : public QuestRequirement

+ 23 - 22
FactoryCraft/QuestReward.cpp

@@ -65,31 +65,29 @@ int ItemStackInfo::getCount() const
 }
 
 ItemStackInfoType::ItemStackInfoType()
-    : TypeFactory<ItemStackInfo>()
+    : ObjectTypeFactory<ItemStackInfo>()
 {}
 
-ItemStackInfo* ItemStackInfoType::createValue(
+ItemStackInfo* ItemStackInfoType::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new ItemStackInfo();
-}
-
-void ItemStackInfoType::fromJson(
-    ItemStackInfo* zObject, Framework::JSON::JSONObject* zJson) const
-{
-    zObject->setItem(Game::INSTANCE->zTypeRegistry()->fromJson<Item>(
+    ItemStackInfo* result = new ItemStackInfo();
+    result->setItem(Game::INSTANCE->zTypeRegistry()->fromJson<Item>(
         zJson->asObject()->zValue("item")));
-    zObject->setCount(
+    result->setCount(
         (int)zJson->asObject()->zValue("count")->asNumber()->getNumber());
+    return result;
 }
 
-void ItemStackInfoType::toJson(
-    ItemStackInfo* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* ItemStackInfoType::toJsonObject(
+    ItemStackInfo* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "item", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zItem()));
-    zResult->addValue(
+    result->addValue(
         "count", new Framework::JSON::JSONNumber((double)zObject->getCount()));
+    return result;
 }
 
 JSONObjectValidationBuilder* ItemStackInfoType::addToValidator(
@@ -200,21 +198,24 @@ QuestRewardGiveItems* QuestRewardGiveItemsType::createValue(
     return new QuestRewardGiveItems();
 }
 
-void QuestRewardGiveItemsType::fromJson(
-    QuestRewardGiveItems* zResult, Framework::JSON::JSONObject* zJson) const
+QuestRewardGiveItems* QuestRewardGiveItemsType::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
+    QuestRewardGiveItems* result = QuestRewardFactoryBase::fromJson(zJson);
     Framework::JSON::JSONArray* itemsJson = zJson->zValue("items")->asArray();
     for (Framework::JSON::JSONValue* itemJson : *itemsJson)
     {
-        zResult->items.add(
+        result->items.add(
             Game::INSTANCE->zTypeRegistry()->fromJson<ItemStackInfo>(itemJson));
     }
-    QuestRewardFactoryBase::fromJson(zResult, zJson);
+    return result;
 }
 
-void QuestRewardGiveItemsType::toJson(
-    QuestRewardGiveItems* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* QuestRewardGiveItemsType::toJsonObject(
+    QuestRewardGiveItems* zObject) const
 {
+    Framework::JSON::JSONObject* zResult
+        = QuestRewardFactoryBase::toJsonObject(zObject);
     zResult->addValue(
         "rewardId", new Framework::JSON::JSONString(zObject->getRewardId()));
     Framework::JSON::JSONArray* itemsJson = new Framework::JSON::JSONArray();
@@ -223,7 +224,7 @@ void QuestRewardGiveItemsType::toJson(
         itemsJson->addValue(Game::INSTANCE->zTypeRegistry()->toJson(item));
     }
     zResult->addValue("items", itemsJson);
-    QuestRewardFactoryBase::toJson(zObject, zResult);
+    return zResult;
 }
 
 JSONObjectValidationBuilder* QuestRewardGiveItemsType::addToValidator(
@@ -236,7 +237,7 @@ JSONObjectValidationBuilder* QuestRewardGiveItemsType::addToValidator(
             ->finishArray());
 }
 
-Framework::Text QuestRewardGiveItemsType::getTypeToken() const
+const char* QuestRewardGiveItemsType::getTypeToken() const
 {
     return "give_items";
 }

+ 22 - 17
FactoryCraft/QuestReward.h

@@ -39,17 +39,22 @@ public:
         : SubTypeFactory<QuestReward, S>()
     {}
 
-    void fromJson(S* zResult, Framework::JSON::JSONObject* zJson) const override
+    S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
-        QuestReward* zRequirement = dynamic_cast<QuestReward*>(zResult);
-        zRequirement->setRewardId(zJson->zValue("rewardId")->asString()->getString());
+        S* result = createValue(zJson);
+        QuestReward* zRequirement = dynamic_cast<QuestReward*>(result);
+        zRequirement->setRewardId(
+            zJson->zValue("rewardId")->asString()->getString());
+        return result;
     }
 
-    void toJson(S* zObject, Framework::JSON::JSONObject* zResult) const override
+    Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
         QuestReward* zRequirement = dynamic_cast<QuestReward*>(zObject);
-        zResult->addValue(
-            "rewardId", new Framework::JSON::JSONString(zRequirement->getRewardId()));
+        result->addValue("rewardId",
+            new Framework::JSON::JSONString(zRequirement->getRewardId()));
+        return result;
     }
 
     JSONObjectValidationBuilder* addToValidator(
@@ -57,6 +62,9 @@ public:
     {
         return builder->withRequiredString("rewardId")->finishString();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };
 
 class ItemStackInfo : public virtual Framework::ReferenceCounter
@@ -74,16 +82,13 @@ public:
     int getCount() const;
 };
 
-class ItemStackInfoType : public TypeFactory<ItemStackInfo>
+class ItemStackInfoType : public ObjectTypeFactory<ItemStackInfo>
 {
 public:
     ItemStackInfoType();
-    ItemStackInfo* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(ItemStackInfo* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(ItemStackInfo* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    ItemStackInfo* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        ItemStackInfo* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -115,11 +120,11 @@ public:
     QuestRewardGiveItemsType();
     QuestRewardGiveItems* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(QuestRewardGiveItems* zResult,
+    QuestRewardGiveItems* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(QuestRewardGiveItems* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        QuestRewardGiveItems* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 0 - 5
FactoryCraft/RandNoise.cpp

@@ -1,12 +1,7 @@
 #include "RandNoise.h"
 
-#include <Random.h>
 #include <stdlib.h>
 
-#include "Constants.h"
-#include "FastNoiseLite.h"
-#include "FastNoiseWrapper.h"
-
 #ifndef RAND_MAX
 #    define RAND_MAX 0x7FFF
 #endif

+ 0 - 1
FactoryCraft/RandNoise.h

@@ -1,7 +1,6 @@
 #pragma once
 
 #include "Noise.h"
-#include <Random.h>
 
 class FastNoiseWrapper;
 

+ 179 - 119
FactoryCraft/Recipie.cpp

@@ -5,6 +5,7 @@
 #include "CraftingStorage.h"
 #include "Game.h"
 #include "Item.h"
+#include "ItemType.h"
 
 RecipieInput::RecipieInput()
     : ReferenceCounter(),
@@ -52,36 +53,33 @@ int RecipieInput::getAmount() const
 }
 
 RecipieInputFactory::RecipieInputFactory()
-    : TypeFactory()
+    : ObjectTypeFactory()
 {}
 
-RecipieInput* RecipieInputFactory::createValue(
+RecipieInput* RecipieInputFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new RecipieInput();
-}
-
-void RecipieInputFactory::fromJson(
-    RecipieInput* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
+    RecipieInput* result = new RecipieInput();
+    result->setFilter(Game::INSTANCE->zTypeRegistry()->fromJson<ItemFilter>(
         zJson->asObject()->zValue("filter")));
-    zResult->setModifier(
-        Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
-            zJson->asObject()->zValue("modifier")));
-    zResult->setAmount(
+    result->setModifier(Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
+        zJson->asObject()->zValue("modifier")));
+    result->setAmount(
         (int)zJson->asObject()->zValue("amount")->asNumber()->getNumber());
+    return result;
 }
 
-void RecipieInputFactory::toJson(
-    RecipieInput* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* RecipieInputFactory::toJsonObject(
+    RecipieInput* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue(
         "filter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zFilter()));
-    zResult->addValue("modifier",
+    result->addValue("modifier",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModifier()));
-    zResult->addValue("amount",
+    result->addValue("amount",
         new Framework::JSON::JSONNumber((double)zObject->getAmount()));
+    return result;
 }
 
 JSONObjectValidationBuilder* RecipieInputFactory::addToValidator(
@@ -162,37 +160,34 @@ Item* RecipieOutput::createItem() const
 }
 
 RecipieOutputFactory::RecipieOutputFactory()
-    : TypeFactory()
+    : ObjectTypeFactory()
 {}
 
-RecipieOutput* RecipieOutputFactory::createValue(
+RecipieOutput* RecipieOutputFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    return new RecipieOutput();
-}
-
-void RecipieOutputFactory::fromJson(
-    RecipieOutput* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    zResult->setItemTypeId(Game::INSTANCE->getItemTypeId(
+    RecipieOutput* result = new RecipieOutput();
+    result->setItemTypeId(Game::INSTANCE->getItemTypeId(
         zJson->asObject()->zValue("itemType")->asString()->getString()));
-    zResult->setAmount(
+    result->setAmount(
         (int)zJson->asObject()->zValue("amount")->asNumber()->getNumber());
-    zResult->setModifier(
-        Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
-            zJson->asObject()->zValue("modifier")));
+    result->setModifier(Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
+        zJson->asObject()->zValue("modifier")));
+    return result;
 }
 
-void RecipieOutputFactory::toJson(
-    RecipieOutput* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* RecipieOutputFactory::toJsonObject(
+    RecipieOutput* zObject) const
 {
-    zResult->addValue("itemType",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("itemType",
         new Framework::JSON::JSONString(
             Game::INSTANCE->zItemType(zObject->getItemTypeId())->getName()));
-    zResult->addValue("amount",
+    result->addValue("amount",
         new Framework::JSON::JSONNumber((double)zObject->getAmount()));
-    zResult->addValue("modifier",
+    result->addValue("modifier",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModifier()));
+    return result;
 }
 
 JSONObjectValidationBuilder* RecipieOutputFactory::addToValidator(
@@ -202,18 +197,10 @@ JSONObjectValidationBuilder* RecipieOutputFactory::addToValidator(
         = new Framework::JSON::JSONObject();
     defaultModifier->addValue(
         "type", new Framework::JSON::JSONString("doNothing"));
-    Framework::RCArray<Framework::Text> itemTypes;
-    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zItemType(i))
-        {
-            itemTypes.add(
-                new Framework::Text(Game::INSTANCE->zItemType(i)->getName()));
-        }
-    }
-    return builder->withRequiredString("itemType")
-        ->whichIsOneOf(itemTypes)
-        ->finishString()
+    return builder
+        ->withRequiredAttribute("itemType",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                ItemTypeNameFactory::TYPE_ID))
         ->withRequiredAttribute("modifier",
             Game::INSTANCE->zTypeRegistry()->getValidator<ItemModifier>())
         ->withRequiredObject("modifier")
@@ -232,6 +219,12 @@ Recipie::Recipie()
     : ReferenceCounter()
 {}
 
+void Recipie::apply(CraftingStorage* zStorage)
+{
+    consumeInputs(zStorage);
+    produceOutputs(zStorage);
+}
+
 void Recipie::addOutput(RecipieOutput* outputs)
 {
     this->outputs.add(outputs);
@@ -284,6 +277,16 @@ Framework::Text Recipie::getGroupName() const
     return groupName;
 }
 
+int Recipie::getTicksNeeded() const
+{
+    return 1;
+}
+
+int Recipie::getFuelPerTickNeeded() const
+{
+    return 0;
+}
+
 UnshapedRecipie::UnshapedRecipie()
     : Recipie()
 {}
@@ -306,9 +309,13 @@ bool UnshapedRecipie::testApplicability(CraftingStorage* zStorage)
     return zStorage->isAllAvailable(inputs);
 }
 
-void UnshapedRecipie::apply(CraftingStorage* zStorage)
+void UnshapedRecipie::consumeInputs(CraftingStorage* zStorage)
 {
     zStorage->consume(inputs);
+}
+
+void UnshapedRecipie::produceOutputs(CraftingStorage* zStorage)
+{
     for (RecipieOutput* output : outputs)
     {
         Item* item = output->createItem();
@@ -316,7 +323,16 @@ void UnshapedRecipie::apply(CraftingStorage* zStorage)
         {
             ItemStack* stack = new ItemStack(item, output->getAmount());
             zStorage->addCraftingResult(stack);
-            stack->release();
+            if (stack->getSize() > 0)
+            {
+                Game::INSTANCE->spawnItem(zStorage->getStorageLocation(),
+                    zStorage->getStorageDimensionId(),
+                    stack);
+            }
+            else
+            {
+                stack->release();
+            }
         }
     }
 }
@@ -366,55 +382,6 @@ const Framework::RCArray<RecipieInput>& UnshapedRecipie::getInputs() const
     return inputs;
 }
 
-UnshapedRecipieFactory::UnshapedRecipieFactory()
-    : RecipieFactory()
-{}
-
-UnshapedRecipie* UnshapedRecipieFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new UnshapedRecipie();
-}
-
-void UnshapedRecipieFactory::fromJson(
-    UnshapedRecipie* zResult, Framework::JSON::JSONObject* zJson) const
-{
-    for (Framework::JSON::JSONValue* input :
-        *zJson->zValue("inputs")->asArray())
-    {
-        zResult->addInput(
-            Game::INSTANCE->zTypeRegistry()->fromJson<RecipieInput>(input));
-    }
-    RecipieFactory::fromJson(zResult, zJson);
-}
-
-void UnshapedRecipieFactory::toJson(
-    UnshapedRecipie* zObject, Framework::JSON::JSONObject* zResult) const
-{
-    Framework::JSON::JSONArray* inputs = new Framework::JSON::JSONArray();
-    for (RecipieInput* input : zObject->getInputs())
-    {
-        inputs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(input));
-    }
-    zResult->addValue("inputs", inputs);
-    RecipieFactory::toJson(zObject, zResult);
-}
-
-JSONObjectValidationBuilder* UnshapedRecipieFactory::addToValidator(
-    JSONObjectValidationBuilder* builder) const
-{
-    return RecipieFactory::addToValidator(
-        builder->withRequiredArray("inputs")
-            ->addAcceptedTypeInArray(
-                Game::INSTANCE->zTypeRegistry()->getValidator<RecipieInput>())
-            ->finishArray());
-}
-
-Framework::Text UnshapedRecipieFactory::getTypeToken() const
-{
-    return "unshaped";
-}
-
 ShapedRecipie::ShapedRecipie()
     : Recipie(),
       width(0),
@@ -442,11 +409,15 @@ bool ShapedRecipie::testApplicability(CraftingStorage* zStorage)
     return zShapedStorage->isAllAvailable(inputs, width, height);
 }
 
-void ShapedRecipie::apply(CraftingStorage* zStorage)
+void ShapedRecipie::consumeInputs(CraftingStorage* zStorage)
 {
     ShapedCraftingStorage* zShapedStorage
         = dynamic_cast<ShapedCraftingStorage*>(zStorage);
     zShapedStorage->consume(inputs, width, height);
+}
+
+void ShapedRecipie::produceOutputs(CraftingStorage* zStorage)
+{
     for (RecipieOutput* output : outputs)
     {
         Item* item = output->createItem();
@@ -454,7 +425,16 @@ void ShapedRecipie::apply(CraftingStorage* zStorage)
         {
             ItemStack* stack = new ItemStack(item, output->getAmount());
             zStorage->addCraftingResult(stack);
-            stack->release();
+            if (stack->getSize() > 0)
+            {
+                Game::INSTANCE->spawnItem(zStorage->getStorageLocation(),
+                    zStorage->getStorageDimensionId(),
+                    stack);
+            }
+            else
+            {
+                stack->release();
+            }
         }
     }
 }
@@ -540,14 +520,15 @@ ShapedRecipie* ShapedRecipieFactory::createValue(
     return new ShapedRecipie();
 }
 
-void ShapedRecipieFactory::fromJson(
-    ShapedRecipie* zResult, Framework::JSON::JSONObject* zJson) const
+ShapedRecipie* ShapedRecipieFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
+    ShapedRecipie* result = RecipieFactory::fromJson(zJson);
     int width = (int)zJson->zValue("width")->asNumber()->getNumber();
     int height = (int)zJson->zValue("height")->asNumber()->getNumber();
     for (int i = 0; i < width * height; i++)
     {
-        zResult->addInput(new RecipieInput());
+        result->addInput(new RecipieInput());
     }
     for (Framework::JSON::JSONValue* input :
         *zJson->zValue("inputs")->asArray())
@@ -558,24 +539,26 @@ void ShapedRecipieFactory::fromJson(
         {
             Framework::Logging::warning()
                 << "Invalid input position in shaped recipie with width="
-                << width << ", height=" << height << ", x=" << x << ", y=" << y;
-            return;
+                << width << ", height=" << height << ", x=" << x << ", y=" << y
+                << " input " << input->toString() << " will be ignored.";
+            continue;
         }
-        zResult->setInput(y * width + x,
+        result->setInput(y * width + x,
             Game::INSTANCE->zTypeRegistry()->fromJson<RecipieInput>(
                 input->asObject()->zValue("input")));
     }
-    zResult->setWidth((int)zJson->zValue("width")->asNumber()->getNumber());
-    zResult->setHeight((int)zJson->zValue("height")->asNumber()->getNumber());
-    RecipieFactory::fromJson(zResult, zJson);
+    result->setWidth((int)zJson->zValue("width")->asNumber()->getNumber());
+    result->setHeight((int)zJson->zValue("height")->asNumber()->getNumber());
+    return result;
 }
 
-void ShapedRecipieFactory::toJson(
-    ShapedRecipie* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* ShapedRecipieFactory::toJsonObject(
+    ShapedRecipie* zObject) const
 {
-    zResult->addValue(
+    Framework::JSON::JSONObject* result = RecipieFactory::toJsonObject(zObject);
+    result->addValue(
         "width", new Framework::JSON::JSONNumber(zObject->getWidth()));
-    zResult->addValue(
+    result->addValue(
         "height", new Framework::JSON::JSONNumber(zObject->getHeight()));
     Framework::JSON::JSONArray* inputs = new Framework::JSON::JSONArray();
     for (int i = 0; i < zObject->getWidth() * zObject->getHeight(); i++)
@@ -589,15 +572,14 @@ void ShapedRecipieFactory::toJson(
             Game::INSTANCE->zTypeRegistry()->toJson(zObject->getInputs().z(i)));
         inputs->addValue(input);
     }
-    zResult->addValue("inputs", inputs);
-    RecipieFactory::toJson(zObject, zResult);
+    result->addValue("inputs", inputs);
+    return result;
 }
 
 JSONObjectValidationBuilder* ShapedRecipieFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return RecipieFactory::addToValidator(
-        builder->withRequiredArray("inputs")
+    return RecipieFactory::addToValidator(builder->withRequiredArray("inputs")
             ->addAcceptedObjectInArray()
             ->withRequiredNumber("x")
             ->whichIsGreaterOrEqual(0.0)
@@ -617,7 +599,85 @@ JSONObjectValidationBuilder* ShapedRecipieFactory::addToValidator(
             ->finishNumber());
 }
 
-Framework::Text ShapedRecipieFactory::getTypeToken() const
+const char* ShapedRecipieFactory::getTypeToken() const
 {
     return "shaped";
+}
+
+MachineRecipie::MachineRecipie()
+    : UnshapedRecipie(),
+      neededTicks(1),
+      neededFuelPerTick(0)
+{}
+
+void MachineRecipie::setTicksNeeded(int ticks)
+{
+    neededTicks = ticks;
+}
+
+int MachineRecipie::getTicksNeeded() const
+{
+    return neededTicks;
+}
+
+void MachineRecipie::setFuelPerTickNeeded(int fuel)
+{
+    neededFuelPerTick = fuel;
+}
+
+int MachineRecipie::getFuelPerTickNeeded() const
+{
+    return neededFuelPerTick;
+}
+
+MachineRecipieFactory::MachineRecipieFactory()
+    : UnshapedRecipieFactory()
+{}
+
+MachineRecipie* MachineRecipieFactory::createValue(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new MachineRecipie();
+}
+
+MachineRecipie* MachineRecipieFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    MachineRecipie* result = UnshapedRecipieFactory::fromJson(zJson);
+    result->setTicksNeeded(
+        (int)zJson->zValue("ticksNeeded")->asNumber()->getNumber());
+    result->setFuelPerTickNeeded(
+        (int)zJson->zValue("fuelPerTickNeeded")->asNumber()->getNumber());
+    return result;
+}
+
+Framework::JSON::JSONObject* MachineRecipieFactory::toJsonObject(
+    MachineRecipie* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = UnshapedRecipieFactory::toJsonObject(zObject);
+    result->addValue("ticksNeeded",
+        new Framework::JSON::JSONNumber(zObject->getTicksNeeded()));
+    result->addValue("fuelPerTickNeeded",
+        new Framework::JSON::JSONNumber(zObject->getFuelPerTickNeeded()));
+    return result;
+}
+
+JSONObjectValidationBuilder* MachineRecipieFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return UnshapedRecipieFactory::addToValidator(builder)
+        ->withRequiredNumber("ticksNeeded")
+        ->whichIsGreaterOrEqual(1.0)
+        ->withDefault(1.0)
+        ->finishNumber()
+        ->withRequiredNumber("fuelPerTickNeeded")
+        ->whichIsGreaterOrEqual(0.0)
+        ->withDefault(0.0)
+        ->finishNumber();
+}
+
+const char* MachineRecipieFactory::getTypeToken() const
+{
+    return "machine";
 }

+ 113 - 37
FactoryCraft/Recipie.h

@@ -2,6 +2,7 @@
 #include <Array.h>
 #include <JSON.h>
 
+#include "Game.h"
 #include "ItemFilter.h"
 #include "ItemModifier.h"
 #include "TypeRegistry.h"
@@ -37,16 +38,13 @@ public:
     int getAmount() const;
 };
 
-class RecipieInputFactory : public TypeFactory<RecipieInput>
+class RecipieInputFactory : public ObjectTypeFactory<RecipieInput>
 {
 public:
     RecipieInputFactory();
-    RecipieInput* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(RecipieInput* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(RecipieInput* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    RecipieInput* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        RecipieInput* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -70,16 +68,13 @@ public:
     Item* createItem() const;
 };
 
-class RecipieOutputFactory : public TypeFactory<RecipieOutput>
+class RecipieOutputFactory : public ObjectTypeFactory<RecipieOutput>
 {
 public:
     RecipieOutputFactory();
-    RecipieOutput* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(RecipieOutput* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(RecipieOutput* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    RecipieOutput* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        RecipieOutput* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };
@@ -93,7 +88,9 @@ protected:
 public:
     Recipie();
     virtual bool testApplicability(CraftingStorage* zStorage) = 0;
-    virtual void apply(CraftingStorage* zStorage) = 0;
+    virtual void consumeInputs(CraftingStorage* zStorage) = 0;
+    virtual void produceOutputs(CraftingStorage* zStorage) = 0;
+    virtual void apply(CraftingStorage* zStorage);
     virtual Framework::Text getRecipieUIML() = 0;
     void addOutput(RecipieOutput* outputs);
     virtual Framework::Array<ItemInfo> getOutput() const;
@@ -101,6 +98,8 @@ public:
     void setGroupName(Framework::Text groupName);
     const Framework::RCArray<RecipieOutput>& getOutputs() const;
     Framework::Text getGroupName() const;
+    virtual int getTicksNeeded() const;
+    virtual int getFuelPerTickNeeded() const;
 };
 
 template<typename S> class RecipieFactory : public SubTypeFactory<Recipie, S>
@@ -110,9 +109,10 @@ public:
         : SubTypeFactory<Recipie, S>()
     {}
 
-    void fromJson(S* zResult, Framework::JSON::JSONObject* zJson) const override
+    S* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
-        Recipie* zRecipie = dynamic_cast<Recipie*>(zResult);
+        S* result = createValue(zJson);
+        Recipie* zRecipie = dynamic_cast<Recipie*>(result);
         for (Framework::JSON::JSONValue* output :
             *zJson->zValue("outputs")->asArray())
         {
@@ -121,19 +121,22 @@ public:
                     output));
         }
         zRecipie->setGroupName(zJson->zValue("group")->asString()->getString());
+        return result;
     }
 
-    void toJson(S* zObject, Framework::JSON::JSONObject* zResult) const override
+    Framework::JSON::JSONObject* toJsonObject(S* zObject) const override
     {
-        Recipie* zRecipie = dynamic_cast<Recipie*>(zResult);
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+        Recipie* zRecipie = dynamic_cast<Recipie*>(result);
         Framework::JSON::JSONArray* outputs = new Framework::JSON::JSONArray();
         for (RecipieOutput* output : zRecipie->getOutputs())
         {
             outputs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(output));
         }
-        zResult->addValue("outputs", outputs);
-        zResult->addValue(
+        result->addValue("outputs", outputs);
+        result->addValue(
             "group", new Framework::JSON::JSONString(zRecipie->getGroupName()));
+        return result;
     };
 
     JSONObjectValidationBuilder* addToValidator(
@@ -146,6 +149,9 @@ public:
             ->withRequiredString("group")
             ->finishString();
     }
+
+protected:
+    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
 };
 
 class UnshapedRecipie : public Recipie
@@ -156,25 +162,67 @@ private:
 public:
     UnshapedRecipie();
     bool testApplicability(CraftingStorage* zStorage) override;
-    void apply(CraftingStorage* zStorage) override;
+    void consumeInputs(CraftingStorage* zStorage) override;
+    void produceOutputs(CraftingStorage* zStorage) override;
     Framework::Text getRecipieUIML() override;
     void addInput(RecipieInput* input);
     const Framework::RCArray<RecipieInput>& getInputs() const;
 };
 
-class UnshapedRecipieFactory : public RecipieFactory<UnshapedRecipie>
+template<class T,
+    typename = std::enable_if<std::is_base_of<UnshapedRecipie, T>::value>>
+class UnshapedRecipieFactory : public RecipieFactory<T>
 {
 public:
-    UnshapedRecipieFactory();
-    UnshapedRecipie* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(UnshapedRecipie* zResult,
-        Framework::JSON::JSONObject* zJson) const override;
-    void toJson(UnshapedRecipie* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    UnshapedRecipieFactory()
+        : RecipieFactory<T>()
+    {}
+
+    T* createValue(Framework::JSON::JSONObject* zJson) const override
+    {
+        return (T*)new UnshapedRecipie();
+    }
+
+    T* fromJson(Framework::JSON::JSONObject* zJson) const override
+    {
+        UnshapedRecipie* result = dynamic_cast<UnshapedRecipie*>(
+            RecipieFactory<T>::fromJson(zJson));
+        for (Framework::JSON::JSONValue* input :
+            *zJson->zValue("inputs")->asArray())
+        {
+            result->addInput(
+                Game::INSTANCE->zTypeRegistry()->fromJson<RecipieInput>(input));
+        }
+        return dynamic_cast<T*>(result);
+    }
+
+    Framework::JSON::JSONObject* toJsonObject(T* zObject) const override
+    {
+        Framework::JSON::JSONObject* result
+            = RecipieFactory<T>::toJsonObject(zObject);
+        Framework::JSON::JSONArray* inputs = new Framework::JSON::JSONArray();
+        for (RecipieInput* input : zObject->getInputs())
+        {
+            inputs->addValue(Game::INSTANCE->zTypeRegistry()->toJson(input));
+        }
+        result->addValue("inputs", inputs);
+        return result;
+    }
+
     JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+        JSONObjectValidationBuilder* builder) const override
+    {
+        return RecipieFactory<T>::addToValidator(
+            builder->withRequiredArray("inputs")
+                ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                        ->getValidator<RecipieInput>())
+                ->finishArray());
+    }
+
+    const char* getTypeToken() const override
+    {
+        return "unshaped";
+    }
 };
 
 class ShapedRecipie : public Recipie
@@ -187,7 +235,8 @@ private:
 public:
     ShapedRecipie();
     bool testApplicability(CraftingStorage* zStorage) override;
-    void apply(CraftingStorage* zStorage) override;
+    void consumeInputs(CraftingStorage* zStorage) override;
+    void produceOutputs(CraftingStorage* zStorage) override;
     Framework::Text getRecipieUIML() override;
     void setWidth(int width);
     int getWidth() const;
@@ -204,11 +253,38 @@ public:
     ShapedRecipieFactory();
     ShapedRecipie* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(ShapedRecipie* zResult,
+    ShapedRecipie* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        ShapedRecipie* zObject) const override;
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+};
+
+class MachineRecipie : public UnshapedRecipie
+{
+private:
+    int neededTicks;
+    int neededFuelPerTick;
+
+public:
+    MachineRecipie();
+    void setTicksNeeded(int ticks);
+    virtual int getTicksNeeded() const override;
+    void setFuelPerTickNeeded(int fuel);
+    virtual int getFuelPerTickNeeded() const override;
+};
+
+class MachineRecipieFactory : public UnshapedRecipieFactory<MachineRecipie>
+{
+public:
+    MachineRecipieFactory();
+    MachineRecipie* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(ShapedRecipie* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    MachineRecipie* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        MachineRecipie* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 62 - 0
FactoryCraft/RecipieGroupConfig.cpp

@@ -0,0 +1,62 @@
+#include "RecipieGroupConfig.h"
+
+#include "Game.h"
+
+RecipieGroupConfig::RecipieGroupConfig()
+    : Framework::ReferenceCounter()
+{}
+
+void RecipieGroupConfig::setGroupName(const Framework::Text& groupName)
+{
+    this->groupName = groupName;
+}
+
+const Framework::Text& RecipieGroupConfig::getGroupName() const
+{
+    return groupName;
+}
+
+void RecipieGroupConfig::setIconItemType(const Framework::Text& iconItemType)
+{
+    this->iconItemType = iconItemType;
+}
+
+const Framework::Text& RecipieGroupConfig::getIconItemType() const
+{
+    return iconItemType;
+}
+
+RecipieGroupConfigFactory::RecipieGroupConfigFactory()
+    : ObjectTypeFactory<RecipieGroupConfig>()
+{}
+
+RecipieGroupConfig* RecipieGroupConfigFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    RecipieGroupConfig* config = new RecipieGroupConfig();
+    config->setGroupName(zJson->zValue("groupName")->asString()->getString());
+    config->setIconItemType(
+        zJson->zValue("iconItemType")->asString()->getString());
+    return config;
+}
+
+Framework::JSON::JSONObject* RecipieGroupConfigFactory::toJsonObject(
+    RecipieGroupConfig* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("groupName",
+        new Framework::JSON::JSONString(zObject->getGroupName().getText()));
+    result->addValue("iconItemType",
+        new Framework::JSON::JSONString(zObject->getIconItemType().getText()));
+    return result;
+}
+
+JSONObjectValidationBuilder* RecipieGroupConfigFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder->withRequiredString("groupName")
+        ->finishString()
+        ->withRequiredAttribute("iconItemType",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                ItemTypeNameFactory::TYPE_ID));
+}

+ 31 - 0
FactoryCraft/RecipieGroupConfig.h

@@ -0,0 +1,31 @@
+#pragma once
+
+#include <Text.h>
+
+#include "TypeRegistry.h"
+
+class RecipieGroupConfig : public Framework::ReferenceCounter
+{
+private:
+    Framework::Text groupName;
+    Framework::Text iconItemType;
+
+public:
+    RecipieGroupConfig();
+    void setGroupName(const Framework::Text& groupName);
+    const Framework::Text& getGroupName() const;
+    void setIconItemType(const Framework::Text& iconItemType);
+    const Framework::Text& getIconItemType() const;
+};
+
+class RecipieGroupConfigFactory : public ObjectTypeFactory<RecipieGroupConfig>
+{
+public:
+    RecipieGroupConfigFactory();
+    RecipieGroupConfig* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        RecipieGroupConfig* zObject) const override;
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+};

+ 16 - 1
FactoryCraft/RecipieList.cpp

@@ -34,4 +34,19 @@ void RecipieList::findRecipies(
             recipies.add(dynamic_cast<Recipie*>(recipie->getThis()));
         }
     }
-}
+}
+
+int RecipieList::getRecipieCount() const
+{
+    return recipies.getEintragAnzahl();
+}
+
+Recipie* RecipieList::zRecipie(int index) const
+{
+    return recipies.z(index);
+}
+
+int RecipieList::getRecipieIndex(Recipie* zRecipie) const
+{
+    return recipies.indexOf(zRecipie);
+}

+ 4 - 2
FactoryCraft/RecipieList.h

@@ -3,8 +3,7 @@
 
 #include "Recipie.h"
 
-class RecipieList
-    : public virtual Framework::ReferenceCounter
+class RecipieList : public virtual Framework::ReferenceCounter
 {
 private:
     Framework::RCArray<Recipie> recipies;
@@ -16,4 +15,7 @@ public:
     Recipie* zFirstRecipie(CraftingStorage* zStorage);
     const Framework::Text& getName() const;
     void findRecipies(int itemTypeId, Framework::RCArray<Recipie>& recipies);
+    int getRecipieCount() const;
+    Recipie* zRecipie(int index) const;
+    int getRecipieIndex(Recipie* zRecipie) const;
 };

+ 96 - 30
FactoryCraft/RecipieLoader.cpp

@@ -6,37 +6,75 @@
 #include <stdexcept>
 
 #include "Game.h"
-#include "ItemType.h"
 #include "JsonUtils.h"
 
 using namespace Framework::JSON;
-using namespace Validator;
+using namespace Framework::Validator;
 
 RecipieLoader::RecipieLoader()
-    : Framework::ReferenceCounter(),
-      validator(0)
+    : Framework::ReferenceCounter()
 {}
 
-RecipieLoader::~RecipieLoader()
-{
-    if (validator) validator->release();
-}
+RecipieLoader::~RecipieLoader() {}
 
 void RecipieLoader::loadRecipies(const char* path)
 {
-    loadAllJsonsFromDirectory(
-        path, [this](JSONValue* zJson, Framework::Text path) {
+    DataValidator* validator
+        = Framework::Validator::DataValidator::buildForArray()
+              ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
+                      ->getValidator<RecipieGroupConfig>())
+              ->removeInvalidEntries()
+              ->finishArray();
+    loadAllJsonsFromDirectory(Framework::Text(path) + "/recipieGroups",
+        [this, &validator](JSONValue* zJson, Framework::Text path) {
+            Framework::Logging::info()
+                << "loading recipie groups from '" << path << "'";
+            Framework::RCArray<ValidationResult> invalidParts;
+            JSONValue* valid = validator->getValidParts(zJson, &invalidParts);
+            for (ValidationResult* invalidPart : invalidParts)
+            {
+                Framework::Logging::error() << invalidPart->getInvalidInfo();
+            }
+            int count = 0;
+            if (valid)
+            {
+                for (JSONValue* value : *valid->asArray())
+                {
+                    RecipieGroupConfig* recipieGroup
+                        = Game::INSTANCE->zTypeRegistry()
+                              ->fromJson<RecipieGroupConfig>(value);
+                    if (recipieGroup)
+                    {
+                        groupConfigs.add(recipieGroup);
+                        count++;
+                    }
+                }
+            }
+            Framework::Logging::info()
+                << count << " recipie groups were loaded.";
+        });
+    Framework::JSON::JSONObject* schema = validator->getJsonSchema();
+    Framework::Datei syntaxFile;
+    syntaxFile.setDatei("data/syntax/schema/recipieGroups.json");
+    syntaxFile.erstellen();
+    syntaxFile.open(Framework::Datei::Style::schreiben);
+    syntaxFile.schreibe(schema->toString(), schema->toString().getLength());
+    syntaxFile.close();
+    schema->release();
+    validator->release();
+    validator
+        = Framework::Validator::DataValidator::buildForArray()
+              ->addAcceptedTypeInArray(
+                  Game::INSTANCE->zTypeRegistry()->getValidator<Recipie>())
+              ->removeInvalidEntries()
+              ->finishArray();
+    loadAllJsonsFromDirectory(Framework::Text(path) + "/recipies",
+        [this, &validator](JSONValue* zJson, Framework::Text path) {
             Framework::Logging::info()
                 << "loading recipies from '" << path << "'";
-            JSONValidator* validator
-                = Framework::JSON::Validator::JSONValidator::buildForArray()
-                      ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
-                                                   ->getValidator<Recipie>())
-                      ->removeInvalidEntries()
-                      ->finishArray();
-            Framework::RCArray<JSONValidationResult> invalidParts;
+            Framework::RCArray<ValidationResult> invalidParts;
             JSONValue* valid = validator->getValidParts(zJson, &invalidParts);
-            for (JSONValidationResult* invalidPart : invalidParts)
+            for (ValidationResult* invalidPart : invalidParts)
             {
                 Framework::Logging::error() << invalidPart->getInvalidInfo();
             }
@@ -64,6 +102,33 @@ void RecipieLoader::loadRecipies(const char* path)
             }
             Framework::Logging::info() << count << " recipies were loaded.";
         });
+    schema = validator->getJsonSchema();
+    syntaxFile.setDatei("data/syntax/schema/recipies.json");
+    syntaxFile.erstellen();
+    syntaxFile.open(Framework::Datei::Style::schreiben);
+    syntaxFile.schreibe(schema->toString(), schema->toString().getLength());
+    syntaxFile.close();
+    schema->release();
+    validator->release();
+    for (RecipieList* list : lists)
+    {
+        bool found = 0;
+        for (RecipieGroupConfig* groupConfig : groupConfigs)
+        {
+            if (list->getName().istGleich(groupConfig->getGroupName()))
+            {
+                found = 1;
+                break;
+            }
+        }
+        if (!found)
+        {
+            Framework::Logging::warning()
+                << "Recipie list '" << list->getName()
+                << "' has no group config. The recipies can not be viewed by "
+                   "the client.";
+        }
+    }
 }
 
 RecipieList* RecipieLoader::zRecipieList(const char* name) const
@@ -92,20 +157,21 @@ Framework::Text RecipieLoader::getCrafingUIML(int itemTypeId)
         list->findRecipies(itemTypeId, recipies);
         if (recipies.getEintragAnzahl() > 0)
         {
-            result.append()
-                << "<craftingRecipieGroup name=\"" << list->getName();
-            if (list->getName().istGleich("inventory"))
-            {
-                result.append()
-                    << "\" itemIcon=\""
-                    << Game::INSTANCE->getItemTypeId("Crafting Table");
-            }
-            result += "\">";
-            for (Recipie* recipie : recipies)
+            for (RecipieGroupConfig* groupConfig : groupConfigs)
             {
-                result += recipie->getRecipieUIML();
+                if (list->getName().istGleich(groupConfig->getGroupName()))
+                {
+                    result.append() << "<craftingRecipieGroup name=\""
+                                    << list->getName() << "\" itemIcon=\""
+                                    << groupConfig->getIconItemType() << "\">";
+                    for (Recipie* recipie : recipies)
+                    {
+                        result += recipie->getRecipieUIML();
+                    }
+                    result += "</craftingRecipieGroup>";
+                    break;
+                }
             }
-            result += "</craftingRecipieGroup>";
         }
     }
     result += "</craftingRecipies></dialog>";

+ 2 - 1
FactoryCraft/RecipieLoader.h

@@ -1,13 +1,14 @@
 #pragma once
 #include <Array.h>
 
+#include "RecipieGroupConfig.h"
 #include "RecipieList.h"
 
 class RecipieLoader : public virtual Framework::ReferenceCounter
 {
 private:
     Framework::RCArray<RecipieList> lists;
-    Framework::JSON::Validator::JSONValidator* validator;
+    Framework::RCArray<RecipieGroupConfig> groupConfigs;
 
 public:
     RecipieLoader();

+ 2 - 1
FactoryCraft/ScaleNoise.cpp

@@ -13,5 +13,6 @@ int ScaleNoise::getSeed() const
 
 double ScaleNoise::getNoise(double x, double y, double z)
 {
-    return MIN(MAX(base->getNoise(x, y, z) * factor, 0.0), 1.0);
+    double value = base->getNoise(x, y, z) * factor;
+    return MIN(MAX(value, 0.0), 1.0);
 }

+ 9 - 13
FactoryCraft/Server.cpp

@@ -2,12 +2,10 @@
 
 #include <AsynchronCall.h>
 #include <Globals.h>
-#include <HttpRequest.h>
 #include <iostream>
-#include <JSON.h>
-#include <Klient.h>
 #include <Logging.h>
 
+#include "Game.h"
 #include "PlayerRegister.h"
 
 // Inhalt der LoginServer Klasse aus LoginServer.h
@@ -66,7 +64,7 @@ FactoryCraftServer::FactoryCraftServer(InitDatei* zIni)
             klient->getNachricht((char*)&bg, 1);
             klient->setEmpfangTimeout(0);
             bool found = 0;
-            EnterCriticalSection(&cs);
+            cs.lock();
             for (FCKlient* client : *klients)
             {
                 if (client->matchAuthKey(key, len))
@@ -85,7 +83,7 @@ FactoryCraftServer::FactoryCraftServer(InitDatei* zIni)
                     break;
                 }
             }
-            LeaveCriticalSection(&cs);
+            cs.unlock();
             if (!found)
             {
                 klient->sende("\0", 1);
@@ -96,7 +94,6 @@ FactoryCraftServer::FactoryCraftServer(InitDatei* zIni)
         }
         runningThreads--;
     });
-    InitializeCriticalSection(&cs);
 }
 
 // Destruktor
@@ -110,7 +107,6 @@ FactoryCraftServer::~FactoryCraftServer()
     server->release();
     if (klients) klients->release();
     ini->release();
-    DeleteCriticalSection(&cs);
 }
 
 // nicht constant
@@ -124,9 +120,9 @@ void FactoryCraftServer::run()
         Framework::getThreadRegister()->cleanUpClosedThreads();
         FCKlient* clHandle = new FCKlient(
             klient, dynamic_cast<FactoryCraftServer*>(getThis()));
-        EnterCriticalSection(&cs);
+        cs.lock();
         klients->add(clHandle);
-        LeaveCriticalSection(&cs);
+        cs.unlock();
         clHandle->start();
     }
     runningThreads--;
@@ -137,17 +133,17 @@ void FactoryCraftServer::close()
     Game::INSTANCE->save();
     sslServer->trenne();
     server->trenne();
-    EnterCriticalSection(&cs);
+    cs.lock();
     for (int i = 0; i < klients->getEintragAnzahl(); i++)
         klients->z(i)->absturz();
-    LeaveCriticalSection(&cs);
+    cs.unlock();
 }
 
 bool FactoryCraftServer::removeKlient(FCKlient* zKlient)
 {
     bool gefunden = 0;
     getThis();
-    EnterCriticalSection(&cs);
+    cs.lock();
     for (int i = 0; i < klients->getEintragAnzahl(); i++)
     {
         if (klients->z(i) == zKlient)
@@ -157,7 +153,7 @@ bool FactoryCraftServer::removeKlient(FCKlient* zKlient)
             break;
         }
     }
-    LeaveCriticalSection(&cs);
+    cs.unlock();
     release();
     return gefunden;
 }

+ 4 - 6
FactoryCraft/Server.h

@@ -1,17 +1,15 @@
 #pragma once
 
-#include <Datei.h>
 #include <InitDatei.h>
 #ifdef _WINDOWS
-#include <Network\Server.h>
+#    include <Network\Server.h>
 #else
-#include <Server.h>
+#    include <Server.h>
 #endif
+#include <Critical.h>
 #include <Text.h>
 #include <Thread.h>
 
-#include "Game.h"
-
 using namespace Framework;
 using namespace Network;
 
@@ -24,7 +22,7 @@ private:
     SSLServer* sslServer;
     Server* server;
     InitDatei* ini;
-    CRITICAL_SECTION cs;
+    Critical cs;
     RCArray<FCKlient>* klients;
     int runningThreads;
     int id;

+ 8 - 4
FactoryCraft/ShapedNoise.cpp

@@ -19,13 +19,17 @@ double ShapedNoise::getNoise(double x, double y, double z)
 {
     double max = 0;
     double noise = delegateNoise->getNoise(x, y, z);
-    max = MAX(max, abs(noise - delegateNoise->getNoise(x + neighborOffset, y, z)));
-    max = MAX(max, abs(noise - delegateNoise->getNoise(x, y + neighborOffset, z)));
-    max = MAX(max, abs(noise - delegateNoise->getNoise(x, y, z + neighborOffset)));
+    double value
+        = abs(noise - delegateNoise->getNoise(x + neighborOffset, y, z));
+    max = MAX(max, value);
+    value = abs(noise - delegateNoise->getNoise(x, y + neighborOffset, z));
+    max = MAX(max, value);
+    value = abs(noise - delegateNoise->getNoise(x, y, z + neighborOffset));
+    max = MAX(max, value);
     return max;
 }
 
 int ShapedNoise::getSeed() const
 {
-	return delegateNoise->getSeed();
+    return delegateNoise->getSeed();
 }

+ 132 - 0
FactoryCraft/SpecificItemDrop.cpp

@@ -0,0 +1,132 @@
+#include "SpecificItemDrop.h"
+
+#include "Block.h"
+#include "Entity.h"
+#include "Inventory.h"
+#include "ItemStack.h"
+
+SpecificItemDrop::SpecificItemDrop(
+    Framework::Text itemTypeName, ItemModifier* modifier, int amount)
+    : DropConfig(),
+      itemTypeName(itemTypeName),
+      zType(0),
+      modifier(modifier),
+      amount(amount)
+{}
+
+SpecificItemDrop::~SpecificItemDrop()
+{
+    if (modifier) modifier->release();
+}
+
+void SpecificItemDrop::initialize()
+{
+    if (!zType)
+    {
+        int id = Game::INSTANCE->getItemTypeId(itemTypeName);
+        if (id >= 0)
+        {
+            zType = Game::INSTANCE->zItemType(id);
+        }
+    }
+}
+
+Framework::Text SpecificItemDrop::getItemTypeName() const
+{
+    return itemTypeName;
+}
+
+const ItemModifier* SpecificItemDrop::zModifier() const
+{
+    return modifier;
+}
+
+int SpecificItemDrop::getAmount() const
+{
+    return amount;
+}
+
+void SpecificItemDrop::doDrop(Entity* zActor,
+    Item* zItem,
+    ItemSkill* zUsedSkill,
+    Framework::Either<Block*, Entity*> zDestroyedObject) const
+{
+    if (zType)
+    {
+        Item* item = zType->createItem();
+        if (item)
+        {
+            if (modifier)
+            {
+                modifier->applyOn(item);
+            }
+            ItemStack* stack = new ItemStack(item, amount);
+            Inventory* inventory;
+            if (zDestroyedObject.isA())
+            {
+                inventory = dynamic_cast<Inventory*>(zDestroyedObject.getA());
+            }
+            else
+            {
+                inventory = dynamic_cast<Inventory*>(zDestroyedObject.getB());
+            }
+            Game::INSTANCE->spawnItem(
+                inventory->getLocation()
+                    + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
+                inventory->getDimensionId(),
+                stack);
+        }
+    }
+}
+
+SpecificItemDropFactory::SpecificItemDropFactory()
+    : DropConfigFactory()
+{}
+
+JSONObjectValidationBuilder* SpecificItemDropFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return DropConfigFactory::addToValidator(builder)
+        ->withRequiredAttribute("itemType",
+            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                ItemTypeNameFactory::TYPE_ID))
+        ->withRequiredAttribute("modifier",
+            Game::INSTANCE->zTypeRegistry()->getValidator<ItemModifier>(),
+            false,
+            true)
+        ->withRequiredNumber("amount")
+        ->whichIsGreaterThen(0.0)
+        ->withDefault(1.0)
+        ->finishNumber();
+}
+
+const char* SpecificItemDropFactory::getTypeToken() const
+{
+    return "specificItem";
+}
+
+SpecificItemDrop* SpecificItemDropFactory::createInstance(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new SpecificItemDrop(
+        zJson->zValue("itemType")->asString()->getString(),
+        zJson->hasValue("modifier")
+            ? Game::INSTANCE->zTypeRegistry()->fromJson<ItemModifier>(
+                  zJson->zValue("modifier"))
+            : 0,
+        (int)zJson->zValue("amount")->asNumber()->getNumber());
+}
+
+void SpecificItemDropFactory::addToJson(
+    Framework::JSON::JSONObject* zJson, SpecificItemDrop* zObject) const
+{
+    zJson->addValue("itemType",
+        new Framework::JSON::JSONString(zObject->getItemTypeName()));
+    if (zObject->zModifier())
+    {
+        zJson->addValue("modifier",
+            Game::INSTANCE->zTypeRegistry()->toJson(zObject->zModifier()));
+    }
+    zJson->addValue(
+        "amount", new Framework::JSON::JSONNumber(zObject->getAmount()));
+}

+ 40 - 0
FactoryCraft/SpecificItemDrop.h

@@ -0,0 +1,40 @@
+#pragma once
+
+#include "DropConfig.h"
+#include "ItemModifier.h"
+#include "ItemType.h"
+
+class SpecificItemDrop : public DropConfig
+{
+private:
+    Framework::Text itemTypeName;
+    const ItemType* zType;
+    ItemModifier* modifier;
+    int amount;
+
+public:
+    SpecificItemDrop(
+        Framework::Text itemTypeName, ItemModifier* modifier, int amount);
+    ~SpecificItemDrop();
+    void initialize() override;
+    Framework::Text getItemTypeName() const;
+    const ItemModifier* zModifier() const;
+    int getAmount() const;
+    void doDrop(Entity* zActor,
+        Item* zItem,
+        ItemSkill* zUsedSkill,
+        Framework::Either<Block*, Entity*> zDestroyedObject) const override;
+};
+
+class SpecificItemDropFactory : public DropConfigFactory<SpecificItemDrop>
+{
+public:
+    SpecificItemDropFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    const char* getTypeToken() const override;
+    SpecificItemDrop* createInstance(
+        Framework::JSON::JSONObject* zJson) const override;
+    void addToJson(Framework::JSON::JSONObject* zJson,
+        SpecificItemDrop* zObject) const override;
+};

+ 26 - 26
FactoryCraft/Start.cpp

@@ -1,30 +1,26 @@
 #include <csignal>
 #include <cstdlib>
 #include <Datei.h>
-#include <fstream>
 #include <Globals.h>
 #include <iostream>
-#include <Klient.h>
 #ifndef _WINDOWS
 #    include <sys/resource.h>
 #else
 #    define NO_MAIN
 #    include <main.h>
 #endif
-#include <AsynchronCall.h>
 #include <Console.h>
 #include <Logging.h>
 #include <Text.h>
 #include <Zeit.h>
 
-#include "Chat.h"
-#include "ChunkMap.h"
 #include "Server.h"
+#include "WorldGenerator.h"
 
 FactoryCraftServer* mserver = 0;
 
 #ifdef _WINDOWS
-LONG WINAPI exceptionHandler(struct _EXCEPTION_POINTERS* apExceptionInfo)
+static LONG WINAPI exceptionHandler(struct _EXCEPTION_POINTERS* apExceptionInfo)
 {
     Sleep(10000);
     Logging::error() << "Creating dump";
@@ -40,7 +36,7 @@ LONG WINAPI exceptionHandler(struct _EXCEPTION_POINTERS* apExceptionInfo)
 }
 #endif
 
-void onError(int i)
+static void onError(int i)
 {
     Sleep(10000);
     Logging::error() << "Creating dump";
@@ -54,7 +50,7 @@ void onError(int i)
     }
 }
 
-void onExit()
+static void onExit()
 {
     Sleep(10000);
     Logging::info() << "Programm exited";
@@ -78,6 +74,11 @@ public:
             int tps = Game::INSTANCE->getTicksPerSecond();
             std::cout << "Players: " << Game::INSTANCE->getPlayerCount()
                       << "\tChunks: " << Game::INSTANCE->getChunkCount()
+                      << "\tChunks/s: "
+                      << (Game::INSTANCE->zGenerator()
+                                 ? Game::INSTANCE->zGenerator()
+                                       ->getGeneratedChunksPerSecond()
+                                 : 0)
                       << "\ttps: ";
             if (tps < 15)
             { // red
@@ -106,7 +107,6 @@ int main()
     SetUnhandledExceptionFilter(exceptionHandler);
 #endif
     Framework::initFramework();
-
     Game::consoleHandler = new ConsoleHandler();
 
 #ifndef _WINDOWS
@@ -117,16 +117,18 @@ int main()
 #endif
     Zeit* z = getZeit();
     Text* pfad = new Text("log/");
-    pfad->append(z->getZeit("y-m-d_h-i-s.log"));
+    Text* tmp = z->getZeit("y-m-d_h-i-s.log");
+    pfad->append(*tmp);
+    tmp->release();
     z->release();
     Datei* logFile = new Datei(pfad);
     Logging::LoggingChannel* fileLogger
         = new Logging::FileLoggingChannel(logFile);
     fileLogger->setFormat(Logging::LoggingFormatBuilder()
-                              .datetime("h:i:s")
-                              .level(false)
-                              .text(": ")
-                              .build());
+            .datetime("h:i:s")
+            .level(false)
+            .text(": ")
+            .build());
     Logging::zLoggingHandler()->addChannel(fileLogger);
     Logging::zLoggingHandler()->removeLoggingChannel(
         Logging::LogLevel::Error, fileLogger);
@@ -135,14 +137,14 @@ int main()
     Logging::LoggingChannel* errorFileLogger = new Logging::FileLoggingChannel(
         dynamic_cast<Datei*>(logFile->getThis()));
     errorFileLogger->setFormat(Logging::LoggingFormatBuilder()
-                                   .datetime("h:i:s")
-                                   .level()
-                                   .fileName()
-                                   .functionName()
-                                   .text("(")
-                                   .fileLine(false)
-                                   .text("): ")
-                                   .build());
+            .datetime("h:i:s")
+            .level()
+            .fileName()
+            .functionName()
+            .text("(")
+            .fileLine(false)
+            .text("): ")
+            .build());
     Framework::Logging::zLoggingHandler()->addChannel(
         Logging::LogLevel::Warning,
         dynamic_cast<Logging::LoggingChannel*>(errorFileLogger->getThis()));
@@ -151,8 +153,7 @@ int main()
     Logging::LoggingChannel* consoleLogger
         = new Logging::ConsoleHandlerLoggingChannel(
             dynamic_cast<ConsoleHandler*>(Game::consoleHandler->getThis()));
-    consoleLogger->setFormat(
-        Logging::LoggingFormatBuilder()
+    consoleLogger->setFormat(Logging::LoggingFormatBuilder()
             .color(Logging::LogLevel::Debug, Color::LIGHT_BLUE)
             .color(Logging::LogLevel::Trace, Color::LIGHT_CYAN)
             .datetime("h:i:s")
@@ -167,8 +168,7 @@ int main()
     Logging::LoggingChannel* errorConsoleLogger
         = new Logging::ConsoleHandlerLoggingChannel(
             dynamic_cast<ConsoleHandler*>(Game::consoleHandler->getThis()));
-    errorConsoleLogger->setFormat(
-        Logging::LoggingFormatBuilder()
+    errorConsoleLogger->setFormat(Logging::LoggingFormatBuilder()
             .color(Logging::LogLevel::Warning, Color::LIGHT_YELLOW)
             .color(Logging::LogLevel::Error, Color::LIGHT_RED)
             .datetime("h:i:s")

+ 38 - 40
FactoryCraft/StructureCollection.cpp

@@ -1,6 +1,5 @@
 #include "StructureCollection.h"
 
-#include "Constants.h"
 #include "Game.h"
 #include "JNoise.h"
 
@@ -28,29 +27,30 @@ void StructureTemplateCollection::initialize(JExpressionMemory* zMemory)
     if (structureNoise) structureNoise->release();
     activeNoise = JNoise::parseNoise(activeNoiseConfig, zMemory);
     structureNoise = JNoise::parseNoise(structureNoiseConfig, zMemory);
+    condition->compile(zMemory);
 }
 
 void StructureTemplateCollection::generateStructures(int x,
     int y,
     int z,
     int dimensionId,
-    JExpressionMemory* zMemory,
-    Framework::Vec3<int> minPos,
-    Framework::Vec3<int> maxPos,
+    Framework::Vec3<int>& minPos,
+    Framework::Vec3<int>& maxPos,
     Framework::RCArray<GeneratedStructure>* zResult)
 {
-    int minSearchX = minPos.x - maxAffected.x;
-    int minSearchY = minPos.y - maxAffected.y;
-    int minSearchZ = MAX(minPos.z - maxAffected.z, 0);
-    int maxSearchX = maxPos.x - minAffected.x;
-    int maxSearchY = maxPos.y - minAffected.y;
-    int maxSearchZ = MIN(maxPos.z - minAffected.z, WORLD_HEIGHT - 1);
-    if (x >= minSearchX && x <= maxSearchX && y >= minSearchY && y <= maxSearchY
-        && z >= minSearchZ && z <= maxSearchZ)
+    if (condition->getValue())
     {
-        if (activeNoise->getNoise((double)x, (double)y, (double)z) < threshold)
+        int minSearchX = minPos.x - maxAffected.x;
+        int minSearchY = minPos.y - maxAffected.y;
+        int minSearchZ = minPos.z - maxAffected.z;
+        int maxSearchX = maxPos.x - minAffected.x;
+        int maxSearchY = maxPos.y - minAffected.y;
+        int maxSearchZ = maxPos.z - minAffected.z;
+        if (x >= minSearchX && x <= maxSearchX && y >= minSearchY
+            && y <= maxSearchY && z >= minSearchZ && z <= maxSearchZ)
         {
-            if (condition->getValue(zMemory))
+            if (activeNoise->getNoise((double)x, (double)y, (double)z)
+                < threshold)
             {
                 double rValue
                     = structureNoise->getNoise((double)x, (double)y, (double)z);
@@ -72,7 +72,8 @@ void StructureTemplateCollection::generateStructures(int x,
     }
 }
 
-void StructureTemplateCollection::setThreshold(double threshold) {
+void StructureTemplateCollection::setThreshold(double threshold)
+{
     this->threshold = threshold;
 }
 
@@ -81,9 +82,10 @@ double StructureTemplateCollection::getThreshold() const
     return threshold;
 }
 
-void StructureTemplateCollection::setCondition(JBoolExpression* condition) {
-	if (this->condition) this->condition->release();
-	this->condition = condition;
+void StructureTemplateCollection::setCondition(JBoolExpression* condition)
+{
+    if (this->condition) this->condition->release();
+    this->condition = condition;
 }
 
 JBoolExpression* StructureTemplateCollection::zCondition() const
@@ -155,55 +157,51 @@ Framework::Vec3<int> StructureTemplateCollection::getMaxAffected() const
 }
 
 StructureTemplateCollectionFactory::StructureTemplateCollectionFactory()
-    : TypeFactory<StructureTemplateCollection>()
+    : ObjectTypeFactory<StructureTemplateCollection>()
 {}
 
-StructureTemplateCollection* StructureTemplateCollectionFactory::createValue(
-    Framework::JSON::JSONObject* zJson) const
-{
-    return new StructureTemplateCollection();
-}
-
-void StructureTemplateCollectionFactory::fromJson(
-    StructureTemplateCollection* zResult,
+StructureTemplateCollection* StructureTemplateCollectionFactory::fromJson(
     Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setActiveNoiseConfig(zJson->getValue("activeNoise")->asObject());
-    zResult->setStructureNoiseConfig(
+    StructureTemplateCollection* result = new StructureTemplateCollection();
+    result->setActiveNoiseConfig(zJson->getValue("activeNoise")->asObject());
+    result->setStructureNoiseConfig(
         zJson->getValue("structureNoise")->asObject());
-    zResult->setThreshold(zJson->zValue("threshold")->asNumber()->getNumber());
-    zResult->setCondition(
+    result->setThreshold(zJson->zValue("threshold")->asNumber()->getNumber());
+    result->setCondition(
         Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(
             zJson->zValue("condition")));
     for (Framework::JSON::JSONValue* structure :
         *zJson->zValue("structures")->asArray())
     {
-        zResult->addStructure(
+        result->addStructure(
             Game::INSTANCE->zTypeRegistry()->fromJson<GeneratorTemplate>(
                 structure->asObject()));
     }
+    return result;
 }
 
-void StructureTemplateCollectionFactory::toJson(
-    StructureTemplateCollection* zObject,
-    Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* StructureTemplateCollectionFactory::toJsonObject(
+    StructureTemplateCollection* zObject) const
 {
-    zResult->addValue("activeNoise",
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("activeNoise",
         dynamic_cast<Framework::JSON::JSONValue*>(
             zObject->zActiveNoiseConfig()->getThis()));
-    zResult->addValue("structureNoise",
+    result->addValue("structureNoise",
         dynamic_cast<Framework::JSON::JSONValue*>(
             zObject->zStructureNoiseConfig()->getThis()));
-    zResult->addValue(
+    result->addValue(
         "threshold", new Framework::JSON::JSONNumber(zObject->getThreshold()));
-    zResult->addValue("condition",
+    result->addValue("condition",
         Game::INSTANCE->zTypeRegistry()->toJson(zObject->zCondition()));
     Framework::JSON::JSONArray* structures = new Framework::JSON::JSONArray();
     for (GeneratorTemplate* t : zObject->getStructures())
     {
         structures->addValue(Game::INSTANCE->zTypeRegistry()->toJson(t));
     }
-    zResult->addValue("structures", structures);
+    result->addValue("structures", structures);
+    return result;
 }
 
 JSONObjectValidationBuilder* StructureTemplateCollectionFactory::addToValidator(

+ 6 - 11
FactoryCraft/StructureCollection.h

@@ -1,7 +1,5 @@
 #pragma once
 
-#include <functional>
-
 #include "GeneratorTemplate.h"
 #include "JsonExpression.h"
 #include "Noise.h"
@@ -27,9 +25,8 @@ public:
         int y,
         int z,
         int dimensionId,
-        JExpressionMemory* zMemory,
-        Framework::Vec3<int> minPos,
-        Framework::Vec3<int> maxPos,
+        Framework::Vec3<int>& minPos,
+        Framework::Vec3<int>& maxPos,
         Framework::RCArray<GeneratedStructure>* zResult);
 
     void setThreshold(double threshold);
@@ -48,16 +45,14 @@ public:
 };
 
 class StructureTemplateCollectionFactory
-    : public TypeFactory<StructureTemplateCollection>
+    : public ObjectTypeFactory<StructureTemplateCollection>
 {
 public:
     StructureTemplateCollectionFactory();
-    StructureTemplateCollection* createValue(
-        Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(StructureTemplateCollection* zResult,
+    StructureTemplateCollection* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(StructureTemplateCollection* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        StructureTemplateCollection* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
 };

+ 0 - 2
FactoryCraft/TickWorker.cpp

@@ -9,8 +9,6 @@
 #    define pid_t int
 #endif
 
-#include "Block.h"
-
 TickWorker::TickWorker(TickQueue* queue)
     : Thread(),
       queue(queue),

+ 27 - 26
FactoryCraft/TreeSeblingBlock.cpp

@@ -1,9 +1,7 @@
 #include "TreeSeblingBlock.h"
 
-#include "BasicBlocks.h"
 #include "Dimension.h"
 #include "Game.h"
-#include "NoBlock.h"
 #include "RandNoise.h"
 #include "TreeTemplate.h"
 #include "WorldGenerator.h"
@@ -244,27 +242,27 @@ TreeSeblingBlockType* TreeSeblingBlockTypeFactory::createValue(
     return new TreeSeblingBlockType();
 }
 
-void TreeSeblingBlockTypeFactory::fromJson(
-    TreeSeblingBlockType* zResult, Framework::JSON::JSONObject* zJson) const
+TreeSeblingBlockType* TreeSeblingBlockTypeFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
 {
-    zResult->setItemTypeName(
-        zJson->zValue("itemType")->asString()->getString());
-    zResult->setWoodTypeName(
-        zJson->zValue("woodType")->asString()->getString());
-    zResult->setLeavesTypeName(
+    TreeSeblingBlockType* result = BlockTypeFactoryBase::fromJson(zJson);
+    result->setItemTypeName(zJson->zValue("itemType")->asString()->getString());
+    result->setWoodTypeName(zJson->zValue("woodType")->asString()->getString());
+    result->setLeavesTypeName(
         zJson->zValue("leavesType")->asString()->getString());
-    zResult->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
-    zResult->setPassable(zJson->zValue("passable")->asBool()->getBool());
-    zResult->setSpeedModifier(
+    result->setTransparent(zJson->zValue("transparent")->asBool()->getBool());
+    result->setPassable(zJson->zValue("passable")->asBool()->getBool());
+    result->setSpeedModifier(
         (float)zJson->zValue("speedModifier")->asNumber()->getNumber());
-    zResult->setInteractable(
-        zJson->zValue("interactable")->asBool()->getBool());
-    BlockTypeFactoryBase::fromJson(zResult, zJson);
+    result->setInteractable(zJson->zValue("interactable")->asBool()->getBool());
+    return result;
 }
 
-void TreeSeblingBlockTypeFactory::toJson(
-    TreeSeblingBlockType* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* TreeSeblingBlockTypeFactory::toJsonObject(
+    TreeSeblingBlockType* zObject) const
 {
+    Framework::JSON::JSONObject* zResult
+        = BlockTypeFactoryBase::toJsonObject(zObject);
     zResult->addValue("itemType",
         new Framework::JSON::JSONString(zObject->getItemTypeName()));
     zResult->addValue("woodType",
@@ -279,19 +277,22 @@ void TreeSeblingBlockTypeFactory::toJson(
         new Framework::JSON::JSONNumber(zObject->getSpeedModifier()));
     zResult->addValue("interactable",
         new Framework::JSON::JSONNumber(zObject->isInteractable()));
-    BlockTypeFactoryBase::toJson(zObject, zResult);
+    return zResult;
 }
 
 JSONObjectValidationBuilder* TreeSeblingBlockTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return BlockTypeFactoryBase::addToValidator(
-        builder->withRequiredString("itemType")
-            ->finishString()
-            ->withRequiredString("woodType")
-            ->finishString()
-            ->withRequiredString("leavesType")
-            ->finishString()
+    return BlockTypeFactoryBase::addToValidator(builder
+            ->withRequiredAttribute("itemType",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    ItemTypeNameFactory::TYPE_ID))
+            ->withRequiredAttribute("woodType",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    BlockTypeNameFactory::TYPE_ID))
+            ->withRequiredAttribute("leavesType",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    BlockTypeNameFactory::TYPE_ID))
             ->withRequiredBool("transparent")
             ->withDefault(true)
             ->finishBool()
@@ -306,7 +307,7 @@ JSONObjectValidationBuilder* TreeSeblingBlockTypeFactory::addToValidator(
             ->finishBool());
 }
 
-Framework::Text TreeSeblingBlockTypeFactory::getTypeToken() const
+const char* TreeSeblingBlockTypeFactory::getTypeToken() const
 {
     return "treeSapling";
 }

+ 4 - 4
FactoryCraft/TreeSeblingBlock.h

@@ -82,11 +82,11 @@ public:
     TreeSeblingBlockTypeFactory();
     TreeSeblingBlockType* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(TreeSeblingBlockType* zResult,
+    TreeSeblingBlockType* fromJson(
         Framework::JSON::JSONObject* zJson) const override;
-    void toJson(TreeSeblingBlockType* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        TreeSeblingBlockType* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 26 - 34
FactoryCraft/TreeTemplate.cpp

@@ -121,66 +121,58 @@ TreeTemplate* TreeTemplateFactory::createValue(
     return new TreeTemplate();
 }
 
-void TreeTemplateFactory::fromJson(
-    TreeTemplate* zResult, Framework::JSON::JSONObject* zConfig) const
+TreeTemplate* TreeTemplateFactory::fromJson(
+    Framework::JSON::JSONObject* zConfig) const
 {
-    zResult->setWoodTypeId(BlockType::getTypeId(
+    TreeTemplate* result = GeneratorTemplateFactory::fromJson(zConfig);
+    result->setWoodTypeId(BlockType::getTypeId(
         zConfig->asObject()->zValue("wood")->asString()->getString()));
-    zResult->setLeavesTypeId(BlockType::getTypeId(
+    result->setLeavesTypeId(BlockType::getTypeId(
         zConfig->asObject()->zValue("leaves")->asString()->getString()));
-    zResult->setMinHeight(
+    result->setMinHeight(
         (int)(zConfig->asObject()->zValue("minSize")->asNumber()->getNumber()));
-    zResult->setMaxHeight(
+    result->setMaxHeight(
         (int)(zConfig->asObject()->zValue("maxSize")->asNumber()->getNumber()));
-    GeneratorTemplateFactory::fromJson(zResult, zConfig);
+    return result;
 }
 
-void TreeTemplateFactory::toJson(
-    TreeTemplate* zObject, Framework::JSON::JSONObject* zResult) const
+Framework::JSON::JSONObject* TreeTemplateFactory::toJsonObject(
+    TreeTemplate* zObject) const
 {
-    zResult->addValue("propability",
+    Framework::JSON::JSONObject* result
+        = GeneratorTemplateFactory::toJsonObject(zObject);
+    result->addValue("propability",
         new Framework::JSON::JSONNumber((double)zObject->getPropability()));
-    zResult->addValue("wood",
+    result->addValue("wood",
         new Framework::JSON::JSONString(zObject->zWoodType()->getName()));
-    zResult->addValue("leaves",
+    result->addValue("leaves",
         new Framework::JSON::JSONString(zObject->zLeavesType()->getName()));
-    zResult->addValue("minSize",
+    result->addValue("minSize",
         new Framework::JSON::JSONNumber((double)zObject->getMinHeight()));
-    zResult->addValue("maxSize",
+    result->addValue("maxSize",
         new Framework::JSON::JSONNumber((double)zObject->getMaxHeight()));
+    return result;
 }
 
 JSONObjectValidationBuilder* TreeTemplateFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    Framework::RCArray<Framework::Text> blockTypeNames;
-    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zBlockType(i))
-        {
-            blockTypeNames.add(
-                new Framework::Text(Game::INSTANCE->zBlockType(i)->getName()));
-        }
-    }
-    return GeneratorTemplateFactory::addToValidator(
-        builder->withRequiredString("wood")
-            ->whichIsOneOf(blockTypeNames)
-            ->finishString()
-            ->withRequiredString("leaves")
-            ->whichIsOneOf(blockTypeNames)
-            ->finishString()
+    return GeneratorTemplateFactory::addToValidator(builder
+            ->withRequiredAttribute("wood",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    BlockTypeNameFactory::TYPE_ID))
+            ->withRequiredAttribute("leaves",
+                Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
+                    BlockTypeNameFactory::TYPE_ID))
             ->withRequiredNumber("minSize")
             ->whichIsGreaterThen(0)
             ->finishNumber()
             ->withRequiredNumber("maxSize")
             ->whichIsGreaterThen(0)
-            ->finishNumber()
-            ->withRequiredNumber("propability")
-            ->whichIsGreaterThen(0)
             ->finishNumber());
 }
 
-Framework::Text TreeTemplateFactory::getTypeToken() const
+const char* TreeTemplateFactory::getTypeToken() const
 {
     return "Tree";
 }

+ 4 - 5
FactoryCraft/TreeTemplate.h

@@ -31,11 +31,10 @@ public:
     TreeTemplateFactory();
     TreeTemplate* createValue(
         Framework::JSON::JSONObject* zJson) const override;
-    void fromJson(TreeTemplate* zResult,
-        Framework::JSON::JSONObject* zConfig) const override;
-    void toJson(TreeTemplate* zObject,
-        Framework::JSON::JSONObject* zResult) const override;
+    TreeTemplate* fromJson(Framework::JSON::JSONObject* zConfig) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        TreeTemplate* zObject) const override;
     JSONObjectValidationBuilder* addToValidator(
         JSONObjectValidationBuilder* builder) const override;
-    virtual Framework::Text getTypeToken() const override;
+    const char* getTypeToken() const override;
 };

+ 64 - 9
FactoryCraft/TypeRegistry.cpp

@@ -2,35 +2,50 @@
 
 #include <Datei.h>
 
+#include "Animal.h"
 #include "BasicBlocks.h"
 #include "BasicItems.h"
 #include "BasicTool.h"
 #include "BlockFilter.h"
 #include "BlockInstanceGeneratorRule.h"
+#include "BlockReplacementDrop.h"
 #include "BlockTypeGeneratorRule.h"
 #include "Chest.h"
-#include "Dimension.h"
+#include "DefaultBlockItemDrop.h"
+#include "DefaultInventoryDrop.h"
 #include "DimensionGenerator.h"
+#include "DropChanceCondition.h"
+#include "DropConditionOperator.h"
+#include "DropUsedItemCondition.h"
+#include "FireBasedProcessingBlockComponent.h"
 #include "FluidBlock.h"
 #include "FluidContainer.h"
-#include "GeneratorRule.h"
 #include "Grass.h"
 #include "GrowingPlant.h"
+#include "ItemSlot.h"
 #include "JsonExpression.h"
 #include "LightSources.h"
 #include "ModelInfo.h"
+#include "OpenDialogInteractionConfig.h"
 #include "PlaceableProof.h"
+#include "PlantConfig.h"
 #include "Quest.h"
 #include "Recipie.h"
+#include "RecipieGroupConfig.h"
+#include "SpecificItemDrop.h"
 #include "TreeSeblingBlock.h"
 #include "TreeTemplate.h"
+#include "UICraftingGrid.h"
+#include "UICraftingProgress.h"
+#include "UIDialogElement.h"
+#include "UIFuelState.h"
+#include "UIInventory.h"
+#include "UIReference.h"
+#include "UIText.h"
 
 TypeRegistry::TypeRegistry()
     : ReferenceCounter()
 {
-    // register templates
-    registerSubType(new TreeTemplateFactory());
-
     // register quest datastructures
     registerType(new QuestRequirementStorageType());
     registerType(new QuestStorageType());
@@ -44,8 +59,7 @@ TypeRegistry::TypeRegistry()
 
     // block types
     registerType(new ModelInfoFactory());
-    registerSubType(new BasicBlockTypeFactory());
-    registerSubType(new AdditionalItemSpawningBlockTypeFactory());
+    registerSubType(new BasicBlockTypeFactory<BasicBlockType>());
     registerSubType(new BasicLightSourceBlockTypeFactory());
     registerSubType(new ChestBlockTypeFactory());
     registerSubType(new FluidBlockTypeFactory());
@@ -85,10 +99,12 @@ TypeRegistry::TypeRegistry()
     registerSubType(new FluidContainerItemSkillFactory());
 
     // reipies
+    registerType(new RecipieGroupConfigFactory());
     registerType(new RecipieInputFactory());
     registerType(new RecipieOutputFactory());
     registerSubType(new ShapedRecipieFactory());
-    registerSubType(new UnshapedRecipieFactory());
+    registerSubType(new UnshapedRecipieFactory<UnshapedRecipie>());
+    registerSubType(new MachineRecipieFactory());
 
     // item modifiers
     registerSubType(new ConsumeItemModifierFactory());
@@ -121,6 +137,45 @@ TypeRegistry::TypeRegistry()
     registerType(new BiomGeneratorFactory());
     registerType(new StructureTemplateCollectionFactory());
     registerSubType(new TreeTemplateFactory());
+    registerType(new EntityGeneratorFactory());
+    registerType(new PlantConfigFactory());
+
+    // entities
+    registerSubType(new AnimalEntityTypeFactory());
+
+    // drop conditions
+    registerSubType(new DropChanceConditionFactory());
+    registerSubType(new DropConditionOperatorFactory());
+    registerSubType(new DropConditionNegationFactory());
+    registerSubType(new DropUsedItemConditionFactory());
+    registerSubType(new DropNoUsedItemConditionFactory());
+    registerSubType(new DropAllwaysConditionFactory());
+
+    // drop configs
+    registerSubType(new DefaultBlockItemDropFactory());
+    registerSubType(new DefaultInventoryItemDropFactory());
+    registerSubType(new SpecificItemDropFactory());
+    registerSubType(new BlockReplacementDropFactory());
+
+    // inventories
+    registerType(new ItemSlotFactory());
+
+    // UI Elements
+    registerSubType(new UITargetReferenceFactory());
+    registerSubType(new UITargetComponentReferenceFactory());
+    registerSubType(new UITActorReferenceFactory());
+    registerSubType(new UITextElementFactory());
+    registerSubType(new UIInventoryElementFactory());
+    registerSubType(new UIDialogElementFactory());
+    registerSubType(new UICraftingGridElementFactory());
+    registerSubType(new UICraftingProgressFactory());
+    registerSubType(new UIFuelStateFactory());
+
+    // interactions
+    registerSubType(new OpenDialogInteractionConfigFactory());
+
+    // block components
+    registerSubType(new FireBasedProcessingBlockComponentFactory());
 }
 
 void TypeRegistry::writeSyntaxInfo(Framework::Text folderPath) const
@@ -129,7 +184,7 @@ void TypeRegistry::writeSyntaxInfo(Framework::Text folderPath) const
     {
         TypeFatoryRef* factory
             = parsableTypes.z(typeId->getText(), typeId->getLength());
-        Framework::JSON::Validator::JSONValidator* validator
+        Framework::Validator::DataValidator* validator
             = factory->getValidator();
         Framework::Datei syntaxFile(
             new Framework::Text(folderPath + "/" + *typeId + ".xml"));

+ 161 - 202
FactoryCraft/TypeRegistry.h

@@ -1,7 +1,7 @@
 #pragma once
 
 #include <Array.h>
-#include <cstdlib>
+#include <DataValidator.h>
 #include <JSON.h>
 #include <Logging.h>
 #include <Trie.h>
@@ -9,34 +9,55 @@
 
 class TypeRegistry;
 
-#define JSONObjectValidationBuilder                      \
-    Framework::JSON::Validator::ObjectValidationBuilder< \
-        Framework::JSON::Validator::JSONValidator>
+#define JSONObjectValidationBuilder                \
+    Framework::Validator::ObjectValidationBuilder< \
+        Framework::Validator::DataValidator>
+
+template<typename T> class SimpleTypeFactory
+    : public Framework::ReferenceCounter
+{
+public:
+    SimpleTypeFactory()
+        : ReferenceCounter() {};
+    virtual T fromJson(Framework::JSON::JSONValue* zJson) const = 0;
+    virtual Framework::JSON::JSONValue* toJson(T value) const = 0;
+    virtual Framework::Validator::DataValidator* getValidator() const = 0;
+};
 
 /*
  * Used to convert an object of type T to a JSONValue and vice versa.
  * Can be registered at the TypeRegistry to be used by the JSON system
  */
-template<typename T> class TypeFactory : public Framework::ReferenceCounter
+template<typename T> class ObjectTypeFactory : public SimpleTypeFactory<T*>
 {
 public:
-    TypeFactory()
-        : ReferenceCounter(){};
-    virtual T* createValue(Framework::JSON::JSONObject* zJson) const = 0;
-    virtual void fromJson(T* zResult, Framework::JSON::JSONObject* zJson) const
-        = 0;
-    virtual void toJson(T* zObject, Framework::JSON::JSONObject* zResult) const
-        = 0;
-    virtual JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const
-        = 0;
+    ObjectTypeFactory()
+        : SimpleTypeFactory<T*>() {};
+
+    T* fromJson(Framework::JSON::JSONValue* zJson) const final override
+    {
+        return fromJson(zJson->asObject());
+    }
+
+    Framework::JSON::JSONValue* toJson(T* value) const final override
+    {
+        return toJsonObject(value);
+    }
 
-    virtual Framework::JSON::Validator::JSONValidator* getValidator() const
+    virtual Framework::Validator::DataValidator* getValidator() const override
     {
         return addToValidator(
-            Framework::JSON::Validator::JSONValidator::buildForObject())
+            Framework::Validator::DataValidator::buildForObject())
             ->finishObject();
     };
+
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const
+        = 0;
+
+protected:
+    virtual T* fromJson(Framework::JSON::JSONObject* zJson) const = 0;
+    virtual Framework::JSON::JSONObject* toJsonObject(T* zObject) const = 0;
 };
 
 /*
@@ -47,53 +68,53 @@ public:
 template<typename T,
     typename S,
     typename = std::enable_if<std::is_base_of<T, S>::value>>
-class SubTypeFactory : public Framework::ReferenceCounter
+class SubTypeFactory : public ObjectTypeFactory<S>
 {
 public:
     SubTypeFactory()
-        : ReferenceCounter(){};
-    virtual S* createValue(Framework::JSON::JSONObject* zJson) const = 0;
-    virtual void fromJson(S* zResult, Framework::JSON::JSONObject* zJson) const
-        = 0;
-    virtual void toJson(S* zObject, Framework::JSON::JSONObject* zResult) const
-        = 0;
-    virtual JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const
-        = 0;
+        : ObjectTypeFactory<S>() {};
 
-    virtual Framework::JSON::Validator::JSONValidator* getValidator() const
+    virtual Framework::Validator::DataValidator*
+    getValidator() const final override
     {
-        return addToValidator(
-            Framework::JSON::Validator::JSONValidator::buildForObject())
+        Framework::Text referenceId = "_type_";
+        referenceId.append() << typeid(T).name() << "_" << getTypeToken();
+        return this
+            ->addToValidator(
+                Framework::Validator::DataValidator::buildForObject()
+                    ->withRequiredString("type")
+                    ->withExactMatch(getTypeToken())
+                    ->finishString()
+                    ->setReferenceId(referenceId))
             ->finishObject();
     };
 
-    virtual Framework::Text getTypeToken() const = 0;
+    virtual const char* getTypeToken() const = 0;
+
+    virtual const char* getTypeName() const
+    {
+        return typeid(S).name();
+    }
 };
 
 template<typename T> class SubTypeFactoryRef
     : public Framework::ReferenceCounter
 {
 private:
-    Framework::Text typetoken;
-    std::function<T*(Framework::JSON::JSONObject*)> createJValueFunc;
-    std::function<void(T*, Framework::JSON::JSONObject*)> fromJsonFunc;
-    std::function<void(T*, Framework::JSON::JSONObject*)> toJsonFunc;
-    std::function<JSONObjectValidationBuilder*(JSONObjectValidationBuilder*)>
-        getValidatorFunc;
+    std::function<const char*()> typetokenFunc;
+    std::function<T*(Framework::JSON::JSONValue*)> fromJsonFunc;
+    std::function<Framework::JSON::JSONValue*(T*)> toJsonFunc;
+    std::function<Framework::Validator::DataValidator*()> getValidatorFunc;
     Framework::ReferenceCounter* factory;
 
 public:
-    SubTypeFactoryRef(Framework::Text typetoken,
-        std::function<T*(Framework::JSON::JSONObject*)> createJValueFunc,
-        std::function<void(T*, Framework::JSON::JSONObject*)> fromJsonFunc,
-        std::function<void(T*, Framework::JSON::JSONObject*)> toJsonFunc,
-        std::function<JSONObjectValidationBuilder*(
-            JSONObjectValidationBuilder*)> getValidatorFunc,
+    SubTypeFactoryRef(std::function<const char*()> typetokenFunc,
+        std::function<T*(Framework::JSON::JSONValue*)> fromJsonFunc,
+        std::function<Framework::JSON::JSONValue*(T*)> toJsonFunc,
+        std::function<Framework::Validator::DataValidator*()> getValidatorFunc,
         Framework::ReferenceCounter* factory)
         : ReferenceCounter(),
-          createJValueFunc(createJValueFunc),
-          typetoken(typetoken),
+          typetokenFunc(typetokenFunc),
           fromJsonFunc(fromJsonFunc),
           toJsonFunc(toJsonFunc),
           getValidatorFunc(getValidatorFunc),
@@ -105,34 +126,28 @@ public:
         factory->release();
     }
 
-    T* createValue(Framework::JSON::JSONObject* zJson) const
+    T* fromJson(Framework::JSON::JSONValue* zJson) const
     {
-        return createJValueFunc(zJson);
+        return fromJsonFunc(zJson);
     }
 
-    void fromJson(T* zResult, Framework::JSON::JSONObject* zJson) const
+    Framework::JSON::JSONValue* toJson(T* zObject) const
     {
-        fromJsonFunc(zResult, zJson);
+        return toJsonFunc(zObject);
     }
 
-    void toJSON(T* zObject, Framework::JSON::JSONObject* zResult) const
+    Framework::Validator::DataValidator* getValidator() const
     {
-        toJsonFunc(zObject, zResult);
-    }
-
-    JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const
-    {
-        return getValidatorFunc(builder);
+        return getValidatorFunc();
     }
 
-    const Framework::Text& getTypetoken() const
+    const char* getTypeToken() const
     {
-        return typetoken;
+        return typetokenFunc();
     }
 };
 
-template<typename T> class PolymorphTypeFactory : public TypeFactory<T>
+template<typename T> class PolymorphTypeFactory : public ObjectTypeFactory<T>
 {
 private:
     Framework::RCArray<SubTypeFactoryRef<T>> factories;
@@ -141,54 +156,45 @@ private:
 
 public:
     PolymorphTypeFactory()
-        : TypeFactory<T>()
+        : ObjectTypeFactory<T>()
     {}
 
-    T* createValue(Framework::JSON::JSONObject* zJson) const override
+    T* fromJson(Framework::JSON::JSONObject* zJson) const override
     {
         for (SubTypeFactoryRef<T>* factory : factories)
         {
-            if (zJson->asObject()
-                    ->zValue("type")
-                    ->asString()
-                    ->getString()
-                    .istGleich(factory->getTypetoken()))
+            if (zJson->zValue("type")->asString()->getString().istGleich(
+                    factory->getTypeToken()))
             {
-                return factory->createValue(zJson->asObject());
+                return factory->fromJson(zJson);
             }
         }
+        Framework::Logging::error()
+            << "No Sub Type Factory for typetoken "
+            << zJson->zValue("type")->asString()->getString() << " of type "
+            << typeid(T).name() << " was found.";
         return 0;
     }
 
-    void fromJson(T* zResult, Framework::JSON::JSONObject* zJson) const override
-    {
-        for (SubTypeFactoryRef<T>* factory : factories)
-        {
-            if (zJson->asObject()
-                    ->zValue("type")
-                    ->asString()
-                    ->getString()
-                    .istGleich(factory->getTypetoken()))
-            {
-                factory->fromJson(zResult, zJson->asObject());
-            }
-        }
-    }
-
-    void toJson(T* zObject, Framework::JSON::JSONObject* zResult) const override
+    Framework::JSON::JSONObject* toJsonObject(T* zObject) const override
     {
         auto name = typeNames.begin();
         for (SubTypeFactoryRef<T>* factory : factories)
         {
             if (name->istGleich(typeid(*zObject).name()))
             {
-                factory->toJSON(zObject, zResult);
-                zResult->addValue("type",
-                    new Framework::JSON::JSONString(factory->getTypetoken()));
-                return;
+                Framework::JSON::JSONObject* result
+                    = factory->toJson(zObject)->asObject();
+                result->addValue("type",
+                    new Framework::JSON::JSONString(factory->getTypeToken()));
+                return result;
             }
             name++;
         }
+        Framework::Logging::error()
+            << "No Sub Type Factory for subtype " << typeid(*zObject).name()
+            << " of type " << typeid(T).name() << " was found.";
+        return new Framework::JSON::JSONObject();
     }
 
     JSONObjectValidationBuilder* addToValidator(
@@ -202,31 +208,18 @@ public:
               "validation builder";
     }
 
-    Framework::JSON::Validator::JSONValidator* getValidator() const override
+    Framework::Validator::DataValidator* getValidator() const override
     {
-        Framework::JSON::Validator::JSONValidator* result;
+        Framework::Validator::DataValidator* result;
         if (!insideGetValidator)
         {
             insideGetValidator = true;
             auto validator
-                = Framework::JSON::Validator::JSONValidator::buildForOneOf()
+                = Framework::Validator::DataValidator::buildForOneOf()
                       ->typeSpecifiedByAttribute("type");
             for (SubTypeFactoryRef<T>* factory : factories)
             {
-                validator = validator->addAcceptedType(
-                    factory
-                        ->addToValidator(
-                            Framework::JSON::Validator::JSONValidator::
-                                buildForObject()
-                                    ->withRequiredString("type")
-                                    ->withExactMatch(factory->getTypetoken())
-                                    ->finishString()
-                                    ->setObjectReferenceId(
-                                        ((Framework::Text("_type_")
-                                             += typeid(T).name())
-                                            += "_")
-                                        += factory->getTypetoken()))
-                        ->finishObject());
+                validator = validator->addAcceptedType(factory->getValidator());
             }
             result = validator->finishOneOf();
             insideGetValidator = false;
@@ -234,15 +227,14 @@ public:
         else
         {
             auto validator
-                = Framework::JSON::Validator::JSONValidator::buildForOneOf()
+                = Framework::Validator::DataValidator::buildForOneOf()
                       ->typeSpecifiedByAttribute("type");
             for (SubTypeFactoryRef<T>* factory : factories)
             {
-                validator = validator->addAcceptedType(Framework::JSON::
-                        Validator::JSONValidator::buildForObjectReference(
-                            ((Framework::Text("_type_") += typeid(T).name())
-                                += "_")
-                            += factory->getTypetoken()));
+                validator = validator->addAcceptedType(
+                    Framework::Validator::DataValidator::buildForReference(
+                        ((Framework::Text("_type_") += typeid(T).name()) += "_")
+                        += factory->getTypeToken()));
             }
             result = validator->finishOneOf();
         }
@@ -254,26 +246,21 @@ public:
     void addFactory(SubTypeFactory<T, S>* factory)
     {
         factories.add(new SubTypeFactoryRef<T>(
-            factory->getTypeToken(),
-            [factory](Framework::JSON::JSONObject* zJson) {
-                S* value = factory->createValue(zJson);
+            [factory]() { return factory->getTypeToken(); },
+            [factory](Framework::JSON::JSONValue* zJson) {
+                S* value = factory->fromJson(zJson);
                 if (value)
                 {
                     return dynamic_cast<T*>(value);
                 }
                 return (T*)0;
             },
-            [factory](T* zResult, Framework::JSON::JSONObject* zJson) {
-                factory->fromJson(dynamic_cast<S*>(zResult), zJson);
-            },
-            [factory](T* zObject, Framework::JSON::JSONObject* zResult) {
-                factory->toJson(dynamic_cast<S*>(zObject), zResult);
-            },
-            [factory](JSONObjectValidationBuilder* builder) {
-                return factory->addToValidator(builder);
+            [factory](T* zObject) {
+                return factory->toJson(dynamic_cast<S*>(zObject));
             },
+            [factory]() { return factory->getValidator(); },
             dynamic_cast<Framework::ReferenceCounter*>(factory)));
-        typeNames.add(new Framework::Text(typeid(S).name()));
+        typeNames.add(new Framework::Text(factory->getTypeName()));
     }
 };
 
@@ -283,31 +270,21 @@ thread_local bool PolymorphTypeFactory<T>::insideGetValidator = false;
 class TypeFatoryRef : public Framework::ReferenceCounter
 {
 private:
-    std::function<void*(Framework::JSON::JSONObject*)> createValueFunc;
-    std::function<void(void*, Framework::JSON::JSONObject*)> fromJsonFunc;
-    std::function<void(void*, Framework::JSON::JSONObject*)> toJsonFunc;
-    std::function<Framework::JSON::Validator::JSONValidator*()>
-        getValidatorFunc;
-    std::function<JSONObjectValidationBuilder*(JSONObjectValidationBuilder*)>
-        addToValidatorFunc;
+    std::function<void*(Framework::JSON::JSONValue*)> fromJsonFunc;
+    std::function<Framework::JSON::JSONValue*(void*)> toJsonFunc;
+    std::function<Framework::Validator::DataValidator*()> getValidatorFunc;
     Framework::ReferenceCounter* factory;
 
 public:
     TypeFatoryRef(
-        std::function<void*(Framework::JSON::JSONObject*)> createValueFunc,
-        std::function<void(void*, Framework::JSON::JSONObject*)> fromJsonFunc,
-        std::function<void(void*, Framework::JSON::JSONObject*)> toJsonFunc,
-        std::function<Framework::JSON::Validator::JSONValidator*()>
-            getValidatorFunc,
-        std::function<JSONObjectValidationBuilder*(
-            JSONObjectValidationBuilder*)> addToValidatorFunc,
+        std::function<void*(Framework::JSON::JSONValue*)> fromJsonFunc,
+        std::function<Framework::JSON::JSONValue*(void*)> toJsonFunc,
+        std::function<Framework::Validator::DataValidator*()> getValidatorFunc,
         Framework::ReferenceCounter* factory)
         : ReferenceCounter(),
-          createValueFunc(createValueFunc),
           fromJsonFunc(fromJsonFunc),
           toJsonFunc(toJsonFunc),
           getValidatorFunc(getValidatorFunc),
-          addToValidatorFunc(addToValidatorFunc),
           factory(factory)
     {}
 
@@ -316,35 +293,24 @@ public:
         factory->release();
     }
 
-    void* createValue(Framework::JSON::JSONObject* zJson) const
-    {
-        return createValueFunc(zJson);
-    }
-
-    void fromJson(void* zResult, Framework::JSON::JSONObject* zJson) const
+    void* fromJson(Framework::JSON::JSONValue* zJson) const
     {
-        return fromJsonFunc(zResult, zJson);
+        return fromJsonFunc(zJson);
     }
 
-    void toJSON(void* zObject, Framework::JSON::JSONObject* zResult) const
+    Framework::JSON::JSONValue* toJson(void* zObject) const
     {
-        return toJsonFunc(zObject, zResult);
+        return toJsonFunc(zObject);
     }
 
-    Framework::JSON::Validator::JSONValidator* getValidator() const
+    Framework::Validator::DataValidator* getValidator() const
     {
         return getValidatorFunc();
     }
 
-    JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const
-    {
-        return addToValidatorFunc(builder);
-    }
-
-    template<typename T> TypeFactory<T>* zFactory() const
+    Framework::ReferenceCounter* zFactory() const
     {
-        return (TypeFactory<T>*)(factory);
+        return factory;
     }
 };
 
@@ -375,7 +341,7 @@ public:
         }
         PolymorphTypeFactory<T>* polymorphFactory
             = dynamic_cast<PolymorphTypeFactory<T>*>(
-                typeFactoryRef->zFactory<T>());
+                typeFactoryRef->zFactory());
         if (!polymorphFactory)
         {
             Framework::Logging::error()
@@ -384,12 +350,20 @@ public:
             throw Framework::Text("Type not registered as Polymorphic type: ")
                 + typeId;
         }
-        polymorphFactory->template addFactory<S>(factory);
+        polymorphFactory->addFactory<S>(factory);
+        Framework::Text typeIdS = typeid(S).name();
+        parsableTypeNames.add(new Framework::Text(typeIdS));
+        registerType(factory);
     }
 
-    template<typename T> void registerType(TypeFactory<T>* factory)
+    template<typename T> void registerType(ObjectTypeFactory<T>* factory)
+    {
+        registerType(typeid(T).name(), factory);
+    }
+
+    template<typename T>
+    void registerType(Framework::Text typeId, SimpleTypeFactory<T>* factory)
     {
-        Framework::Text typeId = typeid(T).name();
         TypeFatoryRef* typeFactoryRef
             = parsableTypes.z(typeId, typeId.getLength());
         if (typeFactoryRef)
@@ -399,27 +373,19 @@ public:
             throw Framework::Text("Type already registered: ") + typeId;
         }
         typeFactoryRef = new TypeFatoryRef(
-            [factory](Framework::JSON::JSONObject* zJson) {
-                return (void*)factory->createValue(zJson);
-            },
-            [factory](void* zResult, Framework::JSON::JSONObject* zJson) {
-                factory->fromJson((T*)zResult, zJson);
-            },
-            [factory](void* zObject, Framework::JSON::JSONObject* zResult) {
-                factory->toJson((T*)zObject, zResult);
+            [factory](Framework::JSON::JSONValue* zJson) {
+                return (void*)factory->fromJson(zJson);
             },
+            [factory](void* zObject) { return factory->toJson((T)zObject); },
             [factory]() { return factory->getValidator(); },
-            [factory](JSONObjectValidationBuilder* builder) {
-                return factory->addToValidator(builder);
-            },
             factory);
         parsableTypes.set(typeId, typeId.getLength(), typeFactoryRef);
         parsableTypeNames.add(new Framework::Text(typeId));
     }
 
-    template<typename T> T* fromJson(Framework::JSON::JSONValue* zJson) const
+    template<typename T>
+    T fromJson(Framework::Text typeId, Framework::JSON::JSONValue* zJson) const
     {
-        Framework::Text typeId = typeid(T).name();
         TypeFatoryRef* typeFactoryRef
             = parsableTypes.z(typeId, typeId.getLength());
         if (!typeFactoryRef)
@@ -428,14 +394,22 @@ public:
                 << Framework::Text("Type not registered: ") + typeId;
             throw Framework::Text("Type not registered: ") + typeId;
         }
-        T* result = (T*)(typeFactoryRef->createValue(zJson->asObject()));
-        (typeFactoryRef->fromJson(result, zJson->asObject()));
-        return result;
+        return (T)(typeFactoryRef->fromJson(zJson));
+    }
+
+    template<typename T> T* fromJson(Framework::JSON::JSONValue* zJson) const
+    {
+        return fromJson<T*>(typeid(T).name(), zJson);
     }
 
     template<typename T> Framework::JSON::JSONValue* toJson(T* zObject) const
     {
-        Framework::Text typeId = typeid(T).name();
+        return toJson<T*>(typeid(T).name(), zObject);
+    }
+
+    template<typename T> Framework::JSON::JSONValue* toJson(
+        Framework::Text typeId, const T zObject) const
+    {
         TypeFatoryRef* typeFactoryRef
             = parsableTypes.z(typeId, typeId.getLength());
         if (!typeFactoryRef)
@@ -444,30 +418,18 @@ public:
                 << Framework::Text("Type not registered: ") + typeId;
             throw Framework::Text("Type not registered: ") + typeId;
         }
-        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
-        typeFactoryRef->toJSON(zObject, result);
-        return result;
+        return typeFactoryRef->toJson((void*)zObject);
     }
 
     template<typename T>
-    Framework::JSON::Validator::JSONValidator* getValidator() const
+    Framework::Validator::DataValidator* getValidator() const
     {
-        Framework::Text typeId = typeid(T).name();
-        TypeFatoryRef* typeFactoryRef
-            = parsableTypes.z(typeId, typeId.getLength());
-        if (!typeFactoryRef)
-        {
-            Framework::Logging::error()
-                << Framework::Text("Type not registered: ") + typeId;
-            throw Framework::Text("Type not registered: ") + typeId;
-        }
-        return typeFactoryRef->getValidator();
+        return getValidator<T>(typeid(T).name());
     }
 
-    template<typename T> JSONObjectValidationBuilder* addToValidator(
-        JSONObjectValidationBuilder* builder) const
+    template<typename T> Framework::Validator::DataValidator* getValidator(
+        Framework::Text typeId) const
     {
-        Framework::Text typeId = typeid(T).name();
         TypeFatoryRef* typeFactoryRef
             = parsableTypes.z(typeId, typeId.getLength());
         if (!typeFactoryRef)
@@ -476,20 +438,17 @@ public:
                 << Framework::Text("Type not registered: ") + typeId;
             throw Framework::Text("Type not registered: ") + typeId;
         }
-        return typeFactoryRef->addToValidator(builder);
+        return typeFactoryRef->getValidator();
     }
 
     template<typename T> Framework::JSON::JSONValue* getValidParts(
         Framework::JSON::JSONValue* zJson) const
     {
-        Framework::RCArray<Framework::JSON::Validator::JSONValidationResult>
-            invalidParts;
-        Framework::JSON::Validator::JSONValidator* validator
-            = getValidator<T>();
+        Framework::RCArray<Framework::Validator::ValidationResult> invalidParts;
+        Framework::Validator::DataValidator* validator = getValidator<T>();
         Framework::JSON::JSONValue* result
             = validator->getValidParts(zJson, &invalidParts);
-        for (Framework::JSON::Validator::JSONValidationResult* invalidPart :
-            invalidParts)
+        for (Framework::Validator::ValidationResult* invalidPart : invalidParts)
         {
             Framework::Logging::error() << invalidPart->getInvalidInfo();
         }

+ 140 - 0
FactoryCraft/UICraftingGrid.cpp

@@ -0,0 +1,140 @@
+#include "UICraftingGrid.h"
+
+#include "UIReference.h"
+
+UICraftingGrid::UICraftingGrid()
+    : UIElement(),
+      rowSize(0),
+      colSize(0),
+      numOutputSlots(0),
+      target(0)
+{}
+
+UICraftingGrid::~UICraftingGrid()
+{
+    if (target)
+    {
+        target->release();
+    }
+}
+
+void UICraftingGrid::setRowSize(int rowSize)
+{
+    this->rowSize = rowSize;
+}
+
+int UICraftingGrid::getRowSize() const
+{
+    return rowSize;
+}
+
+void UICraftingGrid::setColSize(int colSize)
+{
+    this->colSize = colSize;
+}
+
+int UICraftingGrid::getColSize() const
+{
+    return colSize;
+}
+
+void UICraftingGrid::setNumOutputSlots(int numOutputSlots)
+{
+    this->numOutputSlots = numOutputSlots;
+}
+
+int UICraftingGrid::getNumOutputSlots() const
+{
+    return numOutputSlots;
+}
+
+void UICraftingGrid::setTarget(UIReference* target)
+{
+    if (this->target)
+    {
+        this->target->release();
+    }
+    this->target = target;
+}
+
+UIReference* UICraftingGrid::zTarget() const
+{
+    return target;
+}
+
+Framework::XML::Element* UICraftingGrid::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* result = UIElement::toUIML(zTarget, zActor);
+    result->setName("craftingGrid");
+    result->setAttribute("rowSize", rowSize);
+    result->setAttribute("colSize", colSize);
+    result->setAttribute("numOutputSlots", numOutputSlots);
+    if (target)
+    {
+        result->setAttribute("target", target->getReferenceId(zTarget, zActor));
+    }
+    return result;
+}
+
+UICraftingGridElementFactory::UICraftingGridElementFactory()
+    : UIElementFactory<UICraftingGrid>()
+{}
+
+JSONObjectValidationBuilder* UICraftingGridElementFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return UIElementFactory<UICraftingGrid>::addToValidator(builder)
+        ->withRequiredNumber("rowSize")
+        ->whichIsGreaterThen(0)
+        ->finishNumber()
+        ->withRequiredNumber("colSize")
+        ->whichIsGreaterThen(0)
+        ->finishNumber()
+        ->withRequiredNumber("numOutputSlots")
+        ->whichIsGreaterThen(0)
+        ->finishNumber()
+        ->withRequiredAttribute("target",
+            Game::INSTANCE->zTypeRegistry()->getValidator<UIReference>());
+}
+
+UICraftingGrid* UICraftingGridElementFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    UICraftingGrid* result = UIElementFactory<UICraftingGrid>::fromJson(zJson);
+    result->setRowSize((int)zJson->zValue("rowSize")->asNumber()->getNumber());
+    result->setColSize((int)zJson->zValue("colSize")->asNumber()->getNumber());
+    result->setNumOutputSlots(
+        (int)zJson->zValue("numOutputSlots")->asNumber()->getNumber());
+    result->setTarget(Game::INSTANCE->zTypeRegistry()->fromJson<UIReference>(
+        zJson->zValue("target")->asObject()));
+    return result;
+}
+
+Framework::JSON::JSONObject* UICraftingGridElementFactory::toJsonObject(
+    UICraftingGrid* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = UIElementFactory<UICraftingGrid>::toJsonObject(zObject);
+    result->addValue(
+        "rowSize", new Framework::JSON::JSONNumber(zObject->getRowSize()));
+    result->addValue(
+        "colSize", new Framework::JSON::JSONNumber(zObject->getColSize()));
+    result->addValue("numOutputSlots",
+        new Framework::JSON::JSONNumber(zObject->getNumOutputSlots()));
+    result->addValue("target",
+        Game::INSTANCE->zTypeRegistry()->toJson<UIReference>(
+            zObject->zTarget()));
+    return result;
+}
+
+UICraftingGrid* UICraftingGridElementFactory::createElement(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UICraftingGrid();
+}
+
+const char* UICraftingGridElementFactory::getTypeToken() const
+{
+    return "craftingGrid";
+}

+ 44 - 0
FactoryCraft/UICraftingGrid.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include <Either.h>
+
+#include "UIElement.h"
+
+class UIReference;
+
+class UICraftingGrid : public UIElement
+{
+private:
+    int rowSize;
+    int colSize;
+    int numOutputSlots;
+    UIReference* target;
+
+public:
+    UICraftingGrid();
+    ~UICraftingGrid();
+    void setRowSize(int rowSize);
+    int getRowSize() const;
+    void setColSize(int colSize);
+    int getColSize() const;
+    void setNumOutputSlots(int numOutputSlots);
+    int getNumOutputSlots() const;
+    void setTarget(UIReference* target);
+    UIReference* zTarget() const;
+    Framework::XML::Element* toUIML(Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UICraftingGridElementFactory : public UIElementFactory<UICraftingGrid>
+{
+public:
+    UICraftingGridElementFactory();
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UICraftingGrid* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UICraftingGrid* zObject) const override;
+    UICraftingGrid* createElement(
+        Framework::JSON::JSONObject* zJson) const override;
+    const char* getTypeToken() const override;
+};

+ 135 - 0
FactoryCraft/UICraftingProgress.cpp

@@ -0,0 +1,135 @@
+#include "UICraftingProgress.h"
+
+#include "UIReference.h"
+
+UICraftingProgress::UICraftingProgress()
+    : UIElement(),
+      reference(0)
+{}
+
+UICraftingProgress::~UICraftingProgress()
+{
+    if (reference)
+    {
+        reference->release();
+    }
+}
+
+void UICraftingProgress::setReference(UIReference* reference)
+{
+    if (this->reference)
+    {
+        this->reference->release();
+    }
+    this->reference = reference;
+}
+
+UIReference* UICraftingProgress::zReference() const
+{
+    return reference;
+}
+
+void UICraftingProgress::setBackgroundImagePath(
+    const Framework::Text& backgroundImagePath)
+{
+    this->backgroundImagePath = backgroundImagePath;
+}
+
+const Framework::Text& UICraftingProgress::getBackgroundImagePath() const
+{
+    return backgroundImagePath;
+}
+
+void UICraftingProgress::setForegroundImagePath(
+    const Framework::Text& foregroundImagePath)
+{
+    this->foregroundImagePath = foregroundImagePath;
+}
+
+const Framework::Text& UICraftingProgress::getForegroundImagePath() const
+{
+    return foregroundImagePath;
+}
+
+void UICraftingProgress::setDirection(const Framework::Text& direction)
+{
+    this->direction = direction;
+}
+
+const Framework::Text& UICraftingProgress::getDirection() const
+{
+    return direction;
+}
+
+Framework::XML::Element* UICraftingProgress::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* element = UIElement::toUIML(zTarget, zActor);
+    element->setName("craftingProgress");
+    element->setAttribute("target", reference->getReferenceId(zTarget, zActor));
+    element->setAttribute("backgroundImagePath", backgroundImagePath);
+    element->setAttribute("foregroundImagePath", foregroundImagePath);
+    element->setAttribute("direction", direction);
+    return element;
+}
+
+UICraftingProgressFactory::UICraftingProgressFactory()
+    : UIElementFactory()
+{}
+
+JSONObjectValidationBuilder* UICraftingProgressFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return UIElementFactory::addToValidator(builder)
+        ->withRequiredAttribute("reference",
+            Game::INSTANCE->zTypeRegistry()->getValidator<UIReference>())
+        ->withRequiredString("backgroundImagePath")
+        ->finishString()
+        ->withRequiredString("foregroundImagePath")
+        ->finishString()
+        ->withRequiredString("direction")
+        ->whichIsOneOf({"TOP", "LEFT", "BOTTOM", "RIGHT"})
+        ->finishString();
+}
+
+UICraftingProgress* UICraftingProgressFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    UICraftingProgress* result = UIElementFactory::fromJson(zJson);
+    result->setReference(Game::INSTANCE->zTypeRegistry()->fromJson<UIReference>(
+        zJson->zValue("reference")));
+    result->setBackgroundImagePath(
+        zJson->zValue("backgroundImagePath")->asString()->getString());
+    result->setForegroundImagePath(
+        zJson->zValue("foregroundImagePath")->asString()->getString());
+    result->setDirection(zJson->zValue("direction")->asString()->getString());
+
+    return result;
+}
+
+Framework::JSON::JSONObject* UICraftingProgressFactory::toJsonObject(
+    UICraftingProgress* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = UIElementFactory::toJsonObject(zObject);
+    result->addValue("reference",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zReference()));
+    result->addValue("backgroundImagePath",
+        new Framework::JSON::JSONString(zObject->getBackgroundImagePath()));
+    result->addValue("foregroundImagePath",
+        new Framework::JSON::JSONString(zObject->getForegroundImagePath()));
+    result->addValue(
+        "direction", new Framework::JSON::JSONString(zObject->getDirection()));
+    return result;
+}
+
+UICraftingProgress* UICraftingProgressFactory::createElement(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UICraftingProgress();
+}
+
+const char* UICraftingProgressFactory::getTypeToken() const
+{
+    return "craftingProgress";
+}

+ 44 - 0
FactoryCraft/UICraftingProgress.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include "UIElement.h"
+
+class UIReference;
+
+class UICraftingProgress : public UIElement
+{
+private:
+    UIReference* reference;
+    Framework::Text backgroundImagePath;
+    Framework::Text foregroundImagePath;
+    Framework::Text direction;
+
+public:
+    UICraftingProgress();
+    ~UICraftingProgress();
+    void setReference(UIReference* reference);
+    UIReference* zReference() const;
+    void setBackgroundImagePath(const Framework::Text& backgroundImagePath);
+    const Framework::Text& getBackgroundImagePath() const;
+    void setForegroundImagePath(const Framework::Text& foregroundImagePath);
+    const Framework::Text& getForegroundImagePath() const;
+    void setDirection(const Framework::Text& direction);
+    const Framework::Text& getDirection() const;
+    virtual Framework::XML::Element* toUIML(
+        Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UICraftingProgressFactory : public UIElementFactory<UICraftingProgress>
+{
+public:
+    UICraftingProgressFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UICraftingProgress* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UICraftingProgress* zObject) const override;
+    UICraftingProgress* createElement(
+        Framework::JSON::JSONObject* zJson) const override;
+    const char* getTypeToken() const override;
+};

+ 127 - 0
FactoryCraft/UIDialogElement.cpp

@@ -0,0 +1,127 @@
+#include "UIDialogElement.h"
+
+#include "Block.h"
+#include "Entity.h"
+#include "UIReference.h"
+
+UIDialogElement::UIDialogElement()
+    : UIContainerElement(),
+      notifyOnClose(0)
+{}
+
+UIDialogElement::~UIDialogElement()
+{
+    if (notifyOnClose)
+    {
+        notifyOnClose->release();
+    }
+}
+
+void UIDialogElement::setTitle(const Framework::Text& title)
+{
+    this->title = title;
+}
+
+const Framework::Text& UIDialogElement::getTitle() const
+{
+    return title;
+}
+
+void UIDialogElement::setNotifyOnClose(UIReference* notifyOnClose)
+{
+    if (this->notifyOnClose)
+    {
+        this->notifyOnClose->release();
+    }
+    this->notifyOnClose = notifyOnClose;
+}
+
+UIReference* UIDialogElement::zNotifyOnClose() const
+{
+    return notifyOnClose;
+}
+
+Framework::XML::Element* UIDialogElement::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* result
+        = UIContainerElement::toUIML(zTarget, zActor);
+    result->setName("dialog");
+    result->setAttribute("title", title);
+    Framework::Text id = getId();
+    if (zTarget.isA())
+    {
+        id.append() << "_" + zTarget.getA()->getDimensionId() << ","
+                    << zTarget.getA()->getPos().x << ","
+                    << zTarget.getA()->getPos().y << ","
+                    << zTarget.getA()->getPos().z << "_" << zActor->getId();
+    }
+    else
+    {
+        id.append() << "_" << zTarget.getB()->getId() << "_" << zActor->getId();
+    }
+    result->setAttribute("id", id);
+    if (notifyOnClose)
+    {
+        result->setAttribute(
+            "notifyOnClose", notifyOnClose->getReferenceId(zTarget, zActor));
+    }
+    return result;
+}
+
+UIDialogElementFactory::UIDialogElementFactory()
+    : UIContainerElementFactory<UIDialogElement>()
+{}
+
+JSONObjectValidationBuilder* UIDialogElementFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return UIContainerElementFactory::addToValidator(builder)
+        ->withRequiredString("title")
+        ->finishString()
+        ->withRequiredAttribute("notifyOnClose",
+            Game::INSTANCE->zTypeRegistry()->getValidator<UIReference>(),
+            false,
+            true);
+}
+
+UIDialogElement* UIDialogElementFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    UIDialogElement* result = UIContainerElementFactory::fromJson(zJson);
+    result->setTitle(zJson->zValue("title")->asString()->getString());
+    if (zJson->hasValue("notifyOnClose"))
+    {
+        result->setNotifyOnClose(
+            Game::INSTANCE->zTypeRegistry()->fromJson<UIReference>(
+                zJson->zValue("notifyOnClose")));
+    }
+    return result;
+}
+
+Framework::JSON::JSONObject* UIDialogElementFactory::toJsonObject(
+    UIDialogElement* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = UIContainerElementFactory::toJsonObject(zObject);
+    result->addValue(
+        "title", new Framework::JSON::JSONString(zObject->getTitle()));
+    if (zObject->zNotifyOnClose())
+    {
+        result->addValue("notifyOnClose",
+            Game::INSTANCE->zTypeRegistry()->toJson<UIReference>(
+                zObject->zNotifyOnClose()));
+    }
+    return result;
+}
+
+UIDialogElement* UIDialogElementFactory::createElement(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UIDialogElement();
+}
+
+const char* UIDialogElementFactory::getTypeToken() const
+{
+    return "dialog";
+}

+ 37 - 0
FactoryCraft/UIDialogElement.h

@@ -0,0 +1,37 @@
+#pragma once
+
+#include "UIElement.h"
+
+class UIReference;
+
+class UIDialogElement : public UIContainerElement
+{
+private:
+    Framework::Text title;
+    UIReference* notifyOnClose;
+
+public:
+    UIDialogElement();
+    ~UIDialogElement();
+    void setTitle(const Framework::Text& title);
+    const Framework::Text& getTitle() const;
+    void setNotifyOnClose(UIReference* notifyOnClose);
+    UIReference* zNotifyOnClose() const;
+    Framework::XML::Element* toUIML(Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UIDialogElementFactory : public UIContainerElementFactory<UIDialogElement>
+{
+public:
+    UIDialogElementFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UIDialogElement* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UIDialogElement* zObject) const override;
+    UIDialogElement* createElement(
+        Framework::JSON::JSONObject* zJson) const override;
+    const char* getTypeToken() const override;
+};

+ 202 - 0
FactoryCraft/UIElement.cpp

@@ -0,0 +1,202 @@
+#include "UIElement.h"
+
+UIElement::UIElement()
+    : Framework::ReferenceCounter(),
+      marginLeft(0),
+      marginRight(0),
+      marginTop(0),
+      marginBottom(0),
+      width(0),
+      height(0)
+{}
+
+void UIElement::setId(const Framework::Text& id)
+{
+    this->id = id;
+}
+
+const Framework::Text& UIElement::getId() const
+{
+    return id;
+}
+
+void UIElement::setMarginLeft(const Framework::Text& marginLeft)
+{
+    this->marginLeft = marginLeft;
+}
+
+const Framework::Text& UIElement::getMarginLeft() const
+{
+    return marginLeft;
+}
+
+void UIElement::setMarginRight(const Framework::Text& marginRight)
+{
+    this->marginRight = marginRight;
+}
+
+const Framework::Text& UIElement::getMarginRight() const
+{
+    return marginRight;
+}
+
+void UIElement::setMarginTop(const Framework::Text& marginTop)
+{
+    this->marginTop = marginTop;
+}
+
+const Framework::Text& UIElement::getMarginTop() const
+{
+    return marginTop;
+}
+
+void UIElement::setMarginBottom(const Framework::Text& marginBottom)
+{
+    this->marginBottom = marginBottom;
+}
+
+const Framework::Text& UIElement::getMarginBottom() const
+{
+    return marginBottom;
+}
+
+void UIElement::setWidth(const Framework::Text& width)
+{
+    this->width = width;
+}
+
+const Framework::Text& UIElement::getWidth() const
+{
+    return width;
+}
+
+void UIElement::setHeight(const Framework::Text& height)
+{
+    this->height = height;
+}
+
+const Framework::Text& UIElement::getHeight() const
+{
+    return height;
+}
+
+void UIElement::setAlignLeft(const Framework::Text& alignLeft)
+{
+    this->alignLeft = alignLeft;
+}
+
+const Framework::Text& UIElement::getAlignLeft() const
+{
+    return alignLeft;
+}
+
+void UIElement::setAlignRight(const Framework::Text& alignRight)
+{
+    this->alignRight = alignRight;
+}
+
+const Framework::Text& UIElement::getAlignRight() const
+{
+    return alignRight;
+}
+
+void UIElement::setAlignTop(const Framework::Text& alignTop)
+{
+    this->alignTop = alignTop;
+}
+
+const Framework::Text& UIElement::getAlignTop() const
+{
+    return alignTop;
+}
+
+void UIElement::setAlignBottom(const Framework::Text& alignBottom)
+{
+    this->alignBottom = alignBottom;
+}
+
+const Framework::Text& UIElement::getAlignBottom() const
+{
+    return alignBottom;
+}
+
+void UIElement::setStyle(const Framework::Text& style)
+{
+    this->style = style;
+}
+
+const Framework::Text& UIElement::getStyle() const
+{
+    return style;
+}
+
+Framework::XML::Element* UIElement::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* result = new Framework::XML::Element();
+    result->setAttribute("id", id);
+    if (!marginLeft.istGleich("0"))
+    {
+        result->setAttribute("margin-left", marginLeft);
+    }
+    if (!marginRight.istGleich("0"))
+    {
+        result->setAttribute("margin-right", marginRight);
+    }
+    if (!marginTop.istGleich("0"))
+    {
+        result->setAttribute("margin-top", marginTop);
+    }
+    if (!marginBottom.istGleich("0"))
+    {
+        result->setAttribute("margin-bottom", marginBottom);
+    }
+    result->setAttribute("width", width);
+    result->setAttribute("height", height);
+    if (alignLeft.getLength() > 0)
+    {
+        result->setAttribute("align-left", alignLeft);
+    }
+    if (alignRight.getLength() > 0)
+    {
+        result->setAttribute("align-right", alignRight);
+    }
+    if (alignTop.getLength() > 0)
+    {
+        result->setAttribute("align-top", alignTop);
+    }
+    if (alignBottom.getLength() > 0)
+    {
+        result->setAttribute("align-bottom", alignBottom);
+    }
+    if (style.getLength() > 0)
+    {
+        result->setAttribute("style", style);
+    }
+    return result;
+}
+
+UIContainerElement::UIContainerElement()
+    : UIElement()
+{}
+
+void UIContainerElement::addChild(UIElement* child)
+{
+    children.add(child);
+}
+
+const Framework::RCArray<UIElement>& UIContainerElement::getChildren() const
+{
+    return children;
+}
+
+Framework::XML::Element* UIContainerElement::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* result = UIElement::toUIML(zTarget, zActor);
+    for (UIElement* child : children)
+    {
+        result->addChild(child->toUIML(zTarget, zActor));
+    }
+    return result;
+}

+ 300 - 0
FactoryCraft/UIElement.h

@@ -0,0 +1,300 @@
+#pragma once
+
+#include <Array.h>
+#include <Either.h>
+#include <ReferenceCounter.h>
+
+#include "Game.h"
+#include "TypeRegistry.h"
+
+class Block;
+class Entity;
+
+class UIElement : public virtual Framework::ReferenceCounter
+{
+private:
+    Framework::Text id;
+    Framework::Text marginLeft;
+    Framework::Text marginRight;
+    Framework::Text marginTop;
+    Framework::Text marginBottom;
+    Framework::Text width;
+    Framework::Text height;
+    Framework::Text alignLeft;
+    Framework::Text alignRight;
+    Framework::Text alignTop;
+    Framework::Text alignBottom;
+    Framework::Text style;
+
+public:
+    UIElement();
+    void setId(const Framework::Text& id);
+    const Framework::Text& getId() const;
+    void setMarginLeft(const Framework::Text& marginLeft);
+    const Framework::Text& getMarginLeft() const;
+    void setMarginRight(const Framework::Text& marginRight);
+    const Framework::Text& getMarginRight() const;
+    void setMarginTop(const Framework::Text& marginTop);
+    const Framework::Text& getMarginTop() const;
+    void setMarginBottom(const Framework::Text& marginBottom);
+    const Framework::Text& getMarginBottom() const;
+    void setWidth(const Framework::Text& width);
+    const Framework::Text& getWidth() const;
+    void setHeight(const Framework::Text& height);
+    const Framework::Text& getHeight() const;
+    void setAlignLeft(const Framework::Text& alignLeft);
+    const Framework::Text& getAlignLeft() const;
+    void setAlignRight(const Framework::Text& alignRight);
+    const Framework::Text& getAlignRight() const;
+    void setAlignTop(const Framework::Text& alignTop);
+    const Framework::Text& getAlignTop() const;
+    void setAlignBottom(const Framework::Text& alignBottom);
+    const Framework::Text& getAlignBottom() const;
+    void setStyle(const Framework::Text& style);
+    const Framework::Text& getStyle() const;
+    virtual Framework::XML::Element* toUIML(
+        Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const;
+};
+
+class UIContainerElement : public UIElement
+{
+private:
+    Framework::RCArray<UIElement> children;
+
+public:
+    UIContainerElement();
+    void addChild(UIElement* child);
+    const Framework::RCArray<UIElement>& getChildren() const;
+    virtual Framework::XML::Element* toUIML(
+        Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+template<class T> class UIElementFactory : public SubTypeFactory<UIElement, T>
+{
+public:
+    UIElementFactory()
+        : SubTypeFactory<UIElement, T>()
+    {}
+
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override
+    {
+        return builder->withRequiredString("id")
+            ->finishString()
+            ->withRequiredNumber("marginLeft")
+            ->withDefault(0.0)
+            ->finishNumber()
+            ->withRequiredString("marginLeft")
+            ->whichEndsWithMatch("%")
+            ->finishString()
+            ->withRequiredNumber("marginRight")
+            ->withDefault(0.0)
+            ->finishNumber()
+            ->withRequiredString("marginRight")
+            ->whichEndsWithMatch("%")
+            ->finishString()
+            ->withRequiredNumber("marginTop")
+            ->withDefault(0.0)
+            ->finishNumber()
+            ->withRequiredString("marginTop")
+            ->whichEndsWithMatch("%")
+            ->finishString()
+            ->withRequiredNumber("marginBottom")
+            ->withDefault(0.0)
+            ->finishNumber()
+            ->withRequiredString("marginBottom")
+            ->whichEndsWithMatch("%")
+            ->finishString()
+            ->withRequiredNumber("width")
+            ->finishNumber()
+            ->withRequiredString("width")
+            ->whichEndsWithMatch("%")
+            ->finishString()
+            ->withRequiredString("width")
+            ->withExactMatch("auto")
+            ->finishString()
+            ->withRequiredNumber("height")
+            ->finishNumber()
+            ->withRequiredString("height")
+            ->whichEndsWithMatch("%")
+            ->finishString()
+            ->withRequiredString("height")
+            ->withExactMatch("auto")
+            ->finishString()
+            ->withRequiredString("alignLeft")
+            ->withDefault("")
+            ->finishString()
+            ->withRequiredString("alignRight")
+            ->withDefault("")
+            ->finishString()
+            ->withRequiredString("alignTop")
+            ->withDefault("")
+            ->finishString()
+            ->withRequiredString("alignBottom")
+            ->withDefault("")
+            ->finishString()
+            ->withRequiredString("style")
+            ->withDefault("")
+            ->finishString();
+    }
+
+    virtual T* fromJson(Framework::JSON::JSONObject* zJson) const override
+    {
+        T* result = createElement(zJson);
+        result->setId(zJson->zValue("id")->asString()->getString());
+        if (zJson->zValue("marginLeft")->getType()
+            == Framework::AbstractType::NUMBER)
+        {
+            result->setMarginLeft(
+                (int)zJson->zValue("marginLeft")->asNumber()->getNumber());
+        }
+        else
+        {
+            result->setMarginLeft(
+                zJson->zValue("marginLeft")->asString()->getString());
+        }
+        if (zJson->zValue("marginRight")->getType()
+            == Framework::AbstractType::NUMBER)
+        {
+            result->setMarginRight(
+                (int)zJson->zValue("marginRight")->asNumber()->getNumber());
+        }
+        else
+        {
+            result->setMarginRight(
+                zJson->zValue("marginRight")->asString()->getString());
+        }
+        if (zJson->zValue("marginTop")->getType()
+            == Framework::AbstractType::NUMBER)
+        {
+            result->setMarginTop(
+                (int)zJson->zValue("marginTop")->asNumber()->getNumber());
+        }
+        else
+        {
+            result->setMarginTop(
+                zJson->zValue("marginTop")->asString()->getString());
+        }
+        if (zJson->zValue("marginBottom")->getType()
+            == Framework::AbstractType::NUMBER)
+        {
+            result->setMarginBottom(
+                (int)zJson->zValue("marginBottom")->asNumber()->getNumber());
+        }
+        else
+        {
+            result->setMarginBottom(
+                zJson->zValue("marginBottom")->asString()->getString());
+        }
+        if (zJson->zValue("width")->getType()
+            == Framework::AbstractType::NUMBER)
+        {
+            result->setWidth(
+                (int)zJson->zValue("width")->asNumber()->getNumber());
+        }
+        else
+        {
+            result->setWidth(zJson->zValue("width")->asString()->getString());
+        }
+        if (zJson->zValue("height")->getType()
+            == Framework::AbstractType::NUMBER)
+        {
+            result->setHeight(
+                (int)zJson->zValue("height")->asNumber()->getNumber());
+        }
+        else
+        {
+            result->setHeight(zJson->zValue("height")->asString()->getString());
+        }
+        result->setAlignLeft(
+            zJson->zValue("alignLeft")->asString()->getString());
+        result->setAlignRight(
+            zJson->zValue("alignRight")->asString()->getString());
+        result->setAlignTop(zJson->zValue("alignTop")->asString()->getString());
+        result->setAlignBottom(
+            zJson->zValue("alignBottom")->asString()->getString());
+        result->setStyle(zJson->zValue("style")->asString()->getString());
+        return result;
+    }
+
+    virtual Framework::JSON::JSONObject* toJsonObject(T* zObject) const override
+    {
+        Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+        result->addValue(
+            "id", new Framework::JSON::JSONString(zObject->getId()));
+        result->addValue("marginLeft",
+            new Framework::JSON::JSONString(zObject->getMarginLeft()));
+        result->addValue("marginRight",
+            new Framework::JSON::JSONString(zObject->getMarginRight()));
+        result->addValue("marginTop",
+            new Framework::JSON::JSONString(zObject->getMarginTop()));
+        result->addValue("marginBottom",
+            new Framework::JSON::JSONString(zObject->getMarginBottom()));
+        result->addValue(
+            "width", new Framework::JSON::JSONString(zObject->getWidth()));
+        result->addValue(
+            "height", new Framework::JSON::JSONString(zObject->getHeight()));
+        result->addValue("alignLeft",
+            new Framework::JSON::JSONString(zObject->getAlignLeft()));
+        result->addValue("alignRight",
+            new Framework::JSON::JSONString(zObject->getAlignRight()));
+        result->addValue("alignTop",
+            new Framework::JSON::JSONString(zObject->getAlignTop()));
+        result->addValue("alignBottom",
+            new Framework::JSON::JSONString(zObject->getAlignBottom()));
+        result->addValue(
+            "style", new Framework::JSON::JSONString(zObject->getStyle()));
+        return result;
+    }
+
+protected:
+    virtual T* createElement(Framework::JSON::JSONObject* zJson) const = 0;
+};
+
+template<class T> class UIContainerElementFactory : public UIElementFactory<T>
+{
+public:
+    UIContainerElementFactory()
+        : UIElementFactory<T>()
+    {}
+
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override
+    {
+        return UIElementFactory<T>::addToValidator(builder)
+            ->withRequiredArray("children")
+            ->addAcceptedTypeInArray(
+                Game::INSTANCE->zTypeRegistry()->getValidator<UIElement>())
+            ->finishArray();
+    }
+
+    virtual T* fromJson(Framework::JSON::JSONObject* zJson) const override
+    {
+        T* result = UIElementFactory<T>::fromJson(zJson);
+        Framework::JSON::JSONArray* childrenJson
+            = zJson->zValue("children")->asArray();
+        for (Framework::JSON::JSONValue* childJson : *childrenJson)
+        {
+            result->addChild(
+                Game::INSTANCE->zTypeRegistry()->fromJson<UIElement>(
+                    childJson->asObject()));
+        }
+        return result;
+    }
+
+    virtual Framework::JSON::JSONObject* toJsonObject(T* zObject) const override
+    {
+        Framework::JSON::JSONObject* result
+            = UIElementFactory<T>::toJsonObject(zObject);
+        Framework::JSON::JSONArray* childrenJson
+            = new Framework::JSON::JSONArray();
+        for (UIElement* child : zObject->getChildren())
+        {
+            childrenJson->addValue(
+                Game::INSTANCE->zTypeRegistry()->toJson<UIElement>(child));
+        }
+        result->addValue("children", childrenJson);
+        return result;
+    }
+};

+ 135 - 0
FactoryCraft/UIFuelState.cpp

@@ -0,0 +1,135 @@
+#include "UIFuelState.h"
+
+#include "UIReference.h"
+
+UIFuelState::UIFuelState()
+    : UIElement(),
+      reference(0)
+{}
+
+UIFuelState::~UIFuelState()
+{
+    if (reference)
+    {
+        reference->release();
+    }
+}
+
+void UIFuelState::setReference(UIReference* reference)
+{
+    if (this->reference)
+    {
+        this->reference->release();
+    }
+    this->reference = reference;
+}
+
+UIReference* UIFuelState::zReference() const
+{
+    return reference;
+}
+
+void UIFuelState::setBackgroundImagePath(
+    const Framework::Text& backgroundImagePath)
+{
+    this->backgroundImagePath = backgroundImagePath;
+}
+
+const Framework::Text& UIFuelState::getBackgroundImagePath() const
+{
+    return backgroundImagePath;
+}
+
+void UIFuelState::setForegroundImagePath(
+    const Framework::Text& foregroundImagePath)
+{
+    this->foregroundImagePath = foregroundImagePath;
+}
+
+const Framework::Text& UIFuelState::getForegroundImagePath() const
+{
+    return foregroundImagePath;
+}
+
+void UIFuelState::setDirection(const Framework::Text& direction)
+{
+    this->direction = direction;
+}
+
+const Framework::Text& UIFuelState::getDirection() const
+{
+    return direction;
+}
+
+Framework::XML::Element* UIFuelState::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* element = UIElement::toUIML(zTarget, zActor);
+    element->setName("fuelState");
+    element->setAttribute("target", reference->getReferenceId(zTarget, zActor));
+    element->setAttribute("backgroundImagePath", backgroundImagePath);
+    element->setAttribute("foregroundImagePath", foregroundImagePath);
+    element->setAttribute("direction", direction);
+    return element;
+}
+
+UIFuelStateFactory::UIFuelStateFactory()
+    : UIElementFactory()
+{}
+
+JSONObjectValidationBuilder* UIFuelStateFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return UIElementFactory::addToValidator(builder)
+        ->withRequiredAttribute("reference",
+            Game::INSTANCE->zTypeRegistry()->getValidator<UIReference>())
+        ->withRequiredString("backgroundImagePath")
+        ->finishString()
+        ->withRequiredString("foregroundImagePath")
+        ->finishString()
+        ->withRequiredString("direction")
+        ->whichIsOneOf({"TOP", "LEFT", "BOTTOM", "RIGHT"})
+        ->finishString();
+}
+
+UIFuelState* UIFuelStateFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    UIFuelState* result = UIElementFactory::fromJson(zJson);
+    result->setReference(Game::INSTANCE->zTypeRegistry()->fromJson<UIReference>(
+        zJson->zValue("reference")));
+    result->setBackgroundImagePath(
+        zJson->zValue("backgroundImagePath")->asString()->getString());
+    result->setForegroundImagePath(
+        zJson->zValue("foregroundImagePath")->asString()->getString());
+    result->setDirection(zJson->zValue("direction")->asString()->getString());
+
+    return result;
+}
+
+Framework::JSON::JSONObject* UIFuelStateFactory::toJsonObject(
+    UIFuelState* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = UIElementFactory::toJsonObject(zObject);
+    result->addValue("reference",
+        Game::INSTANCE->zTypeRegistry()->toJson(zObject->zReference()));
+    result->addValue("backgroundImagePath",
+        new Framework::JSON::JSONString(zObject->getBackgroundImagePath()));
+    result->addValue("foregroundImagePath",
+        new Framework::JSON::JSONString(zObject->getForegroundImagePath()));
+    result->addValue(
+        "direction", new Framework::JSON::JSONString(zObject->getDirection()));
+    return result;
+}
+
+UIFuelState* UIFuelStateFactory::createElement(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UIFuelState();
+}
+
+const char* UIFuelStateFactory::getTypeToken() const
+{
+    return "fuelState";
+}

+ 43 - 0
FactoryCraft/UIFuelState.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include "UIElement.h"
+
+class UIReference;
+
+class UIFuelState : public UIElement
+{
+private:
+    UIReference* reference;
+    Framework::Text backgroundImagePath;
+    Framework::Text foregroundImagePath;
+    Framework::Text direction;
+
+public:
+    UIFuelState();
+    ~UIFuelState();
+    void setReference(UIReference* reference);
+    UIReference* zReference() const;
+    void setBackgroundImagePath(const Framework::Text& backgroundImagePath);
+    const Framework::Text& getBackgroundImagePath() const;
+    void setForegroundImagePath(const Framework::Text& foregroundImagePath);
+    const Framework::Text& getForegroundImagePath() const;
+    void setDirection(const Framework::Text& direction);
+    const Framework::Text& getDirection() const;
+    virtual Framework::XML::Element* toUIML(
+        Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UIFuelStateFactory : public UIElementFactory<UIFuelState>
+{
+public:
+    UIFuelStateFactory();
+    JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UIFuelState* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UIFuelState* zObject) const override;
+    UIFuelState* createElement(
+        Framework::JSON::JSONObject* zJson) const override;
+    const char* getTypeToken() const override;
+};

+ 159 - 0
FactoryCraft/UIInventory.cpp

@@ -0,0 +1,159 @@
+#include "UIInventory.h"
+
+#include "UIReference.h"
+
+UIInventoryElement::UIInventoryElement()
+    : UIElement(),
+      reference(nullptr),
+      rowSize(0),
+      numSlots(0),
+      hasFilter(0)
+{}
+
+UIInventoryElement::~UIInventoryElement()
+{
+    if (reference)
+    {
+        reference->release();
+    }
+}
+
+void UIInventoryElement::setReference(UIReference* reference)
+{
+    if (this->reference)
+    {
+        this->reference->release();
+    }
+    this->reference = reference;
+}
+
+UIReference* UIInventoryElement::zReference() const
+{
+    return reference;
+}
+
+void UIInventoryElement::setRowSize(int rowSize)
+{
+    this->rowSize = rowSize;
+}
+
+int UIInventoryElement::getRowSize() const
+{
+    return rowSize;
+}
+
+void UIInventoryElement::setNumSlots(int numSlots)
+{
+    this->numSlots = numSlots;
+}
+
+int UIInventoryElement::getNumSlots() const
+{
+    return numSlots;
+}
+
+void UIInventoryElement::setSlotNameFilter(
+    const Framework::Text& slotNameFilter)
+{
+    this->slotNameFilter = slotNameFilter;
+    hasFilter = 1;
+}
+
+const Framework::Text& UIInventoryElement::getSlotNameFilter() const
+{
+    return slotNameFilter;
+}
+
+bool UIInventoryElement::hasSlotNameFilter() const
+{
+    return hasFilter;
+}
+
+Framework::XML::Element* UIInventoryElement::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* result = UIElement::toUIML(zTarget, zActor);
+    result->setName("inventory");
+    if (reference)
+    {
+        result->setAttribute(
+            "target", reference->getReferenceId(zTarget, zActor));
+    }
+    result->setAttribute("rowSize", rowSize);
+    result->setAttribute("numSlots", numSlots);
+    if (hasFilter)
+    {
+        result->setAttribute("slotNameFilter", slotNameFilter);
+    }
+    return result;
+}
+
+UIInventoryElementFactory::UIInventoryElementFactory()
+    : UIElementFactory<UIInventoryElement>()
+{}
+
+JSONObjectValidationBuilder* UIInventoryElementFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return UIElementFactory<UIInventoryElement>::addToValidator(builder)
+        ->withRequiredAttribute("reference",
+            Game::INSTANCE->zTypeRegistry()->getValidator<UIReference>())
+        ->withRequiredNumber("rowSize")
+        ->whichIsGreaterThen(0)
+        ->finishNumber()
+        ->withRequiredNumber("numSlots")
+        ->whichIsGreaterThen(0)
+        ->finishNumber()
+        ->withRequiredString("slotNameFilter")
+        ->whichIsOptional()
+        ->finishString();
+}
+
+UIInventoryElement* UIInventoryElementFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    UIInventoryElement* result
+        = UIElementFactory<UIInventoryElement>::fromJson(zJson);
+    result->setReference(Game::INSTANCE->zTypeRegistry()->fromJson<UIReference>(
+        zJson->zValue("reference")->asObject()));
+    result->setRowSize((int)zJson->zValue("rowSize")->asNumber()->getNumber());
+    result->setNumSlots(
+        (int)zJson->zValue("numSlots")->asNumber()->getNumber());
+    if (zJson->hasValue("slotNameFilter"))
+    {
+        result->setSlotNameFilter(
+            zJson->zValue("slotNameFilter")->asString()->getString());
+    }
+    return result;
+}
+
+Framework::JSON::JSONObject* UIInventoryElementFactory::toJsonObject(
+    UIInventoryElement* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = UIElementFactory<UIInventoryElement>::toJsonObject(zObject);
+    result->addValue("reference",
+        Game::INSTANCE->zTypeRegistry()->toJson<UIReference>(
+            zObject->zReference()));
+    result->addValue(
+        "rowSize", new Framework::JSON::JSONNumber(zObject->getRowSize()));
+    result->addValue(
+        "numSlots", new Framework::JSON::JSONNumber(zObject->getNumSlots()));
+    if (zObject->hasSlotNameFilter())
+    {
+        result->addValue("slotNameFilter",
+            new Framework::JSON::JSONString(zObject->getSlotNameFilter()));
+    }
+    return result;
+}
+
+UIInventoryElement* UIInventoryElementFactory::createElement(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UIInventoryElement();
+}
+
+const char* UIInventoryElementFactory::getTypeToken() const
+{
+    return "inventory";
+}

+ 45 - 0
FactoryCraft/UIInventory.h

@@ -0,0 +1,45 @@
+#pragma once
+
+#include "UIElement.h"
+
+class UIReference;
+
+class UIInventoryElement : public UIElement
+{
+private:
+    UIReference* reference;
+    int rowSize;
+    int numSlots;
+    Framework::Text slotNameFilter;
+    bool hasFilter;
+
+public:
+    UIInventoryElement();
+    ~UIInventoryElement();
+    void setReference(UIReference* reference);
+    UIReference* zReference() const;
+    void setRowSize(int rowSize);
+    int getRowSize() const;
+    void setNumSlots(int numSlots);
+    int getNumSlots() const;
+    void setSlotNameFilter(const Framework::Text& slotNameFilter);
+    const Framework::Text& getSlotNameFilter() const;
+    bool hasSlotNameFilter() const;
+    Framework::XML::Element* toUIML(Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UIInventoryElementFactory : public UIElementFactory<UIInventoryElement>
+{
+public:
+    UIInventoryElementFactory();
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UIInventoryElement* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UIInventoryElement* zObject) const override;
+    UIInventoryElement* createElement(
+        Framework::JSON::JSONObject* zJson) const override;
+    const char* getTypeToken() const override;
+};

+ 80 - 0
FactoryCraft/UIObservable.cpp

@@ -0,0 +1,80 @@
+#include "UIObservable.h"
+
+#include "Entity.h"
+#include "Game.h"
+#include "NetworkMessage.h"
+
+void UIObservable::notifyObservers(NetworkMessage* msg)
+{
+    cs.lock();
+    int index = 0;
+    Framework::Array<int> toDelete;
+    for (auto observer : observers)
+    {
+        Entity* e = Game::INSTANCE->zEntity(observer.sourceEntiryId);
+        if (e)
+        {
+            msg->addressUIElement(
+                observer.uimlElementId, observer.networkApiProcessorId);
+            Game::INSTANCE->sendMessage(msg->clone(), e);
+        }
+        else
+            toDelete.add(index, 0);
+        index++;
+    }
+    for (int i : toDelete)
+        observers.remove(i);
+    cs.unlock();
+    msg->release();
+}
+
+void UIObservable::removeObserver(
+    Entity* zSource, Framework::Text uimlElementId, int networkApiProcessorId)
+{
+    cs.lock();
+    int index = 0;
+    for (auto observer : observers)
+    {
+        if (observer.sourceEntiryId == zSource->getId()
+            && observer.uimlElementId.istGleich(uimlElementId)
+            && observer.networkApiProcessorId == networkApiProcessorId)
+        {
+            observers.remove(index);
+            break;
+        }
+        index++;
+    }
+    cs.unlock();
+}
+
+void UIObservable::addObserver(
+    Entity* zSource, Framework::Text uimlElementId, int networkApiProcessorId)
+{
+    cs.lock();
+    for (auto observer : observers)
+    {
+        if (observer.sourceEntiryId == zSource->getId()
+            && observer.uimlElementId.istGleich(uimlElementId)
+            && observer.networkApiProcessorId == networkApiProcessorId)
+        {
+            cs.unlock();
+            return;
+        }
+    }
+    observers.add({zSource->getId(), uimlElementId, networkApiProcessorId});
+    for (auto call : onObserverAdded)
+    {
+        cs.unlock();
+        call(zSource, uimlElementId, networkApiProcessorId);
+        cs.lock();
+    }
+    cs.unlock();
+}
+
+void UIObservable::registerOnObserverAddedCall(std::function<void(
+        Entity* zSource, Framework::Text uimlElementId, int processor)> call)
+{
+    cs.lock();
+    onObserverAdded.add(call);
+    cs.unlock();
+}

+ 38 - 0
FactoryCraft/UIObservable.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include <Array.h>
+#include <Critical.h>
+#include <Text.h>
+
+struct UIObserver
+{
+    int sourceEntiryId;
+    Framework::Text uimlElementId;
+    int networkApiProcessorId;
+};
+
+class Entity;
+class NetworkMessage;
+
+class UIObservable
+{
+private:
+    Framework::Array<UIObserver> observers;
+    Framework::Array<std::function<void(Entity* zSource,
+        Framework::Text uimlElementId,
+        int networkApiProcessorId)>>
+        onObserverAdded;
+    Framework::Critical cs;
+
+public:
+    void notifyObservers(NetworkMessage* msg);
+    void removeObserver(Entity* zSource,
+        Framework::Text uimlElementId,
+        int networkApiProcessorId);
+    void addObserver(Entity* zSource,
+        Framework::Text uimlElementId,
+        int networkApiProcessorId);
+    void registerOnObserverAddedCall(std::function<void(Entity* zSource,
+            Framework::Text uimlElementId,
+            int networkApiProcessorId)> call);
+};

+ 153 - 0
FactoryCraft/UIReference.cpp

@@ -0,0 +1,153 @@
+#include "UIReference.h"
+
+#include "Block.h"
+#include "Entity.h"
+
+UIReference::UIReference()
+    : Framework::ReferenceCounter()
+{}
+
+UITargetReference::UITargetReference()
+    : UIReference()
+{}
+
+Framework::Text UITargetReference::getReferenceId(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::Text result("");
+    if (zTarget.isA())
+    {
+        result.append() << zTarget.getA()->getDimensionId() << ","
+                        << zTarget.getA()->getPos().x << ","
+                        << zTarget.getA()->getPos().y << ","
+                        << zTarget.getA()->getPos().z;
+    }
+    else
+    {
+        result.append() << zTarget.getB()->getId();
+    }
+    return result;
+}
+
+UITargetComponentReference::UITargetComponentReference()
+    : UIReference(),
+      componentIndex(0)
+{}
+
+Framework::Text UITargetComponentReference::getReferenceId(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::Text result("");
+    if (zTarget.isA())
+    {
+        result.append() << zTarget.getA()->getDimensionId() << ","
+                        << zTarget.getA()->getPos().x << ","
+                        << zTarget.getA()->getPos().y << ","
+                        << zTarget.getA()->getPos().z;
+    }
+    else
+    {
+        result.append() << zTarget.getB()->getId();
+    }
+    result.append() << ":" << componentIndex;
+    return result;
+}
+
+UITActorReference::UITActorReference()
+    : UIReference()
+{}
+
+Framework::Text UITActorReference::getReferenceId(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    return Framework::Text(zActor->getId());
+}
+
+UITargetReferenceFactory::UITargetReferenceFactory()
+    : SubTypeFactory<UIReference, UITargetReference>()
+{}
+
+JSONObjectValidationBuilder* UITargetReferenceFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder;
+}
+
+UITargetReference* UITargetReferenceFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UITargetReference();
+}
+
+Framework::JSON::JSONObject* UITargetReferenceFactory::toJsonObject(
+    UITargetReference* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
+
+const char* UITargetReferenceFactory::getTypeToken() const
+{
+    return "target";
+}
+
+UITActorReferenceFactory::UITActorReferenceFactory()
+    : SubTypeFactory<UIReference, UITActorReference>()
+{}
+
+JSONObjectValidationBuilder* UITActorReferenceFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder;
+}
+
+UITActorReference* UITActorReferenceFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UITActorReference();
+}
+
+Framework::JSON::JSONObject* UITActorReferenceFactory::toJsonObject(
+    UITActorReference* zObject) const
+{
+    return new Framework::JSON::JSONObject();
+}
+
+const char* UITActorReferenceFactory::getTypeToken() const
+{
+    return "actor";
+}
+
+UITargetComponentReferenceFactory::UITargetComponentReferenceFactory()
+    : SubTypeFactory<UIReference, UITargetComponentReference>()
+{}
+
+JSONObjectValidationBuilder* UITargetComponentReferenceFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return builder->withRequiredNumber("componentIndex")
+        ->whichIsGreaterOrEqual(0)
+        ->finishNumber();
+}
+
+UITargetComponentReference* UITargetComponentReferenceFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    UITargetComponentReference* result = new UITargetComponentReference();
+    result->componentIndex
+        = (int)zJson->zValue("componentIndex")->asNumber()->getNumber();
+    return result;
+}
+
+Framework::JSON::JSONObject* UITargetComponentReferenceFactory::toJsonObject(
+    UITargetComponentReference* zObject) const
+{
+    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
+    result->addValue("componentIndex",
+        new Framework::JSON::JSONNumber(zObject->componentIndex));
+    return result;
+}
+
+const char* UITargetComponentReferenceFactory::getTypeToken() const
+{
+    return "targetComponent";
+}

+ 93 - 0
FactoryCraft/UIReference.h

@@ -0,0 +1,93 @@
+#pragma once
+
+#include <Either.h>
+#include <ReferenceCounter.h>
+#include <Text.h>
+
+#include "TypeRegistry.h"
+
+class Block;
+class Entity;
+
+class UIReference : public Framework::ReferenceCounter
+{
+public:
+    UIReference();
+    virtual Framework::Text getReferenceId(
+        Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+        = 0;
+};
+
+class UITargetReference : public UIReference
+{
+public:
+    UITargetReference();
+    virtual Framework::Text getReferenceId(
+        Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UITargetComponentReference : public UIReference
+{
+private:
+    int componentIndex;
+
+public:
+    UITargetComponentReference();
+    virtual Framework::Text getReferenceId(
+        Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+
+    friend class UITargetComponentReferenceFactory;
+};
+
+class UITActorReference : public UIReference
+{
+public:
+    UITActorReference();
+    virtual Framework::Text getReferenceId(
+        Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UITargetReferenceFactory
+    : public SubTypeFactory<UIReference, UITargetReference>
+{
+public:
+    UITargetReferenceFactory();
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UITargetReference* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UITargetReference* zObject) const override;
+    const char* getTypeToken() const override;
+};
+
+class UITActorReferenceFactory
+    : public SubTypeFactory<UIReference, UITActorReference>
+{
+public:
+    UITActorReferenceFactory();
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UITActorReference* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UITActorReference* zObject) const override;
+    const char* getTypeToken() const override;
+};
+
+class UITargetComponentReferenceFactory
+    : public SubTypeFactory<UIReference, UITargetComponentReference>
+{
+public:
+    UITargetComponentReferenceFactory();
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UITargetComponentReference* fromJson(
+        Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UITargetComponentReference* zObject) const override;
+    const char* getTypeToken() const override;
+};

+ 65 - 0
FactoryCraft/UIText.cpp

@@ -0,0 +1,65 @@
+#include "UIText.h"
+
+UITextElement::UITextElement()
+    : UIElement()
+{}
+
+void UITextElement::setText(const Framework::Text& text)
+{
+    this->text = text;
+}
+
+const Framework::Text& UITextElement::getText() const
+{
+    return text;
+}
+
+Framework::XML::Element* UITextElement::toUIML(
+    Framework::Either<Block*, Entity*> zTarget, Entity* zActor) const
+{
+    Framework::XML::Element* result = UIElement::toUIML(zTarget, zActor);
+    result->setName("text");
+    result->setText(text);
+    return result;
+}
+
+UITextElementFactory::UITextElementFactory()
+    : UIElementFactory()
+{}
+
+JSONObjectValidationBuilder* UITextElementFactory::addToValidator(
+    JSONObjectValidationBuilder* builder) const
+{
+    return UIElementFactory::addToValidator(builder)
+        ->withRequiredString("text")
+        ->finishString();
+}
+
+UITextElement* UITextElementFactory::fromJson(
+    Framework::JSON::JSONObject* zJson) const
+{
+    UITextElement* result = UIElementFactory::fromJson(zJson);
+    result->setText(zJson->zValue("text")->asString()->getString());
+    return result;
+}
+
+Framework::JSON::JSONObject* UITextElementFactory::toJsonObject(
+    UITextElement* zObject) const
+{
+    Framework::JSON::JSONObject* result
+        = UIElementFactory::toJsonObject(zObject);
+    result->addValue(
+        "text", new Framework::JSON::JSONString(zObject->getText()));
+    return result;
+}
+
+UITextElement* UITextElementFactory::createElement(
+    Framework::JSON::JSONObject* zJson) const
+{
+    return new UITextElement();
+}
+
+const char* UITextElementFactory::getTypeToken() const
+{
+    return "text";
+}

+ 31 - 0
FactoryCraft/UIText.h

@@ -0,0 +1,31 @@
+#pragma once
+
+#include "UIElement.h"
+
+class UITextElement : public UIElement
+{
+private:
+    Framework::Text text;
+
+public:
+    UITextElement();
+    void setText(const Framework::Text& text);
+    const Framework::Text& getText() const;
+    virtual Framework::XML::Element* toUIML(
+        Framework::Either<Block*, Entity*> zTarget,
+        Entity* zActor) const override;
+};
+
+class UITextElementFactory : public UIElementFactory<UITextElement>
+{
+public:
+    UITextElementFactory();
+    virtual JSONObjectValidationBuilder* addToValidator(
+        JSONObjectValidationBuilder* builder) const override;
+    UITextElement* fromJson(Framework::JSON::JSONObject* zJson) const override;
+    Framework::JSON::JSONObject* toJsonObject(
+        UITextElement* zObject) const override;
+    UITextElement* createElement(
+        Framework::JSON::JSONObject* zJson) const override;
+    const char* getTypeToken() const override;
+};

+ 64 - 20
FactoryCraft/WorldGenerator.cpp

@@ -1,42 +1,42 @@
 #include "WorldGenerator.h"
 
-#include <Betriebssystem.h>
+#include <Datei.h>
 #include <functional>
 #include <Logging.h>
 
 #include "Dimension.h"
 #include "Game.h"
 #include "JsonUtils.h"
-#include "NoiseInterpolator.h"
 
 using namespace Framework;
 using namespace Framework::JSON;
-using namespace Framework::JSON::Validator;
+using namespace Framework::Validator;
 
 WorldGenerator::WorldGenerator(int seed)
     : Thread(),
       exit(0),
-      seed(seed)
+      seed(seed),
+      chunksPerSecond(0.0)
 {
     setName("World Generator");
     Framework::Logging::info()
         << "loading world generator configs. Changes at the config files "
            "may lead to a sudden change in landscape.";
-    JSONValidator* configValidator
-        = JSONValidator::buildForArray()
+    DataValidator* configValidator
+        = DataValidator::buildForArray()
               ->removeInvalidEntries()
               ->addAcceptedTypeInArray(Game::INSTANCE->zTypeRegistry()
-                                           ->getValidator<DimensionGenerator>())
+                      ->getValidator<DimensionGenerator>())
               ->finishArray();
     loadAllJsonsFromDirectory("data/generator",
         [this, configValidator, seed](
             Framework::JSON::JSONValue* zValue, Framework::Text path) {
             Framework::Logging::info()
                 << "loading dimension configs from '" << path << "'";
-            Framework::RCArray<JSONValidationResult> invalidParts;
+            Framework::RCArray<ValidationResult> invalidParts;
             JSONValue* valid
                 = configValidator->getValidParts(zValue, &invalidParts);
-            for (JSONValidationResult* invalidPart : invalidParts)
+            for (ValidationResult* invalidPart : invalidParts)
             {
                 Framework::Logging::error() << invalidPart->getInvalidInfo();
             }
@@ -53,6 +53,14 @@ WorldGenerator::WorldGenerator(int seed)
                 valid->release();
             }
         });
+    Framework::JSON::JSONObject* schema = configValidator->getJsonSchema();
+    Framework::Datei syntaxFile;
+    syntaxFile.setDatei("data/syntax/schema/generator.json");
+    syntaxFile.erstellen();
+    syntaxFile.open(Framework::Datei::Style::schreiben);
+    syntaxFile.schreibe(schema->toString(), schema->toString().getLength());
+    syntaxFile.close();
+    schema->release();
     configValidator->release();
 
     start();
@@ -83,6 +91,8 @@ DimensionGenerator* WorldGenerator::zGenerator(int dimensionId)
 
 void WorldGenerator::thread()
 {
+    double completeTime = 0.0;
+    int generatedChunks = 0;
     while (!exit)
     {
         cs.lock();
@@ -97,46 +107,70 @@ void WorldGenerator::thread()
         cs.unlock();
         if (!hasNext)
         {
+            chunksPerSecond = 0.0;
+            completeTime = 0;
+            generatedChunks = 0;
             Sleep(1000);
             continue;
         }
+        // TODO: prevent that world loader and world generator create the
+        // dimension at the same time
+        Dimension* dim = Game::INSTANCE->zDimension(next.dimensionId);
+        if (!dim)
+        {
+            dim = new Dimension(next.dimensionId);
+            Game::INSTANCE->addDimension(dim);
+        }
         Punkt start = Game::INSTANCE->getChunkCenter(next.startX, next.startY);
         Punkt end = Game::INSTANCE->getChunkCenter(next.endX, next.endY);
         int xDir = start.x > end.x ? -1 : 1;
         int yDir = start.y > end.y ? -1 : 1;
         for (int x = start.x; xDir < 0 ? x >= end.x : x <= end.x;
-             x += CHUNK_SIZE * xDir)
+            x += CHUNK_SIZE * xDir)
         {
             for (int y = start.y; yDir < 0 ? y >= end.y : y <= end.y;
-                 y += CHUNK_SIZE * yDir)
+                y += CHUNK_SIZE * yDir)
             {
                 if (!Game::INSTANCE->doesChunkExist(x, y, next.dimensionId))
                 {
+                    ZeitMesser zm;
+                    zm.messungStart();
                     Chunk* generatedChunk
                         = zGenerator(next.dimensionId)->generateChunk(x, y);
-                    ZeitMesser zm;
+#ifdef CHUNK_GENERATION_DEBUG_LOG
+                    zm.messungEnde();
+                    Framework::Logging::trace()
+                        << "block generation time: " << zm.getSekunden();
+                    completeTime += zm.getSekunden();
                     zm.messungStart();
+#endif
                     generatedChunk->initializeLightning();
+#ifdef CHUNK_GENERATION_DEBUG_LOG
                     zm.messungEnde();
                     Framework::Logging::trace()
                         << "light calculation: " << zm.getSekunden();
+                    completeTime += zm.getSekunden();
                     zm.messungStart();
+#endif
                     generatedChunk->removeUnusedBlocks();
+#ifdef CHUNK_GENERATION_DEBUG_LOG
                     zm.messungEnde();
                     Framework::Logging::trace()
                         << "unused block removal: " << zm.getSekunden();
+                    completeTime += zm.getSekunden();
                     zm.messungStart();
-                    Dimension* dim
-                        = Game::INSTANCE->zDimension(next.dimensionId);
-                    if (!dim)
-                    {
-                        dim = new Dimension(next.dimensionId);
-                        Game::INSTANCE->addDimension(dim);
-                    }
+#endif
+                    generatedChunk->getThis();
                     dim->setChunk(generatedChunk, Punkt(x, y));
+                    generatedChunk->release();
                     zm.messungEnde();
+#ifdef CHUNK_GENERATION_DEBUG_LOG
                     Framework::Logging::trace()
                         << "adding chunk to map: " << zm.getSekunden();
+#endif
+                    completeTime += zm.getSekunden();
+                    generatedChunks++;
+                    chunksPerSecond = generatedChunks / completeTime;
                 }
             }
         }
@@ -164,9 +198,19 @@ Framework::Either<Block*, int> WorldGenerator::generateSingleBlock(
     return zGenerator(dimensionId)->generateBlock(location);
 }
 
+void WorldGenerator::postprocessChunk(Chunk* zChunk)
+{
+    zGenerator(zChunk->getDimensionId())->postprocessChunk(zChunk);
+}
+
 bool WorldGenerator::spawnStructure(Framework::Vec3<int> location,
     int dimensionId,
     std::function<bool(GeneratorTemplate* tmpl)> filter)
 {
     return zGenerator(dimensionId)->spawnStructure(location, filter);
-}
+}
+
+double WorldGenerator::getGeneratedChunksPerSecond() const
+{
+    return chunksPerSecond;
+}

+ 6 - 1
FactoryCraft/WorldGenerator.h

@@ -6,6 +6,8 @@
 #include "Area.h"
 #include "DimensionGenerator.h"
 
+class Chunk;
+
 class WorldGenerator : public Framework::Thread
 {
 private:
@@ -14,19 +16,22 @@ private:
     Framework::RCArray<DimensionGenerator> dimensionGenerators;
     bool exit;
     int seed;
+    double chunksPerSecond;
 
     DimensionGenerator* zGenerator(int dimensionId);
 
 public:
     WorldGenerator(int seed);
     ~WorldGenerator();
-    Dimension *createDimension(int dimensionId);
+    Dimension* createDimension(int dimensionId);
     void thread() override;
     void requestGeneration(Area request);
     void exitAndWait();
     Framework::Either<Block*, int> generateSingleBlock(
         Framework::Vec3<int> location, int dimensionId);
+    void postprocessChunk(Chunk* zChunk);
     bool spawnStructure(Framework::Vec3<int> location,
         int dimensionId,
         std::function<bool(GeneratorTemplate* tmpl)> filter);
+    double getGeneratedChunksPerSecond() const;
 };

+ 2 - 3
FactoryCraft/WorldLoader.cpp

@@ -6,7 +6,6 @@
 #include <Text.h>
 
 #include "Dimension.h"
-#include "Entity.h"
 #include "EntityType.h"
 #include "Game.h"
 #include "WorldGenerator.h"
@@ -83,10 +82,10 @@ void WorldLoader::thread()
         int xDir = start.x > end.x ? -1 : 1;
         int yDir = start.y > end.y ? -1 : 1;
         for (int x = start.x; xDir < 0 ? x >= end.x : x <= end.x;
-             x += CHUNK_SIZE * xDir)
+            x += CHUNK_SIZE * xDir)
         {
             for (int y = start.y; yDir < 0 ? y >= end.y : y <= end.y;
-                 y += CHUNK_SIZE * yDir)
+                y += CHUNK_SIZE * yDir)
             {
                 Dimension* zDim = Game::INSTANCE->zDimension(next.dimensionId);
                 bool revived = 0;

+ 0 - 1
FactoryCraft/WorldLoader.h

@@ -1,7 +1,6 @@
 #pragma once
 
 #include <Critical.h>
-#include <HashMap.h>
 #include <Thread.h>
 
 #include "Area.h"

+ 0 - 30
FactoryCraft/WorldUpdate.cpp

@@ -1,30 +0,0 @@
-#include "WorldUpdate.h"
-
-WorldUpdate::WorldUpdate(int type, int dimensionId, Framework::Vec3<float> pos)
-    : ReferenceCounter(),
-      affectedDimensionId(dimensionId),
-      type(type),
-      pos(pos)
-{}
-
-void WorldUpdate::writeAndCheck(Framework::StreamWriter* zWriter)
-{
-    zWriter->schreibe((char*)&type, 4);
-    this->write(zWriter);
-    zWriter->schreibe((char*)&type, 4);
-}
-
-int WorldUpdate::getAffectedDimension() const
-{
-    return affectedDimensionId;
-}
-
-int WorldUpdate::getType() const
-{
-    return type;
-}
-
-int WorldUpdate::distanceTo(int x, int y) const
-{
-    return (int)pos.abstand(Framework::Vec3<float>((float)x, (float)y, pos.z));
-}

+ 0 - 35
FactoryCraft/WorldUpdate.h

@@ -1,35 +0,0 @@
-#pragma once
-
-#include <ReferenceCounter.h>
-#include <Vec3.h>
-#include <Writer.h>
-
-class Dimension;
-
-class WorldUpdateTypeEnum
-{
-public:
-    static const int ADD_ENTITY = 0;
-    static const int REMOVE_ENTITY = 1;
-};
-
-class WorldUpdate : public Framework::ReferenceCounter
-{
-private:
-    int affectedDimensionId;
-    int type;
-    Framework::Vec3<float> pos;
-
-protected:
-    virtual void write(Framework::StreamWriter* zWriter) = 0;
-
-public:
-    WorldUpdate(int type, int dimensionId, Framework::Vec3<float> pos);
-
-    virtual void onUpdate(Dimension* zDimension) = 0;
-    void writeAndCheck(Framework::StreamWriter* zWriter);
-
-    int getAffectedDimension() const;
-    int getType() const;
-    int distanceTo(int x, int y) const;
-};

+ 103 - 53
FactoryCraft/WormCaveGenerator.cpp

@@ -20,21 +20,23 @@ NoiseWorm3D::NoiseWorm3D(Noise* pitch,
       startChunk(Game::INSTANCE->getChunkCenter(startPos.x, startPos.y))
 {
     Framework::Vec3<float> lastPos = (Framework::Vec3<float>)startPos;
-    keyPoints.add(lastPos);
-    this->size.add((float)minRad);
+    Framework::Array<Framework::Vec3<float>> tmpPointList;
+    Framework::Array<float> tmpSizeList;
+    tmpPointList.add(lastPos);
+    tmpSizeList.add((float)minRad);
     minAffected.x = (int)lastPos.x - minRad;
     minAffected.y = (int)lastPos.y - minRad;
     minAffected.z = (int)lastPos.z - minRad;
     maxAffected.x = (int)lastPos.x + minRad;
     maxAffected.y = (int)lastPos.y + minRad;
     maxAffected.z = (int)lastPos.z + minRad;
-    while (keyPoints.getEintragAnzahl() < distant * 20)
+    while (tmpSizeList.getEintragAnzahl() < distant * 20)
     {
         Framework::Vec3<float> defaultDir(1.f, 0.f, 0.f);
-        if (keyPoints.getEintragAnzahl() > 1)
+        if (tmpPointList.getEintragAnzahl() > 1)
         {
-            defaultDir = keyPoints.get(keyPoints.getEintragAnzahl() - 1)
-                       - keyPoints.get(keyPoints.getEintragAnzahl() - 2);
+            defaultDir = tmpPointList.get(tmpPointList.getEintragAnzahl() - 1)
+                       - tmpPointList.get(tmpPointList.getEintragAnzahl() - 2);
         }
         float n = (float)yaw->getNoise(lastPos.x, lastPos.y, lastPos.z);
         defaultDir.rotateZ((n - 0.5f) / 2.f);
@@ -48,11 +50,11 @@ NoiseWorm3D::NoiseWorm3D(Noise* pitch,
                 .getLengthSq()
             >= (float)(distant * distant))
             break;
-        keyPoints.add(lastPos);
+        tmpPointList.add(lastPos);
         float rad = (float)size->getNoise(lastPos.x, lastPos.y, lastPos.z)
                       * (float)(maxRad - minRad)
                   + (float)minRad;
-        this->size.add(rad);
+        tmpSizeList.add(rad);
         minAffected.x = MIN(minAffected.x, (int)(lastPos.x - rad));
         minAffected.y = MIN(minAffected.y, (int)(lastPos.y - rad));
         minAffected.z = MIN(minAffected.z, (int)(lastPos.z - rad));
@@ -60,9 +62,30 @@ NoiseWorm3D::NoiseWorm3D(Noise* pitch,
         maxAffected.y = MAX(maxAffected.y, (int)(lastPos.y + rad));
         maxAffected.z = MAX(maxAffected.z, (int)(lastPos.z + rad));
     }
+    keyPoints = new float[3 * tmpPointList.getEintragAnzahl()];
+    keyPointSize = new float[tmpPointList.getEintragAnzahl()];
+    float* keyPointsP = keyPoints;
+    float* keyPointSizeP = keyPointSize;
+    auto pi = tmpPointList.begin();
+    auto si = tmpSizeList.begin();
+    while (pi)
+    {
+        *(keyPointsP++) = pi.val().x;
+        *(keyPointsP++) = pi.val().y;
+        *(keyPointsP++) = pi.val().z;
+        *(keyPointSizeP++) = si.val();
+        ++pi;
+        ++si;
+    }
 }
 
-Framework::Punkt NoiseWorm3D::getStartChunkCenter()
+NoiseWorm3D::~NoiseWorm3D()
+{
+    delete[] keyPoints;
+    delete[] keyPointSize;
+}
+
+const Framework::Punkt& NoiseWorm3D::getStartChunkCenter()
 {
     return startChunk;
 }
@@ -71,50 +94,52 @@ void NoiseWorm3D::getPartAffectedByChunk(
     int x, int y, Framework::RCArray<NoiseWorm3D>* zResult)
 {
     NoiseWorm3D* result = 0;
+    Framework::Array<Framework::Vec3<float>> tmpPointList;
+    Framework::Array<float> tmpSizeList;
     if (x - CHUNK_SIZE / 2 <= maxAffected.x
         && x + CHUNK_SIZE / 2 >= minAffected.x
         && y - CHUNK_SIZE / 2 <= maxAffected.y
         && y + CHUNK_SIZE / 2 >= minAffected.y)
     {
-        auto pi = keyPoints.begin();
-        auto si = size.begin();
+        float* pi = keyPoints;
+        float* si = keyPointSize;
         int newWormThreshold = 5;
         int outsideCounter = 0;
-        while (pi && si)
+        for (int i = 0; i < keyPointCount; i++)
         {
             if ((Framework::Vec2<float>((float)x, (float)y)
-                    - Framework::Vec2<float>(pi.val().x, pi.val().y))
+                    - Framework::Vec2<float>(*pi, *(pi + 1)))
                     .getLengthSq()
-                < (si.val() + CHUNK_SIZE / 2) * (si.val() + CHUNK_SIZE / 2))
+                < (*si + CHUNK_SIZE / 2) * (*si + CHUNK_SIZE / 2))
             {
                 outsideCounter = 0;
                 if (result == 0)
                 {
                     result = new NoiseWorm3D();
-                    result->minAffected.x = (int)(pi.val().x - si.val());
-                    result->minAffected.y = (int)(pi.val().y - si.val());
-                    result->minAffected.z = (int)(pi.val().z - si.val());
-                    result->maxAffected.x = (int)(pi.val().x + si.val());
-                    result->maxAffected.y = (int)(pi.val().y + si.val());
-                    result->maxAffected.z = (int)(pi.val().z + si.val());
+                    result->minAffected.x = (int)(*pi - *si);
+                    result->minAffected.y = (int)(*(pi + 1) - *si);
+                    result->minAffected.z = (int)(*(pi + 2) - *si);
+                    result->maxAffected.x = (int)(*pi + *si);
+                    result->maxAffected.y = (int)(*(pi + 1) + *si);
+                    result->maxAffected.z = (int)(*(pi + 2) + *si);
                 }
                 else
                 {
-                    result->minAffected.x = MIN(
-                        result->minAffected.x, (int)(pi.val().x - si.val()));
-                    result->minAffected.y = MIN(
-                        result->minAffected.y, (int)(pi.val().y - si.val()));
-                    result->minAffected.z = MIN(
-                        result->minAffected.z, (int)(pi.val().z - si.val()));
-                    result->maxAffected.x = MAX(
-                        result->maxAffected.x, (int)(pi.val().x + si.val()));
-                    result->maxAffected.y = MAX(
-                        result->maxAffected.y, (int)(pi.val().y + si.val()));
-                    result->maxAffected.z = MAX(
-                        result->maxAffected.z, (int)(pi.val().z + si.val()));
+                    result->minAffected.x
+                        = MIN(result->minAffected.x, (int)(*pi - *si));
+                    result->minAffected.y
+                        = MIN(result->minAffected.y, (int)(*(pi + 1) - *si));
+                    result->minAffected.z
+                        = MIN(result->minAffected.z, (int)(*(pi + 2) - *si));
+                    result->maxAffected.x
+                        = MAX(result->maxAffected.x, (int)(*pi + *si));
+                    result->maxAffected.y
+                        = MAX(result->maxAffected.y, (int)(*(pi + 1) + *si));
+                    result->maxAffected.z
+                        = MAX(result->maxAffected.z, (int)(*(pi + 2) + *si));
                 }
-                result->keyPoints.add(pi.val());
-                result->size.add(si.val());
+                tmpPointList.add({*pi, *(pi + 1), *(pi + 2)});
+                tmpSizeList.add(*si);
             }
             else
             {
@@ -123,18 +148,52 @@ void NoiseWorm3D::getPartAffectedByChunk(
                 {
                     if (result != 0)
                     {
+                        result->keyPoints
+                            = new float[tmpPointList.getEintragAnzahl() * 3];
+                        result->keyPointSize
+                            = new float[tmpPointList.getEintragAnzahl()];
+                        float* rkeyPointsP = result->keyPoints;
+                        float* rkeyPointSizeP = result->keyPointSize;
+                        auto rpi = tmpPointList.begin();
+                        auto rsi = tmpSizeList.begin();
+                        while (rpi)
+                        {
+                            *(rkeyPointsP++) = rpi.val().x;
+                            *(rkeyPointsP++) = rpi.val().y;
+                            *(rkeyPointsP++) = rpi.val().z;
+                            *(rkeyPointSizeP++) = rsi.val();
+                            ++rpi;
+                            ++rsi;
+                        }
+                        tmpPointList.leeren();
+                        tmpSizeList.leeren();
                         zResult->add(result);
                         result = 0;
                     }
                     outsideCounter = 0;
                 }
             }
-            ++pi;
+            pi += 3;
             ++si;
         }
     }
     if (result)
     {
+        result->keyPoints = new float[tmpPointList.getEintragAnzahl() * 3];
+        result->keyPointSize = new float[tmpPointList.getEintragAnzahl()];
+        float* rkeyPointsP = result->keyPoints;
+        float* rkeyPointSizeP = result->keyPointSize;
+        auto rpi = tmpPointList.begin();
+        auto rsi = tmpSizeList.begin();
+        while (rpi)
+        {
+            *(rkeyPointsP++) = rpi.val().x;
+            *(rkeyPointsP++) = rpi.val().y;
+            *(rkeyPointsP++) = rpi.val().z;
+            *(rkeyPointSizeP++) = rsi.val();
+            ++rpi;
+            ++rsi;
+        }
         zResult->add(result);
     }
 }
@@ -144,15 +203,15 @@ bool NoiseWorm3D::isInside(int x, int y, int z)
     if (x >= minAffected.x && x <= maxAffected.x && y >= minAffected.y
         && y <= maxAffected.y && z >= minAffected.z && z <= maxAffected.z)
     {
-        auto pi = keyPoints.begin();
-        auto si = size.begin();
+        float* pi = keyPoints;
+        float* si = keyPointSize;
         while (pi && si)
         {
             if (Framework::Vec3<float>((float)x, (float)y, (float)z)
-                    .abstandSq(pi.val())
-                < si.val() * si.val())
+                    .abstandSq({*pi, *(pi + 1), *(pi + 2)})
+                < *si * *si)
                 return 1;
-            ++pi;
+            pi += 3;
             ++si;
         }
     }
@@ -204,11 +263,8 @@ NoiseWorm3D* WormCaveGenerator::zWormOfChunk(int x, int y)
             return worm;
         }
     }
-    for (Framework::Punkt p : noWormChunks)
-    {
-        if (p.x == x && p.y == y) return 0;
-    }
-    float cNoise = (float)wormStartNoise->getNoise(x, y, 0);
+    float cNoise
+        = (float)wormStartNoise->getNoise((double)x, (double)y, (double)0);
     if (cNoise < cavePosibillity)
     {
         FastNoiseLite* noise = new FastNoiseLite(seed + x * y + y + x);
@@ -235,7 +291,8 @@ NoiseWorm3D* WormCaveGenerator::zWormOfChunk(int x, int y)
             yaw,
             size,
             start,
-            (int)(wormStartNoise->getNoise(start.x, start.y, start.z)
+            (int)(wormStartNoise->getNoise(
+                      (double)start.x, (double)start.y, (double)start.z)
                       * (maxDistant - minDistant)
                   + minDistant),
             minRadius,
@@ -246,13 +303,6 @@ NoiseWorm3D* WormCaveGenerator::zWormOfChunk(int x, int y)
         cache.add(worm);
         return worm;
     }
-    else
-    {
-        if (noWormChunks.getEintragAnzahl()
-            > (maxDistant * 2) / CHUNK_SIZE * (maxDistant * 2) / CHUNK_SIZE * 3)
-            noWormChunks.remove(0);
-        noWormChunks.add(Framework::Punkt(x, y));
-    }
     return 0;
 }
 

+ 5 - 4
FactoryCraft/WormCaveGenerator.h

@@ -14,8 +14,9 @@ private:
     Framework::Vec3<int> minAffected;
     Framework::Vec3<int> maxAffected;
 
-    Framework::Array<Framework::Vec3<float>> keyPoints;
-    Framework::Array<float> size;
+    float* keyPoints;
+    float* keyPointSize;
+    int keyPointCount;
     NoiseWorm3D();
 
 public:
@@ -26,7 +27,8 @@ public:
         int distant,
         int minRad,
         int maxRad);
-    Framework::Punkt getStartChunkCenter();
+    ~NoiseWorm3D();
+    const Framework::Punkt& getStartChunkCenter();
     void getPartAffectedByChunk(
         int x, int y, Framework::RCArray<NoiseWorm3D>* zResult);
     bool isInside(int x, int y, int z);
@@ -52,7 +54,6 @@ private:
     float cavePosibillity;
     Noise* wormStartNoise;
     Framework::RCArray<NoiseWorm3D> cache;
-    Framework::Array<Framework::Punkt> noWormChunks;
 
     NoiseWorm3D* zWormOfChunk(int x, int y);
 

+ 4 - 4
NoiseTest/NoiseTest.vcxproj

@@ -29,26 +29,26 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>

+ 69 - 14
Windows Version/Windows Version.vcxproj

@@ -29,26 +29,26 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v143</PlatformToolset>
+    <PlatformToolset>v145</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
@@ -115,7 +115,8 @@
       <SDLCheck>true</SDLCheck>
       <PreprocessorDefinitions>_DEBUG;_CONSOLE;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>true</ConformanceMode>
-      <LanguageStandard>stdcpp20</LanguageStandard>
+      <LanguageStandard>stdcpplatest</LanguageStandard>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
@@ -140,6 +141,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\debug\Framework.dll Framework.dll</C
       <PreprocessorDefinitions>NDEBUG;_CONSOLE;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>true</ConformanceMode>
       <LanguageStandard>stdcpp20</LanguageStandard>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
@@ -157,7 +159,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     </CustomBuildStep>
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClCompile Include="..\FactoryCraft\AddEntityUpdate.cpp" />
     <ClCompile Include="..\FactoryCraft\Animal.cpp" />
     <ClCompile Include="..\FactoryCraft\AnimalAI.cpp" />
     <ClCompile Include="..\FactoryCraft\Area.cpp" />
@@ -167,11 +168,14 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\BasicTool.cpp" />
     <ClCompile Include="..\FactoryCraft\BiomGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\Block.cpp" />
+    <ClCompile Include="..\FactoryCraft\BlockComponent.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockFilter.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockInfoCommand.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockInstanceGeneratorRule.cpp" />
+    <ClCompile Include="..\FactoryCraft\BlockReplacementDrop.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockType.cpp" />
     <ClCompile Include="..\FactoryCraft\BlockTypeGeneratorRule.cpp" />
+    <ClCompile Include="..\FactoryCraft\BlockTypeNameFactory.cpp" />
     <ClCompile Include="..\FactoryCraft\CaveGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\Chat.cpp" />
     <ClCompile Include="..\FactoryCraft\ChatCommand.cpp" />
@@ -182,25 +186,34 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\Chunk.cpp" />
     <ClCompile Include="..\FactoryCraft\ChunkMap.cpp" />
     <ClCompile Include="..\FactoryCraft\CraftingStorage.cpp" />
+    <ClCompile Include="..\FactoryCraft\DefaultBlockItemDrop.cpp" />
+    <ClCompile Include="..\FactoryCraft\DefaultInventoryDrop.cpp" />
     <ClCompile Include="..\FactoryCraft\Dimension.cpp" />
     <ClCompile Include="..\FactoryCraft\DimensionGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\DimensionMap.cpp" />
     <ClCompile Include="..\FactoryCraft\DoLaterHandler.cpp" />
+    <ClCompile Include="..\FactoryCraft\DropChanceCondition.cpp" />
+    <ClCompile Include="..\FactoryCraft\DropConditionOperator.cpp" />
+    <ClCompile Include="..\FactoryCraft\DropConfig.cpp" />
+    <ClCompile Include="..\FactoryCraft\DropUsedItemCondition.cpp" />
     <ClCompile Include="..\FactoryCraft\Entity.cpp" />
-    <ClCompile Include="..\FactoryCraft\EntityRemovedUpdate.cpp" />
+    <ClCompile Include="..\FactoryCraft\EntityGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\EntityType.cpp" />
     <ClCompile Include="..\FactoryCraft\FactorizeNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\FastNoiseWrapper.cpp" />
+    <ClCompile Include="..\FactoryCraft\FireBasedProcessingBlockComponent.cpp" />
     <ClCompile Include="..\FactoryCraft\FlattenNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\FluidBlock.cpp" />
     <ClCompile Include="..\FactoryCraft\FluidContainer.cpp" />
     <ClCompile Include="..\FactoryCraft\Game.cpp" />
+    <ClCompile Include="..\FactoryCraft\GameClient.cpp" />
     <ClCompile Include="..\FactoryCraft\GeneratedStructure.cpp" />
     <ClCompile Include="..\FactoryCraft\GeneratorTemplate.cpp" />
     <ClCompile Include="..\FactoryCraft\GeneratorRule.cpp" />
     <ClCompile Include="..\FactoryCraft\GrantCommand.cpp" />
     <ClCompile Include="..\FactoryCraft\Grass.cpp" />
     <ClCompile Include="..\FactoryCraft\InformationObserver.cpp" />
+    <ClCompile Include="..\FactoryCraft\InteractionConfig.cpp" />
     <ClCompile Include="..\FactoryCraft\Inventory.cpp" />
     <ClCompile Include="..\FactoryCraft\Item.cpp" />
     <ClCompile Include="..\FactoryCraft\ItemEntity.cpp" />
@@ -210,20 +223,25 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\ItemSlot.cpp" />
     <ClCompile Include="..\FactoryCraft\ItemStack.cpp" />
     <ClCompile Include="..\FactoryCraft\ItemType.cpp" />
+    <ClCompile Include="..\FactoryCraft\ItemTypeNameFactory.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" />
+    <ClCompile Include="..\FactoryCraft\MultiblockStructureManager.cpp" />
     <ClCompile Include="..\FactoryCraft\MultiblockTree.cpp" />
     <ClCompile Include="..\FactoryCraft\MultiplyNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\NegateNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\NetworkMessage.cpp" />
+    <ClCompile Include="..\FactoryCraft\NeutralAnimalAI.cpp" />
     <ClCompile Include="..\FactoryCraft\NoBlock.cpp" />
     <ClCompile Include="..\FactoryCraft\Noise.cpp" />
     <ClCompile Include="..\FactoryCraft\NoiseInterpolator.cpp" />
+    <ClCompile Include="..\FactoryCraft\OpenDialogInteractionConfig.cpp" />
     <ClCompile Include="..\FactoryCraft\PlaceableProof.cpp" />
+    <ClCompile Include="..\FactoryCraft\PlantConfig.cpp" />
     <ClCompile Include="..\FactoryCraft\Player.cpp" />
     <ClCompile Include="..\FactoryCraft\PlayerHand.cpp" />
     <ClCompile Include="..\FactoryCraft\PlayerRegister.cpp" />
@@ -232,6 +250,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\QuestEvent.cpp" />
     <ClCompile Include="..\FactoryCraft\QuestRequirement.cpp" />
     <ClCompile Include="..\FactoryCraft\QuestReward.cpp" />
+    <ClCompile Include="..\FactoryCraft\RecipieGroupConfig.cpp" />
     <ClCompile Include="..\FactoryCraft\RecipieList.cpp" />
     <ClCompile Include="..\FactoryCraft\RandNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\Recipie.cpp" />
@@ -240,6 +259,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\SpecificItemDrop.cpp" />
     <ClCompile Include="..\FactoryCraft\Start.cpp" />
     <ClCompile Include="..\FactoryCraft\StructureCollection.cpp" />
     <ClCompile Include="..\FactoryCraft\TickOrganizer.cpp" />
@@ -248,29 +268,51 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\TreeSeblingBlock.cpp" />
     <ClCompile Include="..\FactoryCraft\TreeTemplate.cpp" />
     <ClCompile Include="..\FactoryCraft\GrowingPlant.cpp" />
-    <ClCompile Include="..\FactoryCraft\TypeRegistry.cpp" />
+    <ClCompile Include="..\FactoryCraft\TypeRegistry.cpp">
+      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/bigobj</AdditionalOptions>
+    </ClCompile>
     <ClCompile Include="..\FactoryCraft\UIController.cpp" />
+    <ClCompile Include="..\FactoryCraft\UICraftingGrid.cpp" />
+    <ClCompile Include="..\FactoryCraft\UICraftingProgress.cpp" />
     <ClCompile Include="..\FactoryCraft\UIDialog.cpp" />
+    <ClCompile Include="..\FactoryCraft\UIDialogElement.cpp" />
+    <ClCompile Include="..\FactoryCraft\UIElement.cpp" />
+    <ClCompile Include="..\FactoryCraft\UIFuelState.cpp" />
+    <ClCompile Include="..\FactoryCraft\UIInventory.cpp" />
+    <ClCompile Include="..\FactoryCraft\UIObservable.cpp" />
+    <ClCompile Include="..\FactoryCraft\UIReference.cpp" />
+    <ClCompile Include="..\FactoryCraft\UIText.cpp" />
     <ClCompile Include="..\FactoryCraft\WorldGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\WorldLoader.cpp" />
-    <ClCompile Include="..\FactoryCraft\WorldUpdate.cpp" />
     <ClCompile Include="..\FactoryCraft\WormCaveGenerator.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\FactoryCraft\Animal.h" />
     <ClInclude Include="..\FactoryCraft\AnimalAI.h" />
     <ClInclude Include="..\FactoryCraft\ArrayUtils.h" />
+    <ClInclude Include="..\FactoryCraft\BlockComponent.h" />
     <ClInclude Include="..\FactoryCraft\BlockFilter.h" />
     <ClInclude Include="..\FactoryCraft\BlockInfoCommand.h" />
     <ClInclude Include="..\FactoryCraft\BlockInstanceGeneratorRule.h" />
+    <ClInclude Include="..\FactoryCraft\BlockReplacementDrop.h" />
+    <ClInclude Include="..\FactoryCraft\BlockTypeNameFactory.h" />
+    <ClInclude Include="..\FactoryCraft\DefaultBlockItemDrop.h" />
+    <ClInclude Include="..\FactoryCraft\DefaultInventoryDrop.h" />
+    <ClInclude Include="..\FactoryCraft\DropChanceCondition.h" />
+    <ClInclude Include="..\FactoryCraft\DropCondition.h" />
+    <ClInclude Include="..\FactoryCraft\DropConditionOperator.h" />
+    <ClInclude Include="..\FactoryCraft\DropConfig.h" />
+    <ClInclude Include="..\FactoryCraft\DropUsedItemCondition.h" />
+    <ClInclude Include="..\FactoryCraft\EntityGenerator.h" />
     <ClInclude Include="..\FactoryCraft\FactorizeNoise.h" />
+    <ClInclude Include="..\FactoryCraft\FireBasedProcessingBlockComponent.h" />
     <ClInclude Include="..\FactoryCraft\FlattenNoise.h" />
     <ClInclude Include="..\FactoryCraft\FluidContainer.h" />
+    <ClInclude Include="..\FactoryCraft\GameClient.h" />
     <ClInclude Include="..\FactoryCraft\GeneratorRule.h" />
     <ClInclude Include="..\FactoryCraft\BlockTypeGeneratorRule.h" />
     <ClInclude Include="..\FactoryCraft\Chest.h" />
     <ClInclude Include="..\FactoryCraft\ChunkMap.h" />
-    <ClInclude Include="..\FactoryCraft\AddEntityUpdate.h" />
     <ClInclude Include="..\FactoryCraft\Area.h" />
     <ClInclude Include="..\FactoryCraft\BasicBlocks.h" />
     <ClInclude Include="..\FactoryCraft\BasicItems.h" />
@@ -288,10 +330,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\CraftingStorage.h" />
     <ClInclude Include="..\FactoryCraft\DimensionGenerator.h" />
     <ClInclude Include="..\FactoryCraft\DoLaterHandler.h" />
-    <ClInclude Include="..\FactoryCraft\Effect.h" />
-    <ClInclude Include="..\FactoryCraft\EffectFactory.h" />
     <ClInclude Include="..\FactoryCraft\Entity.h" />
-    <ClInclude Include="..\FactoryCraft\EntityRemovedUpdate.h" />
     <ClInclude Include="..\FactoryCraft\EntityType.h" />
     <ClInclude Include="..\FactoryCraft\FastNoiseLite.h" />
     <ClInclude Include="..\FactoryCraft\FastNoiseWrapper.h" />
@@ -303,6 +342,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\Grass.h" />
     <ClInclude Include="..\FactoryCraft\Chat.h" />
     <ClInclude Include="..\FactoryCraft\InformationObserver.h" />
+    <ClInclude Include="..\FactoryCraft\InteractionConfig.h" />
     <ClInclude Include="..\FactoryCraft\Inventory.h" />
     <ClInclude Include="..\FactoryCraft\Item.h" />
     <ClInclude Include="..\FactoryCraft\ItemEntity.h" />
@@ -312,6 +352,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\ItemSlot.h" />
     <ClInclude Include="..\FactoryCraft\ItemStack.h" />
     <ClInclude Include="..\FactoryCraft\ItemType.h" />
+    <ClInclude Include="..\FactoryCraft\ItemTypeNameFactory.h" />
     <ClInclude Include="..\FactoryCraft\JNoise.h" />
     <ClInclude Include="..\FactoryCraft\JsonExpression.h" />
     <ClInclude Include="..\FactoryCraft\JsonUtils.h" />
@@ -319,14 +360,18 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\DimensionMap.h" />
     <ClInclude Include="..\FactoryCraft\ModelInfo.h" />
     <ClInclude Include="..\FactoryCraft\MultiblockStructure.h" />
+    <ClInclude Include="..\FactoryCraft\MultiblockStructureManager.h" />
     <ClInclude Include="..\FactoryCraft\MultiblockTree.h" />
     <ClInclude Include="..\FactoryCraft\MultiplyNoise.h" />
     <ClInclude Include="..\FactoryCraft\NegateNoise.h" />
     <ClInclude Include="..\FactoryCraft\NetworkMessage.h" />
+    <ClInclude Include="..\FactoryCraft\NeutralAnimalAI.h" />
     <ClInclude Include="..\FactoryCraft\Noise.h" />
     <ClInclude Include="..\FactoryCraft\NoBlock.h" />
     <ClInclude Include="..\FactoryCraft\NoiseInterpolator.h" />
+    <ClInclude Include="..\FactoryCraft\OpenDialogInteractionConfig.h" />
     <ClInclude Include="..\FactoryCraft\PlaceableProof.h" />
+    <ClInclude Include="..\FactoryCraft\PlantConfig.h" />
     <ClInclude Include="..\FactoryCraft\Player.h" />
     <ClInclude Include="..\FactoryCraft\PlayerHand.h" />
     <ClInclude Include="..\FactoryCraft\PlayerRegister.h" />
@@ -337,6 +382,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\QuestReward.h" />
     <ClInclude Include="..\FactoryCraft\RandNoise.h" />
     <ClInclude Include="..\FactoryCraft\Recipie.h" />
+    <ClInclude Include="..\FactoryCraft\RecipieGroupConfig.h" />
     <ClInclude Include="..\FactoryCraft\RecipieList.h" />
     <ClInclude Include="..\FactoryCraft\RecipieLoader.h" />
     <ClInclude Include="..\FactoryCraft\SaveCommand.h" />
@@ -344,6 +390,7 @@ 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\SpecificItemDrop.h" />
     <ClInclude Include="..\FactoryCraft\StructureCollection.h" />
     <ClInclude Include="..\FactoryCraft\Tickable.h" />
     <ClInclude Include="..\FactoryCraft\TickOrganizer.h" />
@@ -355,10 +402,18 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\GrowingPlant.h" />
     <ClInclude Include="..\FactoryCraft\TypeRegistry.h" />
     <ClInclude Include="..\FactoryCraft\UIController.h" />
+    <ClInclude Include="..\FactoryCraft\UICraftingGrid.h" />
+    <ClInclude Include="..\FactoryCraft\UICraftingProgress.h" />
     <ClInclude Include="..\FactoryCraft\UIDialog.h" />
+    <ClInclude Include="..\FactoryCraft\UIDialogElement.h" />
+    <ClInclude Include="..\FactoryCraft\UIElement.h" />
+    <ClInclude Include="..\FactoryCraft\UIFuelState.h" />
+    <ClInclude Include="..\FactoryCraft\UIInventory.h" />
+    <ClInclude Include="..\FactoryCraft\UIObservable.h" />
+    <ClInclude Include="..\FactoryCraft\UIReference.h" />
+    <ClInclude Include="..\FactoryCraft\UIText.h" />
     <ClInclude Include="..\FactoryCraft\WorldGenerator.h" />
     <ClInclude Include="..\FactoryCraft\WorldLoader.h" />
-    <ClInclude Include="..\FactoryCraft\WorldUpdate.h" />
     <ClInclude Include="..\FactoryCraft\WormCaveGenerator.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 204 - 30
Windows Version/Windows Version.vcxproj.filters

@@ -7,9 +7,6 @@
     <Filter Include="game">
       <UniqueIdentifier>{26d8996d-452d-4c1f-b52b-82310b4ee42f}</UniqueIdentifier>
     </Filter>
-    <Filter Include="effects">
-      <UniqueIdentifier>{d758dbfd-2172-4c68-bc59-b39c289c28df}</UniqueIdentifier>
-    </Filter>
     <Filter Include="entities">
       <UniqueIdentifier>{56ad694e-70aa-4ef4-b698-7ff7755b3e60}</UniqueIdentifier>
     </Filter>
@@ -28,9 +25,6 @@
     <Filter Include="world\ticking">
       <UniqueIdentifier>{03a72d46-51b8-4f26-b04a-f5f4d4f5af6e}</UniqueIdentifier>
     </Filter>
-    <Filter Include="world\update">
-      <UniqueIdentifier>{05bf4218-e0cd-4d0d-bd7b-eaea87023838}</UniqueIdentifier>
-    </Filter>
     <Filter Include="world\loader">
       <UniqueIdentifier>{12fac988-c4d8-4db8-b4a8-1c025f117866}</UniqueIdentifier>
     </Filter>
@@ -106,6 +100,33 @@
     <Filter Include="entities\animals">
       <UniqueIdentifier>{1c04d738-2f59-40e4-9660-14aaf6bf68aa}</UniqueIdentifier>
     </Filter>
+    <Filter Include="world\generator\biom\entityGenerator">
+      <UniqueIdentifier>{87911234-37d0-41ac-975c-329d2963ca52}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="drops">
+      <UniqueIdentifier>{79a25f96-c848-40a9-ad5f-f26d89fcd0ad}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="drops\conditions">
+      <UniqueIdentifier>{df6eb2a2-0491-4687-92ce-dd34edaaee45}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="drops\implementations">
+      <UniqueIdentifier>{d4e7dadf-eb55-4257-ad1b-90d18018a9fe}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="UI\UIElements">
+      <UniqueIdentifier>{327469e3-2704-4e52-b31a-2e3823386ad9}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="interaction">
+      <UniqueIdentifier>{7d7c98b1-2773-42e7-8c68-6cdb7519fa0f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="world\blocks\components">
+      <UniqueIdentifier>{a9dadb06-9971-42a7-82e0-81ac95faa38f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="UI\Observable">
+      <UniqueIdentifier>{0959e746-5b3e-4592-b633-8899ba10be59}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="world\generator\biom\plants">
+      <UniqueIdentifier>{a0c4e992-95df-42f1-8e50-bc332ce9f179}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\FactoryCraft\Server.cpp">
@@ -150,9 +171,6 @@
     <ClCompile Include="..\FactoryCraft\WorldLoader.cpp">
       <Filter>world\loader</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\WorldUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\Dimension.cpp">
       <Filter>world</Filter>
     </ClCompile>
@@ -195,12 +213,6 @@
     <ClCompile Include="..\FactoryCraft\ItemEntity.cpp">
       <Filter>entities</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\AddEntityUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
-    <ClCompile Include="..\FactoryCraft\EntityRemovedUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\GeneratedStructure.cpp">
       <Filter>world\generator\templates</Filter>
     </ClCompile>
@@ -402,6 +414,93 @@
     <ClCompile Include="..\FactoryCraft\Animal.cpp">
       <Filter>entities\animals</Filter>
     </ClCompile>
+    <ClCompile Include="..\FactoryCraft\EntityGenerator.cpp">
+      <Filter>world\generator\biom\entityGenerator</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\NeutralAnimalAI.cpp">
+      <Filter>entities\animals</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\GameClient.cpp">
+      <Filter>game</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\BlockTypeNameFactory.cpp">
+      <Filter>server\config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\ItemTypeNameFactory.cpp">
+      <Filter>server\config</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\DropChanceCondition.cpp">
+      <Filter>drops\conditions</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\DropConditionOperator.cpp">
+      <Filter>drops\conditions</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\DropUsedItemCondition.cpp">
+      <Filter>drops\conditions</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\DefaultBlockItemDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\DefaultInventoryDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\SpecificItemDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\DropConfig.cpp">
+      <Filter>drops</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\MultiblockStructureManager.cpp">
+      <Filter>world\structures</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\BlockReplacementDrop.cpp">
+      <Filter>drops\implementations</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UICraftingGrid.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UIDialogElement.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UIInventory.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UIText.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UIElement.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UIReference.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\InteractionConfig.cpp">
+      <Filter>interaction</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\OpenDialogInteractionConfig.cpp">
+      <Filter>interaction</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\BlockComponent.cpp">
+      <Filter>world\blocks\components</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\FireBasedProcessingBlockComponent.cpp">
+      <Filter>world\blocks\components</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UICraftingProgress.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UIFuelState.cpp">
+      <Filter>UI\UIElements</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\UIObservable.cpp">
+      <Filter>UI\Observable</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\RecipieGroupConfig.cpp">
+      <Filter>inventory\recipies</Filter>
+    </ClCompile>
+    <ClCompile Include="..\FactoryCraft\PlantConfig.cpp">
+      <Filter>world\generator\biom\plants</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\FactoryCraft\Chunk.h">
@@ -437,12 +536,6 @@
     <ClInclude Include="..\FactoryCraft\ItemSlot.h">
       <Filter>inventory</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\Effect.h">
-      <Filter>effects</Filter>
-    </ClInclude>
-    <ClInclude Include="..\FactoryCraft\EffectFactory.h">
-      <Filter>effects</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\ItemSkill.h">
       <Filter>inventory</Filter>
     </ClInclude>
@@ -464,9 +557,6 @@
     <ClInclude Include="..\FactoryCraft\TickOrganizer.h">
       <Filter>world\ticking</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\WorldUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\EntityType.h">
       <Filter>entities</Filter>
     </ClInclude>
@@ -494,12 +584,6 @@
     <ClInclude Include="..\FactoryCraft\ItemEntity.h">
       <Filter>entities</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\AddEntityUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
-    <ClInclude Include="..\FactoryCraft\EntityRemovedUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\GeneratorTemplate.h">
       <Filter>world\generator\templates</Filter>
     </ClInclude>
@@ -713,5 +797,95 @@
     <ClInclude Include="..\FactoryCraft\TickSourceType.h">
       <Filter>world\ticking</Filter>
     </ClInclude>
+    <ClInclude Include="..\FactoryCraft\EntityGenerator.h">
+      <Filter>world\generator\biom\entityGenerator</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\NeutralAnimalAI.h">
+      <Filter>entities\animals</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\GameClient.h">
+      <Filter>game</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\BlockTypeNameFactory.h">
+      <Filter>server\config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\ItemTypeNameFactory.h">
+      <Filter>server\config</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\DropCondition.h">
+      <Filter>drops</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\DropConfig.h">
+      <Filter>drops</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\DropChanceCondition.h">
+      <Filter>drops\conditions</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\DropConditionOperator.h">
+      <Filter>drops\conditions</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\DropUsedItemCondition.h">
+      <Filter>drops\conditions</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\DefaultBlockItemDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\DefaultInventoryDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\SpecificItemDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\MultiblockStructureManager.h">
+      <Filter>world\structures</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\BlockReplacementDrop.h">
+      <Filter>drops\implementations</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UICraftingGrid.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIDialogElement.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIInventory.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIText.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIElement.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIReference.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\InteractionConfig.h">
+      <Filter>interaction</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\OpenDialogInteractionConfig.h">
+      <Filter>interaction</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\BlockComponent.h">
+      <Filter>world\blocks\components</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\FireBasedProcessingBlockComponent.h">
+      <Filter>world\blocks\components</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UICraftingProgress.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIFuelState.h">
+      <Filter>UI\UIElements</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\UIObservable.h">
+      <Filter>UI\Observable</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\RecipieGroupConfig.h">
+      <Filter>inventory\recipies</Filter>
+    </ClInclude>
+    <ClInclude Include="..\FactoryCraft\PlantConfig.h">
+      <Filter>world\generator\biom\plants</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 973 - 147
Windows Version/data/blocks/blockTypes.json

@@ -15,12 +15,14 @@
       ]
     },
     "mapColor": "0xFF3C7C29",
-    "groupNames": [ "Shovel" ]
+    "groupNames": [
+      "Shovel"
+    ]
   },
   {
     "type": "basicBlock",
     "name": "Stone",
-    "itemType": "Stone",
+    "itemType": "Stone Block",
     "model": {
       "modelPath": "cube",
       "texturePaths": [
@@ -52,7 +54,9 @@
     },
     "mapColor": "0xFFAE8558",
     "hardness": 0.5,
-    "groupNames": [ "Shovel" ]
+    "groupNames": [
+      "Shovel"
+    ]
   },
   {
     "type": "basicBlock",
@@ -65,16 +69,101 @@
         "blocks.ltdb/oak.png",
         "blocks.ltdb/oak.png",
         "blocks.ltdb/oak.png",
-        "blocks.ltdb/oak.png",
-        "blocks.ltdb/oak.png"
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
+      ]
+    },
+    "mapColor": "0xFF7F7A70",
+    "hardness": 1.5,
+    "groupNames": [
+      "Wood"
+    ],
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "blockReplacement",
+        "condition": {
+          "type": "noItem"
+        },
+        "blockType": "Stripped Oak Wood"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "blockItem",
+        "condition": {
+          "type": "not",
+          "condition": {
+            "type": "noItem"
+          }
+        }
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Stripped Oak Wood",
+    "itemType": null,
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
       ]
     },
     "mapColor": "0xFF7F7A70",
     "hardness": 1.5,
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ],
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "allways"
+        },
+        "itemType": "Oak Wood"
+      }
+    ]
   },
   {
-    "type": "additionalItemsBlockType",
+    "type": "basicBlock",
     "name": "Oak Wood Leaves",
     "itemType": "Oak Wood Leaves",
     "model": {
@@ -90,12 +179,25 @@
     },
     "mapColor": "0xFF6A7C37",
     "hardness": 0.1,
-    "spawns": [
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.015
+        },
+        "amount": 1,
+        "itemType": "Oak Wood Sapling"
+      },
       {
-        "min": 1,
-        "max": 1,
-        "itemType": "Oak Wood Sapling",
-        "chance": 0.015
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.2
+        },
+        "amount": 1,
+        "itemType": "Wooden Stick"
       }
     ],
     "groupNames": [
@@ -119,7 +221,55 @@
     },
     "mapColor": "0xFF928D8C",
     "hardness": 0.75,
-    "groupNames": [ "Shovel" ]
+    "groupNames": [
+      "Shovel"
+    ],
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "blockItem",
+        "condition": {
+          "type": "not",
+          "condition": {
+            "type": "noItem"
+          }
+        }
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.2
+            }
+          ]
+        },
+        "itemType": "Flint"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.5
+            }
+          ]
+        },
+        "itemType": "Stone"
+      }
+    ]
   },
   {
     "type": "basicBlock",
@@ -167,16 +317,101 @@
         "blocks.ltdb/birch.png",
         "blocks.ltdb/birch.png",
         "blocks.ltdb/birch.png",
-        "blocks.ltdb/birch.png",
-        "blocks.ltdb/birch.png"
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
       ]
     },
     "mapColor": "0xFF99999D",
     "hardness": 1.5,
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ],
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "blockReplacement",
+        "condition": {
+          "type": "noItem"
+        },
+        "blockType": "Stripped Birch Wood"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "blockItem",
+        "condition": {
+          "type": "not",
+          "condition": {
+            "type": "noItem"
+          }
+        }
+      }
+    ]
   },
   {
-    "type": "additionalItemsBlockType",
+    "type": "basicBlock",
+    "name": "Stripped Birch Wood",
+    "itemType": null,
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
+      ]
+    },
+    "mapColor": "0xFF99999D",
+    "hardness": 1.5,
+    "groupNames": [
+      "Wood"
+    ],
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "allways"
+        },
+        "itemType": "Birch Wood"
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
     "name": "Birch Wood Leaves",
     "itemType": "Birch Wood Leaves",
     "model": {
@@ -192,12 +427,25 @@
     },
     "mapColor": "0xFF6A7C37",
     "hardness": 0.1,
-    "spawns": [
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.03
+        },
+        "amount": 1,
+        "itemType": "Birch Wood Sapling"
+      },
       {
-        "min": 1,
-        "max": 1,
-        "itemType": "Birch Wood Sapling",
-        "chance": 0.03
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.2
+        },
+        "amount": 1,
+        "itemType": "Wooden Stick"
       }
     ],
     "groupNames": [
@@ -215,16 +463,101 @@
         "blocks.ltdb/beech.png",
         "blocks.ltdb/beech.png",
         "blocks.ltdb/beech.png",
-        "blocks.ltdb/beech.png",
-        "blocks.ltdb/beech.png"
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
       ]
     },
     "mapColor": "0xFF778172",
     "hardness": 1.5,
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ],
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "blockReplacement",
+        "condition": {
+          "type": "noItem"
+        },
+        "blockType": "Stripped Beech Wood"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "blockItem",
+        "condition": {
+          "type": "not",
+          "condition": {
+            "type": "noItem"
+          }
+        }
+      }
+    ]
   },
   {
-    "type": "additionalItemsBlockType",
+    "type": "basicBlock",
+    "name": "Stripped Beech Wood",
+    "itemType": null,
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
+      ]
+    },
+    "mapColor": "0xFF778172",
+    "hardness": 1.5,
+    "groupNames": [
+      "Wood"
+    ],
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "allways"
+        },
+        "itemType": "Beech Wood"
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
     "name": "Beech Wood Leaves",
     "itemType": "Beech Wood Leaves",
     "model": {
@@ -240,12 +573,25 @@
     },
     "mapColor": "0xFF6A7C37",
     "hardness": 0.1,
-    "spawns": [
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.02
+        },
+        "amount": 1,
+        "itemType": "Beech Wood Sapling"
+      },
       {
-        "min": 1,
-        "max": 1,
-        "itemType": "Beech Wood Sapling",
-        "chance": 0.02
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.2
+        },
+        "amount": 1,
+        "itemType": "Wooden Stick"
       }
     ],
     "groupNames": [
@@ -281,16 +627,118 @@
         "blocks.ltdb/pine.png",
         "blocks.ltdb/pine.png",
         "blocks.ltdb/pine.png",
-        "blocks.ltdb/pine.png",
-        "blocks.ltdb/pine.png"
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
       ]
     },
     "mapColor": "0xFF786C72",
     "hardness": 1.4,
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ],
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "blockReplacement",
+        "condition": {
+          "type": "noItem"
+        },
+        "blockType": "Stripped Pine Wood"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.75
+            }
+          ]
+        },
+        "itemType": "Tree bark"
+      },
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "operator",
+          "operator": "AND",
+          "conditions": [
+            {
+              "type": "noItem"
+            },
+            {
+              "type": "chance",
+              "chance": 0.25
+            }
+          ]
+        },
+        "itemType": "Resin"
+      },
+      {
+        "type": "blockItem",
+        "condition": {
+          "type": "not",
+          "condition": {
+            "type": "noItem"
+          }
+        }
+      }
+    ]
   },
   {
-    "type": "additionalItemsBlockType",
+    "type": "basicBlock",
+    "name": "Stripped Pine Wood",
+    "itemType": null,
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png",
+        "blocks.ltdb/wood.png"
+      ]
+    },
+    "mapColor": "0xFF786C72",
+    "hardness": 1.4,
+    "groupNames": [
+      "Wood"
+    ],
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "allways"
+        },
+        "itemType": "Pine Wood"
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
     "name": "Pine Wood Leaves",
     "itemType": "Pine Wood Leaves",
     "model": {
@@ -306,12 +754,25 @@
     },
     "mapColor": "0xFF6A7C37",
     "hardness": 0.1,
-    "spawns": [
+    "damagableByHand": true,
+    "drops": [
+      {
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.025
+        },
+        "amount": 1,
+        "itemType": "Pine Wood Sapling"
+      },
       {
-        "min": 1,
-        "max": 1,
-        "itemType": "Pine Wood Sapling",
-        "chance": 0.025
+        "type": "specificItem",
+        "condition": {
+          "type": "chance",
+          "chance": 0.2
+        },
+        "amount": 1,
+        "itemType": "Wooden Stick"
       }
     ],
     "groupNames": [
@@ -336,7 +797,9 @@
     "mapColor": "0x00F69A54",
     "lightColor": "0x00F69A54",
     "hardness": 0,
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ]
   },
   {
     "type": "treeSapling",
@@ -352,7 +815,9 @@
     "hardness": 0.1,
     "woodType": "Oak Wood",
     "leavesType": "Oak Wood Leaves",
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ]
   },
   {
     "type": "treeSapling",
@@ -368,7 +833,9 @@
     "hardness": 0.1,
     "woodType": "Birch Wood",
     "leavesType": "Birch Wood Leaves",
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ]
   },
   {
     "type": "treeSapling",
@@ -384,7 +851,9 @@
     "hardness": 0.1,
     "woodType": "Beech Wood",
     "leavesType": "Beech Wood Leaves",
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ]
   },
   {
     "type": "treeSapling",
@@ -400,29 +869,8 @@
     "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
-    },
-    "transparent": true,
-    "passable": true,
-    "speedModifier": 0.5,
-    "mapColor": "0x5076C011",
-    "spawns": [
-      {
-        "min": 1,
-        "max": 1,
-        "itemType": "Wheat Seeds",
-        "chance": 0.1
-      }
+    "groupNames": [
+      "Wood"
     ]
   },
   {
@@ -442,84 +890,8 @@
     },
     "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
-      }
+    "groupNames": [
+      "Shovel"
     ]
   },
   {
@@ -562,7 +934,9 @@
       ]
     },
     "mapColor": "0xFFC4A783",
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ]
   },
   {
     "type": "chest",
@@ -576,6 +950,458 @@
       ]
     },
     "mapColor": "0xFFE2C292",
-    "groupNames": [ "Wood" ]
+    "groupNames": [
+      "Wood"
+    ],
+    "inventorySlots": [
+      {
+        "pullPriority": 1,
+        "pushPriority": 1
+      },
+      {
+        "pullPriority": 2,
+        "pushPriority": 2
+      },
+      {
+        "pullPriority": 3,
+        "pushPriority": 3
+      },
+      {
+        "pullPriority": 4,
+        "pushPriority": 4
+      },
+      {
+        "pullPriority": 5,
+        "pushPriority": 5
+      },
+      {
+        "pullPriority": 6,
+        "pushPriority": 6
+      },
+      {
+        "pullPriority": 7,
+        "pushPriority": 7
+      },
+      {
+        "pullPriority": 8,
+        "pushPriority": 8
+      },
+      {
+        "pullPriority": 9,
+        "pushPriority": 9
+      },
+      {
+        "pullPriority": 10,
+        "pushPriority": 10
+      },
+      {
+        "pullPriority": 11,
+        "pushPriority": 11
+      },
+      {
+        "pullPriority": 12,
+        "pushPriority": 12
+      },
+      {
+        "pullPriority": 13,
+        "pushPriority": 13
+      },
+      {
+        "pullPriority": 14,
+        "pushPriority": 14
+      },
+      {
+        "pullPriority": 15,
+        "pushPriority": 15
+      },
+      {
+        "pullPriority": 16,
+        "pushPriority": 16
+      },
+      {
+        "pullPriority": 17,
+        "pushPriority": 17
+      },
+      {
+        "pullPriority": 18,
+        "pushPriority": 18
+      },
+      {
+        "pullPriority": 19,
+        "pushPriority": 19
+      },
+      {
+        "pullPriority": 20,
+        "pushPriority": 20
+      },
+      {
+        "pullPriority": 21,
+        "pushPriority": 21
+      },
+      {
+        "pullPriority": 22,
+        "pushPriority": 22
+      },
+      {
+        "pullPriority": 23,
+        "pushPriority": 23
+      },
+      {
+        "pullPriority": 24,
+        "pushPriority": 24
+      },
+      {
+        "pullPriority": 25,
+        "pushPriority": 25
+      },
+      {
+        "pullPriority": 26,
+        "pushPriority": 26
+      },
+      {
+        "pullPriority": 27,
+        "pushPriority": 27
+      },
+      {
+        "pullPriority": 28,
+        "pushPriority": 28
+      },
+      {
+        "pullPriority": 29,
+        "pushPriority": 29
+      },
+      {
+        "pullPriority": 30,
+        "pushPriority": 30
+      }
+    ],
+    "interactions": [
+      {
+        "type": "OpenDialogInteractionConfig",
+        "dialogElement": {
+          "type": "dialog",
+          "id": "chest_inventory",
+          "title": "Chest",
+          "width": 610,
+          "height": 480,
+          "children": [
+            {
+              "type": "inventory",
+              "id": "chest_inventory",
+              "marginBottom": 18,
+              "alignBottom": "player_label",
+              "alignLeft": "start",
+              "marginLeft": 9,
+              "width": 592,
+              "height": 172,
+              "rowSize": 10,
+              "numSlots": 30,
+              "slotNameFilter": "",
+              "reference": {
+                "type": "target"
+              }
+            },
+            {
+              "type": "text",
+              "id": "player_label",
+              "width": "100%",
+              "height": "auto",
+              "style": "0x7003",
+              "marginBottom": 9,
+              "alignBottom": "player_inventory",
+              "text": "Player Inventory"
+            },
+            {
+              "type": "inventory",
+              "id": "player_inventory",
+              "marginBottom": 18,
+              "alignBottom": "item_bar",
+              "alignLeft": "start",
+              "marginLeft": 9,
+              "width": 592,
+              "height": 172,
+              "rowSize": 10,
+              "numSlots": 30,
+              "slotNameFilter": "Inventory",
+              "reference": {
+                "type": "actor"
+              }
+            },
+            {
+              "type": "inventory",
+              "id": "item_bar",
+              "marginBottom": 9,
+              "alignBottom": "end",
+              "alignLeft": "start",
+              "marginLeft": 9,
+              "width": 592,
+              "height": 52,
+              "rowSize": 10,
+              "numSlots": 10,
+              "slotNameFilter": "ItemBar",
+              "reference": {
+                "type": "actor"
+              }
+            }
+          ]
+        }
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Campfire",
+    "itemType": "Campfire",
+    "model": {
+      "modelPath": "blocks.m3/campfire",
+      "texturePaths": [
+        "blocks.ltdb/campfire.png"
+      ]
+    },
+    "mapColor": "0xFFE25822",
+    "components": [
+      {
+        "type": "fireBasedProcessing",
+        "fireStartingInventorySlotName": "fireStart",
+        "fuelInventorySlotName": "fuel",
+        "inputInventorySlotName": "input",
+        "outputInventorySlotName": "output",
+        "recipieGroup": "fire",
+        "fuelItemFilter": {
+          "type": "type",
+          "itemType": "Wooden Stick"
+        },
+        "fireStartingItemFilter": {
+          "type": "type",
+          "itemType": "Tree bark"
+        },
+        "lightColor": "0x00E25822"
+      }
+    ],
+    "inventorySlots": [
+      {
+        "category": "input",
+        "allowedPullSides": [],
+        "allowedPushSides": [
+          "BOTTOM",
+          "EAST",
+          "NORTH",
+          "SOUTH",
+          "TOP",
+          "WEST"
+        ],
+        "maxSize": 50,
+        "pushPriority": 1
+      },
+      {
+        "category": "fuel",
+        "allowedPullSides": [],
+        "allowedPushSides": [
+          "BOTTOM",
+          "EAST",
+          "NORTH",
+          "SOUTH",
+          "TOP",
+          "WEST"
+        ],
+        "maxSize": 50,
+        "pushPriority": 2
+      },
+      {
+        "category": "fireStart",
+        "allowedPullSides": [],
+        "allowedPushSides": [
+          "BOTTOM",
+          "EAST",
+          "NORTH",
+          "SOUTH",
+          "TOP",
+          "WEST"
+        ],
+        "maxSize": 50,
+        "pushPriority": 3
+      },
+      {
+        "category": "output",
+        "allowedPullSides": [
+          "BOTTOM",
+          "EAST",
+          "NORTH",
+          "SOUTH",
+          "TOP",
+          "WEST"
+        ],
+        "allowedPushSides": [],
+        "maxSize": 50,
+        "pullPriority": 1
+      }
+    ],
+    "lightSource": true,
+    "interactions": [
+      {
+        "type": "OpenDialogInteractionConfig",
+        "dialogElement": {
+          "type": "dialog",
+          "title": "Camp Fire",
+          "id": "fireDialog",
+          "width": 610,
+          "height": 480,
+          "children": [
+            {
+              "type": "inventory",
+              "id": "input",
+              "marginBottom": 10,
+              "alignBottom": "fuel_state",
+              "alignLeft": "start_input",
+              "marginLeft": 10,
+              "width": 52,
+              "height": 52,
+              "rowSize": 1,
+              "numSlots": 1,
+              "slotNameFilter": "input",
+              "reference": {
+                "type": "target"
+              }
+            },
+            {
+              "type": "craftingProgress",
+              "id": "crafting_progres",
+              "marginBottom": 10,
+              "alignBottom": "fuel_state",
+              "alignLeft": "input",
+              "marginLeft": 10,
+              "width": 50,
+              "height": 50,
+              "backgroundImagePath": "data/images/gui_icons.ltdb/craftingbg.png",
+              "foregroundImagePath": "data/images/gui_icons.ltdb/crafting.png",
+              "direction": "RIGHT",
+              "reference": {
+                "type": "targetComponent",
+                "componentIndex": 0
+              }
+            },
+            {
+              "type": "inventory",
+              "id": "output",
+              "marginBottom": 10,
+              "alignBottom": "fuel_state",
+              "alignLeft": "crafting_progres",
+              "marginLeft": 10,
+              "width": 52,
+              "height": 52,
+              "rowSize": 1,
+              "numSlots": 1,
+              "slotNameFilter": "output",
+              "reference": {
+                "type": "target"
+              }
+            },
+            {
+              "type": "fuelState",
+              "id": "fuel_state",
+              "marginBottom": 10,
+              "alignBottom": "fuel_input",
+              "alignLeft": "start_input",
+              "marginLeft": 10,
+              "width": 50,
+              "height": 50,
+              "backgroundImagePath": "data/images/gui_icons.ltdb/flamebg.png",
+              "foregroundImagePath": "data/images/gui_icons.ltdb/flame.png",
+              "direction": "TOP",
+              "reference": {
+                "type": "targetComponent",
+                "componentIndex": 0
+              }
+            },
+            {
+              "type": "inventory",
+              "id": "start_input",
+              "marginBottom": 18,
+              "alignBottom": "player_label",
+              "alignLeft": "start",
+              "marginLeft": 9,
+              "width": 52,
+              "height": 52,
+              "rowSize": 1,
+              "numSlots": 1,
+              "slotNameFilter": "fireStart",
+              "reference": {
+                "type": "target"
+              }
+            },
+            {
+              "type": "inventory",
+              "id": "fuel_input",
+              "marginBottom": 18,
+              "alignBottom": "player_label",
+              "alignLeft": "start_input",
+              "marginLeft": 9,
+              "width": 52,
+              "height": 52,
+              "rowSize": 1,
+              "numSlots": 1,
+              "slotNameFilter": "fuel",
+              "reference": {
+                "type": "target"
+              }
+            },
+            {
+              "type": "text",
+              "id": "player_label",
+              "width": "100%",
+              "height": "auto",
+              "style": "0x7003",
+              "marginBottom": 9,
+              "alignBottom": "player_inventory",
+              "text": "Player Inventory"
+            },
+            {
+              "type": "inventory",
+              "id": "player_inventory",
+              "marginBottom": 18,
+              "alignBottom": "item_bar",
+              "alignLeft": "start",
+              "marginLeft": 9,
+              "width": 592,
+              "height": 172,
+              "rowSize": 10,
+              "numSlots": 30,
+              "slotNameFilter": "Inventory",
+              "reference": {
+                "type": "actor"
+              }
+            },
+            {
+              "type": "inventory",
+              "id": "item_bar",
+              "marginBottom": 9,
+              "alignBottom": "end",
+              "alignLeft": "start",
+              "marginLeft": 9,
+              "width": 592,
+              "height": 52,
+              "rowSize": 10,
+              "numSlots": 10,
+              "slotNameFilter": "ItemBar",
+              "reference": {
+                "type": "actor"
+              }
+            }
+          ]
+        }
+      }
+    ]
+  },
+  {
+    "type": "basicBlock",
+    "name": "Vines",
+    "itemType": "Vines",
+    "model": {
+      "modelPath": "blocks.m3/vines",
+      "texturePaths": [
+        "blocks.ltdb/leaves.png"
+      ]
+    },
+    "mapColor": "0xFF33A033"
   }
 ]

+ 239 - 0
Windows Version/data/blocks/plants.json

@@ -0,0 +1,239 @@
+[
+    {
+        "type": "grass",
+        "name": "Grass",
+        "itemType": null,
+        "model": {
+            "modelPath": "grass",
+            "texturePaths": [
+                "blocks.ltdb/grass.png"
+            ],
+            "transparent": true
+        },
+        "damagableByHand": true,
+        "transparent": true,
+        "passable": true,
+        "speedModifier": 0.5,
+        "mapColor": "0x5076C011",
+        "drops": [
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.1
+                },
+                "amount": 1,
+                "itemType": "Wheat Seeds"
+            }
+        ]
+    },
+    {
+        "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,
+        "transparent": true,
+        "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": "basicBlock",
+        "name": "Wheat",
+        "itemType": null,
+        "model": {
+            "modelPath": "grass",
+            "texturePaths": [
+                "plants.ltdb/wheat.png"
+            ],
+            "transparent": true
+        },
+        "mapColor": "0x90A8C011",
+        "transparent": true,
+        "drops": [
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.6
+                },
+                "amount": 1,
+                "itemType": "Wheat"
+            },
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.6
+                },
+                "amount": 1,
+                "itemType": "Wheat"
+            },
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.6
+                },
+                "amount": 1,
+                "itemType": "Wheat"
+            },
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.6
+                },
+                "amount": 1,
+                "itemType": "Wheat"
+            }
+        ]
+    },
+    {
+        "type": "growingPlant",
+        "name": "CottonSeeds",
+        "readableName": "Growing Cotton",
+        "blockTypeAfterGrowth": "Cotton Plant",
+        "model": {
+            "modelPath": "grass",
+            "texturePaths": [
+                "plants.ltdb/cottonseeds.png"
+            ],
+            "transparent": true
+        },
+        "mapColor": "0x909090",
+        "hardness": 0.1,
+        "ticksNeeded": 18000,
+        "transparent": true,
+        "states": [
+            {
+                "percentage": 0,
+                "model": {
+                    "modelPath": "plants.m3/smallPlant",
+                    "texturePaths": [
+                        "plants.ltdb/smallplant.png"
+                    ]
+                }
+            },
+            {
+                "percentage": 0.5,
+                "model": {
+                    "modelPath": "plants.m3/cotton_growing",
+                    "texturePaths": [
+                        "plants.ltdb/cottongrowing."
+                    ]
+                }
+            }
+        ]
+    },
+    {
+        "type": "basicBlock",
+        "name": "Cotton Plant",
+        "itemType": null,
+        "model": {
+            "modelPath": "plants.m3/cotton",
+            "texturePaths": [
+                "plants.ltdb/cotton.png"
+            ],
+            "transparent": true
+        },
+        "mapColor": "0xB0B0B0",
+        "transparent": true,
+        "drops": [
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.75
+                },
+                "amount": 1,
+                "itemType": "Wool"
+            },
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.75
+                },
+                "amount": 1,
+                "itemType": "Wool"
+            },
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.75
+                },
+                "amount": 1,
+                "itemType": "Wool"
+            },
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.7
+                },
+                "amount": 1,
+                "itemType": "Cotton Seeds"
+            },
+            {
+                "type": "specificItem",
+                "condition": {
+                    "type": "chance",
+                    "chance": 0.4
+                },
+                "amount": 1,
+                "itemType": "Cotton Seeds"
+            }
+        ]
+    }
+]

+ 13 - 0
Windows Version/data/entities/animals.json

@@ -0,0 +1,13 @@
+[
+    {
+        "type": "animal",
+        "typeName": "Kow",
+        "drops": [],
+        "model": {
+            "modelPath": "entities.m3/kow",
+            "texturePaths": [
+                "entities.ltdb/kow.png"
+            ]
+        }
+    }
+]

+ 569 - 644
Windows Version/data/generator/overworld.json

@@ -1,685 +1,610 @@
 [
-  {
-    "type": "cavedBioms",
-    "name": "Overworld",
-    "id": 0,
-    "dimensionSeed": {
-      "type": "operator",
-      "operator": "+",
-      "values": [
-        {
-          "type": "variable",
-          "name": "worldSeed"
-        },
-        {
-          "type": "variable",
-          "name": "dimensionId"
-        }
-      ]
-    },
-    "biomNoise": {
-      "type": "Cellular",
-      "seed": {
-        "type": "variable",
-        "name": "dimensionSeed"
-      },
-      "rotationType3D": "None",
-      "frequency": 0.015,
-      "fractalType": "None",
-      "cellularDistanceFunction": "Hybrid",
-      "cellularReturnType": "CellValue",
-      "cellularJitter": 1,
-      "domainWarpType": "OpenSimplex2Reduced",
-      "domainWarpAmp": 30
-    },
-    "heightLayers": [
-      {
-        "name": "h",
-        "noise": {
-          "type": "factorize",
-          "noiseA": {
-            "type": "flatten",
-            "noise": {
-              "type": "Perlin",
-              "multiplier": 0.05,
-              "seed": {
-                "type": "operator",
-                "operator": "+",
-                "values": [
-                  {
-                    "type": "variable",
-                    "name": "dimensionSeed"
-                  },
-                  {
-                    "type": "constant",
-                    "value": 23
-                  }
-                ]
-              }
-            },
-            "factor": 0.5,
-            "addition": 0.25
-          },
-          "noiseB": {
-            "type": "multiply",
-            "base": {
-              "type": "factorize",
-              "noiseA": {
-                "type": "Perlin",
-                "frequency": 0.02,
-                "seed": {
-                  "type": "operator",
-                  "operator": "+",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "dimensionSeed"
-                    },
-                    {
-                      "type": "constant",
-                      "value": 22
-                    }
-                  ]
-                }
-              },
-              "noiseB": {
-                "type": "Perlin",
-                "frequency": 0.25,
-                "seed": {
-                  "type": "operator",
-                  "operator": "+",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "dimensionSeed"
-                    },
-                    {
-                      "type": "constant",
-                      "value": 21
-                    }
-                  ]
-                }
-              },
-              "factorA": 0.9
-            },
-            "multiplier": {
-              "type": "flatten",
-              "noise": {
-                "type": "scale",
-                "noise": {
-                  "type": "negate",
-                  "noise": {
-                    "type": "scale",
-                    "noise": {
-                      "type": "Cellular",
-                      "multiplier": 0.4,
-                      "frequency": 0.005,
-                      "rotationType3D": "None",
-                      "fractalType": "DomainWarpIndependent",
-                      "cellularDistanceFunction": "Euclidean",
-                      "cellularReturnType": "Distance",
-                      "cellularJitter": 1.5,
-                      "domainWarpType": "OpenSimplex2Reduced",
-                      "domainWarpAmp": 100,
-                      "fractalOctaves": 3,
-                      "fractalLacunarity": 2,
-                      "fractalGain": 0.5,
-                      "seed": {
-                        "type": "operator",
-                        "operator": "+",
-                        "values": [
-                          {
-                            "type": "variable",
-                            "name": "dimensionSeed"
-                          },
-                          {
-                            "type": "constant",
-                            "value": 20
-                          }
-                        ]
-                      }
-                    },
-                    "factor": 3.5
-                  }
-                },
-                "factor": 1.5
-              },
-              "factor": 0.95,
-              "addition": 0.05
-            }
-          },
-          "factorA": 0.5
-        },
-        "value": {
-          "type": "operator",
-          "operator": "+",
-          "values": [
-            {
-              "type": "constant",
-              "value": 50
-            },
-            {
-              "type": "operator",
-              "operator": "*",
-              "values": [
+    {
+        "type": "cavedBioms",
+        "name": "Overworld",
+        "id": 0,
+        "seaFluidBlockType": "Water",
+        "globalSeaLevel": 200,
+        "terrainHeightLeyerName": "h",
+        "dimensionSeed": {
+            "type": "operator",
+            "operator": "+",
+            "values": [
                 {
-                  "type": "noise",
-                  "name": "h",
-                  "x": {
-                    "type": "variable",
-                    "name": "x"
-                  },
-                  "y": {
                     "type": "variable",
-                    "name": "y"
-                  },
-                  "z": {
-                    "type": "constant",
-                    "value": 0
-                  }
+                    "name": "worldSeed"
                 },
                 {
-                  "type": "constant",
-                  "value": 400
-                }
-              ]
-            }
-          ]
-        }
-      },
-      {
-        "name": "u",
-        "noise": {
-          "type": "ValueCubic",
-          "seed": {
-            "type": "variable",
-            "name": "dimensionSeed"
-          }
-        },
-        "value": {
-          "type": "operator",
-          "operator": "-",
-          "values": [
-            {
-              "type": "variable",
-              "name": "h"
-            },
-            {
-              "type": "constant",
-              "value": 5
-            },
-            {
-              "type": "operator",
-              "operator": "*",
-              "values": [
-                {
-                  "type": "noise",
-                  "name": "u",
-                  "x": {
                     "type": "variable",
-                    "name": "x"
-                  },
-                  "y": {
-                    "type": "variable",
-                    "name": "y"
-                  },
-                  "z": {
-                    "type": "constant",
-                    "value": 0
-                  }
-                },
-                {
-                  "type": "constant",
-                  "value": 45
+                    "name": "dimensionId"
                 }
-              ]
-            }
-          ]
-        }
-      }
-    ],
-    "bioms": [
-      {
-        "name": "Grassland",
-        "structurCollections": [
-          {
-            "activeNoise": {
-              "type": "random",
-              "seed": {
+            ]
+        },
+        "biomNoise": {
+            "type": "Cellular",
+            "seed": {
                 "type": "variable",
                 "name": "dimensionSeed"
-              }
-            },
-            "structureNoise": {
-              "type": "random",
-              "seed": {
-                "type": "operator",
-                "operator": "+",
-                "values": [
-                  {
-                    "type": "variable",
-                    "name": "dimensionSeed"
-                  },
-                  {
-                    "type": "constant",
-                    "value": 10
-                  }
-                ]
-              }
             },
-            "threshold": 0.0025,
-            "structures": [
-              {
-                "type": "Tree",
-                "wood": "Birch Wood",
-                "leaves": "Birch Wood Leaves",
-                "minSize": 8,
-                "maxSize": 15,
-                "propability": 0.5
-              },
-              {
-                "type": "Tree",
-                "wood": "Beech Wood",
-                "leaves": "Beech Wood Leaves",
-                "minSize": 8,
-                "maxSize": 13,
-                "propability": 0.25
-              },
-              {
-                "type": "Tree",
-                "wood": "Oak Wood",
-                "leaves": "Oak Wood Leaves",
-                "minSize": 10,
-                "maxSize": 15,
-                "propability": 0.125
-              },
-              {
-                "type": "Tree",
-                "wood": "Pine Wood",
-                "leaves": "Pine Wood Leaves",
-                "minSize": 15,
-                "maxSize": 24,
-                "propability": 0.075
-              }
-            ],
-            "condition": {
-              "type": "operator",
-              "operator": "&&",
-              "values": [
-                {
-                  "type": "comparsion",
-                  "operator": "==i",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "z"
+            "rotationType3D": "None",
+            "frequency": 0.015,
+            "fractalType": "None",
+            "cellularDistanceFunction": "Hybrid",
+            "cellularReturnType": "CellValue",
+            "cellularJitter": 1,
+            "domainWarpType": "OpenSimplex2Reduced",
+            "domainWarpAmp": 30
+        },
+        "heightLayers": [
+            {
+                "name": "h",
+                "noise": {
+                    "type": "factorize",
+                    "noiseA": {
+                        "type": "flatten",
+                        "noise": {
+                            "type": "Perlin",
+                            "multiplier": 0.05,
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 23
+                                    }
+                                ]
+                            }
+                        },
+                        "factor": 0.5,
+                        "addition": 0.25
                     },
-                    {
-                      "type": "operator",
-                      "operator": "-",
-                      "values": [
-                        {
-                          "type": "variable",
-                          "name": "h"
+                    "noiseB": {
+                        "type": "multiply",
+                        "base": {
+                            "type": "factorize",
+                            "noiseA": {
+                                "type": "Perlin",
+                                "frequency": 0.02,
+                                "seed": {
+                                    "type": "operator",
+                                    "operator": "+",
+                                    "values": [
+                                        {
+                                            "type": "variable",
+                                            "name": "dimensionSeed"
+                                        },
+                                        {
+                                            "type": "constant",
+                                            "value": 22
+                                        }
+                                    ]
+                                }
+                            },
+                            "noiseB": {
+                                "type": "Perlin",
+                                "frequency": 0.25,
+                                "seed": {
+                                    "type": "operator",
+                                    "operator": "+",
+                                    "values": [
+                                        {
+                                            "type": "variable",
+                                            "name": "dimensionSeed"
+                                        },
+                                        {
+                                            "type": "constant",
+                                            "value": 21
+                                        }
+                                    ]
+                                }
+                            },
+                            "factorA": 0.9
                         },
-                        {
-                          "type": "constant",
-                          "value": 1
+                        "multiplier": {
+                            "type": "flatten",
+                            "noise": {
+                                "type": "scale",
+                                "noise": {
+                                    "type": "negate",
+                                    "noise": {
+                                        "type": "scale",
+                                        "noise": {
+                                            "type": "Cellular",
+                                            "multiplier": 0.4,
+                                            "frequency": 0.005,
+                                            "rotationType3D": "None",
+                                            "fractalType": "DomainWarpIndependent",
+                                            "cellularDistanceFunction": "Euclidean",
+                                            "cellularReturnType": "Distance",
+                                            "cellularJitter": 1.5,
+                                            "domainWarpType": "OpenSimplex2Reduced",
+                                            "domainWarpAmp": 100,
+                                            "fractalOctaves": 3,
+                                            "fractalLacunarity": 2,
+                                            "fractalGain": 0.5,
+                                            "seed": {
+                                                "type": "operator",
+                                                "operator": "+",
+                                                "values": [
+                                                    {
+                                                        "type": "variable",
+                                                        "name": "dimensionSeed"
+                                                    },
+                                                    {
+                                                        "type": "constant",
+                                                        "value": 20
+                                                    }
+                                                ]
+                                            }
+                                        },
+                                        "factor": 3.5
+                                    }
+                                },
+                                "factor": 1.5
+                            },
+                            "factor": 0.95,
+                            "addition": 0.05
                         }
-                      ]
-                    }
-                  ]
-                },
-                {
-                  "type": "comparsion",
-                  "operator": ">=i",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "h"
-                    },
-                    {
-                      "type": "constant",
-                      "value": 200
-                    }
-                  ]
-                },
-                {
-                  "type": "comparsion",
-                  "operator": "<i",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "h"
-                    },
-                    {
-                      "type": "constant",
-                      "value": 300
-                    }
-                  ]
-                }
-              ]
-            }
-          }
-        ],
-        "blocks": [
-          {
-            "type": "blockInstance",
-            "blockType": "Water",
-            "condition": {
-              "type": "operator",
-              "operator": "&&",
-              "values": [
-                {
-                  "type": "comparsion",
-                  "operator": ">=i",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "z"
                     },
-                    {
-                      "type": "variable",
-                      "name": "h"
-                    }
-                  ]
+                    "factorA": 0.5
                 },
-                {
-                  "type": "comparsion",
-                  "operator": "<i",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "z"
-                    },
-                    {
-                      "type": "constant",
-                      "value": 200
-                    }
-                  ]
-                }
-              ]
-            }
-          },
-          {
-            "type": "blockType",
-            "blockType": "Air",
-            "condition": {
-              "type": "comparsion",
-              "operator": ">i",
-              "values": [
-                {
-                  "type": "variable",
-                  "name": "z"
-                },
-                {
-                  "type": "variable",
-                  "name": "h"
+                "value": {
+                    "type": "operator",
+                    "operator": "+",
+                    "values": [
+                        {
+                            "type": "constant",
+                            "value": 50
+                        },
+                        {
+                            "type": "operator",
+                            "operator": "*",
+                            "values": [
+                                {
+                                    "type": "noise",
+                                    "name": "h",
+                                    "x": {
+                                        "type": "variable",
+                                        "name": "x"
+                                    },
+                                    "y": {
+                                        "type": "variable",
+                                        "name": "y"
+                                    },
+                                    "z": {
+                                        "type": "constant",
+                                        "value": 0
+                                    }
+                                },
+                                {
+                                    "type": "constant",
+                                    "value": 400
+                                }
+                            ]
+                        }
+                    ]
                 }
-              ]
-            }
-          },
-          {
-            "type": "blockType",
-            "blockType": "Grass",
-            "noise": {
-              "type": "random",
-              "seed": {
-                "type": "operator",
-                "operator": "+",
-                "values": [
-                  {
-                    "type": "variable",
-                    "name": "dimensionSeed"
-                  },
-                  {
-                    "type": "constant",
-                    "value": 3
-                  }
-                ]
-              }
             },
-            "threshold": 0.25,
-            "condition": {
-              "type": "operator",
-              "operator": "&&",
-              "values": [
-                {
-                  "type": "comparsion",
-                  "operator": "==i",
-                  "values": [
-                    {
-                      "type": "variable",
-                      "name": "z"
-                    },
-                    {
-                      "type": "variable",
-                      "name": "h"
+            {
+                "name": "u",
+                "noise": {
+                    "type": "ValueCubic",
+                    "seed": {
+                        "type": "variable",
+                        "name": "dimensionSeed"
                     }
-                  ]
                 },
-                {
-                  "type": "blockType",
-                  "x": {
-                    "type": "variable",
-                    "name": "x"
-                  },
-                  "y": {
-                    "type": "variable",
-                    "name": "y"
-                  },
-                  "z": {
+                "value": {
                     "type": "operator",
                     "operator": "-",
                     "values": [
-                      {
-                        "type": "variable",
-                        "name": "z"
-                      },
-                      {
-                        "type": "constant",
-                        "value": 1
-                      }
+                        {
+                            "type": "variable",
+                            "name": "h"
+                        },
+                        {
+                            "type": "constant",
+                            "value": 5
+                        },
+                        {
+                            "type": "operator",
+                            "operator": "*",
+                            "values": [
+                                {
+                                    "type": "noise",
+                                    "name": "u",
+                                    "x": {
+                                        "type": "variable",
+                                        "name": "x"
+                                    },
+                                    "y": {
+                                        "type": "variable",
+                                        "name": "y"
+                                    },
+                                    "z": {
+                                        "type": "constant",
+                                        "value": 0
+                                    }
+                                },
+                                {
+                                    "type": "constant",
+                                    "value": 45
+                                }
+                            ]
+                        }
                     ]
-                  },
-                  "blockType": "Dirt"
                 }
-              ]
             }
-          },
-          {
-            "type": "blockType",
-            "blockType": "Gravel",
-            "noise": {
-              "type": "ValueCubic",
-              "frequency": 0.1,
-              "seed": {
-                "type": "operator",
-                "operator": "+",
-                "values": [
-                  {
-                    "type": "variable",
-                    "name": "dimensionSeed"
-                  },
-                  {
-                    "type": "constant",
-                    "value": 2
-                  }
-                ]
-              }
-            },
-            "threshold": 0.35,
-            "condition": {
-              "type": "comparsion",
-              "operator": "<i",
-              "values": [
-                {
-                  "type": "variable",
-                  "name": "z"
-                },
-                {
-                  "type": "variable",
-                  "name": "h"
-                }
-              ]
-            }
-          },
-          {
-            "type": "blockType",
-            "blockType": "Dirt",
-            "noise": {
-              "type": "ValueCubic",
-              "frequency": 0.125,
-              "seed": {
-                "type": "operator",
-                "operator": "+",
-                "values": [
-                  {
-                    "type": "variable",
-                    "name": "dimensionSeed"
-                  },
-                  {
-                    "type": "constant",
-                    "value": 1
-                  }
-                ]
-              }
-            },
-            "threshold": 0.35,
-            "condition": {
-              "type": "comparsion",
-              "operator": "<i",
-              "values": [
-                {
-                  "type": "variable",
-                  "name": "z"
-                },
-                {
-                  "type": "variable",
-                  "name": "h"
-                }
-              ]
-            }
-          },
-          {
-            "type": "blockType",
-            "blockType": "Sand",
-            "noise": {
-              "type": "ValueCubic",
-              "frequency": 0.125,
-              "seed": {
-                "type": "operator",
-                "operator": "+",
-                "values": [
-                  {
-                    "type": "variable",
-                    "name": "dimensionSeed"
-                  },
-                  {
-                    "type": "constant",
-                    "value": 2
-                  }
-                ]
-              }
-            },
-            "threshold": 0.35,
-            "condition": {
-              "type": "operator",
-              "operator": "&&",
-              "values": [
-                {
-                  "type": "comparsion",
-                  "operator": "<i",
-                  "values": [
+        ],
+        "bioms": [
+            {
+                "name": "Grassland",
+                "entities": [
                     {
-                      "type": "variable",
-                      "name": "z"
-                    },
+                        "type": "Kow",
+                        "condition": {
+                            "blockType": "Dirt",
+                            "type": "blockType",
+                            "x": {
+                                "type": "variable",
+                                "name": "x"
+                            },
+                            "y": {
+                                "type": "variable",
+                                "name": "y"
+                            },
+                            "z": {
+                                "type": "operator",
+                                "operator": "-",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "z"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 2
+                                    }
+                                ]
+                            }
+                        },
+                        "threshold": 0.996,
+                        "noise": {
+                            "type": "random",
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 101
+                                    }
+                                ]
+                            }
+                        }
+                    }
+                ],
+                "structurCollections": [
                     {
-                      "type": "variable",
-                      "name": "h"
+                        "activeNoise": {
+                            "type": "random",
+                            "seed": {
+                                "type": "variable",
+                                "name": "dimensionSeed"
+                            }
+                        },
+                        "structureNoise": {
+                            "type": "random",
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 10
+                                    }
+                                ]
+                            }
+                        },
+                        "threshold": 0.0025,
+                        "structures": [
+                            {
+                                "type": "Tree",
+                                "wood": "Birch Wood",
+                                "leaves": "Birch Wood Leaves",
+                                "minSize": 8,
+                                "maxSize": 15,
+                                "propability": 0.5
+                            },
+                            {
+                                "type": "Tree",
+                                "wood": "Beech Wood",
+                                "leaves": "Beech Wood Leaves",
+                                "minSize": 8,
+                                "maxSize": 13,
+                                "propability": 0.25
+                            },
+                            {
+                                "type": "Tree",
+                                "wood": "Oak Wood",
+                                "leaves": "Oak Wood Leaves",
+                                "minSize": 10,
+                                "maxSize": 15,
+                                "propability": 0.125
+                            },
+                            {
+                                "type": "Tree",
+                                "wood": "Pine Wood",
+                                "leaves": "Pine Wood Leaves",
+                                "minSize": 15,
+                                "maxSize": 24,
+                                "propability": 0.075
+                            }
+                        ],
+                        "condition": {
+                            "type": "operator",
+                            "operator": "&&",
+                            "values": [
+                                {
+                                    "type": "comparsion",
+                                    "operator": "==i",
+                                    "values": [
+                                        {
+                                            "type": "variable",
+                                            "name": "z"
+                                        },
+                                        {
+                                            "type": "operator",
+                                            "operator": "-",
+                                            "values": [
+                                                {
+                                                    "type": "variable",
+                                                    "name": "h"
+                                                },
+                                                {
+                                                    "type": "constant",
+                                                    "value": 1
+                                                }
+                                            ]
+                                        }
+                                    ]
+                                },
+                                {
+                                    "type": "comparsion",
+                                    "operator": ">=i",
+                                    "values": [
+                                        {
+                                            "type": "variable",
+                                            "name": "h"
+                                        },
+                                        {
+                                            "type": "constant",
+                                            "value": 200
+                                        }
+                                    ]
+                                },
+                                {
+                                    "type": "comparsion",
+                                    "operator": "<i",
+                                    "values": [
+                                        {
+                                            "type": "variable",
+                                            "name": "h"
+                                        },
+                                        {
+                                            "type": "constant",
+                                            "value": 300
+                                        }
+                                    ]
+                                }
+                            ]
+                        }
                     }
-                  ]
-                },
-                {
-                  "type": "comparsion",
-                  "operator": ">i",
-                  "values": [
+                ],
+                "blocks": [
                     {
-                      "type": "variable",
-                      "name": "z"
+                        "type": "blockType",
+                        "blockType": "Gravel",
+                        "noise": {
+                            "type": "ValueCubic",
+                            "frequency": 0.1,
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 2
+                                    }
+                                ]
+                            }
+                        },
+                        "threshold": 0.35,
+                        "topLayer": "h"
                     },
                     {
-                      "type": "variable",
-                      "name": "u"
-                    }
-                  ]
-                }
-              ]
-            }
-          },
-          {
-            "type": "blockType",
-            "blockType": "Dirt",
-            "condition": {
-              "type": "operator",
-              "operator": "&&",
-              "values": [
-                {
-                  "type": "comparsion",
-                  "operator": "<i",
-                  "values": [
+                        "type": "blockType",
+                        "blockType": "Dirt",
+                        "noise": {
+                            "type": "ValueCubic",
+                            "frequency": 0.125,
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 1
+                                    }
+                                ]
+                            }
+                        },
+                        "threshold": 0.35,
+                        "topLayer": "h"
+                    },
+                    {
+                        "type": "blockType",
+                        "blockType": "Sand",
+                        "noise": {
+                            "type": "ValueCubic",
+                            "frequency": 0.125,
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 2
+                                    }
+                                ]
+                            }
+                        },
+                        "threshold": 0.35,
+                        "topLayer": "h",
+                        "bottomLayer": "u"
+                    },
                     {
-                      "type": "variable",
-                      "name": "z"
+                        "type": "blockType",
+                        "blockType": "Dirt",
+                        "topLayer": "h",
+                        "bottomLayer": "u"
                     },
                     {
-                      "type": "variable",
-                      "name": "h"
+                        "type": "blockType",
+                        "blockType": "Stone",
+                        "topLayer": "u"
                     }
-                  ]
-                },
-                {
-                  "type": "comparsion",
-                  "operator": ">i",
-                  "values": [
+                ],
+                "plants": [
                     {
-                      "type": "variable",
-                      "name": "z"
+                        "plantBlock": "Grass",
+                        "condition": {
+                            "blockType": "Dirt",
+                            "type": "blockType",
+                            "x": {
+                                "type": "variable",
+                                "name": "x"
+                            },
+                            "y": {
+                                "type": "variable",
+                                "name": "y"
+                            },
+                            "z": {
+                                "type": "operator",
+                                "operator": "-",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "z"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 1
+                                    }
+                                ]
+                            }
+                        },
+                        "locations": [
+                            "SURFACE"
+                        ],
+                        "plantHeight": 1,
+                        "threshold": 0.7,
+                        "noise": {
+                            "type": "random",
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 55
+                                    }
+                                ]
+                            }
+                        }
                     },
                     {
-                      "type": "variable",
-                      "name": "u"
+                        "plantBlock": "Cotton Plant",
+                        "condition": {
+                            "blockType": "Dirt",
+                            "type": "blockType",
+                            "x": {
+                                "type": "variable",
+                                "name": "x"
+                            },
+                            "y": {
+                                "type": "variable",
+                                "name": "y"
+                            },
+                            "z": {
+                                "type": "operator",
+                                "operator": "-",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "z"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 1
+                                    }
+                                ]
+                            }
+                        },
+                        "locations": [
+                            "SURFACE"
+                        ],
+                        "plantHeight": 1,
+                        "threshold": 0.995,
+                        "noise": {
+                            "type": "random",
+                            "seed": {
+                                "type": "operator",
+                                "operator": "+",
+                                "values": [
+                                    {
+                                        "type": "variable",
+                                        "name": "dimensionSeed"
+                                    },
+                                    {
+                                        "type": "constant",
+                                        "value": 56
+                                    }
+                                ]
+                            }
+                        }
                     }
-                  ]
-                }
-              ]
-            }
-          },
-          {
-            "type": "blockType",
-            "blockType": "Stone",
-            "condition": {
-              "type": "comparsion",
-              "operator": "<=i",
-              "values": [
-                {
-                  "type": "variable",
-                  "name": "z"
-                },
-                {
-                  "type": "variable",
-                  "name": "u"
-                }
-              ]
+                ]
             }
-          }
-        ],
-        "condition": {
-          "type": "constant",
-          "value": true
-        }
-      }
-    ]
-  }
+        ]
+    }
 ]

+ 104 - 17
Windows Version/data/items/itemTypes.json

@@ -71,19 +71,6 @@
     "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",
@@ -133,7 +120,9 @@
         {
           "targetFilter": {
             "type": "types",
-            "typeNames": [ "Dirt" ]
+            "typeNames": [
+              "Dirt"
+            ]
           },
           "replacementBlockType": "Farmland"
         }
@@ -160,7 +149,9 @@
         {
           "targetFilter": {
             "type": "groups",
-            "groupNames": [ "Shovel" ]
+            "groupNames": [
+              "Shovel"
+            ]
           }
         }
       ]
@@ -186,7 +177,9 @@
         {
           "targetFilter": {
             "type": "groups",
-            "groupNames": [ "Wood" ]
+            "groupNames": [
+              "Wood"
+            ]
           }
         }
       ]
@@ -237,8 +230,102 @@
       "direction": "bottom",
       "filter": {
         "type": "types",
-        "typeNames": [ "Farmland" ]
+        "typeNames": [
+          "Farmland"
+        ]
       }
     }
+  },
+  {
+    "type": "placeable",
+    "name": "Cotton Seeds",
+    "model": {
+      "modelPath": "grass",
+      "texturePaths": [
+        "plants.ltdb/cottonseeds.png"
+      ],
+      "transparent": true
+    },
+    "hardness": 0.1,
+    "transparent": true,
+    "passable": true,
+    "speedModifier": 0.5,
+    "blockType": "CottonSeeds",
+    "placeableProof": {
+      "type": "blockFilter",
+      "direction": "bottom",
+      "filter": {
+        "type": "types",
+        "typeNames": [
+          "Farmland"
+        ]
+      }
+    }
+  },
+  {
+    "type": "basic",
+    "name": "Tree bark",
+    "model": {
+      "modelPath": "items.m3/treebark",
+      "texturePaths": [
+        "items.ltdb/treebark.png"
+      ]
+    },
+    "itemName": "Tree bark"
+  },
+  {
+    "type": "basic",
+    "name": "Stone",
+    "model": {
+      "modelPath": "items.m3/stone",
+      "texturePaths": [
+        "blocks.ltdb/stone.png"
+      ]
+    },
+    "itemName": "Stone"
+  },
+  {
+    "type": "basic",
+    "name": "Glue",
+    "model": {
+      "modelPath": "cube",
+      "texturePaths": [
+        "items.ltdb/glue.png",
+        "items.ltdb/glue.png",
+        "items.ltdb/glue.png",
+        "items.ltdb/glue.png",
+        "items.ltdb/glue.png",
+        "items.ltdb/glue.png"
+      ]
+    },
+    "itemName": "Glue",
+    "hp": 1,
+    "durability": 10
+  },
+  {
+    "type": "basic",
+    "name": "Wool",
+    "model": {
+      "modelPath": "items.m3/cottonpiece",
+      "texturePaths": [
+        "items.ltdb/cottonpiece.png"
+      ]
+    },
+    "itemName": "Wool",
+    "hp": 1,
+    "durability": 10
+  },
+  {
+    "type": "basic",
+    "name": "Thread",
+    "model": {
+      "modelPath": "items.m3/thread",
+      "texturePaths": [
+        "items.ltdb/thread.png"
+      ]
+    },
+    "itemName": "Thread",
+    "hp": 1,
+    "durability": 10
   }
 ]

BIN
Windows Version/data/models/blocks.m3


BIN
Windows Version/data/models/entities.m3


BIN
Windows Version/data/models/items.m3


BIN
Windows Version/data/models/plants.m3


BIN
Windows Version/data/models/tools.m3


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

@@ -1,64 +1,64 @@
 [
-  {
-    "name": "Tutorial",
-    "quests": [
-      {
-        "questId": "tutorial_1",
-        "questName": "Quest Dialog",
-        "description": "Welcome to Factory Craft!\nThis is a tutorial quest to get you started.\nYou have already completed it by opening the quest dialog.\nHere you can see all current open or completed quests.\nCompleting a quest can make other quests visible.\nYou can view all current quests by clicking on a quest category on the left.",
-        "imagePath": "data/images/gui_icons.ltdb/questdialog.png",
-        "requirements": [
-          {
-            "id": "1",
-            "description": "Open the quest dialog",
-            "type": "open_dialog",
-            "dialogId": "quests"
-          }
-        ],
-        "rewards": [
-          {
-            "rewardId": "1",
-            "type": "give_items",
-            "items": [
-              {
-                "item": {
-                  "type": "Flint"
-                },
-                "count": 10
-              }
-            ]
-          }
+    {
+        "name": "Tutorial",
+        "quests": [
+            {
+                "questId": "tutorial_1",
+                "questName": "Quest Dialog",
+                "description": "Welcome to Factory Craft!\nThis is a tutorial quest to get you started.\nYou have already completed it by opening the quest dialog.\nHere you can see all current open or completed quests.\nCompleting a quest can make other quests visible.\nYou can view all current quests by clicking on a quest category on the left.",
+                "imagePath": "data/images/gui_icons.ltdb/questdialog.png",
+                "requirements": [
+                    {
+                        "id": "1",
+                        "description": "Open the quest dialog",
+                        "type": "open_dialog",
+                        "dialogId": "quests"
+                    }
+                ],
+                "rewards": [
+                    {
+                        "rewardId": "1",
+                        "type": "give_items",
+                        "items": [
+                            {
+                                "item": {
+                                    "type": "Flint"
+                                },
+                                "count": 10
+                            }
+                        ]
+                    }
+                ]
+            },
+            {
+                "questId": "tutorial_2",
+                "questName": "Inventory",
+                "description": "Your inventory shows you all the items you currently have.\nYou can open it by pressing the tab key on your keyboard.\nIn your inventory you can also combine items to to create new once.\n",
+                "imagePath": "data/images/gui_icons.ltdb/questdialog.png",
+                "requiredQuestIds": [ [ "tutorial_1" ] ],
+                "requirements": [
+                    {
+                        "id": "1",
+                        "description": "Open your inventory",
+                        "type": "open_dialog",
+                        "dialogId": "player_inventory"
+                    }
+                ],
+                "rewards": [
+                    {
+                        "rewardId": "1",
+                        "type": "give_items",
+                        "items": [
+                            {
+                                "item": {
+                                    "type": "Wooden Stick"
+                                },
+                                "count": 10
+                            }
+                        ]
+                    }
+                ]
+            }
         ]
-      },
-      {
-        "questId": "tutorial_2",
-        "questName": "Inventory",
-        "description": "Your inventory shows you all the items you currently have.\nYou can open it by pressing the tab key on your keyboard.\nIn your inventory you can also combine items to to create new once.\n",
-        "imagePath": "data/images/gui_icons.ltdb/questdialog.png",
-        "requiredQuestIds": [ [ "tutorial_1" ] ],
-        "requirements": [
-          {
-            "id": "1",
-            "description": "Open your inventory",
-            "type": "open_dialog",
-            "dialogId": "player_inventory"
-          }
-        ],
-        "rewards": [
-          {
-            "rewardId": "1",
-            "type": "give_items",
-            "items": [
-              {
-                "item": {
-                  "type": "Wooden Stick"
-                },
-                "count": 10
-              }
-            ]
-          }
-        ]
-      }
-    ]
-  }
+    }
 ]

+ 10 - 0
Windows Version/data/recipieGroups/groups.json

@@ -0,0 +1,10 @@
+[
+    {
+        "groupName": "inventory",
+        "iconItemType": "Crafting Table"
+    },
+    {
+        "groupName": "fire",
+        "iconItemType": "Campfire"
+    }
+]

+ 38 - 35
Windows Version/data/recipies/basicItems.json

@@ -275,7 +275,9 @@
         "input": {
           "filter": {
             "type": "groups",
-            "groupNames": [ "Wood" ]
+            "groupNames": [
+              "Wood"
+            ]
           }
         },
         "x": 0,
@@ -290,39 +292,6 @@
     "type": "shaped",
     "width": 1
   },
-  {
-    "group": "inventory",
-    "height": 2,
-    "inputs": [
-      {
-        "input": {
-          "filter": {
-            "type": "type",
-            "itemType": "Flint"
-          }
-        },
-        "x": 0,
-        "y": 0
-      },
-      {
-        "input": {
-          "filter": {
-            "type": "type",
-            "itemType": "Pine Wood"
-          }
-        },
-        "x": 0,
-        "y": 1
-      }
-    ],
-    "outputs": [
-      {
-        "itemType": "Resin"
-      }
-    ],
-    "type": "shaped",
-    "width": 1
-  },
   {
     "group": "inventory",
     "height": 2,
@@ -364,7 +333,9 @@
         "input": {
           "filter": {
             "type": "groups",
-            "groupNames": [ "Leaves" ]
+            "groupNames": [
+              "Leaves"
+            ]
           }
         },
         "x": 0,
@@ -481,5 +452,37 @@
     ],
     "type": "shaped",
     "width": 3
+  },
+  {
+    "type": "unshaped",
+    "group": "inventory",
+    "inputs": [
+      {
+        "amount": 1,
+        "filter": {
+          "type": "type",
+          "itemType": "Wool"
+        }
+      },
+      {
+        "amount": 1,
+        "filter": {
+          "type": "type",
+          "itemType": "Wool"
+        }
+      },
+      {
+        "amount": 1,
+        "filter": {
+          "type": "type",
+          "itemType": "Wool"
+        }
+      }
+    ],
+    "outputs": [
+      {
+        "itemType": "Thread"
+      }
+    ]
   }
 ]

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

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

+ 23 - 0
Windows Version/data/recipies/fire.json

@@ -0,0 +1,23 @@
+[
+    {
+        "type": "machine",
+        "group": "fire",
+        "fuelPerTickNeeded": 1,
+        "ticksNeeded": 60,
+        "inputs": [
+            {
+                "amount": 1,
+                "filter": {
+                    "type": "type",
+                    "itemType": "Resin"
+                }
+            }
+        ],
+        "outputs": [
+            {
+                "amount": 1,
+                "itemType": "Glue"
+            }
+        ]
+    }
+]

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

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

BIN
Windows Version/error_core_memory_dump.dmp


+ 165 - 0
assembly/assembly.vcxproj

@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>17.0</VCProjectVersion>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectGuid>{1c0b0808-0d8e-49a6-87c2-1d03ca6b937d}</ProjectGuid>
+    <RootNamespace>assembly</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v145</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v145</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v145</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v145</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <CustomBuildAfterTargets>
+    </CustomBuildAfterTargets>
+    <IncludePath>..\..\..\..\..\Allgemein\Framework;..\FactoryCraft;..\..\..\..\..\Allgemein\Network\Network;..\..\..\..\..\Allgemein\Network;$(IncludePath)</IncludePath>
+    <LibraryPath>..\..\..\..\..\Allgemein\Framework\x64\release;..\..\..\..\..\Allgemein\Network\x64\release;$(LibraryPath)</LibraryPath>
+    <ExternalIncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</ExternalIncludePath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IncludePath>..\..\..\..\..\Allgemein\Framework;..\FactoryCraft;..\..\..\..\..\Allgemein\Network\Network;..\..\..\..\..\Allgemein\Network;$(IncludePath)</IncludePath>
+    <LibraryPath>..\..\..\..\..\Allgemein\Framework\x64\debug;..\..\..\..\..\Allgemein\Network\x64\debug;$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>Framework.lib;Network.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <Optimization>MaxSpeed</Optimization>
+      <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+      <WholeProgramOptimization>true</WholeProgramOptimization>
+      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>Framework.lib;Network.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <CustomBuildStep>
+      <Command>
+      </Command>
+    </CustomBuildStep>
+    <CustomBuildStep>
+      <Outputs>
+      </Outputs>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="start.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="test.asm">
+      <FileType>Document</FileType>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nasm -f win64 -o test.obj test.asm</Command>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">test.obj</Outputs>
+    </CustomBuild>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+    <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
+  </ImportGroup>
+</Project>

+ 27 - 0
assembly/assembly.vcxproj.filters

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Quelldateien">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Headerdateien">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Ressourcendateien">
+      <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>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="start.cpp">
+      <Filter>Quelldateien</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <CustomBuild Include="test.asm">
+      <Filter>Quelldateien</Filter>
+    </CustomBuild>
+  </ItemGroup>
+</Project>

+ 307 - 0
assembly/start.cpp

@@ -0,0 +1,307 @@
+#include <Assembly.h>
+#include <functional>
+#include <iostream>
+#include <malloc.h>
+#include <windows.h>
+#include <Zeit.h>
+
+using namespace Framework;
+using namespace Assembly;
+
+typedef int (*valF)(void*);
+typedef int (*compF)();
+
+template<typename T> class Val
+{
+protected:
+    AssemblyBlock block;
+    T* self;
+
+public:
+    Val(T* self)
+        : self(self)
+    {}
+
+    inline int getValueInline()
+    {
+        return self->getValue2();
+    }
+
+    virtual int getValue() = 0;
+    virtual valF compileFP() = 0;
+    virtual std::function<int()> compileStdF() = 0;
+
+    compF compileToAssembly()
+    {
+        internalCompileAssembly();
+        block.optimize();
+        return block.compileToFunction<compF>();
+    }
+
+    virtual AssemblyBlock& internalCompileAssembly() = 0;
+
+    inline AssemblyBlock& getBlock()
+    {
+        return block;
+    }
+};
+
+class RandVal : public Val<RandVal>
+{
+public:
+    RandVal()
+        : Val(this)
+    {}
+
+    int getValue() override
+    {
+        return rand();
+    }
+
+    int getValue2()
+    {
+        return rand();
+    }
+
+    valF compileFP() override
+    {
+        return [](void* v) { return rand(); };
+    }
+
+    std::function<int()> compileStdF() override
+    {
+        return []() { return rand(); };
+    }
+
+    AssemblyBlock& internalCompileAssembly() override
+    {
+        block.addCall(rand);
+        return block;
+    }
+};
+
+class ConstVal : public Val<ConstVal>
+{
+private:
+    int value;
+
+public:
+    ConstVal(int value)
+        : Val(this),
+          value(value)
+    {}
+
+    int getValue() override
+    {
+        return value;
+    }
+
+    inline int getValue2()
+    {
+        return value;
+    }
+
+    valF compileFP() override
+    {
+        return [](void* v) { return ((ConstVal*)v)->value; };
+    }
+
+    std::function<int()> compileStdF() override
+    {
+        const int& value = this->value;
+        return [value]() { return value; };
+    }
+
+    AssemblyBlock& internalCompileAssembly() override
+    {
+        block.addLoadValue(&value, RAX);
+        return block;
+    }
+};
+
+template<typename T1, typename T2> class AdditionVal
+    : public Val<AdditionVal<T1, T2>>
+{
+private:
+    Val<T1>* a;
+    Val<T2>* b;
+    valF af;
+    valF bf;
+    std::function<int()> saf;
+    std::function<int()> sbf;
+
+public:
+    AdditionVal(Val<T1>* a, Val<T2>* b)
+        : Val<AdditionVal<T1, T2>>(this),
+          a(a),
+          b(b),
+          af(a->compileFP()),
+          bf(b->compileFP()),
+          saf(a->compileStdF()),
+          sbf(b->compileStdF())
+    {}
+
+    int getValue() override
+    {
+        return a->getValue() + b->getValue();
+    }
+
+    inline int getValue2()
+    {
+        return a->getValueInline() + b->getValueInline();
+    }
+
+    valF compileFP() override
+    {
+        return [](void* v) {
+            AdditionVal* av = (AdditionVal*)v;
+            return av->af(av->a) + av->bf(av->b);
+        };
+    }
+
+    std::function<int()> compileStdF() override
+    {
+        const std::function<int()>& aFunc = saf;
+        const std::function<int()>& bFunc = sbf;
+        return [aFunc, bFunc]() { return aFunc() + bFunc(); };
+    }
+
+    AssemblyBlock& internalCompileAssembly() override
+    {
+        GPRegister result = RAX;
+        GPRegister result2 = RAX;
+        FPRegister resultFP;
+        this->getBlock().addBlock(
+            &a->internalCompileAssembly(), {}, {}, &result, &resultFP);
+        this->getBlock().addBlock(
+            &b->internalCompileAssembly(), {result}, {}, &result2, &resultFP);
+        this->getBlock().addInstruction(new Instruction(ADD,
+            {new GPRegisterArgument(result, LOWER32),
+                new GPRegisterArgument(result2, LOWER32)}));
+        if (result != RAX)
+        {
+            this->getBlock().addMoveValue(result, RAX, LOWER32);
+        }
+        return this->getBlock();
+    }
+};
+
+extern "C"
+{
+    extern int getVal(void*);
+}
+
+template<typename T> __declspec(noinline) int get(T* t)
+{
+    return t->getValueInline();
+}
+
+int main()
+{
+    RandVal* r = new RandVal();
+    auto test
+        = new AdditionVal<AdditionVal<AdditionVal<RandVal, ConstVal>, ConstVal>,
+            AdditionVal<ConstVal, ConstVal>>(
+            new AdditionVal<AdditionVal<RandVal, ConstVal>, ConstVal>(
+                new AdditionVal<RandVal, ConstVal>(r, new ConstVal(2)),
+                new ConstVal(3)),
+            new AdditionVal<ConstVal, ConstVal>(
+                new ConstVal(4), new ConstVal(5)));
+    ZeitMesser zeitMesser;
+    srand(0);
+    zeitMesser.messungStart();
+    __int64 res = 0;
+    for (int i = 0; i < 100000000; i++)
+    {
+        res += get(test);
+    }
+    zeitMesser.messungEnde();
+    std::cout << "inlined Time: " << zeitMesser.getSekunden() << "s"
+              << " result: " << res << std::endl;
+    srand(0);
+    zeitMesser.messungStart();
+    res = 0;
+    for (int i = 0; i < 100000000; i++)
+    {
+        res += test->getValue();
+    }
+    zeitMesser.messungEnde();
+    std::cout << "getValue() Time: " << zeitMesser.getSekunden() << "s"
+              << " result: " << res << std::endl;
+    res = 0;
+    srand(0);
+    auto val = test->compileFP();
+    zeitMesser.messungStart();
+    for (int i = 0; i < 100000000; i++)
+    {
+        res += val(test);
+    }
+    zeitMesser.messungEnde();
+    std::cout << "compile() Time: " << zeitMesser.getSekunden() << "s"
+              << " result: " << res << std::endl;
+    res = 0;
+    auto stdf = test->compileStdF();
+    srand(0);
+    zeitMesser.messungStart();
+    for (int i = 0; i < 100000000; i++)
+    {
+        res += stdf();
+    }
+    zeitMesser.messungEnde();
+    std::cout << "compileStdF() Time: " << zeitMesser.getSekunden() << "s"
+              << " result: " << res << std::endl;
+    res = 0;
+    auto assembly = test->compileToAssembly();
+    srand(0);
+    zeitMesser.messungStart();
+    for (int i = 0; i < 100000000; i++)
+    {
+        res += assembly();
+    }
+    zeitMesser.messungEnde();
+    std::cout << "compileToAssembly() Time: " << zeitMesser.getSekunden() << "s"
+              << " result: " << res << std::endl;
+    res = 0;
+    int i2 = 2;
+    int i3 = 3;
+    int i4 = 4;
+    int i5 = 5;
+    AssemblyBlock fastest;
+    fastest.addMoveValue(RCX, 2);
+    fastest.addMoveValue(RDX, 3);
+    fastest.addMoveValue(R8, 4);
+    fastest.addMoveValue(R9, 5);
+    fastest.addCall(rand);
+    fastest.addInstruction(new Instruction(ADD,
+        {new GPRegisterArgument(RAX, LOWER32),
+            new GPRegisterArgument(RCX, LOWER32)}));
+    fastest.addInstruction(new Instruction(ADD,
+        {new GPRegisterArgument(RAX, LOWER32),
+            new GPRegisterArgument(RDX, LOWER32)}));
+    fastest.addInstruction(new Instruction(ADD,
+        {new GPRegisterArgument(RAX, LOWER32),
+            new GPRegisterArgument(R8, LOWER32)}));
+    fastest.addInstruction(new Instruction(ADD,
+        {new GPRegisterArgument(RAX, LOWER32),
+            new GPRegisterArgument(R9, LOWER32)}));
+    auto f = fastest.compileToFunction<compF>();
+    zeitMesser.messungStart();
+    srand(0);
+    for (int i = 0; i < 100000000; i++)
+    {
+        res += assembly();
+    }
+    zeitMesser.messungEnde();
+    srand(0);
+    std::cout << "fastest Time: " << zeitMesser.getSekunden() << "s"
+              << " result: " << res << std::endl;
+    res = 0;
+    zeitMesser.messungStart();
+    for (int i = 0; i < 100000000; i++)
+    {
+        res += getVal(rand);
+    }
+    zeitMesser.messungEnde();
+    std::cout << "fastest Time: " << zeitMesser.getSekunden() << "s"
+              << " result: " << res << std::endl;
+}

+ 18 - 0
assembly/test.asm

@@ -0,0 +1,18 @@
+bits 64
+default rel
+
+segment .text
+global getVal
+
+getVal:
+	call        rcx
+	mov         rcx,2h  
+	add         eax,ecx
+	mov         rcx,3h  
+	add         eax,ecx
+	mov         rdx,4h  
+	mov         edx,edx
+	mov         rcx,5h  
+	add         edx,ecx
+	add         eax,edx  
+	ret