Sfoglia il codice sorgente

add tick and world update system

Kolja Strohm 3 anni fa
parent
commit
40a9ac8c27
40 ha cambiato i file con 1266 aggiunte e 181 eliminazioni
  1. 18 0
      FactoryCraft/AddChunkUpdate.h
  2. 10 0
      FactoryCraft/Area.h
  3. 49 17
      FactoryCraft/BasicBlock.cpp
  4. 30 14
      FactoryCraft/BasicBlocks.h
  5. 106 68
      FactoryCraft/Block.cpp
  6. 63 20
      FactoryCraft/Block.h
  7. 85 0
      FactoryCraft/BlockType.cpp
  8. 12 8
      FactoryCraft/BlockType.h
  9. 143 0
      FactoryCraft/Chunk.cpp
  10. 13 7
      FactoryCraft/Chunk.h
  11. 2 1
      FactoryCraft/Constants.h
  12. 1 1
      FactoryCraft/Dimension.h
  13. 2 2
      FactoryCraft/DimensionGenerator.cpp
  14. 6 0
      FactoryCraft/Entity.h
  15. 33 0
      FactoryCraft/EntityType.h
  16. 15 0
      FactoryCraft/FactoryCraft.vcxproj
  17. 54 0
      FactoryCraft/FactoryCraft.vcxproj.filters
  18. 16 4
      FactoryCraft/Game.h
  19. 1 1
      FactoryCraft/GrasslandBiom.cpp
  20. 100 0
      FactoryCraft/Item.cpp
  21. 7 5
      FactoryCraft/Item.h
  22. 48 7
      FactoryCraft/ItemType.cpp
  23. 6 5
      FactoryCraft/ItemType.h
  24. 1 1
      FactoryCraft/OverworldDimension.cpp
  25. 2 1
      FactoryCraft/OverworldDimension.h
  26. 16 1
      FactoryCraft/Player.h
  27. 8 1
      FactoryCraft/StaticInitializerOrder.cpp
  28. 5 2
      FactoryCraft/StaticRegistry.h
  29. 57 0
      FactoryCraft/TickOrganizer.cpp
  30. 23 0
      FactoryCraft/TickOrganizer.h
  31. 90 0
      FactoryCraft/TickQueue.cpp
  32. 30 0
      FactoryCraft/TickQueue.h
  33. 31 0
      FactoryCraft/TickWorker.cpp
  34. 19 0
      FactoryCraft/TickWorker.h
  35. 8 4
      FactoryCraft/WorldGenerator.cpp
  36. 3 11
      FactoryCraft/WorldGenerator.h
  37. 81 0
      FactoryCraft/WorldLoader.cpp
  38. 23 0
      FactoryCraft/WorldLoader.h
  39. 23 0
      FactoryCraft/WorldUpdate.cpp
  40. 26 0
      FactoryCraft/WorldUpdate.h

+ 18 - 0
FactoryCraft/AddChunkUpdate.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include "WorldUpdate.h"
+
+class Chunk;
+
+class AddChunkUpdate : public WorldUpdate
+{
+private:
+    Chunk *chunk;
+
+public:
+    AddChunkUpdate( Chunk *chunk );
+    ~AddChunkUpdate();
+
+    void onUpdate( Dimension *zDimension ) override;
+    void write( Framework::Writer *zWriter ) override;
+};

+ 10 - 0
FactoryCraft/Area.h

@@ -0,0 +1,10 @@
+#pragma once
+
+struct Area
+{
+    int startX;
+    int startY;
+    int endX;
+    int endY;
+    int dimensionId;
+};

+ 49 - 17
FactoryCraft/BasicBlock.cpp

@@ -1,43 +1,75 @@
 #include "BasicBlocks.h"
 
 
-BasicBlockType::BasicBlockType()
-    : BlockType( 1 )
-{
+BasicBlock::BasicBlock( BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos )
+    : Block( zType, zTool, pos )
+{}
 
+bool BasicBlock::onTick( TickQueue *zQueue, int numTicks, bool &blocked )
+{
+    return 0;
 }
 
-void BasicBlockType::loadSuperBlock( Block *zBlock, Framework::Reader *zReader )
-{
+void BasicBlock::onPostTick()
+{}
 
-}
 
-void BasicBlockType::createSuperBlock( Block *zBlock, Framework::Reader *zReader )
-{
+DirtBlockType::DirtBlockType()
+    : BlockType( ID )
+{}
 
+void DirtBlockType::loadSuperBlock( Block *zBlock, Framework::Reader *zReader )
+{
+    BlockType::loadSuperBlock( zBlock, zReader );
 }
 
-void BasicBlockType::createSuperItem( Block *zBlock, Item *zItem )
+void DirtBlockType::saveSuperBlock( Block *zBlock, Framework::Writer *zWriter )
 {
-
+    BlockType::saveSuperBlock( zBlock, zWriter );
 }
 
-Block *BasicBlockType::loadBlock( Framework::Vec3<int> position, Game *zTarget, Framework::Reader *zReader )
+void DirtBlockType::createSuperBlock( Block *zBlock, Item *zItem )
 {
-
+    if( zItem )
+        BlockType::createSuperBlock( zBlock, zItem );
+    else
+    {
+        BasicBlock *block = dynamic_cast<BasicBlock *>( zBlock );
+        if( !block )
+            throw "DirtBlockType::createSuperBlock was called with a block witch is not an instance of BasicBlock";
+        block->transparent = 0;
+        block->passable = 0;
+        block->hp = 100;
+        block->maxHP = 100;
+        block->hardness = 1;
+        block->zTool = 0;
+        block->speedModifier = 1;
+    }
 }
 
-void BasicBlockType::saveBlock( Block *zBlock, Framework::Writer *zWriter )
+void DirtBlockType::createSuperItem( Block *zBlock, Item *zItem )
 {
-
+    BlockType::createSuperItem( zBlock, zItem );
 }
 
-Item *BasicBlockType::getItemFromBlock( Block *zBlock, Game *zTarget )
+Block *DirtBlockType::createBlock( Framework::Vec3<int> position, Game *zTarget )
 {
-
+    return new BasicBlock( this, 0, position ); // TODO: add efective tool
 }
 
-Block *BasicBlockType::createBlockAt( Framework::Vec3<int> position, Game *zTarget, Item *zUsedItem )
+Item *DirtBlockType::createItem( Game *zTarget )
 {
+    return StaticRegistry<ItemType>::INSTANCE.zElement( DirtBlockItemType::ID )->createItem();
+}
 
+
+DirtBlockItemType::DirtBlockItemType()
+    : BasicBlockItemType( ID, 0, 0 )
+{}
+
+Item *DirtBlockItemType::createItem() const
+{
+    BasicBlockItem *item = new BasicBlockItem( (ItemType *)this, "Dirt" );
+    initializeItem( item, 0, 0, 100, 100, 1, 0, 1 );
+    return item;
 }

+ 30 - 14
FactoryCraft/BasicBlocks.h

@@ -4,34 +4,50 @@
 #include "BlockType.h"
 #include "Item.h"
 
-class BasicBlockType;
+class BlockType;
+class ItemType;
+class DirtBlockType;
+class DirtBlockItemType;
 
 class BasicBlock : public Block
 {
-private:
+public:
+    BasicBlock( BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos );
+    virtual bool onTick( TickQueue *zQueue, int numTicks, bool &blocked ) override;
+    virtual void onPostTick() override;
 
-    friend BasicBlockType;
+    friend DirtBlockType;
 };
 
-class BasicBlockType : public BlockType
+class DirtBlockType : public BlockType
 {
-    REGISTRABLE( BasicBlockType )
+    REGISTRABLE( DirtBlockType )
 
 protected:
     virtual void loadSuperBlock( Block *zBlock, Framework::Reader *zReader ) override;
-    virtual void createSuperBlock( Block *zBlock, Framework::Reader *zReader ) override;
+    virtual void saveSuperBlock( Block *zBlock, Framework::Writer *zWriter ) override;
+    virtual void createSuperBlock( Block *zBlock, Item *zItem ) override;
     virtual void createSuperItem( Block *zBlock, Item *zItem ) override;
+    virtual Block *createBlock( Framework::Vec3<int> position, Game *zTarget ) override;
+    virtual Item *createItem( Game *zTarget ) override;
+    DirtBlockType();
+};
 
-public:
-    BasicBlockType();
+#ifdef REGISTER
+REGISTER( DirtBlockType, BlockType )
+#endif
 
-    virtual Block *loadBlock( Framework::Vec3<int> position, Game *zTarget, Framework::Reader *zReader ) override;
-    virtual void saveBlock( Block *zBlock, Framework::Writer *zWriter ) override;
-    virtual Item *getItemFromBlock( Block *zBlock, Game *zTarget ) override;
-    virtual Block *createBlockAt( Framework::Vec3<int> position, Game *zTarget, Item *zUsedItem ) override;
+class DirtBlockItemType : public BasicBlockItemType
+{
+    REGISTRABLE( DirtBlockItemType )
+
+protected:
+    DirtBlockItemType();
+
+public:
+    virtual Item *createItem() const override;
 };
 
 #ifdef REGISTER
-REGISTER( BasicBlockType )
+REGISTER( DirtBlockItemType, ItemType )
 #endif
-

+ 106 - 68
FactoryCraft/Block.cpp

@@ -1,6 +1,6 @@
 #include "Block.h"
 
-Block::Block( BlockType *zType, ItemType *zTool )
+Block::Block( BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos )
 {
     transparent = false;
     passable = false;
@@ -10,73 +10,58 @@ Block::Block( BlockType *zType, ItemType *zTool )
     this->zType = zType;
     this->zTool = zTool;
     speedModifier = 1;
-    fluidCapacity = 10;
-    fluidAmount = 0;
-    fluidTypeId = -1;
-    fluidSpeed = 4;
-}
-
-void Block::tick()
-{
-    if( fluidTypeId >= 0 )
+    ticksLeftCounter = 0;
+    wasTicked = 0;
+    onTickCalled = 0;
+    minTickTimeout = -1;
+    maxTickTimeout = -1;
+    tickSource = 0;
+    currentTickTimeout = 0;
+    this->pos = pos;
+}
+
+void Block::tick( TickQueue *zQueue )
+{
+    if( wasTicked )
+        return;
+    wasTicked = 1;
+    ticksLeftCounter++;
+    if( minTickTimeout >= 0 )
     {
-        int fluidLeft = MIN( fluidSpeed, fluidAmount );
-        if( fluidLeft > 0 )
+        if( currentTickTimeout < ticksLeftCounter )
         {
-            if( neighbours[ BOTTOM ] )
-            {
-                int result = neighbours[ BOTTOM ]->addFluid( fluidTypeId, fluidLeft, TOP );
-                fluidLeft -= result;
-                fluidAmount -= result;
-            }
-            int distribution = (int)ceil( (float)fluidLeft / 4.f );
-            if( neighbours[ NORTH ] && neighbours[ NORTH ]->getFluidAmount() < fluidAmount - 1 )
-            {
-                int amount = MIN( distribution, ( fluidAmount - neighbours[ NORTH ]->getFluidAmount() ) / 2 );
-                int result = neighbours[ NORTH ]->addFluid( fluidTypeId, amount, SOUTH );
-                fluidLeft -= result;
-                fluidAmount -= result;
-            }
-            if( neighbours[ EAST ] && neighbours[ EAST ]->getFluidAmount() < fluidAmount - 1 )
-            {
-                int amount = MIN( distribution, ( fluidAmount - neighbours[ EAST ]->getFluidAmount() ) / 2 );
-                int result = neighbours[ EAST ]->addFluid( fluidTypeId, amount, WEST );
-                fluidLeft -= result;
-                fluidAmount -= result;
-            }
-            if( neighbours[ SOUTH ] && neighbours[ SOUTH ]->getFluidAmount() < fluidAmount - 1 )
-            {
-                int amount = MIN( distribution, ( fluidAmount - neighbours[ SOUTH ]->getFluidAmount() ) / 2 );
-                int result = neighbours[ SOUTH ]->addFluid( fluidTypeId, amount, NORTH );
-                fluidLeft -= result;
-                fluidAmount -= result;
-            }
-            if( neighbours[ WEST ] && neighbours[ WEST ]->getFluidAmount() < fluidAmount - 1 )
+            onTickCalled = 1;
+            bool blocked = 0;
+            bool result = onTick( zQueue, ticksLeftCounter, blocked );
+            if( blocked )
             {
-                int amount = MIN( distribution, ( fluidAmount - neighbours[ WEST ]->getFluidAmount() ) / 2 );
-                int result = neighbours[ WEST ]->addFluid( fluidTypeId, amount, EAST );
-                fluidLeft -= result;
-                fluidAmount -= result;
+                wasTicked = 0;
+                ticksLeftCounter--;
+                onTickCalled = 0;
+                return;
             }
-            if( fluidAmount == 0 )
-                fluidTypeId = -1;
+            if( result )
+                currentTickTimeout = MAX( MIN( currentTickTimeout - 1, maxTickTimeout ), MAX( minTickTimeout, 0 ) );
+            else
+                currentTickTimeout = MAX( MIN( currentTickTimeout + 1, maxTickTimeout ), MAX( minTickTimeout, 0 ) );
+            ticksLeftCounter = 0;
         }
     }
 }
 
 void Block::postTick()
 {
-
+    wasTicked = 0;
+    if( onTickCalled )
+    {
+        onPostTick();
+        onTickCalled = 0;
+    }
 }
 
-int Block::addFluid( int fluidTypeId, int amount, DIRECTION dir )
+bool Block::isTickSource() const
 {
-    if( this->fluidTypeId != -1 && this->fluidTypeId != fluidTypeId )
-        return 0;
-    this->fluidTypeId = fluidTypeId;
-    int result = MIN( amount, fluidCapacity - fluidAmount );
-    fluidAmount += result;
-    return result;
+    return tickSource;
 }
 
 BlockType *Block::zBlockType() const
@@ -119,22 +104,75 @@ float Block::getSpeedModifier() const
     return speedModifier;
 }
 
-int Block::getFluidCapacity() const
+const Framework::Vec3<int> &Block::getPos() const
 {
-    return fluidCapacity;
+    return pos;
 }
 
-int Block::getFluidAmount() const
-{
-    return fluidAmount;
-}
 
-int Block::getFluidTypeId() const
-{
-    return fluidTypeId;
-}
+BasicBlockItem::BasicBlockItem( ItemType *zType, const char *name )
+    : Item( zType, name )
+{}
 
-int Block::getFluidSpeed() const
+bool BasicBlockItem::canBeStackedWith( Item *zItem ) const
 {
-    return fluidSpeed;
-}
+    BasicBlockItem *item = dynamic_cast<BasicBlockItem *>( zItem );
+    if( item )
+    {
+        return Item::canBeStackedWith( zItem ) &&
+            transparent == item->transparent &&
+            passable == item->passable &&
+            hp == item->hp &&
+            maxHP == item->maxHP &&
+            hardness == item->hardness &&
+            toolId == item->toolId &&
+            speedModifier == item->speedModifier;
+    }
+    return 0;
+}
+
+
+BasicBlockItemType::BasicBlockItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType )
+    : ItemType( id, levelUpRule, zBrokenType )
+{}
+
+void BasicBlockItemType::loadSuperItem( Item *zItem, Framework::Reader *zReader ) const
+{
+    ItemType::loadSuperItem( zItem, zReader );
+    BasicBlockItem *item = dynamic_cast<BasicBlockItem *>( zItem );
+    if( !item )
+        throw "BasicBlockItemType::loadSuperItem was called with an invalid item";
+    zReader->lese( (char *)&item->transparent, 1 );
+    zReader->lese( (char *)&item->passable, 1 );
+    zReader->lese( (char *)&item->hp, 4 );
+    zReader->lese( (char *)&item->maxHP, 4 );
+    zReader->lese( (char *)&item->hardness, 4 );
+    zReader->lese( (char *)&item->toolId, 4 );
+    zReader->lese( (char *)&item->speedModifier, 4 );
+}
+
+void BasicBlockItemType::saveSuperItem( Item *zItem, Framework::Writer *zWriter ) const
+{
+    ItemType::saveSuperItem( zItem, zWriter );
+    BasicBlockItem *item = dynamic_cast<BasicBlockItem *>( zItem );
+    if( !item )
+        throw "BasicBlockItemType::saveSuperItem was called with an invalid item";
+    zWriter->schreibe( (char *)&item->transparent, 1 );
+    zWriter->schreibe( (char *)&item->passable, 1 );
+    zWriter->schreibe( (char *)&item->hp, 4 );
+    zWriter->schreibe( (char *)&item->maxHP, 4 );
+    zWriter->schreibe( (char *)&item->hardness, 4 );
+    zWriter->schreibe( (char *)&item->toolId, 4 );
+    zWriter->schreibe( (char *)&item->speedModifier, 4 );
+}
+
+void BasicBlockItemType::initializeItem( BasicBlockItem *zItem, bool transparent, bool passable, float hp, float maxHP, float hardness, int toolId, float speedModifier ) const
+{
+    zItem->transparent = transparent;
+    zItem->passable = passable;
+    zItem->hp = hp;
+    zItem->maxHP = maxHP;
+    zItem->hardness = hardness;
+    zItem->toolId = toolId;
+    zItem->speedModifier = speedModifier;
+}

+ 63 - 20
FactoryCraft/Block.h

@@ -4,13 +4,17 @@
 #include "BlockType.h"
 #include "ReferenceCounter.h"
 #include "EventThrower.h"
+#include "Item.h"
 
 #include <Trie.h>
+#include <Vec3.h>
 
+class BlockType;
 class ItemType;
 class Chunk;
+class BasicBlockItemType;
 
-enum DIRECTION
+enum Direction
 {
     NORTH,
     EAST,
@@ -21,10 +25,16 @@ enum DIRECTION
     DIRECTION_COUNT
 };
 
+class TickQueue;
+
 class Block : public virtual Framework::ReferenceCounter
 {
 private:
     BlockType *type;
+    int ticksLeftCounter;
+    int currentTickTimeout;
+    bool wasTicked;
+    bool onTickCalled;
 
 protected:
     bool transparent;
@@ -35,27 +45,34 @@ protected:
     BlockType *zType;
     ItemType *zTool;
     float speedModifier;
-    int fluidCapacity;
-    int fluidAmount;
-    int fluidTypeId;
-    int fluidSpeed;
     Block *neighbours[ DIRECTION_COUNT ];
+    Framework::Vec3<int> pos;
 
-public:
-    Block( BlockType *zType, ItemType *zTool );
-
-    virtual void tick();
-    virtual void postTick();
+    int minTickTimeout;
+    int maxTickTimeout;
+    bool tickSource;
 
     /// <summary>
-    /// adds fluid to the internal storage of this block
+    /// executes block specific things
     /// </summary>
-    /// <param name="fluidTypeId">the id of the fluid to add</param>
-    /// <param name="amount">the amount of fluids to add</param>
-    /// <param name="dir">the direction from witch the fluid is added</param>
-    /// <returns>the amount of fluids that were added</returns>
-    int addFluid( int fluidTypeId, int amount, DIRECTION dir );
+    /// <param name="zqueue">a queue to add neighbor blocks that should be ticked after this block</param>
+    /// <param name="numTicks">the number of ticks passed since the last call (only for tickSources)</param>
+    /// <param name="blocked">can be set to one to tell that this block needs to be tickt again later in the queue of this tick</param>
+    /// <returns>true, iff the block needs to be ticked more often</returns>
+    virtual bool onTick( TickQueue *zQueue, int numTicks, bool &blocked ) = 0;
+    /// <summary>
+    /// gets called after each block was tickt.
+    /// the order of blocks called will be exactly the same as onTick
+    /// </summary>
+    virtual void onPostTick() = 0;
+
+public:
+    Block( BlockType *zType, ItemType *zTool, Framework::Vec3<int> pos );
 
+    void tick( TickQueue *zQueue );
+    void postTick();
+
+    bool isTickSource() const;
     BlockType *zBlockType() const;
     bool isTransparent() const;
     bool isPassable() const;
@@ -64,10 +81,36 @@ public:
     float getHardness() const;
     ItemType *zEffectiveTool() const;
     float getSpeedModifier() const;
-    int getFluidCapacity() const;
-    int getFluidAmount() const;
-    int getFluidTypeId() const;
-    int getFluidSpeed() const;
+    const Framework::Vec3<int> &getPos() const;
 
     friend Chunk;
+    friend BlockType;
+};
+
+class BasicBlockItem : public Item
+{
+protected:
+    bool transparent;
+    bool passable;
+    float hp;
+    float maxHP;
+    float hardness;
+    int toolId;
+    float speedModifier;
+
+public:
+    BasicBlockItem( ItemType *zType, const char *name );
+    virtual bool canBeStackedWith( Item *zItem ) const override;
+
+    friend BasicBlockItemType;
+    friend BlockType;
+};
+
+class BasicBlockItemType : public ItemType
+{
+protected:
+    BasicBlockItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType );
+    virtual void loadSuperItem( Item *zItem, Framework::Reader *zReader ) const override;
+    virtual void saveSuperItem( Item *zItem, Framework::Writer *zWriter ) const override;
+    void initializeItem( BasicBlockItem *zItem, bool transparent, bool passable, float hp, float maxHP, float hardness, int toolId, float speedModifier ) const;
 };

+ 85 - 0
FactoryCraft/BlockType.cpp

@@ -1,4 +1,6 @@
 #include "BlockType.h"
+#include "ItemType.h"
+#include "BasicBlocks.h"
 
 using namespace Framework;
 
@@ -9,6 +11,89 @@ BlockType::BlockType( int id )
     StaticRegistry<BlockType>::INSTANCE.registerT( this, id );
 }
 
+void BlockType::loadSuperBlock( Block *zBlock, Framework::Reader *zReader )
+{
+    zReader->lese( (char *)&zBlock->transparent, 1 );
+    zReader->lese( (char *)&zBlock->passable, 1 );
+    zReader->lese( (char *)&zBlock->hp, 4 );
+    zReader->lese( (char *)&zBlock->maxHP, 4 );
+    zReader->lese( (char *)&zBlock->hardness, 4 );
+    zReader->lese( (char *)&zBlock->speedModifier, 4 );
+    int effectiveToolId;
+    zReader->lese( (char *)&effectiveToolId, 4 );
+    zBlock->zTool = StaticRegistry<ItemType>::INSTANCE.zElement( effectiveToolId );
+}
+
+void BlockType::saveSuperBlock( Block *zBlock, Framework::Writer *zWriter )
+{
+    zWriter->schreibe( (char *)&zBlock->transparent, 1 );
+    zWriter->schreibe( (char *)&zBlock->passable, 1 );
+    zWriter->schreibe( (char *)&zBlock->hp, 4 );
+    zWriter->schreibe( (char *)&zBlock->maxHP, 4 );
+    zWriter->schreibe( (char *)&zBlock->hardness, 4 );
+    zWriter->schreibe( (char *)&zBlock->speedModifier, 4 );
+    int effectiveToolId = zBlock->zTool->getId();
+    zWriter->schreibe( (char *)&effectiveToolId, 4 );
+}
+
+void BlockType::createSuperBlock( Block *zBlock, Item *zItem )
+{
+    BasicBlockItem *item = dynamic_cast<BasicBlockItem *>( zItem );
+    if( !item )
+    {
+        throw "BlockType::createSuperBlock was called with an item witch was not an instance of BasicBlockItem";
+    }
+    zBlock->transparent = item->transparent;
+    zBlock->passable = item->passable;
+    zBlock->hp = item->hp;
+    zBlock->maxHP = item->maxHP;
+    zBlock->hardness = item->hardness;
+    zBlock->speedModifier = item->speedModifier;
+    zBlock->zTool = StaticRegistry<ItemType>::INSTANCE.zElement( item->toolId );
+}
+
+void BlockType::createSuperItem( Block *zBlock, Item *zItem )
+{
+    BasicBlockItem *item = dynamic_cast<BasicBlockItem *>( zItem );
+    if( !item )
+    {
+        throw "BlockType::createSuperItem was called with an item witch was not an instance of BasicBlockItem";
+    }
+    item->transparent = zBlock->transparent;
+    item->passable = zBlock->passable;
+    item->hp = zBlock->maxHP; // reset hp
+    item->maxHP = zBlock->maxHP;
+    item->hardness = zBlock->hardness;
+    item->speedModifier = zBlock->speedModifier;
+    item->toolId = zBlock->zTool->getId();
+}
+
+Block *BlockType::loadBlock( Framework::Vec3<int> position, Game *zTarget, Framework::Reader *zReader )
+{
+    Block *result = createBlock( position, zTarget );
+    loadSuperBlock( result, zReader );
+    return result;
+}
+
+void BlockType::saveBlock( Block *zBlock, Framework::Writer *zWriter )
+{
+    saveSuperBlock( zBlock, zWriter );
+}
+
+Item *BlockType::getItemFromBlock( Block *zBlock, Game *zTarget )
+{
+    Item *result = createItem( zTarget );
+    createSuperItem( zBlock, result );
+    return result;
+}
+
+Block *BlockType::createBlockAt( Framework::Vec3<int> position, Game *zTarget, Item *zUsedItem )
+{
+    Block *result = createBlock( position, zTarget );
+    createSuperBlock( result, zUsedItem );
+    return result;
+}
+
 int BlockType::getId() const
 {
     return id;

+ 12 - 8
FactoryCraft/BlockType.h

@@ -5,10 +5,11 @@
 #include <Writer.h>
 
 #include "StaticRegistry.h"
+#include "Block.h"
 
 class Game;
-class Block;
 class Item;
+class Block;
 
 class BlockType : public virtual Framework::ReferenceCounter
 {
@@ -18,15 +19,18 @@ private:
 protected:
     BlockType( int id );
 
-    virtual void loadSuperBlock( Block *zBlock, Framework::Reader *zReader ) = 0;
-    virtual void createSuperBlock( Block *zBlock, Framework::Reader *zReader ) = 0;
-    virtual void createSuperItem( Block *zBlock, Item *zItem ) = 0;
+    virtual void loadSuperBlock( Block *zBlock, Framework::Reader *zReader );
+    virtual void saveSuperBlock( Block *zBlock, Framework::Writer *zWriter );
+    virtual void createSuperBlock( Block *zBlock, Item *zItem );
+    virtual void createSuperItem( Block *zBlock, Item *zItem );
+    virtual Block *createBlock( Framework::Vec3<int> position, Game *zTarget ) = 0;
+    virtual Item *createItem( Game *zTarget ) = 0;
 
 public:
-    virtual Block *loadBlock( Framework::Vec3<int> position, Game *zTarget, Framework::Reader *zReader ) = 0;
-    virtual void saveBlock( Block *zBlock, Framework::Writer *zWriter ) = 0;
-    virtual Item *getItemFromBlock( Block *zBlock, Game *zTarget ) = 0;
-    virtual Block *createBlockAt( Framework::Vec3<int> position, Game *zTarget, Item *zUsedItem ) = 0;
+    virtual Block *loadBlock( Framework::Vec3<int> position, Game *zTarget, Framework::Reader *zReader );
+    virtual void saveBlock( Block *zBlock, Framework::Writer *zWriter );
+    virtual Item *getItemFromBlock( Block *zBlock, Game *zTarget );
+    virtual Block *createBlockAt( Framework::Vec3<int> position, Game *zTarget, Item *zUsedItem );
 
     int getId() const;
 };

+ 143 - 0
FactoryCraft/Chunk.cpp

@@ -0,0 +1,143 @@
+#include "Chunk.h"
+#include "Constants.h"
+#include "Game.h"
+
+
+Chunk::Chunk( Framework::Punkt location, Game *zGame, int dimensionId )
+    : EventThrower(),
+    zGame( zGame ),
+    dimensionId( dimensionId ),
+    location( location )
+{
+    blocks = new Block * [ CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT ];
+    memset( blocks, 0, sizeof( Block * ) * CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT );
+    zNeighbours[ 0 ] = 0;
+    zNeighbours[ 1 ] = 0;
+    zNeighbours[ 2 ] = 0;
+    zNeighbours[ 3 ] = 0;
+}
+
+Chunk::~Chunk()
+{
+    for( int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++ )
+    {
+        if( blocks[ i ] )
+            blocks[ i ]->release();
+    }
+    delete[] blocks;
+}
+
+Block *Chunk::getBlockAt( Framework::Vec3<int> location )
+{
+    location.x -= this->location.x - CHUNK_SIZE / 2;
+    location.y -= this->location.x - CHUNK_SIZE / 2;
+    Block *result = dynamic_cast<Block *>( blocks[ ( location.x * CHUNK_SIZE + location.y ) * CHUNK_SIZE + location.z ]->getThis() );
+    return result;
+}
+
+void Chunk::putBlockAt( Framework::Vec3<int> location, Block *block )
+{
+    location.x -= this->location.x - CHUNK_SIZE / 2;
+    location.y -= this->location.x - CHUNK_SIZE / 2;
+    int index = ( location.x * CHUNK_SIZE + location.y ) * CHUNK_SIZE + location.z;
+    Block *old = blocks[ index ];
+    blocks[ index ] = block;
+    Block *neighbor = zGame->zBlockAt( Framework::Vec3<int>( location.x - 1, location.y, location.z ), dimensionId );
+    if( neighbor )
+        neighbor->neighbours[ WEST ] = block;
+    neighbor = zGame->zBlockAt( Framework::Vec3<int>( location.x + 1, location.y, location.z ), dimensionId );
+    if( neighbor )
+        neighbor->neighbours[ EAST ] = block;
+    neighbor = zGame->zBlockAt( Framework::Vec3<int>( location.x, location.y - 1, location.z ), dimensionId );
+    if( neighbor )
+        neighbor->neighbours[ NORTH ] = block;
+    neighbor = zGame->zBlockAt( Framework::Vec3<int>( location.x, location.y + 1, location.z ), dimensionId );
+    if( neighbor )
+        neighbor->neighbours[ SOUTH ] = block;
+    neighbor = zGame->zBlockAt( Framework::Vec3<int>( location.x, location.y, location.z - 1 ), dimensionId );
+    if( neighbor )
+        neighbor->neighbours[ BOTTOM ] = block;
+    neighbor = zGame->zBlockAt( Framework::Vec3<int>( location.x, location.y, location.z + 1 ), dimensionId );
+    if( neighbor )
+        neighbor->neighbours[ TOP ] = block;
+    if( old )
+        old->release();
+}
+
+void Chunk::setNeighbor( Direction dir, Chunk *zChunk )
+{
+    zNeighbours[ dir ] = zChunk;
+    for( int i = 0; i < CHUNK_SIZE; i++ )
+    {
+        for( int z = 0; z < WORLD_HEIGHT; z++ )
+        {
+            if( dir == NORTH )
+            {
+                int index = i * CHUNK_SIZE * CHUNK_SIZE + z;
+                if( blocks[ index ] )
+                    blocks[ index ]->neighbours[ NORTH ] = zChunk->blocks[ ( i * CHUNK_SIZE + CHUNK_SIZE - 1 ) * CHUNK_SIZE + z ];
+            }
+            else if( dir == EAST )
+            {
+                int index = ( ( CHUNK_SIZE - 1 ) * CHUNK_SIZE + i ) * CHUNK_SIZE + z;
+                if( blocks[ index ] )
+                    blocks[ index ]->neighbours[ EAST ] = zChunk->blocks[ i * CHUNK_SIZE + z ];
+            }
+            else if( dir == SOUTH )
+            {
+                int index = ( i * CHUNK_SIZE + CHUNK_SIZE - 1 ) * CHUNK_SIZE + z;
+                if( blocks[ index ] )
+                    blocks[ index ]->neighbours[ SOUTH ] = zChunk->blocks[ i * CHUNK_SIZE * CHUNK_SIZE + z ];
+            }
+            else if( dir == WEST )
+            {
+                int index = i * CHUNK_SIZE + z;
+                if( blocks[ index ] )
+                    blocks[ index ]->neighbours[ WEST ] = zChunk->blocks[ ( ( CHUNK_SIZE - 1 ) * CHUNK_SIZE + i ) * CHUNK_SIZE + z ];
+            }
+        }
+    }
+}
+
+void Chunk::load( Framework::Reader *zReader )
+{
+    for( int x = 0; x < CHUNK_SIZE; x++ )
+    {
+        for( int y = 0; y < CHUNK_SIZE; y++ )
+        {
+            for( int z = 0; z < WORLD_HEIGHT; z++ )
+            {
+                int blockType;
+                zReader->lese( (char *)&blockType, 4 );
+                if( blockType >= 0 )
+                {
+                    Block *block = StaticRegistry<BlockType>::INSTANCE.zElement( blockType )->loadBlock( Framework::Vec3<int>( x, y, z ), zGame, zReader );
+                    blocks[ ( x * CHUNK_SIZE + y ) * CHUNK_SIZE + z ] = block;
+                }
+            }
+        }
+    }
+}
+
+void Chunk::save( Framework::Writer *zWriter )
+{
+    for( int x = 0; x < CHUNK_SIZE; x++ )
+    {
+        for( int y = 0; y < CHUNK_SIZE; y++ )
+        {
+            for( int z = 0; z < WORLD_HEIGHT; z++ )
+            {
+                int index = ( x * CHUNK_SIZE + y ) * CHUNK_SIZE + z;
+                int blockType = blocks[ index ] ? blocks[ ( x * CHUNK_SIZE + y ) * CHUNK_SIZE + z ]->zType->getId() : -1;
+                zWriter->schreibe( (char *)&blockType, 4 );
+                if( blockType >= 0 )
+                    StaticRegistry<BlockType>::INSTANCE.zElement( blockType )->saveBlock( blocks[ index ], zWriter );
+            }
+        }
+    }
+}
+
+int Chunk::getDimensionId() const
+{
+    return dimensionId;
+}

+ 13 - 7
FactoryCraft/Chunk.h

@@ -8,19 +8,25 @@
 #include <Datei.h>
 #include <Punkt.h>
 
+class Game;
+
 class Chunk : public EventThrower
 {
 private:
-    Block **blocks;
+    Game *zGame;
+    int dimensionId;
     Framework::Punkt location;
-    Framework::RCArray<Event> events;
-    Chunk *neighbours[ 4 ];
+    Block **blocks;
+    Chunk *zNeighbours[ 4 ];
 
 public:
-    Chunk( Framework::Punkt location );
+    Chunk( Framework::Punkt location, Game *zGame, int dimensionId );
+    Chunk( Framework::Punkt location, Game *zGame, int dimensionId, Framework::Reader *zReader );
+    ~Chunk();
     Block *getBlockAt( Framework::Vec3<int> location );
     void putBlockAt( Framework::Vec3<int> location, Block *block );
-    void setNeighbor( Chunk *zChunk );
-    virtual void tick();
-    virtual void postTick();
+    void setNeighbor( Direction dir, Chunk *zChunk );
+    void load( Framework::Reader *zReader );
+    void save( Framework::Writer *zWriter );
+    int getDimensionId() const;
 };

+ 2 - 1
FactoryCraft/Constants.h

@@ -6,4 +6,5 @@
 #define BIOM_GENERATION_Z_OFFSET 100
 #define AIR_LEVEL_Z_OFFSET 99
 #define MIN_AIR_LEVEL 100
-#define MAX_AIR_LEVEL 400
+#define MAX_AIR_LEVEL 400
+#define NUM_TICK_WORKERS 4

+ 1 - 1
FactoryCraft/Dimension.h

@@ -11,5 +11,5 @@ private:
 public:
     Dimension( int id );
 
-
+    Block *zBlock( Framework::Vec3<int> location );
 };

+ 2 - 2
FactoryCraft/DimensionGenerator.cpp

@@ -23,7 +23,7 @@ void DimensionGenerator::findBiom( int x, int y, Noise *zNoise, BiomGenerator **
     firstChoiceWeight = 0;
     secondChoiceWeight = 0;
     int z = BIOM_GENERATION_Z_OFFSET;
-    for( Framework::Iterator<BiomGenerator *> it = biomGenerators.getIterator(); it.hasNext(); it.next() )
+    for( Framework::Iterator<BiomGenerator *> it = biomGenerators.getIterator(); it; it++ )
     {
         double noise = zNoise->getNoise( x * it->getBiomXMultiplier(), y * it->getBiomYMultiplier(), z ) * it->getBiomOutputMultiplier();
         if( noise > firstChoiceWeight )
@@ -53,7 +53,7 @@ Chunk *DimensionGenerator::generateChunk( Noise *zNoise, Game *zGame, int center
     BiomGenerator *neighborBiom;
     double actualWeight;
     double neighborWeight;
-    Chunk *chunk = new Chunk( Framework::Punkt( centerX, centerY ) );
+    Chunk *chunk = new Chunk( Framework::Punkt( centerX, centerY ), zGame, dimensionId );
     for( int x = -CHUNK_SIZE / 2; x < CHUNK_SIZE / 2; x++ )
     {
         for( int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++ )

+ 6 - 0
FactoryCraft/Entity.h

@@ -5,12 +5,18 @@
 
 #include "Effect.h"
 
+class EntityType;
+
 class Entity : public virtual Framework::ReferenceCounter
 {
 private:
     float maxHP;
     float currentHP;
     Framework::Vec3<float> position;
+    EntityType *zEntityType;
+
+public:
 
     friend Effect;
+    friend EntityType;
 };

+ 33 - 0
FactoryCraft/EntityType.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include <Reader.h>
+#include <ReferenceCounter.h>
+#include <Writer.h>
+#include <Vec3.h>
+
+#include "StaticRegistry.h"
+
+class Entity;
+class Game;
+
+class EntityType : public virtual Framework::ReferenceCounter
+{
+private:
+    const int id;
+
+protected:
+    EntityType( int id );
+
+    virtual void loadSuperEntity( Entity *zEntity, Framework::Reader *zReader );
+    virtual void saveSuperEntity( Entity *zEntity, Framework::Writer *zWriter );
+    virtual void createSuperEntity( Entity *zEntity );
+    virtual void saveSuperEntity( Entity *zEntity );
+    virtual Entity *createEntity( Game *zTarget ) = 0;
+
+public:
+    virtual Entity *loadEntity( Framework::Vec3<float> position, Game *zTarget, Framework::Reader *zReader );
+    virtual void saveEntity( Entity *zEntity, Framework::Writer *zWriter );
+    virtual Entity *createEntityAt( Framework::Vec3<float> position, Game *zTarget );
+
+    int getId() const;
+};

+ 15 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -93,6 +93,8 @@
   </PropertyGroup>
   <ItemGroup>
     <ClInclude Include="AbstractEventListener.h" />
+    <ClInclude Include="AddChunkUpdate.h" />
+    <ClInclude Include="Area.h" />
     <ClInclude Include="BasicBlocks.h" />
     <ClInclude Include="BasicInterpolator.h" />
     <ClInclude Include="BiomGenerator.h" />
@@ -108,6 +110,7 @@
     <ClInclude Include="Effect.h" />
     <ClInclude Include="EffectFactory.h" />
     <ClInclude Include="Entity.h" />
+    <ClInclude Include="EntityType.h" />
     <ClInclude Include="Event.h" />
     <ClInclude Include="EventListener.h" />
     <ClInclude Include="DefaultEventListener.h" />
@@ -128,7 +131,12 @@
     <ClInclude Include="Server.h" />
     <ClInclude Include="Dimension.h" />
     <ClInclude Include="StaticRegistry.h" />
+    <ClInclude Include="TickOrganizer.h" />
+    <ClInclude Include="TickQueue.h" />
+    <ClInclude Include="TickWorker.h" />
     <ClInclude Include="WorldGenerator.h" />
+    <ClInclude Include="WorldLoader.h" />
+    <ClInclude Include="WorldUpdate.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="BasicBlock.cpp" />
@@ -136,9 +144,11 @@
     <ClCompile Include="BiomGenerator.cpp" />
     <ClCompile Include="Block.cpp" />
     <ClCompile Include="BlockType.cpp" />
+    <ClCompile Include="Chunk.cpp" />
     <ClCompile Include="Datenbank.cpp" />
     <ClCompile Include="DimensionGenerator.cpp" />
     <ClCompile Include="GrasslandBiom.cpp" />
+    <ClCompile Include="Item.cpp" />
     <ClCompile Include="ItemType.cpp" />
     <ClCompile Include="Noise.cpp" />
     <ClCompile Include="OverworldDimension.cpp" />
@@ -146,7 +156,12 @@
     <ClCompile Include="Server.cpp" />
     <ClCompile Include="Start.cpp" />
     <ClCompile Include="StaticInitializerOrder.cpp" />
+    <ClCompile Include="TickOrganizer.cpp" />
+    <ClCompile Include="TickQueue.cpp" />
+    <ClCompile Include="TickWorker.cpp" />
     <ClCompile Include="WorldGenerator.cpp" />
+    <ClCompile Include="WorldLoader.cpp" />
+    <ClCompile Include="WorldUpdate.cpp" />
   </ItemGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <Link>

+ 54 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -49,6 +49,15 @@
     <Filter Include="world\generator\interpolators">
       <UniqueIdentifier>{0a55e1c5-132f-4a40-bbfe-9bc9f100e4fa}</UniqueIdentifier>
     </Filter>
+    <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>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Datenbank.h">
@@ -162,6 +171,30 @@
     <ClInclude Include="Constants.h">
       <Filter>game</Filter>
     </ClInclude>
+    <ClInclude Include="TickWorker.h">
+      <Filter>world\ticking</Filter>
+    </ClInclude>
+    <ClInclude Include="TickQueue.h">
+      <Filter>world\ticking</Filter>
+    </ClInclude>
+    <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>
+    <ClInclude Include="AddChunkUpdate.h">
+      <Filter>world\update</Filter>
+    </ClInclude>
+    <ClInclude Include="WorldLoader.h">
+      <Filter>world\loader</Filter>
+    </ClInclude>
+    <ClInclude Include="Area.h">
+      <Filter>world</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -212,5 +245,26 @@
     <ClCompile Include="BiomGenerator.cpp">
       <Filter>world\generator</Filter>
     </ClCompile>
+    <ClCompile Include="TickWorker.cpp">
+      <Filter>world\ticking</Filter>
+    </ClCompile>
+    <ClCompile Include="TickOrganizer.cpp">
+      <Filter>world\ticking</Filter>
+    </ClCompile>
+    <ClCompile Include="TickQueue.cpp">
+      <Filter>world\ticking</Filter>
+    </ClCompile>
+    <ClCompile Include="Item.cpp">
+      <Filter>items</Filter>
+    </ClCompile>
+    <ClCompile Include="Chunk.cpp">
+      <Filter>world</Filter>
+    </ClCompile>
+    <ClCompile Include="WorldLoader.cpp">
+      <Filter>world\loader</Filter>
+    </ClCompile>
+    <ClCompile Include="WorldUpdate.cpp">
+      <Filter>world\update</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 16 - 4
FactoryCraft/Game.h

@@ -2,23 +2,35 @@
 
 #include <Text.h>
 #include <Punkt.h>
+#include <Thread.h>
 
 #include "Dimension.h"
 #include "Player.h"
 #include "WorldGenerator.h"
 #include "Constants.h"
+#include "WorldUpdate.h"
+#include "WorldLoader.h"
 
-class Game : public virtual Framework::ReferenceCounter
+class Game : public virtual Framework::Thread
 {
 private:
     Framework::Text name;
     Framework::RCArray<Dimension> *dimension;
     Framework::RCArray<Entity> *entities;
+    Framework::RCArray<WorldUpdate> *updates;
     WorldGenerator *generator;
+    WorldLoader *loader;
     __int64 tickId;
 
+    void thread() override;
 public:
-
-    void addChunck( Chunk *chunk, int dimensionId );
-    Framework::Punkt getChunkCenter( int x, int y );
+    Game();
+    ~Game();
+    void requestWorldUpdate( WorldUpdate *update );
+    bool doesChunkExist( int x, int y, int dimension ) const;
+    Block *zBlockAt( Framework::Vec3<int> location, int dimension ) const;
+    Framework::Punkt getChunkCenter( int x, int y ) const;
+    Text getWorldDirectory() const;
+    void requestArea( Area area );
+    void save();
 };

+ 1 - 1
FactoryCraft/GrasslandBiom.cpp

@@ -18,5 +18,5 @@ GrasslandBiom::GrasslandBiom( double biomXMultiplier, double biomYMultiplier, do
 
 Block *GrasslandBiom::getBlock( Noise *zNoise, int x, int y, int z, Game *zGame )
 {
-    StaticRegistry<BlockType>::INSTANCE.zElement( 1 )->createBlockAt( Framework::Vec3<int>( x, y, z ), zGame, 0 );
+    return StaticRegistry<BlockType>::INSTANCE.zElement( 1 )->createBlockAt( Framework::Vec3<int>( x, y, z ), zGame, 0 );
 }

+ 100 - 0
FactoryCraft/Item.cpp

@@ -0,0 +1,100 @@
+#include "Item.h"
+
+
+Item::Item( ItemType *zType, const char *name )
+    : ReferenceCounter(),
+    zType( zType ),
+    damage( 0 ),
+    maxDamage( 0 ),
+    durability( 0 ),
+    maxDurability( 0 ),
+    eatable( 0 ),
+    placeable( 0 ),
+    equippable( 0 ),
+    usable( 0 ),
+    maxStackSize( 50 ),
+    name( name )
+{}
+
+void Item::tick()
+{}
+
+const ItemType *Item::zItemType() const
+{
+    return zType;
+}
+
+float Item::getDamage() const
+{
+    return damage;
+}
+
+float Item::getDurability() const
+{
+    return durability;
+}
+
+bool Item::isUsable() const
+{
+    return usable;
+}
+
+bool Item::isEatable() const
+{
+    return eatable;
+}
+
+bool Item::isPlaceable() const
+{
+    return placeable;
+}
+
+bool Item::isEquippable() const
+{
+    return equippable;
+}
+
+float Item::getMaxDurability() const
+{
+    return maxDurability;
+}
+
+int Item::getMaxStackSize() const
+{
+    return maxStackSize;
+}
+
+float Item::getMaxDamage() const
+{
+    return maxDamage;
+}
+
+bool Item::canBeStackedWith( Item *zItem ) const
+{
+    return zType == zItem->zType && damage == 0 &&
+        zItem->damage == 0 &&
+        durability == maxDurability &&
+        zItem->durability == zItem->maxDurability &&
+        maxDamage == zItem->maxDamage &&
+        eatable == zItem->eatable &&
+        placeable == zItem->placeable &&
+        equippable == zItem->eatable &&
+        usable == zItem->usable &&
+        maxStackSize == zItem->maxStackSize &&
+        name.istGleich( zItem->name );
+}
+
+void Item::applyInventoryEffects( Entity *zTarget )
+{}
+
+void Item::removeInventoryEffects( Entity *zTarget )
+{}
+
+void Item::applyEquippedEffects( Entity *zTarget )
+{}
+
+void Item::removeEquippedEffects( Entity *zTarget )
+{}
+
+void Item::applyFoodEffects( Entity *zTarget )
+{}

+ 7 - 5
FactoryCraft/Item.h

@@ -3,6 +3,8 @@
 #include "ItemType.h"
 #include "Reader.h"
 
+class ItemType;
+
 class Item : public virtual Framework::ReferenceCounter
 {
 private:
@@ -14,14 +16,12 @@ private:
     bool eatable;
     bool placeable;
     bool equippable;
+    bool usable;
     int maxStackSize;
     Framework::Text name;
 
-private:
-    Item( ItemType *zType, float damage );
-    Item( ItemType *zType );
-    Item( Item *zClone );
-    Item( Framework::StreamReader *zItemInfo );
+protected:
+    Item( ItemType *zType, const char *name );
 
 public:
     virtual void tick();
@@ -29,12 +29,14 @@ public:
     const ItemType *zItemType() const;
     float getDamage() const;
     float getDurability() const;
+    bool isUsable() const;
     bool isEatable() const;
     bool isPlaceable() const;
     bool isEquippable() const;
     float getMaxDurability() const;
     int getMaxStackSize() const;
     float getMaxDamage() const;
+    virtual bool canBeStackedWith( Item *zItem ) const;
 
     virtual void applyInventoryEffects( Entity *zTarget );
     virtual void removeInventoryEffects( Entity *zTarget );

+ 48 - 7
FactoryCraft/ItemType.cpp

@@ -3,11 +3,12 @@
 #include "ItemSkill.h"
 #include "ItemStack.h"
 
-ItemType::ItemType( int id, ItemSkillLevelUpRule *levelUpRule )
+ItemType::ItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType )
     : ReferenceCounter(),
-    id( id )
+    id( id ),
+    levelUpRule( levelUpRule ),
+    zBrokenType( zBrokenType )
 {
-    this->levelUpRule = levelUpRule;
     StaticRegistry<ItemType>::INSTANCE.registerT( this, id );
 }
 
@@ -17,14 +18,49 @@ ItemType::~ItemType()
         levelUpRule->release();
 }
 
-void ItemType::loadSupperItem( Item *zItem, Framework::Reader *zReader ) const {}
-void ItemType::saveSupperItem( Item *zItem, Framework::Writer *zWriter ) const {}
+void ItemType::loadSuperItem( Item *zItem, Framework::Reader *zReader ) const
+{
+    zReader->lese( (char *)&zItem->damage, 4 );
+    zReader->lese( (char *)&zItem->maxDamage, 4 );
+    zReader->lese( (char *)&zItem->durability, 4 );
+    zReader->lese( (char *)&zItem->maxDurability, 4 );
+    zReader->lese( (char *)&zItem->eatable, 1 );
+    zReader->lese( (char *)&zItem->placeable, 1 );
+    zReader->lese( (char *)&zItem->equippable, 1 );
+    zReader->lese( (char *)&zItem->usable, 1 );
+    zReader->lese( (char *)&zItem->maxStackSize, 1 );
+    unsigned char len = 0;
+    zReader->lese( (char *)&len, 1 );
+    zItem->name.fillText( ' ', len );
+    zReader->lese( zItem->name, len );
+}
+
+void ItemType::saveSuperItem( Item *zItem, Framework::Writer *zWriter ) const
+{
+    zWriter->schreibe( (char *)&zItem->damage, 4 );
+    zWriter->schreibe( (char *)&zItem->maxDamage, 4 );
+    zWriter->schreibe( (char *)&zItem->durability, 4 );
+    zWriter->schreibe( (char *)&zItem->maxDurability, 4 );
+    zWriter->schreibe( (char *)&zItem->eatable, 1 );
+    zWriter->schreibe( (char *)&zItem->placeable, 1 );
+    zWriter->schreibe( (char *)&zItem->equippable, 1 );
+    zWriter->schreibe( (char *)&zItem->usable, 1 );
+    zWriter->schreibe( (char *)&zItem->maxStackSize, 1 );
+    unsigned char len = (unsigned char)zItem->name.getLength();
+    zWriter->schreibe( (char *)&len, 1 );
+    zWriter->schreibe( zItem->name, len );
+}
 
 int ItemType::getId() const
 {
     return id;
 }
 
+ItemType *ItemType::zBrokenItemType() const
+{
+    return zBrokenType;
+}
+
 ItemStack *ItemType::createItemStack( int size ) const
 {
     Item *item = createItem();
@@ -46,7 +82,12 @@ void ItemType::levelUpItemSkill( ItemSkill *zSkill ) const
 
 Item *ItemType::loadItem( Framework::Reader *zReader ) const
 {
-    return createItem();
+    Item *item = createItem();
+    loadSuperItem( item, zReader );
+    return item;
 }
 
-void ItemType::saveItem( Item *zItem, Framework::Writer *zWriter ) const {}
+void ItemType::saveItem( Item *zItem, Framework::Writer *zWriter ) const
+{
+    saveSuperItem( zItem, zWriter );
+}

+ 6 - 5
FactoryCraft/ItemType.h

@@ -15,20 +15,21 @@ class ItemSkillLevelUpRule;
 
 class ItemType : public virtual Framework::ReferenceCounter
 {
-private:
+protected:
     const int id;
     ItemSkillLevelUpRule *levelUpRule;
+    ItemType *zBrokenType;
 
-protected:
-    ItemType( int id, ItemSkillLevelUpRule *levelUpRule );
+    ItemType( int id, ItemSkillLevelUpRule *levelUpRule, ItemType *zBrokenType );
 
-    virtual void loadSupperItem( Item *zItem, Framework::Reader *zReader ) const;
-    virtual void saveSupperItem( Item *zItem, Framework::Writer *zWriter ) const;
+    virtual void loadSuperItem( Item *zItem, Framework::Reader *zReader ) const;
+    virtual void saveSuperItem( Item *zItem, Framework::Writer *zWriter ) const;
 
 public:
     ~ItemType();
 
     int getId() const;
+    ItemType *zBrokenItemType() const;
     virtual Item *createItem() const = 0;
     virtual ItemStack *createItemStack( int size ) const;
     virtual ItemSkill *createDefaultItemSkill() const;

+ 1 - 1
FactoryCraft/OverworldDimension.cpp

@@ -3,7 +3,7 @@
 #include "GrasslandBiom.h"
 
 OverworldDimension::OverworldDimension()
-    : DimensionGenerator( new BasicInterpolator(), 0 )
+    : DimensionGenerator( new BasicInterpolator(), ID )
 {
     registerBiom( new GrasslandBiom() );
 }

+ 2 - 1
FactoryCraft/OverworldDimension.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "DimensionGenerator.h"
+#include "StaticRegistry.h"
 
 class OverworldDimension : public DimensionGenerator
 {
@@ -10,5 +11,5 @@ public:
 };
 
 #ifdef REGISTER
-REGISTER( OverworldDimension )
+REGISTER( OverworldDimension, DimensionGenerator )
 #endif

+ 16 - 1
FactoryCraft/Player.h

@@ -1,12 +1,27 @@
 #pragma once
 
 #include "Entity.h"
+#include "EntityType.h"
+
+class PlayerEntityType;
 
 class Player : public Entity
 {
 private:
 
+public:
+
+    friend PlayerEntityType;
+};
+
+class PlayerEntityType : public EntityType
+{
+    REGISTRABLE( PlayerEntityType )
 
 public:
+    PlayerEntityType();
+
+    Entity *createEntity( Game *zTarget ) override;
+};
 
-};
+REGISTER( PlayerEntityType, EntityType )

+ 8 - 1
FactoryCraft/StaticInitializerOrder.cpp

@@ -2,7 +2,14 @@
 #include "BlockType.h"
 #include "ItemType.h"
 
-#define REGISTER(x) const x* x::INSTANCE = new x();
+int count_DimensionGenerator = 0;
+int count_ItemType = 0;
+int count_BlockType = 0;
+
+#define REGISTER(c, typ)               \
+const int c::ID = count_##typ++;       \
+const c *c::INSTANCE = new c(); 
 
 #include "BasicBlocks.h"
+#include "OverworldDimension.h"
 

+ 5 - 2
FactoryCraft/StaticRegistry.h

@@ -1,11 +1,14 @@
 #pragma once
 
-#define REGISTRABLE(x)            \
+#define REGISTRABLE( c )          \
 public:                           \
-    static const x *INSTANCE;           \
+    static const c *INSTANCE;     \
+    static const int ID;          \
                                   \
 private:
 
+#define REGISTER(c, typ)
+
 
 template<typename T>
 class StaticRegistry

+ 57 - 0
FactoryCraft/TickOrganizer.cpp

@@ -0,0 +1,57 @@
+#include "TickOrganizer.h"
+#include "Constants.h"
+
+
+TickOrganizer::TickOrganizer()
+    : ReferenceCounter()
+{
+    queue = new TickQueue();
+    workerCount = NUM_TICK_WORKERS;
+    workers = new TickWorker * [ workerCount ];
+    for( int i = 0; i < workerCount; i++ )
+        workers[ i ] = new TickWorker( queue );
+}
+
+TickOrganizer::~TickOrganizer()
+{
+    queue->requestExit();
+    for( int i = 0; i < workerCount; i++ )
+    {
+        workers[ i ]->warteAufThread( 10000 );
+        workers[ i ]->ende();
+        workers[ i ]->release();
+    }
+    queue->release();
+    delete[] workers;
+}
+
+void TickOrganizer::nextTick()
+{
+    bool waiting = 0;
+    do
+    {
+        if( waiting )
+            queue->waitForEmpty();
+        for( int i = 0; i < workerCount; i++ )
+            waiting |= workers[ i ]->isWaiting();
+    } while( waiting );
+    queue->startNextTick( &tickSources );
+}
+
+void TickOrganizer::addTickSource( Block *zBlock )
+{
+    tickSources.add( zBlock );
+}
+
+void TickOrganizer::removeTickSource( Block *zBlock )
+{
+    int index = 0;
+    for( Framework::Iterator<Block *> it = tickSources.getIterator(); it; it++, index++ )
+    {
+        if( it == zBlock )
+        {
+            tickSources.remove( index );
+            return;
+        }
+    }
+}

+ 23 - 0
FactoryCraft/TickOrganizer.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include <Array.h>
+
+#include "TickWorker.h"
+
+class TickOrganizer : public virtual Framework::ReferenceCounter
+{
+private:
+    int workerCount;
+    TickWorker **workers;
+    Framework::Array<Block *> tickSources;
+    TickQueue *queue;
+
+public:
+    TickOrganizer();
+    ~TickOrganizer();
+
+    void nextTick();
+
+    void addTickSource( Block *zBlock );
+    void removeTickSource( Block *zBlock );
+};

+ 90 - 0
FactoryCraft/TickQueue.cpp

@@ -0,0 +1,90 @@
+#include "TickQueue.h"
+
+
+TickQueue::TickQueue()
+    : ReferenceCounter()
+{
+    maxSize = 0;
+    readPosition = 0;
+    writePosition = 0;
+    queue = 0;
+    exit = 0;
+}
+
+TickQueue::~TickQueue()
+{
+    delete[] queue;
+}
+
+void TickQueue::startNextTick( Framework::Array<Block *> *zSources )
+{
+    std::unique_lock<std::mutex> lk( mutex );
+    readPosition = 0;
+    writePosition = 0;
+    int count = zSources->getEintragAnzahl();
+    if( count <= maxSize )
+    {
+        Block **temp = new Block * [ count + 1000 ];
+        memcpy( queue, temp, sizeof( Block * ) * maxSize );
+        memset( temp + sizeof( Block * ) * maxSize, 0, sizeof( Block * ) * ( count + 1000 - maxSize ) );
+        maxSize = count + 1000;
+        delete[]queue;
+        queue = temp;
+    }
+    for( Framework::Iterator<Block *> it = zSources->getIterator(); it; it++ )
+        queue[ writePosition++ ] = it;
+    lk.unlock();
+    hasBlocks.notify_all();
+}
+
+void TickQueue::addToQueue( Block *zBlock )
+{
+    std::unique_lock<std::mutex> lk( mutex );
+    if( writePosition <= maxSize )
+    {
+        Block **temp = new Block * [ maxSize + 1000 ];
+        memcpy( queue, temp, sizeof( Block * ) * maxSize );
+        memset( temp + sizeof( Block * ) * maxSize, 0, sizeof( Block * ) * 1000 );
+        maxSize += 1000;
+        delete[]queue;
+        queue = temp;
+    }
+    queue[ writePosition++ ] = zBlock;
+    lk.unlock();
+    hasBlocks.notify_one();
+}
+
+Block *TickQueue::zNextBlock( bool &waiting )
+{
+    std::unique_lock<std::mutex> lk( mutex );
+    if( readPosition == writePosition && exit )
+        return 0;
+    if( readPosition == writePosition )
+    {
+        lk.unlock();
+        hasNoBlocks.notify_all();
+        lk.lock();
+        waiting = 1;
+        hasBlocks.wait( lk, [this] { return readPosition < writePosition || exit; } );
+        waiting = 0;
+    }
+    if( readPosition < writePosition )
+        return queue[ readPosition++ ];
+    return 0;
+}
+
+void TickQueue::requestExit()
+{
+    std::unique_lock<std::mutex> lk( mutex );
+    exit = 1;
+    lk.unlock();
+    hasBlocks.notify_all();
+    hasNoBlocks.notify_all();
+}
+
+void TickQueue::waitForEmpty()
+{
+    std::unique_lock<std::mutex> lk( mutex );
+    if( readPosition != writePosition )
+        hasNoBlocks.wait( lk, [this] { return readPosition == writePosition || exit; } );
+}

+ 30 - 0
FactoryCraft/TickQueue.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+#include <Array.h>
+#include <condition_variable>
+
+class Block;
+
+class TickQueue : public virtual Framework::ReferenceCounter
+{
+private:
+    int maxSize;
+    int readPosition;
+    int writePosition;
+    Block **queue;
+    std::mutex mutex;
+    std::condition_variable hasBlocks;
+    std::condition_variable hasNoBlocks;
+    bool exit;
+
+public:
+    TickQueue();
+    ~TickQueue();
+
+    void startNextTick( Framework::Array<Block *> *zSources );
+    void addToQueue( Block *zBlock );
+    Block *zNextBlock( bool &waiting );
+    void requestExit();
+    void waitForEmpty();
+};

+ 31 - 0
FactoryCraft/TickWorker.cpp

@@ -0,0 +1,31 @@
+#include "TickWorker.h"
+#include "Block.h"
+
+
+TickWorker::TickWorker( TickQueue *queue )
+    : Thread(),
+    queue( queue ),
+    waiting( 0 )
+{
+    start();
+}
+
+TickWorker::~TickWorker()
+{
+    queue->release();
+}
+
+void TickWorker::thread()
+{
+    Block *zTickBlock = queue->zNextBlock( waiting );
+    while( zTickBlock )
+    {
+        zTickBlock->tick( queue );
+        zTickBlock = queue->zNextBlock( waiting );
+    }
+}
+
+bool TickWorker::isWaiting() const
+{
+    return waiting;
+}

+ 19 - 0
FactoryCraft/TickWorker.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include <Thread.h>
+
+#include "TickQueue.h"
+
+class TickWorker : public Framework::Thread
+{
+private:
+    TickQueue *queue;
+    bool waiting;
+
+public:
+    TickWorker( TickQueue *queue );
+    ~TickWorker();
+
+    void thread() override;
+    bool isWaiting() const;
+};

+ 8 - 4
FactoryCraft/WorldGenerator.cpp

@@ -2,6 +2,7 @@
 #include "StaticRegistry.h"
 #include "Game.h"
 #include "PerlinNoise.h"
+#include "AddChunkUpdate.h"
 
 using namespace Framework;
 
@@ -24,7 +25,7 @@ void WorldGenerator::thread()
     while( !exit )
     {
         cs.Enter();
-        GenerationRequest next;
+        Area next;
         bool hasNext = false;
         if( requestQueue.getEintragAnzahl() > 0 )
         {
@@ -45,14 +46,17 @@ void WorldGenerator::thread()
         {
             for( int y = start.y; y != end.y; y += CHUNK_SIZE * yDir )
             {
-                Chunk *generatedChunk = StaticRegistry<DimensionGenerator>::INSTANCE.zElement( next.dimensionId )->generateChunk( noise, zGame, x, y );
-                zGame->addChunck( generatedChunk, next.dimensionId );
+                if( !zGame->doesChunkExist( x, y, next.dimensionId ) )
+                {
+                    Chunk *generatedChunk = StaticRegistry<DimensionGenerator>::INSTANCE.zElement( next.dimensionId )->generateChunk( noise, zGame, x, y );
+                    zGame->requestWorldUpdate( new AddChunkUpdate( generatedChunk ) );
+                }
             }
         }
     }
 }
 
-void WorldGenerator::requestGeneration( GenerationRequest request )
+void WorldGenerator::requestGeneration( Area request )
 {
     cs.Enter();
     requestQueue.add( request );

+ 3 - 11
FactoryCraft/WorldGenerator.h

@@ -3,23 +3,15 @@
 #include <Thread.h>
 
 #include "DimensionGenerator.h"
+#include "Area.h"
 
 class Game;
 
-struct GenerationRequest
-{
-    int startX;
-    int startY;
-    int endX;
-    int endY;
-    int dimensionId;
-};
-
 class WorldGenerator : public Framework::Thread
 {
 private:
     CriticalSection cs;
-    Framework::Array<GenerationRequest> requestQueue;
+    Framework::Array<Area> requestQueue;
     Game *zGame;
     Noise *noise;
     bool exit;
@@ -28,6 +20,6 @@ public:
     WorldGenerator( int seed, Game *zGame );
     ~WorldGenerator();
     void thread() override;
-    void requestGeneration( GenerationRequest request );
+    void requestGeneration( Area request );
     void exitAndWait();
 };

+ 81 - 0
FactoryCraft/WorldLoader.cpp

@@ -0,0 +1,81 @@
+#include <Punkt.h>
+#include <Text.h>
+
+#include "WorldLoader.h"
+#include "Game.h"
+#include "AddChunkUpdate.h"
+
+using namespace Framework;
+
+WorldLoader::WorldLoader( Game *zGame )
+    : Thread(),
+    zGame( zGame ),
+    exit( 0 )
+{
+    start();
+}
+
+WorldLoader::~WorldLoader()
+{}
+
+void WorldLoader::thread()
+{
+    while( !exit )
+    {
+        cs.Enter();
+        Area next;
+        bool hasNext = false;
+        if( requestQueue.getEintragAnzahl() > 0 )
+        {
+            next = requestQueue.get( 0 );
+            requestQueue.remove( 0 );
+        }
+        cs.Leave();
+        if( !hasNext )
+        {
+            sleep( 1 );
+            continue;
+        }
+        Punkt start = zGame->getChunkCenter( next.startX, next.startY );
+        Punkt end = zGame->getChunkCenter( next.endX, next.endY );
+        int xDir = start.x > end.x ? -1 : ( start.x < end.x ? 1 : 0 );
+        int yDir = start.y > end.y ? -1 : ( start.y < end.y ? 1 : 0 );
+        for( int x = start.x; x != end.x; x += CHUNK_SIZE * xDir )
+        {
+            for( int y = start.y; y != end.y; y += CHUNK_SIZE * yDir )
+            {
+                if( !zGame->doesChunkExist( x, y, next.dimensionId ) )
+                {
+                    Datei *file = new Datei();
+                    Text filePath = zGame->getWorldDirectory() + "/dim/" + next.dimensionId + "/";
+                    filePath.appendHex( x );
+                    filePath += "_";
+                    filePath.appendHex( y );
+                    filePath += ".chunk";
+                    file->setDatei( filePath );
+                    if( file->open( Datei::Style::lesen ) )
+                    {
+                        Chunk *chunk = new Chunk( Framework::Punkt( x, y ), zGame, next.dimensionId, file );
+                        zGame->requestWorldUpdate( new AddChunkUpdate( chunk ) );
+                    }
+                    file->close();
+                    file->release();
+                }
+            }
+        }
+    }
+}
+
+void WorldLoader::requestGeneration( Area request )
+{
+    cs.Enter();
+    requestQueue.add( request );
+    cs.Leave();
+}
+
+void WorldLoader::exitAndWait()
+{
+    exit = 1;
+    warteAufThread( 10000 );
+    ende();
+}

+ 23 - 0
FactoryCraft/WorldLoader.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include <Thread.h>
+
+#include "Area.h"
+
+class Game;
+
+class WorldLoader : public Framework::Thread
+{
+private:
+    CriticalSection cs;
+    Framework::Array<Area> requestQueue;
+    Game *zGame;
+    bool exit;
+
+public:
+    WorldLoader( Game *zGame );
+    ~WorldLoader();
+    void thread() override;
+    void requestGeneration( Area request );
+    void exitAndWait();
+};

+ 23 - 0
FactoryCraft/WorldUpdate.cpp

@@ -0,0 +1,23 @@
+#include "WorldUpdate.h"
+
+WorldUpdate::WorldUpdate( int dimensionId, Framework::Vec3<int> minAffected, Framework::Vec3<int> maxAffected )
+    : ReferenceCounter(),
+    affectedDimensionId( dimensionId ),
+    minAffected( minAffected ),
+    maxAffected( maxAffected )
+{}
+
+int WorldUpdate::getAffectedDimension() const
+{
+    return affectedDimensionId;
+}
+
+const Framework::Vec3<int> &WorldUpdate::getMinAffectedPoint() const
+{
+    return minAffected;
+}
+
+const Framework::Vec3<int> &WorldUpdate::getMaxAffectedPoint() const
+{
+    return maxAffected;
+}

+ 26 - 0
FactoryCraft/WorldUpdate.h

@@ -0,0 +1,26 @@
+#pragma once
+
+#include <ReferenceCounter.h>
+#include <Vec3.h>
+#include <Writer.h>
+
+class Dimension;
+
+class WorldUpdate : public Framework::ReferenceCounter
+{
+private:
+    int affectedDimensionId;
+    Framework::Vec3<int> minAffected;
+    Framework::Vec3<int> maxAffected;
+
+public:
+    WorldUpdate( int dimensionId, Framework::Vec3<int> minAffected, Framework::Vec3<int> maxAffected );
+
+    virtual void onUpdate( Dimension *zDimension ) = 0;
+    virtual void write( Framework::Writer *zWriter ) = 0;
+
+    int getAffectedDimension() const;
+    const Framework::Vec3<int> &getMinAffectedPoint() const;
+    const Framework::Vec3<int> &getMaxAffectedPoint() const;
+};
+