Bladeren bron

Implemented Item usage ans Skill system

Kolja Strohm 3 jaren geleden
bovenliggende
commit
d703f6bfdf

+ 1 - 1
FactoryCraft/AddChunkUpdate.cpp

@@ -5,7 +5,7 @@
 
 
 AddChunkUpdate::AddChunkUpdate( Chunk* chunk )
-    : WorldUpdate( AddChunkUpdateType::ID, chunk->getDimensionId(), Framework::Vec3<int>( chunk->getCenter().x - CHUNK_SIZE / 2, chunk->getCenter().y - CHUNK_SIZE / 2, 0 ), Framework::Vec3<int>( chunk->getCenter().x + CHUNK_SIZE / 2, chunk->getCenter().y + CHUNK_SIZE / 2, WORLD_HEIGHT - 1 ) ),
+    : WorldUpdate( AddChunkUpdateType::ID, chunk->getDimensionId(), Framework::Vec3<int>( chunk->getCenter().x - CHUNK_SIZE / 2, chunk->getCenter().y - CHUNK_SIZE / 2, 0 ), Framework::Vec3<int>( chunk->getCenter().x + CHUNK_SIZE / 2 - 1, chunk->getCenter().y + CHUNK_SIZE / 2 - 1, WORLD_HEIGHT - 1 ) ),
     chunk( chunk )
 {}
 

+ 2 - 0
FactoryCraft/Area.h

@@ -23,6 +23,8 @@ enum Direction
 };
 typedef int Directions;
 
+#define ANY_DIRECTION NORTH | EAST | SOUTH | WEST | TOP | BOTTOM
+
 Direction getOppositeDirection( Direction dir );
 Directions getDirections( Framework::Vec3<float> currentPos, Framework::Vec3<float> otherPos );
 Framework::Vec3<int> getDirection( Directions dir );

+ 10 - 9
FactoryCraft/BasicBlock.cpp

@@ -1,7 +1,7 @@
 #include "BasicBlocks.h"
 
 
-BasicBlock::BasicBlock( BlockType* zType, ItemType* zTool, Framework::Vec3<int> pos )
+BasicBlock::BasicBlock( const BlockType* zType, ItemType* zTool, Framework::Vec3<int> pos )
     : Block( zType, zTool, pos, false )
 {}
 
@@ -15,20 +15,20 @@ void BasicBlock::onPostTick()
 
 
 DirtBlockType::DirtBlockType()
-    : BlockType( ID )
+    : BlockType( ID, createBlock( { 0, 0, 0 }, 0 ) )
 {}
 
-void DirtBlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader )
+void DirtBlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader ) const
 {
     BlockType::loadSuperBlock( zBlock, zReader );
 }
 
-void DirtBlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter )
+void DirtBlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const
 {
     BlockType::saveSuperBlock( zBlock, zWriter );
 }
 
-void DirtBlockType::createSuperBlock( Block* zBlock, Item* zItem )
+void DirtBlockType::createSuperBlock( Block* zBlock, Item* zItem ) const
 {
     if( zItem )
         BlockType::createSuperBlock( zBlock, zItem );
@@ -44,20 +44,21 @@ void DirtBlockType::createSuperBlock( Block* zBlock, Item* zItem )
         block->hardness = 1;
         block->zTool = 0;
         block->speedModifier = 1;
+        block->interactable = 1;
     }
 }
 
-void DirtBlockType::createSuperItem( Block* zBlock, Item* zItem )
+void DirtBlockType::createSuperItem( Block* zBlock, Item* zItem ) const
 {
     BlockType::createSuperItem( zBlock, zItem );
 }
 
-Block* DirtBlockType::createBlock( Framework::Vec3<int> position, Game* zTarget )
+Block* DirtBlockType::createBlock( Framework::Vec3<int> position, Game* zTarget ) const
 {
     return new BasicBlock( this, 0, position ); // TODO: add efective tool
 }
 
-Item* DirtBlockType::createItem( Game* zTarget )
+Item* DirtBlockType::createItem( Game* zTarget ) const
 {
     return StaticRegistry<ItemType>::INSTANCE.zElement( DirtBlockItemType::ID )->createItem();
 }
@@ -69,7 +70,7 @@ DirtBlockItemType::DirtBlockItemType()
 
 Item* DirtBlockItemType::createItem() const
 {
-    BasicBlockItem* item = new BasicBlockItem( (ItemType*)this, "Dirt" );
+    BasicBlockItem* item = new BasicBlockItem( (ItemType*)this, DirtBlockType::INSTANCE, "Dirt" );
     initializeItem( item, 0, 0, 100, 100, 1, 0, 1 );
     return item;
 }

+ 7 - 7
FactoryCraft/BasicBlocks.h

@@ -12,7 +12,7 @@ class DirtBlockItemType;
 class BasicBlock : public Block
 {
 public:
-    BasicBlock( BlockType* zType, ItemType* zTool, Framework::Vec3<int> pos );
+    BasicBlock( const BlockType* zType, ItemType* zTool, Framework::Vec3<int> pos );
     virtual bool onTick( TickQueue* zQueue, int numTicks, bool& blocked ) override;
     virtual void onPostTick() override;
 
@@ -24,12 +24,12 @@ class DirtBlockType : public BlockType
     REGISTRABLE( DirtBlockType )
 
 protected:
-    virtual void loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader ) override;
-    virtual void saveSuperBlock( Block* zBlock, Framework::StreamWriter* 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;
+    virtual void loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader ) const override;
+    virtual void saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const override;
+    virtual void createSuperBlock( Block* zBlock, Item* zItem ) const override;
+    virtual void createSuperItem( Block* zBlock, Item* zItem ) const override;
+    virtual Block* createBlock( Framework::Vec3<int> position, Game* zTarget ) const override;
+    virtual Item* createItem( Game* zTarget ) const override;
     DirtBlockType();
 };
 REGISTER( DirtBlockType, BlockType )

+ 8 - 1
FactoryCraft/Block.cpp

@@ -21,6 +21,7 @@ Block::Block( const BlockType* zType, ItemType* zTool, Framework::Vec3<int> pos,
     tickSource = 0;
     currentTickTimeout = 0;
     dimansionId = 0;
+    interactable = 0;
     memset( zNeighbours, 0, sizeof( Block* ) * 6 );
 }
 
@@ -119,6 +120,11 @@ bool Block::isPassable() const
     return passable;
 }
 
+bool Block::isInteractable() const
+{
+    return interactable;
+}
+
 float Block::getHP() const
 {
     return hp;
@@ -168,10 +174,11 @@ bool Block::isVisible() const
 }
 
 
-BasicBlockItem::BasicBlockItem( const ItemType* zType, const char* name )
+BasicBlockItem::BasicBlockItem( const ItemType* zType, const BlockType* zPlacedBlockType, const char* name )
     : Item( zType, name )
 {
     placeable = 1;
+    zBlockType = zPlacedBlockType;
 }
 
 bool BasicBlockItem::canBeStackedWith( Item* zItem ) const

+ 3 - 1
FactoryCraft/Block.h

@@ -42,6 +42,7 @@ protected:
     int minTickTimeout;
     int maxTickTimeout;
     bool tickSource;
+    bool interactable;
 
     /// <summary>
     /// executes block specific things
@@ -74,6 +75,7 @@ public:
     const BlockType* zBlockType() const;
     bool isTransparent() const;
     bool isPassable() const;
+    bool isInteractable() const;
     float getHP() const;
     float getMaxHP() const;
     float getHardness() const;
@@ -98,7 +100,7 @@ protected:
     float speedModifier;
 
 public:
-    BasicBlockItem( const ItemType* zType, const char* name );
+    BasicBlockItem( const ItemType* zType, const BlockType* zPlacedBlockType, const char* name );
     virtual bool canBeStackedWith( Item* zItem ) const override;
 
     friend BasicBlockItemType;

+ 11 - 13
FactoryCraft/BlockType.cpp

@@ -5,10 +5,10 @@
 
 using namespace Framework;
 
-BlockType::BlockType( int id )
+BlockType::BlockType( int id, Block* defaultBlock )
     : ReferenceCounter(),
     id( id ),
-    defaultBlock( 0 )
+    defaultBlock( defaultBlock )
 {
     StaticRegistry<BlockType>::INSTANCE.registerT( this, id );
 }
@@ -19,7 +19,7 @@ BlockType::~BlockType()
         defaultBlock->release();
 }
 
-void BlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader )
+void BlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader ) const
 {
     zBlock->loadInventory( zReader );
     zReader->lese( (char*)&zBlock->transparent, 1 );
@@ -36,7 +36,7 @@ void BlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader
         zBlock->zTool = 0;
 }
 
-void BlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter )
+void BlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const
 {
     zBlock->saveInventory( zWriter );
     zWriter->schreibe( (char*)&zBlock->transparent, 1 );
@@ -49,7 +49,7 @@ void BlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter
     zWriter->schreibe( (char*)&effectiveToolId, 4 );
 }
 
-void BlockType::createSuperBlock( Block* zBlock, Item* zItem )
+void BlockType::createSuperBlock( Block* zBlock, Item* zItem ) const
 {
     BasicBlockItem* item = dynamic_cast<BasicBlockItem*>(zItem);
     if( !item )
@@ -65,7 +65,7 @@ void BlockType::createSuperBlock( Block* zBlock, Item* zItem )
     zBlock->zTool = StaticRegistry<ItemType>::INSTANCE.zElement( item->toolId );
 }
 
-void BlockType::createSuperItem( Block* zBlock, Item* zItem )
+void BlockType::createSuperItem( Block* zBlock, Item* zItem ) const
 {
     BasicBlockItem* item = dynamic_cast<BasicBlockItem*>(zItem);
     if( !item )
@@ -81,26 +81,26 @@ void BlockType::createSuperItem( Block* zBlock, Item* zItem )
     item->toolId = zBlock->zTool->getId();
 }
 
-Block* BlockType::loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader )
+Block* BlockType::loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader ) const
 {
     Block* result = createBlock( position, zTarget );
     loadSuperBlock( result, zReader );
     return result;
 }
 
-void BlockType::saveBlock( Block* zBlock, Framework::StreamWriter* zWriter )
+void BlockType::saveBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const
 {
     saveSuperBlock( zBlock, zWriter );
 }
 
-Item* BlockType::getItemFromBlock( Block* zBlock, Game* zTarget )
+Item* BlockType::getItemFromBlock( Block* zBlock, Game* zTarget ) const
 {
     Item* result = createItem( zTarget );
     createSuperItem( zBlock, result );
     return result;
 }
 
-Block* BlockType::createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem )
+Block* BlockType::createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem ) const
 {
     Block* result = createBlock( position, zTarget );
     createSuperBlock( result, zUsedItem );
@@ -112,10 +112,8 @@ int BlockType::getId() const
     return id;
 }
 
-const Block* BlockType::zDefault()
+const Block* BlockType::zDefault() const
 {
-    if( !defaultBlock )
-        defaultBlock = createBlock( { 0, 0, 0 }, 0 );
     return defaultBlock;
 }
 

+ 12 - 12
FactoryCraft/BlockType.h

@@ -18,22 +18,22 @@ private:
     Block* defaultBlock;
 
 protected:
-    BlockType( int id );
+    BlockType( int id, Block* defaultBlock );
     virtual ~BlockType();
 
-    virtual void loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader );
-    virtual void saveSuperBlock( Block* zBlock, Framework::StreamWriter* 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;
+    virtual void loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader ) const;
+    virtual void saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const;
+    virtual void createSuperBlock( Block* zBlock, Item* zItem ) const;
+    virtual void createSuperItem( Block* zBlock, Item* zItem ) const;
+    virtual Block* createBlock( Framework::Vec3<int> position, Game* zTarget ) const = 0;
+    virtual Item* createItem( Game* zTarget ) const = 0;
 
 public:
-    virtual Block* loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader );
-    virtual void saveBlock( Block* zBlock, Framework::StreamWriter* zWriter );
-    virtual Item* getItemFromBlock( Block* zBlock, Game* zTarget );
-    virtual Block* createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem );
-    virtual const Block* zDefault();
+    virtual Block* loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader ) const;
+    virtual void saveBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const;
+    virtual Item* getItemFromBlock( Block* zBlock, Game* zTarget ) const;
+    virtual Block* createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem ) const;
+    virtual const Block* zDefault() const;
     int getId() const;
 };
 

+ 39 - 0
FactoryCraft/Dimension.cpp

@@ -26,6 +26,11 @@ void Dimension::api( Framework::StreamReader* zRequest, NetworkResponse* zRespon
 
 void Dimension::tickEntities( Game* zGame )
 {
+    for( auto entity : *entities )
+    {
+        if( zChunk( Punkt( (int)entity->getPosition().x, (int)entity->getPosition().y ) ) )
+            entity->prepareTick( this, zGame );
+    }
     int index = 0;
     Array<int> removed;
     for( auto entity : *entities )
@@ -79,6 +84,40 @@ Framework::Either<Block*, int> Dimension::zBlock( Vec3<int> location, const Game
     return 0;
 }
 
+Block* Dimension::zRealBlockInstance( Framework::Vec3<int> location, Game* zGame )
+{
+    Chunk* c = zChunk( zGame->getChunkCenter( location.x, location.y ) );
+    if( c )
+    {
+        int x = location.x % CHUNK_SIZE;
+        int y = location.y % CHUNK_SIZE;
+        if( x < 0 )
+            x += CHUNK_SIZE;
+        if( y < 0 )
+            y += CHUNK_SIZE;
+        c->instantiateBlock( Vec3<int>( x, y, location.z ) );
+        return c->zBlockAt( Vec3<int>( x, y, location.z ) );
+    }
+    return 0;
+}
+
+void Dimension::placeBlock( Block* block )
+{
+    Chunk* c = zChunk( Game::getChunkCenter( block->getPos().x, block->getPos().y ) );
+    if( c )
+    {
+        int x = block->getPos().x % CHUNK_SIZE;
+        int y = block->getPos().y % CHUNK_SIZE;
+        if( x < 0 )
+            x += CHUNK_SIZE;
+        if( y < 0 )
+            y += CHUNK_SIZE;
+        c->putBlockAt( block->getPos(), block );
+    }
+    else
+        block->release();
+}
+
 void Dimension::addEntity( Entity* entity )
 {
     entities->add( entity );

+ 2 - 0
FactoryCraft/Dimension.h

@@ -25,6 +25,8 @@ public:
     void tickEntities( Game* zGame );
 
     Framework::Either<Block*, int> zBlock( Framework::Vec3<int> location, const Game* zGame );
+    Block* zRealBlockInstance( Framework::Vec3<int> location, Game* zGame );
+    void placeBlock( Block* block );
     void addEntity( Entity* entity );
     void setChunk( Chunk* chunk, Framework::Punkt center );
     void save( Framework::Text worldDir ) const;

+ 229 - 0
FactoryCraft/Entity.cpp

@@ -2,11 +2,72 @@
 #include "Dimension.h"
 #include "Game.h"
 #include "BlockType.h"
+#include "ItemSkill.h"
+#include "PlaceBlockUpdate.h"
+
+ActionTarget::ActionTarget( Vec3<int> blockPos, Direction blockSide )
+    : blockPos( blockPos ),
+    targetBlockSide( blockSide ),
+    entityId( -1 )
+{}
+
+ActionTarget::ActionTarget( int entityId )
+    : entityId( entityId )
+{}
+
+void ActionTarget::applyItemSkillOnTarget( Entity* zActor, ItemSkill* zItemSkill, Item* zUsedItem, Game* zGame )
+{
+    if( entityId >= 0 )
+    {
+        // TODO: get entity from game and apply skill
+    }
+    else
+    {
+        Block* block = zGame->zRealBlockInstance( blockPos, zActor->getCurrentDimensionId() );
+        if( block )
+            zItemSkill->use( zActor, zUsedItem, block );
+    }
+}
+
+void ActionTarget::placeBlock( Entity* zActor, Item* zItem, Game* zGame )
+{
+    // TODO: check stamina of actor
+    Block* block = zItem->zPlacedBlockType()->createBlockAt( blockPos + getDirection( targetBlockSide ), zGame, zItem );
+    if( block )
+    {
+        if( zGame->requestWorldUpdate( new PlaceBlockUpdate( block, zActor->getCurrentDimensionId() ) ) )
+        {
+            zItem->onPlaced();
+            // TODO: decrese stamina of actor
+        }
+    }
+}
+
+void ActionTarget::save( Framework::StreamWriter* zWriter ) const
+{
+    if( entityId >= 0 )
+    {
+        char b = 1;
+        zWriter->schreibe( &b, 1 );
+        zWriter->schreibe( (char*)&entityId, 4 );
+    }
+    else
+    {
+        char b = 2;
+        zWriter->schreibe( &b, 1 );
+        zWriter->schreibe( (char*)&blockPos.x, 4 );
+        zWriter->schreibe( (char*)&blockPos.y, 4 );
+        zWriter->schreibe( (char*)&blockPos.z, 4 );
+        zWriter->schreibe( (char*)&targetBlockSide, 4 );
+    }
+}
+
 
 Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId )
     : Inventory( location, true ),
     speed( 0, 0, 0 ),
     faceDir( 1, 0, 0 ),
+    target( 0 ),
     zEntityType( zType ),
     currentDimensionId( dimensionId ),
     removed( 0 ),
@@ -17,6 +78,169 @@ Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int di
 void Entity::onDeath()
 {}
 
+void Entity::useItem( const ItemType* zType, Item* zItem, Game* zGame )
+{
+    if( zItem && zItem->isEatable() )
+    { // TODO: eat item
+        zItem->applyFoodEffects( this );
+    }
+    else if( zItem && zItem->isPlaceable() )
+    { // TODO: place item
+        if( target )
+            target->placeBlock( this, zItem, zGame );
+    }
+    else if( !zItem || zItem->isUsable() )
+    { // use item skill
+        if( target )
+        {
+            ItemSkill* selected = 0;
+            for( ItemSkill* skill : skills )
+            {
+                if( skill->zSkillType() == zType )
+                {
+                    selected = skill;
+                    break;
+                }
+            }
+            if( !selected )
+            {
+                selected = zType->createDefaultItemSkill();
+                skills.add( selected );
+            }
+            target->applyItemSkillOnTarget( this, selected, zItem, zGame );
+        }
+    }
+}
+
+void Entity::prepareTick( const Dimension* zDimension, Game* zGame )
+{
+    Vec3<float> headPosition = location + faceOffset;
+    int px = (int)floor( headPosition.x );
+    int py = (int)floor( headPosition.y );
+    int pz = (int)floor( headPosition.z );
+    faceDir.normalize();
+    bool needCollisionCheck = 1;
+    while( needCollisionCheck )
+    {
+        if( getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py, pz }, zDimension->getDimensionId() ) )->isInteractable() )
+        {
+            delete target;
+            target = new ActionTarget( { px, py, pz }, BOTTOM );
+            break;
+        }
+        needCollisionCheck = 0;
+        // collision to neighbor of current block current block
+        if( faceDir.x > 0 )
+        {
+            float xt = ((float)px + 1.f - headPosition.x) / faceDir.x;
+            Vec3<float> tmp = headPosition + faceDir * xt;
+            if( xt <= targetDistanceLimit && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
+            {
+                if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px + 1, py, pz }, zDimension->getDimensionId() ) )->isInteractable() )
+                {
+                    delete target;
+                    target = new ActionTarget( { px, py, pz }, WEST );
+                    break;
+                }
+                else
+                    px++;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( faceDir.x < 0 )
+        {
+            float xt = ((float)px - headPosition.x) / faceDir.x;
+            Vec3<float> tmp = headPosition + faceDir * xt;
+            if( xt <= 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
+            {
+                if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px - 1, py, pz }, zDimension->getDimensionId() ) )->isPassable() )
+                {
+                    delete target;
+                    target = new ActionTarget( { px, py, pz }, EAST );
+                    break;
+                }
+                else
+                    px--;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.y > 0 )
+        {
+            float yt = ((float)py + 1.f - headPosition.y) / faceDir.y;
+            Vec3<float> tmp = headPosition + faceDir * yt;
+            if( yt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
+            {
+                if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py + 1, pz }, zDimension->getDimensionId() ) )->isPassable() )
+                {
+                    delete target;
+                    target = new ActionTarget( { px, py, pz }, NORTH );
+                    break;
+                }
+                else
+                    py++;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.y < 0 )
+        {
+            float yt = ((float)py - headPosition.y) / faceDir.y;
+            Vec3<float> tmp = headPosition + faceDir * yt;
+            if( yt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.z >= (float)pz && tmp.z < (float)pz + 1.f )
+            {
+                if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py - 1, pz }, zDimension->getDimensionId() ) )->isPassable() )
+                {
+                    delete target;
+                    target = new ActionTarget( { px, py, pz }, SOUTH );
+                    break;
+                }
+                else
+                    py--;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.z > 0 )
+        {
+            float zt = ((float)pz + 1.f - headPosition.z) / faceDir.z;
+            Vec3<float> tmp = headPosition + faceDir * zt;
+            if( zt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1.f )
+            {
+                if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py, pz + 1 }, zDimension->getDimensionId() ) )->isPassable() )
+                {
+                    delete target;
+                    target = new ActionTarget( { px, py, pz }, BOTTOM );
+                    break;
+                }
+                else
+                    pz++;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.z < 0 )
+        {
+            float zt = ((float)pz - headPosition.z) / faceDir.z;
+            Vec3<float> tmp = headPosition + faceDir * zt;
+            if( zt <= 1.f && tmp.x >= (float)px && tmp.x < (float)px + 1.f && tmp.y >= (float)py && tmp.y < (float)py + 1 )
+            {
+                if( !getDefaultBlock( zGame->zBlockAt( Vec3<int>{ px, py, pz - 1 }, zDimension->getDimensionId() ) )->isPassable() )
+                {
+                    delete target;
+                    target = new ActionTarget( { px, py, pz }, TOP );
+                    break;
+                }
+                else
+                    pz--;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+    }
+}
+
 void Entity::tick( const Dimension* zDimension, Game* zGame )
 {
     Vec3<float> oldPos = location;
@@ -234,6 +458,11 @@ const EntityType* Entity::zType() const
     return zEntityType;
 }
 
+const ActionTarget* Entity::zTarget() const
+{
+    return target;
+}
+
 int Entity::getId() const
 {
     return id;

+ 25 - 0
FactoryCraft/Entity.h

@@ -3,6 +3,7 @@
 #include <ReferenceCounter.h>
 #include <Vec3.h>
 #include <Vec2.h>
+#include <Writer.h>
 
 #include "Effect.h"
 #include "Inventory.h"
@@ -11,6 +12,23 @@
 class EntityType;
 class Dimension;
 class Game;
+class ItemSkill;
+
+class ActionTarget
+{
+private:
+    Framework::Vec3<int> blockPos;
+    Direction targetBlockSide;
+    int entityId;
+
+public:
+    ActionTarget( Framework::Vec3<int> blockPos, Direction blockSide );
+    ActionTarget( int entityId );
+
+    void applyItemSkillOnTarget( Entity* zActor, ItemSkill* zItemSkill, Item* zUsedItem, Game* zGame );
+    void placeBlock( Entity* zActor, Item* zItem, Game* zGame );
+    void save( Framework::StreamWriter* zWriter ) const;
+};
 
 class Entity : public Inventory
 {
@@ -23,8 +41,12 @@ protected:
     float maxHunger;
     float thirst;
     float maxThirst;
+    float targetDistanceLimit;
     Framework::Vec3<float> speed;
     Framework::Vec3<float> faceDir;
+    Framework::Vec3<float> faceOffset;
+    Framework::RCArray<ItemSkill> skills;
+    ActionTarget* target;
     const EntityType* zEntityType;
     int currentDimensionId;
     bool removed;
@@ -32,9 +54,11 @@ protected:
     int id;
 
     virtual void onDeath();
+    virtual void useItem( const ItemType* zType, Item* zItem, Game* zGame );
     Entity( const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId );
 
 public:
+    void prepareTick( const Dimension* zDimension, Game* zGame );
     virtual void tick( const Dimension* zDimension, Game* zGame );
 
     virtual void api( Framework::StreamReader* zRequest, NetworkResponse* zResponse );
@@ -57,6 +81,7 @@ public:
     bool isRemoved() const;
 
     const EntityType* zType() const;
+    const ActionTarget* zTarget() const;
     int getId() const;
 
     friend Effect;

+ 4 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -122,7 +122,9 @@
     <ClInclude Include="NoBlock.h" />
     <ClInclude Include="OverworldDimension.h" />
     <ClInclude Include="NoiseInterpolator.h" />
+    <ClInclude Include="PlaceBlockUpdate.h" />
     <ClInclude Include="Player.h" />
+    <ClInclude Include="PlayerHand.h" />
     <ClInclude Include="Server.h" />
     <ClInclude Include="Dimension.h" />
     <ClInclude Include="StaticRegistry.h" />
@@ -161,7 +163,9 @@
     <ClCompile Include="Noise.cpp" />
     <ClCompile Include="OverworldDimension.cpp" />
     <ClCompile Include="NoiseInterpolator.cpp" />
+    <ClCompile Include="PlaceBlockUpdate.cpp" />
     <ClCompile Include="Player.cpp" />
+    <ClCompile Include="PlayerHand.cpp" />
     <ClCompile Include="Server.cpp" />
     <ClCompile Include="Start.cpp" />
     <ClCompile Include="StaticInitializerOrder.cpp" />

+ 15 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -52,6 +52,9 @@
     <Filter Include="server\response">
       <UniqueIdentifier>{bc887e43-0958-4685-91b8-670eee24b5c0}</UniqueIdentifier>
     </Filter>
+    <Filter Include="inventory\items">
+      <UniqueIdentifier>{eb49f18d-6127-4d38-87db-e8427471535f}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Chunk.h">
@@ -174,6 +177,12 @@
     <ClInclude Include="FastNoiseWrapper.h">
       <Filter>world\generator\noise</Filter>
     </ClInclude>
+    <ClInclude Include="PlayerHand.h">
+      <Filter>inventory\items</Filter>
+    </ClInclude>
+    <ClInclude Include="PlaceBlockUpdate.h">
+      <Filter>world\update</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -287,5 +296,11 @@
     <ClCompile Include="FastNoiseWrapper.cpp">
       <Filter>world\generator\noise</Filter>
     </ClCompile>
+    <ClCompile Include="PlaceBlockUpdate.cpp">
+      <Filter>world\update</Filter>
+    </ClCompile>
+    <ClCompile Include="PlayerHand.cpp">
+      <Filter>inventory\items</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 30 - 2
FactoryCraft/Game.cpp

@@ -5,6 +5,7 @@
 #include "AddChunkUpdate.h"
 #include "NoBlock.h"
 #include "AsynchronCall.h"
+#include "Entity.h"
 
 using namespace Framework;
 
@@ -108,6 +109,13 @@ void GameClient::reply( Game* zGame )
         f = zPlayer->getFaceDir().z;
         client->zForegroundWriter()->schreibe( (char*)&f, 4 );
     }
+    if( zPlayer->zTarget() )
+        zPlayer->zTarget()->save( client->zForegroundWriter() );
+    else
+    {
+        char b = 0;
+        client->zForegroundWriter()->schreibe( &b, 1 );
+    }
     foreground.unlock();
     // send world to client
     if( first )
@@ -359,11 +367,23 @@ void Game::distributeResponse( NetworkResponse* zResponse )
         client->sendResponse( zResponse );
 }
 
-void Game::requestWorldUpdate( WorldUpdate* update )
+bool Game::requestWorldUpdate( WorldUpdate* update )
 {
     cs.lock();
+    for( WorldUpdate* u : *updates )
+    {
+        if( u->getMaxAffectedPoint().x >= update->getMinAffectedPoint().x && u->getMinAffectedPoint().x <= update->getMaxAffectedPoint().x &&
+            u->getMaxAffectedPoint().y >= update->getMinAffectedPoint().y && u->getMinAffectedPoint().y <= update->getMaxAffectedPoint().y &&
+            u->getMaxAffectedPoint().z >= update->getMinAffectedPoint().z && u->getMinAffectedPoint().z <= update->getMaxAffectedPoint().z )
+        {
+            cs.unlock();
+            update->release();
+            return 0;
+        }
+    }
     updates->add( update );
     cs.unlock();
+    return 1;
 }
 
 GameClient* Game::addPlayer( FCKlient* client, Framework::Text name )
@@ -436,6 +456,14 @@ Framework::Either<Block*, int> Game::zBlockAt( Framework::Vec3<int> location, in
     return 0;
 }
 
+Block* Game::zRealBlockInstance( Framework::Vec3<int> location, int dimension )
+{
+    Dimension* dim = zDimension( dimension );
+    if( dim )
+        return dim->zRealBlockInstance( location, this );
+    return 0;
+}
+
 Dimension* Game::zDimension( int id ) const
 {
     for( auto dim : *dimensions )
@@ -446,7 +474,7 @@ Dimension* Game::zDimension( int id ) const
     return 0;
 }
 
-Framework::Punkt Game::getChunkCenter( int x, int y ) const
+Framework::Punkt Game::getChunkCenter( int x, int y )
 {
     return Punkt( ((x < 0 ? x + 1 : x) / CHUNK_SIZE) * CHUNK_SIZE + (x < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2, ((y < 0 ? y + 1 : y) / CHUNK_SIZE) * CHUNK_SIZE + (y < 0 ? -CHUNK_SIZE : CHUNK_SIZE) / 2 );
 }

+ 3 - 2
FactoryCraft/Game.h

@@ -80,13 +80,14 @@ public:
     ~Game();
     void api( Framework::StreamReader* zRequest, GameClient* zOrigin );
     void distributeResponse( NetworkResponse* zResponse );
-    void requestWorldUpdate( WorldUpdate* update );
+    bool requestWorldUpdate( WorldUpdate* update );
     GameClient* addPlayer( FCKlient* client, Framework::Text name );
     bool doesChunkExist( int x, int y, int dimension );
     bool isChunkLoaded( int x, int y, int dimension ) const;
     Framework::Either<Block*, int> zBlockAt( Framework::Vec3<int> location, int dimension ) const;
+    Block* zRealBlockInstance( Framework::Vec3<int> location, int dimension );
     Dimension* zDimension( int id ) const;
-    Framework::Punkt getChunkCenter( int x, int y ) const;
+    static Framework::Punkt getChunkCenter( int x, int y );
     Area getChunckArea( Punkt center ) const;
     Framework::Text getWorldDirectory() const;
     void requestArea( Area area );

+ 56 - 0
FactoryCraft/Inventory.cpp

@@ -429,6 +429,62 @@ void Inventory::localTransaction( Array< ItemSlot* >* zSourceSlots, Array< ItemS
     }
 }
 
+void Inventory::addItems( ItemStack* items, Direction dir )
+{
+    if( itemCache && items && items->getSize() > 0 )
+    {
+        cs.lock();
+        for( auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++ )
+        {
+            if( !targetSlot->isFull() )
+            {
+                if( targetSlot->zStack() )
+                {
+                    int number = MIN( targetSlot->numberOfAddableItems( items, dir ), items->getSize() );
+                    int tmp = number;
+                    if( number > 0 && allowPushStack( targetSlot, dir, items->zItem(), tmp ) )
+                    {
+                        number = MIN( number, tmp );
+                        ItemStack* stack = items->split( number );
+                        if( stack )
+                        {
+                            targetSlot->addItems( stack, dir );
+                            afterPushStack( targetSlot, dir, targetSlot->zStack()->zItem(), number );
+                            if( stack->getSize() )
+                                throw stack;
+                            stack->release();
+                            if( !items->getSize() )
+                                break;
+                        }
+                    }
+                }
+                else
+                {
+                    int number = MIN( targetSlot->numberOfAddableItems( items, dir ), items->getSize() );
+                    int tmp = number;
+                    if( number > 0 && allowPushStack( targetSlot, dir, items->zItem(), tmp ) )
+                    {
+                        number = MIN( number, tmp );
+                        ItemStack* stack = items->split( number );
+                        if( stack )
+                        {
+                            targetSlot->addItems( stack, dir );
+                            updateCache( targetSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
+                            afterPushStack( targetSlot, dir, targetSlot->zStack()->zItem(), number );
+                            if( stack->getSize() )
+                                throw stack;
+                            stack->release();
+                            if( !items->getSize() )
+                                break;
+                        }
+                    }
+                }
+            }
+        }
+        cs.unlock();
+    }
+}
+
 InventoryInteraction Inventory::interactWith( Inventory* zInventory, Direction dir )
 {
     return InventoryInteraction( this, zInventory, dir );

+ 1 - 0
FactoryCraft/Inventory.h

@@ -50,6 +50,7 @@ protected:
     virtual void afterPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int count );
     virtual void loadInventory( Framework::StreamReader* zReader );
     virtual void saveInventory( Framework::StreamWriter* zWriter );
+    virtual void addItems( ItemStack* items, Direction dir );
 
 public:
     Inventory( const Framework::Vec3<float> location, bool hasInventory );

+ 12 - 0
FactoryCraft/Item.cpp

@@ -4,6 +4,7 @@
 Item::Item( const ItemType* zType, const char* name )
     : ReferenceCounter(),
     zType( zType ),
+    zBlockType( 0 ),
     damage( 0 ),
     maxDamage( 0 ),
     durability( 0 ),
@@ -25,6 +26,11 @@ const ItemType* Item::zItemType() const
     return zType;
 }
 
+const BlockType* Item::zPlacedBlockType() const
+{
+    return zBlockType;
+}
+
 float Item::getDamage() const
 {
     return damage;
@@ -91,6 +97,12 @@ bool Item::canBeStackedWith( Item* zItem ) const
         name.istGleich( zItem->name );
 }
 
+void Item::onPlaced()
+{
+    damage = maxDamage;
+    durability = 0;
+}
+
 void Item::applyInventoryEffects( Entity* zTarget )
 {}
 

+ 4 - 0
FactoryCraft/Item.h

@@ -4,11 +4,13 @@
 #include "Reader.h"
 
 class ItemType;
+class BlockType;
 
 class Item : public virtual Framework::ReferenceCounter
 {
 protected:
     const ItemType* zType;
+    const BlockType* zBlockType;
     float damage;
     float maxDamage;
     float durability;
@@ -26,6 +28,7 @@ public:
     virtual void tick();
 
     const ItemType* zItemType() const;
+    const BlockType* zPlacedBlockType() const;
     float getDamage() const;
     float getDurability() const;
     bool isUsable() const;
@@ -37,6 +40,7 @@ public:
     int getMaxStackSize() const;
     float getMaxDamage() const;
     virtual bool canBeStackedWith( Item* zItem ) const;
+    virtual void onPlaced();
 
     virtual void applyInventoryEffects( Entity* zTarget );
     virtual void removeInventoryEffects( Entity* zTarget );

+ 17 - 5
FactoryCraft/ItemSkill.cpp

@@ -1,7 +1,19 @@
 #include "ItemSkill.h"
 
-BasicItemSkill::BasicItemSkill( float maxXP, float durabilityModifier, float speedModifier, float luckModifier, float staminaModifier, float hungerModifier, float xpIncrease )
-    : ReferenceCounter(),
+
+ItemSkill::ItemSkill( const ItemType* zSkillType )
+    : Framework::ReferenceCounter(),
+    skillType( zSkillType )
+{}
+
+const ItemType* ItemSkill::zSkillType()
+{
+    return skillType;
+}
+
+
+BasicItemSkill::BasicItemSkill( const ItemType* zSkillType, float maxXP, float durabilityModifier, float speedModifier, float luckModifier, float staminaModifier, float hungerModifier, float xpIncrease )
+    : ItemSkill( zSkillType ),
     level( 1 ),
     xp( 0 ),
     maxXP( maxXP ),
@@ -12,8 +24,8 @@ BasicItemSkill::BasicItemSkill( float maxXP, float durabilityModifier, float spe
     hungerModifier( hungerModifier )
 {}
 
-void BasicItemSkill::use( Entity* zActor, Block* zTarget, Dimension* zDimension )
+void BasicItemSkill::use( Entity* zActor, Item* zUsedItem, Block* zTarget )
 {}
 
-void BasicItemSkill::use( Entity* zActor, Entity* zTarget, Dimension* zDimension )
-{}
+void BasicItemSkill::use( Entity* zActor, Item* zUsedItem, Entity* zTarget )
+{}

+ 11 - 5
FactoryCraft/ItemSkill.h

@@ -10,6 +10,7 @@ class ItemSkill;
 class Block;
 class Entity;
 class Dimension;
+class Item;
 
 class ItemSkillLevelUpRule : public virtual Framework::ReferenceCounter
 {
@@ -19,9 +20,14 @@ public:
 
 class ItemSkill : public virtual Framework::ReferenceCounter
 {
+private:
+    const ItemType* skillType;
+
 public:
-    virtual void use( Entity* zActor, Block* zTarget, Dimension* zDimension ) = 0;
-    virtual void use( Entity* zActor, Entity* zTarget, Dimension* zDimension ) = 0;
+    ItemSkill( const ItemType* zSkillType );
+    virtual void use( Entity* zActor, Item* zUsedItem, Block* zTarget ) = 0;
+    virtual void use( Entity* zActor, Item* zUsedItem, Entity* zTarget ) = 0;
+    const ItemType* zSkillType();
 };
 
 class BasicItemSkill : public ItemSkill
@@ -36,11 +42,11 @@ protected:
     float staminaModifier;
     float hungerModifier;
 
-    BasicItemSkill( float maxXp = 100.f, float durabilityModifier = 1.f, float speedModifier = 1.f, float luckModifier = 1.f, float staminaModifier = 1.f, float hungerModifier = 1.f, float xpIncrease = 1.1f );
+    BasicItemSkill( const ItemType* zSkillType, float maxXp = 100.f, float durabilityModifier = 1.f, float speedModifier = 1.f, float luckModifier = 1.f, float staminaModifier = 1.f, float hungerModifier = 1.f, float xpIncrease = 1.1f );
 
 public:
-    virtual void use( Entity* zActor, Block* zTarget, Dimension* zDimension ) override;
-    virtual void use( Entity* zActor, Entity* zTarget, Dimension* zDimension ) override;
+    virtual void use( Entity* zActor, Item* zUsedItem, Block* zTarget ) override;
+    virtual void use( Entity* zActor, Item* zUsedItem, Entity* zTarget ) override;
 
     friend ItemType;
 };

+ 5 - 0
FactoryCraft/ItemSlot.cpp

@@ -92,4 +92,9 @@ int ItemSlot::getPushPriority() const
 bool ItemSlot::isFull() const
 {
     return items ? items->getSize() < items->getMaxSize() : 0;
+}
+
+int ItemSlot::getFreeSpace() const
+{
+    return items ? items->getMaxSize() - items->getSize() : maxSize;
 }

+ 1 - 0
FactoryCraft/ItemSlot.h

@@ -26,4 +26,5 @@ public:
     int getPullPriority() const;
     int getPushPriority() const;
     bool isFull() const;
+    int getFreeSpace() const;
 };

+ 27 - 0
FactoryCraft/ItemType.cpp

@@ -54,6 +54,16 @@ void ItemType::saveSuperItem( const Item* zItem, Framework::StreamWriter* zWrite
     zWriter->schreibe( zItem->name, len );
 }
 
+void ItemType::loadSuperItemSkill( ItemSkill* zSkill, Framework::StreamReader* zReader ) const
+{
+
+}
+
+void ItemType::saveSuperItemSkill( const ItemSkill* zSkill, Framework::StreamWriter* zWriter ) const
+{
+
+}
+
 int ItemType::getId() const
 {
     return id;
@@ -100,4 +110,21 @@ Item* ItemType::cloneItem( Item* zItem ) const
     Framework::InMemoryBuffer buffer;
     saveItem( zItem, &buffer );
     return loadItem( &buffer );
+}
+
+ItemSkill* ItemType::loadItemSkill( Framework::StreamReader* zReader ) const
+{
+    ItemSkill* skill = createDefaultItemSkill();
+    loadSuperItemSkill( skill, zReader );
+    return skill;
+}
+
+void ItemType::saveItemSkill( const ItemSkill* zSkill, Framework::StreamWriter* zWriter ) const
+{
+    saveSuperItemSkill( zSkill, zWriter );
+}
+
+Item* ItemType::breakItem( Item* zItem ) const
+{
+    return 0;
 }

+ 5 - 0
FactoryCraft/ItemType.h

@@ -24,6 +24,8 @@ protected:
 
     virtual void loadSuperItem( Item* zItem, Framework::StreamReader* zReader ) const;
     virtual void saveSuperItem( const Item* zItem, Framework::StreamWriter* zWriter ) const;
+    virtual void loadSuperItemSkill( ItemSkill* zSkill, Framework::StreamReader* zReader ) const;
+    virtual void saveSuperItemSkill( const ItemSkill* zSkill, Framework::StreamWriter* zWriter ) const;
 
 public:
     ~ItemType();
@@ -36,5 +38,8 @@ public:
     virtual void levelUpItemSkill( ItemSkill* zSkill ) const;
     virtual Item* loadItem( Framework::StreamReader* zReader ) const;
     virtual void saveItem( const Item* zItem, Framework::StreamWriter* zWriter ) const;
+    virtual ItemSkill* loadItemSkill( Framework::StreamReader* zReader ) const;
+    virtual void saveItemSkill( const ItemSkill* zSkill, Framework::StreamWriter* zWriter ) const;
     virtual Item* cloneItem( Item* zItem ) const;
+    virtual Item* breakItem( Item* zItem ) const;
 };

+ 10 - 10
FactoryCraft/NoBlock.cpp

@@ -21,42 +21,42 @@ const NoBlock NoBlock::INSTANCE;
 
 
 NoBlockBlockType::NoBlockBlockType()
-    : BlockType( ID )
+    : BlockType( ID, 0 )
 {}
 
 NoBlockBlockType::NoBlockBlockType( int id )
-    : BlockType( id )
+    : BlockType( id, 0 )
 {}
 
-Block* NoBlockBlockType::createBlock( Framework::Vec3<int> position, Game* zTarget )
+Block* NoBlockBlockType::createBlock( Framework::Vec3<int> position, Game* zTarget ) const
 {
     return 0;
 }
 
-Item* NoBlockBlockType::createItem( Game* zTarget )
+Item* NoBlockBlockType::createItem( Game* zTarget ) const
 {
     return 0;
 }
 
-Block* NoBlockBlockType::loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader )
+Block* NoBlockBlockType::loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader ) const
 {
     return 0;
 }
 
-void NoBlockBlockType::saveBlock( Block* zBlock, Framework::StreamWriter* zWriter )
+void NoBlockBlockType::saveBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const
 {}
 
-Item* NoBlockBlockType::getItemFromBlock( Block* zBlock, Game* zTarget )
+Item* NoBlockBlockType::getItemFromBlock( Block* zBlock, Game* zTarget ) const
 {
     return 0;
 }
 
-Block* NoBlockBlockType::createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem )
+Block* NoBlockBlockType::createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem ) const
 {
     return 0;
 }
 
-const Block* NoBlockBlockType::zDefault()
+const Block* NoBlockBlockType::zDefault() const
 {
     return &NoBlock::INSTANCE;
 }
@@ -86,7 +86,7 @@ AirBlockBlockType::AirBlockBlockType()
     : NoBlockBlockType( ID )
 {}
 
-const Block* AirBlockBlockType::zDefault()
+const Block* AirBlockBlockType::zDefault() const
 {
     return &AirBlock::INSTANCE;
 }

+ 8 - 8
FactoryCraft/NoBlock.h

@@ -24,13 +24,13 @@ class NoBlockBlockType : public BlockType
 protected:
     NoBlockBlockType();
     NoBlockBlockType( int id );
-    virtual Block* createBlock( Framework::Vec3<int> position, Game* zTarget ) override;
-    virtual Item* createItem( Game* zTarget ) override;
-    virtual Block* loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader ) override;
-    virtual void saveBlock( Block* zBlock, Framework::StreamWriter* zWriter ) override;
-    virtual Item* getItemFromBlock( Block* zBlock, Game* zTarget ) override;
-    virtual Block* createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem ) override;
-    virtual const Block* zDefault() override;
+    virtual Block* createBlock( Framework::Vec3<int> position, Game* zTarget ) const override;
+    virtual Item* createItem( Game* zTarget ) const override;
+    virtual Block* loadBlock( Framework::Vec3<int> position, Game* zTarget, Framework::StreamReader* zReader ) const override;
+    virtual void saveBlock( Block* zBlock, Framework::StreamWriter* zWriter ) const override;
+    virtual Item* getItemFromBlock( Block* zBlock, Game* zTarget ) const override;
+    virtual Block* createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem ) const override;
+    virtual const Block* zDefault() const override;
 };
 REGISTER( NoBlockBlockType, BlockType )
 
@@ -52,6 +52,6 @@ class AirBlockBlockType : public NoBlockBlockType
 
 protected:
     AirBlockBlockType();
-    virtual const Block* zDefault() override;
+    virtual const Block* zDefault() const override;
 };
 REGISTER( AirBlockBlockType, BlockType )

+ 37 - 0
FactoryCraft/PlaceBlockUpdate.cpp

@@ -0,0 +1,37 @@
+#include "PlaceBlockUpdate.h"
+#include "Block.h"
+#include "Dimension.h"
+
+
+PlaceBlockUpdate::PlaceBlockUpdate( Block* block, int dimensionId )
+    : WorldUpdate( PlaceBlockUpdateType::ID, dimensionId, block->getPos(), block->getPos() ),
+    block( block )
+{}
+
+PlaceBlockUpdate::~PlaceBlockUpdate()
+{
+    block->release();
+}
+
+void PlaceBlockUpdate::onUpdate( Dimension* zDimension )
+{
+    zDimension->placeBlock( dynamic_cast<Block*>(block->getThis()) );
+}
+
+void PlaceBlockUpdate::write( Framework::StreamWriter* zWriter )
+{
+    zWriter->schreibe( (char*)&PlaceBlockUpdateType::ID, 4 );
+    int id = block->zBlockType()->getId();
+    zWriter->schreibe( (char*)&id, 4 );
+    block->zBlockType()->saveBlock( block, zWriter );
+}
+
+Block* PlaceBlockUpdate::zBlock() const
+{
+    return block;
+}
+
+
+PlaceBlockUpdateType::PlaceBlockUpdateType()
+    : WorldUpdateType( ID )
+{}

+ 28 - 0
FactoryCraft/PlaceBlockUpdate.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "WorldUpdate.h"
+
+class Block;
+
+class PlaceBlockUpdate : public WorldUpdate
+{
+private:
+    Block* block;
+
+public:
+    PlaceBlockUpdate( Block* block, int dimensionId );
+    ~PlaceBlockUpdate();
+
+    void onUpdate( Dimension* zDimension ) override;
+    void write( Framework::StreamWriter* zWriter ) override;
+    Block* zBlock() const;
+};
+
+class PlaceBlockUpdateType : WorldUpdateType
+{
+    REGISTRABLE( PlaceBlockUpdateType )
+
+protected:
+    PlaceBlockUpdateType();
+};
+REGISTER( PlaceBlockUpdateType, WorldUpdateType )

+ 112 - 13
FactoryCraft/Player.cpp

@@ -1,9 +1,18 @@
 #include "Player.h"
 #include "Game.h"
+#include "PlayerHand.h"
+#include "ItemFilter.h"
 
 Player::Player( Framework::Vec3<float> location, int dimensionId, int entityId )
     : Entity( PlayerEntityType::INSTANCE, location, dimensionId, entityId )
 {
+    for( int i = 0; i < 9; i++ )
+    {
+        ItemSlot* slot = new ItemSlot( 50, 0, i, 0, ANY_DIRECTION, 0 );
+        itemBar.add( slot );
+        addSlot( slot );
+    }
+    leftHandPosition = 0;
     maxHP = 10;
     currentHP = 10;
     stamina = 10;
@@ -14,6 +23,69 @@ Player::Player( Framework::Vec3<float> location, int dimensionId, int entityId )
     maxThirst = 10;
     keyState = 0;
     jumping = 0;
+    faceOffset = { 0.f, 0.f, 1.5f };
+}
+
+void Player::useItemSlot( ItemSlot* zSlot, Game* zGame )
+{
+    if( zSlot->zStack() )
+    {
+        ItemStack* stack = zSlot->takeItemsOut( 1, NO_DIRECTION );
+        if( stack )
+        {
+            Item* item = stack->extractFromStack();
+            Entity::useItem( item->zItemType(), item, zGame );
+            if( item->getDurability() > 0 && item->getDamage() < item->getMaxDamage() )
+            { // put used item back
+                stack->addToStack( item );
+                if( !zSlot->numberOfAddableItems( stack, NO_DIRECTION ) )
+                { // move other items to other space
+                    ItemStack* oldItems = zSlot->takeItemsOut( zSlot->zStack()->getSize(), NO_DIRECTION );
+                    zSlot->addItems( stack, NO_DIRECTION );
+                    addItems( oldItems, NO_DIRECTION );
+                    if( oldItems->getSize() > 0 )
+                    {
+                        // TODO: drop remaining items
+                    }
+                }
+                else
+                    zSlot->addItems( stack, NO_DIRECTION );
+            }
+            else
+            { // item is broken
+                // move other items of the same type to the slot
+                Array< ItemSlot*> fromSlots;
+                for( ItemSlot* slot : itemBar )
+                {
+                    if( slot != zSlot )
+                        fromSlots.add( slot );
+                }
+                Array<ItemSlot*> targetSlots;
+                targetSlots.add( zSlot );
+                TypeItemFilter filter( item->zItemType() );
+                localTransaction( &fromSlots, &targetSlots, &filter, zSlot->getFreeSpace() );
+                // place broken item in inventory
+                const ItemType* brokenType = item->zItemType()->zBrokenItemType();
+                if( brokenType )
+                {
+                    Item* broken = item->zItemType()->breakItem( item );
+                    if( broken )
+                    {
+                        stack->addToStack( broken );
+                        addItems( stack, NO_DIRECTION );
+                        if( stack->getSize() > 0 )
+                        {
+                            // TODO: drop remaining items
+                        }
+                    }
+                }
+                item->release();
+            }
+            stack->release();
+        }
+    }
+    else
+        Entity::useItem( PlayerHandItemType::INSTANCE, 0, zGame ); // hand usage
 }
 
 void Player::setName( Framework::Text name )
@@ -30,21 +102,34 @@ void Player::tick( const Dimension* zDimension, Game* zGame )
 {
     speed = { 0, 0, speed.z };
     if( (keyState | Key::MOVE_FRONT) == keyState )
-        speed += {faceDir.x * 1.5f, faceDir.y * 1.5f, 0};
+        speed += {faceDir.x, faceDir.y, 0};
     if( (keyState | Key::MOVE_BACK) == keyState )
-        speed += {-faceDir.x * 1.5f, -faceDir.y * 1.5f, 0};
+        speed += {-faceDir.x, -faceDir.y, 0};
     if( (keyState | Key::MOVE_RIGHT) == keyState )
     {
-        Vec3<float> right = Vec3<float>( faceDir ).rotateZ( (float)PI / 2.f );
-        speed += {right.x * 1.5f, right.y * 1.5f, 0};
+        Vec2<float> norm = { faceDir.x, faceDir.y };
+        norm.CCW90().normalize();
+        speed += {norm.x, norm.y, 0};
     }
     if( (keyState | Key::MOVE_LEFT) == keyState )
     {
-        Vec3<float> left = Vec3<float>( faceDir ).rotateZ( -(float)PI / 2.f );
-        speed += {left.x * 1.5f, left.y * 1.5f, 0};
+        Vec2<float> norm = { faceDir.x, faceDir.y };
+        norm.CCW90().normalize();
+        speed += {norm.x, norm.y, 0};
     }
-    if( (keyState | Key::MOVE_DOWN) == keyState && !jumping )
-        speed.z = -1.5f;
+    Vec2<float> norm = { speed.x, speed.y };
+    if( norm.getLengthSq() != 0 )
+    {
+        norm.normalize();
+        speed.x = norm.x * 4.f; // 4 blocks per second movement speed
+        speed.y = norm.y * 4.f;
+    }
+    if( (keyState | Key::MOVE_DOWN) == keyState && gravityMultiplier == 0.f )
+        speed.z = -4.f;
+    if( (keyState | Key::LEFT_HAND_ACTION) == keyState )
+        useItemSlot( itemBar.z( leftHandPosition ), zGame );
+    if( (keyState | Key::RIGHT_HAND_ACTION) == keyState )
+        useItemSlot( itemBar.z( (leftHandPosition + 1) % itemBar.getEintragAnzahl() ), zGame );
     return Entity::tick( zDimension, zGame );
 }
 
@@ -86,6 +171,12 @@ void Player::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse
                 speed.z = 0;
             keyState = keyState & ~Key::MOVE_UP;
             break;
+        case 8:
+            keyState = keyState & ~Key::LEFT_HAND_ACTION;
+            break;
+        case 9:
+            keyState = keyState & ~Key::RIGHT_HAND_ACTION;
+            break;
         }
         break;
     case 1:
@@ -136,13 +227,21 @@ void Player::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse
             }
             keyState = keyState | Key::MOVE_UP;
             break;
+        case 8:
+            keyState = keyState | Key::LEFT_HAND_ACTION;
+            break;
+        case 9:
+            keyState = keyState | Key::RIGHT_HAND_ACTION;
+            break;
         }
         break;
-        case 2
-            :
-                zRequest->lese( (char*)&faceDir.x, 4 );
-                zRequest->lese( (char*)&faceDir.y, 4 );
-                zRequest->lese( (char*)&faceDir.z, 4 );
+    case 2:
+        zRequest->lese( (char*)&faceDir.x, 4 );
+        zRequest->lese( (char*)&faceDir.y, 4 );
+        zRequest->lese( (char*)&faceDir.z, 4 );
+    case 3:
+        zRequest->lese( (char*)&leftHandPosition, 4 );
+        leftHandPosition = leftHandPosition % itemBar.getEintragAnzahl();
     }
 }
 

+ 8 - 0
FactoryCraft/Player.h

@@ -2,6 +2,7 @@
 
 #include "Entity.h"
 #include "EntityType.h"
+#include <Array.h>
 
 class PlayerEntityType;
 
@@ -19,12 +20,19 @@ public:
         const static __int64 MOVE_DOWN = 0x20;
         const static __int64 ROTATE_LEFT = 0x40;
         const static __int64 ROTATE_RIGHT = 0x80;
+        const static __int64 LEFT_HAND_ACTION = 0x100;
+        const static __int64 RIGHT_HAND_ACTION = 0x200;
     };
+
 private:
     Framework::Text name;
+    Framework::RCArray<ItemSlot> itemBar;
+    int leftHandPosition;
     bool jumping;
     __int64 keyState;
 
+    void useItemSlot( ItemSlot* zSlot, Game* zGame );
+
 public:
     Player( Framework::Vec3<float> location, int dimensionId, int entityId );
     void setName( Framework::Text name );

+ 51 - 0
FactoryCraft/PlayerHand.cpp

@@ -0,0 +1,51 @@
+#include "PlayerHand.h"
+
+
+PlayerHandItemType::PlayerHandItemType()
+    : ItemType( ID, new PlayerHandLevelUpRule(), 0 )
+{}
+
+void PlayerHandItemType::loadSuperItemSkill( ItemSkill* zSkill, Framework::StreamReader* zReader ) const
+{
+    // TODO: load skill data
+}
+
+void PlayerHandItemType::saveSuperItemSkill( const ItemSkill* zSkill, Framework::StreamWriter* zWriter ) const
+{
+    // TODO: store skill data
+}
+
+Item* PlayerHandItemType::createItem() const
+{
+    return 0; // there is no player hand item
+}
+
+ItemSkill* PlayerHandItemType::createDefaultItemSkill() const
+{
+    return new PlayerHandSkill();
+}
+
+
+PlayerHandLevelUpRule::PlayerHandLevelUpRule()
+    : ItemSkillLevelUpRule()
+{}
+
+void PlayerHandLevelUpRule::applyOn( ItemSkill* zSkill )
+{
+    // TODO: level up the skill
+}
+
+
+PlayerHandSkill::PlayerHandSkill()
+    : ItemSkill( PlayerHandItemType::INSTANCE )
+{}
+
+void PlayerHandSkill::use( Entity* zActor, Item* zUsedItem, Block* zTarget )
+{
+    // TODO: make damage on the block
+}
+
+void PlayerHandSkill::use( Entity* zActor, Item* zUsedItem, Entity* zTarget )
+{
+    // TODO: make damage on the entity
+}

+ 34 - 0
FactoryCraft/PlayerHand.h

@@ -0,0 +1,34 @@
+#pragma once
+
+#include "ItemType.h"
+#include "ItemSkill.h"
+
+class PlayerHandItemType : public ItemType
+{
+    REGISTRABLE( PlayerHandItemType )
+
+protected:
+    void loadSuperItemSkill( ItemSkill* zSkill, Framework::StreamReader* zReader ) const override;
+    void saveSuperItemSkill( const ItemSkill* zSkill, Framework::StreamWriter* zWriter ) const override;
+
+public:
+    PlayerHandItemType();
+    Item* createItem() const override;
+    ItemSkill* createDefaultItemSkill() const override;
+};
+REGISTER( PlayerHandItemType, ItemType )
+
+class PlayerHandLevelUpRule : public ItemSkillLevelUpRule
+{
+public:
+    PlayerHandLevelUpRule();
+    void applyOn( ItemSkill* zSkill ) override;
+};
+
+class PlayerHandSkill : public ItemSkill
+{
+public:
+    PlayerHandSkill();
+    void use( Entity* zActor, Item* zUsedItem, Block* zTarget ) override;
+    void use( Entity* zActor, Item* zUsedItem, Entity* zTarget ) override;
+};

+ 3 - 1
FactoryCraft/StaticInitializerOrder.cpp

@@ -17,4 +17,6 @@ const c *c::INSTANCE = new c();
 #include "BasicBlocks.h"
 #include "OverworldDimension.h"
 #include "AddChunkUpdate.h"
-#include "Player.h"
+#include "Player.h"
+#include "PlaceBlockUpdate.h"
+#include "PlayerHand.h"