Просмотр исходного кода

add collision detection and gravity

Kolja Strohm 3 лет назад
Родитель
Сommit
028be923b5

+ 15 - 2
FactoryCraft/BiomGenerator.cpp

@@ -1,9 +1,17 @@
 #include "BiomGenerator.h"
 
 
-BiomGenerator::BiomGenerator()
+BiomGenerator::BiomGenerator( double biomXMultiplier, double biomYMultiplier, double biomOutputMultiplier, double airXMultiplier, double airYMultiplier, double airOutputMultiplier, double airOutputAddition )
     : ReferenceCounter()
-{}
+{
+    this->biomXMultiplier = biomXMultiplier;
+    this->biomYMultiplier = biomYMultiplier;
+    this->biomOutputMultiplier = biomOutputMultiplier;
+    this->airXMultiplier = airXMultiplier;
+    this->airYMultiplier = airYMultiplier;
+    this->airOutputMultiplier = airOutputMultiplier;
+    this->airOutputAddition = airOutputAddition;
+}
 
 double BiomGenerator::getBiomXMultiplier()
 {
@@ -34,3 +42,8 @@ double BiomGenerator::getAirLevelOutputMultiplier()
 {
     return airOutputMultiplier;
 }
+
+double BiomGenerator::getAirLevelOutputAddition()
+{
+    return airOutputAddition;
+}

+ 3 - 1
FactoryCraft/BiomGenerator.h

@@ -16,9 +16,10 @@ protected:
     double airXMultiplier;
     double airYMultiplier;
     double airOutputMultiplier;
+    double airOutputAddition;
 
 public:
-    BiomGenerator();
+    BiomGenerator( double biomXMultiplier, double biomYMultiplier, double biomOutputMultiplier, double airXMultiplier, double airYMultiplier, double airOutputMultiplier, double airOutputAddition );
     virtual Framework::Either<Block*, int> getBlock( Noise* zNoise, int x, int y, int z, Game* zGame ) = 0;
     double getBiomXMultiplier();
     double getBiomYMultiplier();
@@ -26,4 +27,5 @@ public:
     double getAirLevelXMultiplier();
     double getAirLevelYMultiplier();
     double getAirLevelOutputMultiplier();
+    double getAirLevelOutputAddition();
 };

+ 9 - 0
FactoryCraft/BlockType.cpp

@@ -117,4 +117,13 @@ const Block* BlockType::zDefault()
     if( !defaultBlock )
         defaultBlock = createBlock( { 0, 0, 0 }, 0 );
     return defaultBlock;
+}
+
+
+const Block* getDefaultBlock( Either<Block*, int> b )
+{
+    if( b.isA() )
+        return b;
+    else
+        return StaticRegistry<BlockType>::INSTANCE.zElement( b )->zDefault();
 }

+ 4 - 1
FactoryCraft/BlockType.h

@@ -3,6 +3,7 @@
 #include <Vec3.h>
 #include <Array.h>
 #include <Writer.h>
+#include <Either.h>
 
 #include "StaticRegistry.h"
 
@@ -34,4 +35,6 @@ public:
     virtual Block* createBlockAt( Framework::Vec3<int> position, Game* zTarget, Item* zUsedItem );
     virtual const Block* zDefault();
     int getId() const;
-};
+};
+
+const Block* getDefaultBlock( Framework::Either<Block*, int> b );

+ 6 - 0
FactoryCraft/Dimension.cpp

@@ -8,6 +8,7 @@ using namespace Framework;
 
 Dimension::Dimension( int id )
     : dimensionId( id ),
+    gravity( 9.8f ),
     chunks( new Trie<Chunk>() ),
     entities( new RCArray<Entity>() )
 {}
@@ -195,6 +196,11 @@ bool Dimension::hasChunck( int x, int y ) const
     return zChunk( Punkt( x, y ) );
 }
 
+float Dimension::getGravity() const
+{
+    return gravity;
+}
+
 void Dimension::removeOldChunks()
 {
     Array<int> removed;

+ 2 - 0
FactoryCraft/Dimension.h

@@ -10,6 +10,7 @@ class Dimension : public virtual Framework::ReferenceCounter
 {
 private:
     int dimensionId;
+    float gravity;
     Framework::Trie<Chunk>* chunks;
     Framework::Array<Chunk*> chunkList;
     Framework::RCArray<Entity>* entities;
@@ -30,5 +31,6 @@ public:
     int getDimensionId() const;
     bool hasChunck( int x, int y ) const;
     Chunk* zChunk( Framework::Punkt wPos ) const;
+    float getGravity() const;
     void removeOldChunks();
 };

+ 20 - 4
FactoryCraft/DimensionGenerator.cpp

@@ -58,9 +58,25 @@ Chunk* DimensionGenerator::generateChunk( Noise* zNoise, Game* zGame, int center
     {
         for( int y = -CHUNK_SIZE / 2; y < CHUNK_SIZE / 2; y++ )
         {
+            BiomGenerator* actualBiom;
+            BiomGenerator* neighborBiom;
+            double actualWeight;
+            double neighborWeight;
+            findBiom( x + centerX, y + centerY, zNoise, &actualBiom, &neighborBiom, actualWeight, neighborWeight );
+            double actualHeight = zNoise->getNoise( (x + centerX) * actualBiom->getAirLevelXMultiplier(), (y + centerY) * actualBiom->getAirLevelYMultiplier(), AIR_LEVEL_Z_OFFSET ) * actualBiom->getAirLevelOutputMultiplier() + actualBiom->getAirLevelOutputAddition();
+            double neighborHeight = zNoise->getNoise( (x + centerX) * neighborBiom->getAirLevelXMultiplier(), (y + centerY) * neighborBiom->getAirLevelYMultiplier(), AIR_LEVEL_Z_OFFSET ) * neighborBiom->getAirLevelOutputMultiplier() + neighborBiom->getAirLevelOutputAddition();
+            int height = MIN_AIR_LEVEL;
+            if( actualWeight + neighborWeight > 0 )
+                height += (int)(((actualHeight * actualWeight + neighborHeight * neighborWeight) / (actualWeight + neighborWeight)) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
             for( int z = 0; z < WORLD_HEIGHT; z++ )
             {
-                auto generated = generateBlock( zNoise, zGame, { x + centerX, y + centerY, z } );
+                Framework::Either<Block*, int> generated = AirBlockBlockType::ID;
+                if( z < height )
+                {
+                    auto actualBlock = actualBiom->getBlock( zNoise, x + centerX, y + centerY, z, zGame );
+                    auto neighborBlock = neighborBiom->getBlock( zNoise, x + centerX, y + centerY, z, zGame );
+                    generated = interpolator->interpolateBlocks( actualBlock, neighborBlock, actualHeight, neighborWeight, zNoise );
+                }
                 if( generated.isA() )
                     chunk->putBlockAt( Framework::Vec3<int>( x + CHUNK_SIZE / 2, y + CHUNK_SIZE / 2, z ), generated );
                 else
@@ -78,11 +94,11 @@ Framework::Either<Block*, int> DimensionGenerator::generateBlock( Noise* zNoise,
     double actualWeight;
     double neighborWeight;
     findBiom( location.x, location.y, zNoise, &actualBiom, &neighborBiom, actualWeight, neighborWeight );
-    double actualHeight = zNoise->getNoise( location.x * actualBiom->getAirLevelXMultiplier(), location.y * actualBiom->getAirLevelYMultiplier(), AIR_LEVEL_Z_OFFSET ) * actualBiom->getAirLevelOutputMultiplier();
-    double neighborHeight = zNoise->getNoise( location.x * neighborBiom->getAirLevelXMultiplier(), location.y * neighborBiom->getAirLevelYMultiplier(), AIR_LEVEL_Z_OFFSET ) * neighborBiom->getAirLevelOutputMultiplier();
+    double actualHeight = zNoise->getNoise( location.x * actualBiom->getAirLevelXMultiplier(), location.y * actualBiom->getAirLevelYMultiplier(), AIR_LEVEL_Z_OFFSET ) * actualBiom->getAirLevelOutputMultiplier() + actualBiom->getAirLevelOutputAddition();
+    double neighborHeight = zNoise->getNoise( location.x * neighborBiom->getAirLevelXMultiplier(), location.y * neighborBiom->getAirLevelYMultiplier(), AIR_LEVEL_Z_OFFSET ) * neighborBiom->getAirLevelOutputMultiplier() + neighborBiom->getAirLevelOutputAddition();
     int height = MIN_AIR_LEVEL;
     if( actualWeight + neighborWeight > 0 )
-        height += (int)(((actualHeight * actualHeight + neighborHeight * neighborWeight) / (actualWeight + neighborWeight)) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
+        height += (int)(((actualHeight * actualWeight + neighborHeight * neighborWeight) / (actualWeight + neighborWeight)) * (MAX_AIR_LEVEL - MIN_AIR_LEVEL));
     if( location.z < height )
     {
         auto actualBlock = actualBiom->getBlock( zNoise, location.x, location.y, location.z, zGame );

+ 139 - 3
FactoryCraft/Entity.cpp

@@ -1,12 +1,16 @@
 #include "Entity.h"
+#include "Dimension.h"
+#include "Game.h"
+#include "BlockType.h"
 
 Entity::Entity( const EntityType* zType, Framework::Vec3<float> location, int dimensionId, int entityId )
     : Inventory( location, true ),
     speed( 0, 0, 0 ),
-    faceDir( 1, 0 ),
+    faceDir( 1, 0, 0 ),
     zEntityType( zType ),
     currentDimensionId( dimensionId ),
     removed( 0 ),
+    gravityMultiplier( 1.f ),
     id( entityId )
 {}
 
@@ -15,7 +19,126 @@ void Entity::onDeath()
 
 void Entity::tick( const Dimension* zDimension, Game* zGame )
 {
-    // TODO
+    Vec3<float> oldPos = location;
+    // current block cooredinates
+    int px = (int)floor( location.x );
+    int py = (int)floor( location.y );
+    int pz = (int)floor( location.z );
+    // falling down
+    speed.z -= (zDimension->getGravity() * gravityMultiplier) / 30.f;
+    // movement in current tick
+    Vec3<float> frameSpeed = speed / 30.f;
+    // loop through all collided blocks
+    bool needCollisionCheck = 1;
+    while( needCollisionCheck )
+    {
+        needCollisionCheck = 0;
+        // collision to neighbor of current block current block
+        if( speed.x > 0 )
+        {
+            float xt = ((float)px + 1.f - oldPos.x) / frameSpeed.x;
+            Vec3<float> tmp = oldPos + frameSpeed * 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() )
+                {
+                    frameSpeed.x = frameSpeed.x * (xt - 0.1f);
+                    speed.x = 0;
+                }
+                else
+                    px++;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.x < 0 )
+        {
+            float xt = ((float)px - oldPos.x) / frameSpeed.x;
+            Vec3<float> tmp = oldPos + frameSpeed * 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() )
+                {
+                    frameSpeed.x = frameSpeed.x * (xt - 0.1f);
+                    speed.x = 0;
+                }
+                else
+                    px--;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.y > 0 )
+        {
+            float yt = ((float)py + 1.f - oldPos.y) / frameSpeed.y;
+            Vec3<float> tmp = oldPos + frameSpeed * 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() )
+                {
+                    frameSpeed.y = frameSpeed.y * (yt - 0.1f);
+                    speed.y = 0;
+                }
+                else
+                    py++;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.y < 0 )
+        {
+            float yt = ((float)py - oldPos.y) / frameSpeed.y;
+            Vec3<float> tmp = oldPos + frameSpeed * 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() )
+                {
+                    frameSpeed.y = frameSpeed.y * (yt - 0.1f);
+                    speed.y = 0;
+                }
+                else
+                    py--;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.z > 0 )
+        {
+            float zt = ((float)pz + 1.f - oldPos.z) / frameSpeed.z;
+            Vec3<float> tmp = oldPos + frameSpeed * 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() )
+                {
+                    frameSpeed.z = frameSpeed.z * (zt - 0.1f);
+                    speed.z = 0;
+                }
+                else
+                    pz++;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+        if( speed.z < 0 )
+        {
+            float zt = ((float)pz - oldPos.z) / frameSpeed.z;
+            Vec3<float> tmp = oldPos + frameSpeed * 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() )
+                {
+                    frameSpeed.z = frameSpeed.z * (zt - 0.1f);
+                    onFall( speed.z );
+                    speed.z = 0;
+                }
+                else
+                    pz--;
+                needCollisionCheck = 1;
+                continue;
+            }
+        }
+    }
+    location += frameSpeed;
 }
 
 void Entity::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse )
@@ -23,6 +146,14 @@ void Entity::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse
     // TODO: answer api requests
 }
 
+void Entity::onFall( float collisionSpeed )
+{
+    if( collisionSpeed > 5 )
+    {
+        // TODO: take damage
+    }
+}
+
 void Entity::setPosition( Framework::Vec3<float> pos )
 {
     location = pos;
@@ -73,7 +204,7 @@ Framework::Vec3<float> Entity::getSpeed() const
     return speed;
 }
 
-Framework::Vec2<float> Entity::getFaceDir() const
+Framework::Vec3<float> Entity::getFaceDir() const
 {
     return faceDir;
 }
@@ -83,6 +214,11 @@ Framework::Vec3<float> Entity::getPosition() const
     return location;
 }
 
+float Entity::getGravityMultiplier() const
+{
+    return gravityMultiplier;
+}
+
 int Entity::getCurrentDimensionId() const
 {
     return currentDimensionId;

+ 5 - 2
FactoryCraft/Entity.h

@@ -24,10 +24,11 @@ protected:
     float thirst;
     float maxThirst;
     Framework::Vec3<float> speed;
-    Framework::Vec2<float> faceDir;
+    Framework::Vec3<float> faceDir;
     const EntityType* zEntityType;
     int currentDimensionId;
     bool removed;
+    float gravityMultiplier;
     int id;
 
     virtual void onDeath();
@@ -38,6 +39,7 @@ public:
 
     virtual void api( Framework::StreamReader* zRequest, NetworkResponse* zResponse );
 
+    virtual void onFall( float collisionSpeed );
     void setPosition( Framework::Vec3<float> pos );
     float getMaxHP() const;
     float getCurrentHP() const;
@@ -48,8 +50,9 @@ public:
     float getThirst() const;
     float getMaxThirst() const;
     Framework::Vec3<float> getSpeed() const;
-    Framework::Vec2<float> getFaceDir() const;
+    Framework::Vec3<float> getFaceDir() const;
     Framework::Vec3<float> getPosition() const;
+    float getGravityMultiplier() const;
     int getCurrentDimensionId() const;
     bool isRemoved() const;
 

+ 2 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -120,6 +120,7 @@
     <ClInclude Include="Noise.h" />
     <ClInclude Include="NoBlock.h" />
     <ClInclude Include="OverworldDimension.h" />
+    <ClInclude Include="NoiseInterpolator.h" />
     <ClInclude Include="PerlinNoise.h" />
     <ClInclude Include="Player.h" />
     <ClInclude Include="Server.h" />
@@ -158,6 +159,7 @@
     <ClCompile Include="NoBlock.cpp" />
     <ClCompile Include="Noise.cpp" />
     <ClCompile Include="OverworldDimension.cpp" />
+    <ClCompile Include="NoiseInterpolator.cpp" />
     <ClCompile Include="PerlinNoise.cpp" />
     <ClCompile Include="Player.cpp" />
     <ClCompile Include="Server.cpp" />

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -171,6 +171,9 @@
     <ClInclude Include="NoBlock.h">
       <Filter>world\blocks</Filter>
     </ClInclude>
+    <ClInclude Include="NoiseInterpolator.h">
+      <Filter>world\generator\noise</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -281,5 +284,8 @@
     <ClCompile Include="NoBlock.cpp">
       <Filter>world\blocks</Filter>
     </ClCompile>
+    <ClCompile Include="NoiseInterpolator.cpp">
+      <Filter>world\generator\noise</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 14 - 5
FactoryCraft/Game.cpp

@@ -99,10 +99,15 @@ void GameClient::reply( Game* zGame )
     client->zForegroundWriter()->schreibe( (char*)&f, 4 );
     f = zPlayer->getPosition().z;
     client->zForegroundWriter()->schreibe( (char*)&f, 4 );
-    f = zPlayer->getFaceDir().x;
-    client->zForegroundWriter()->schreibe( (char*)&f, 4 );
-    f = zPlayer->getFaceDir().y;
-    client->zForegroundWriter()->schreibe( (char*)&f, 4 );
+    if( first )
+    {
+        f = zPlayer->getFaceDir().x;
+        client->zForegroundWriter()->schreibe( (char*)&f, 4 );
+        f = zPlayer->getFaceDir().y;
+        client->zForegroundWriter()->schreibe( (char*)&f, 4 );
+        f = zPlayer->getFaceDir().z;
+        client->zForegroundWriter()->schreibe( (char*)&f, 4 );
+    }
     foreground.unlock();
     // send world to client
     if( first )
@@ -305,6 +310,10 @@ void Game::thread()
         double sec = m.getSekunden();
         if( sec < 0.05 )
             Sleep( (int)((0.05 - sec) * 1000) );
+        else
+        {
+            std::cout << "WARNING: tick needed " << sec << " seconds. The game will run sower then normal.\n";
+        }
     }
     save();
 }
@@ -366,7 +375,7 @@ GameClient* Game::addPlayer( FCKlient* client, Framework::Text name )
     bool isNew = 0;
     if( !pFile.existiert() || !pFile.open( Datei::Style::lesen ) )
     {
-        player = (Player*)PlayerEntityType::INSTANCE->createEntityAt( Vec3<float>( 0, 0, 0 ), OverworldDimension::ID, this );
+        player = (Player*)PlayerEntityType::INSTANCE->createEntityAt( Vec3<float>( 0.5, 0.5, 0 ), OverworldDimension::ID, this );
         player->setName( name );
         isNew = 1;
     }

+ 1 - 12
FactoryCraft/GrasslandBiom.cpp

@@ -3,20 +3,9 @@
 #include "BasicBlocks.h"
 
 GrasslandBiom::GrasslandBiom()
-    : GrasslandBiom( 1, 1, 1, 1, 1, 1 )
+    : BiomGenerator( 1, 1, 1, 1, 1, 0.5, 0.25 )
 {}
 
-GrasslandBiom::GrasslandBiom( double biomXMultiplier, double biomYMultiplier, double biomOutputMultiplier, double airXMultiplier, double airYMultiplier, double airOutputMultiplier )
-    : BiomGenerator()
-{
-    this->biomXMultiplier = biomXMultiplier;
-    this->biomYMultiplier = biomYMultiplier;
-    this->biomOutputMultiplier = biomOutputMultiplier;
-    this->airXMultiplier = airXMultiplier;
-    this->airYMultiplier = airYMultiplier;
-    this->airOutputMultiplier = airOutputMultiplier;
-}
-
 Framework::Either<Block*, int> GrasslandBiom::getBlock( Noise* zNoise, int x, int y, int z, Game* zGame )
 {
     return DirtBlockType::ID;

+ 0 - 1
FactoryCraft/GrasslandBiom.h

@@ -7,6 +7,5 @@ class GrasslandBiom : public BiomGenerator
 {
 public:
     GrasslandBiom();
-    GrasslandBiom( double biomXMultiplier, double biomYMultiplier, double biomOutputMultiplier, double airXMultiplier, double airYMultiplier, double airOutputMultiplier );
     Framework::Either<Block*, int> getBlock( Noise* zNoise, int x, int y, int z, Game* zGame ) override;
 };

+ 1 - 1
FactoryCraft/Noise.cpp

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

+ 2 - 2
FactoryCraft/Noise.h

@@ -15,6 +15,6 @@ public:
     /// <param name="y">the y coord of the noice value</param>
     /// <param name="z">the z coord of the noice value</param>
     /// <returns>the noise value scaled to a range from 0 to 1</returns>
-    virtual double getNoise( double x, double y, double z ) const = 0;
-    double getNoise( Framework::Vec3<double>& pos ) const;
+    virtual double getNoise( double x, double y, double z ) = 0;
+    double getNoise( Framework::Vec3<double>& pos );
 };

+ 44 - 0
FactoryCraft/NoiseInterpolator.cpp

@@ -0,0 +1,44 @@
+#include "NoiseInterpolator.h"
+#include "Text.h"
+
+using namespace Framework;
+
+NoiseInterpolator::NoiseInterpolator( int seed, std::function<Noise* (int)> noiseSupplier, int width, int height )
+    : Noise(),
+    noiseSize( width, height ),
+    cache( 10, []( int k ) {return k; }, CacheCleanupStrategy::LONGEST_NOT_USED ),
+    noiseSupplier( noiseSupplier ),
+    seed( seed )
+{}
+
+double NoiseInterpolator::getRealNoise( double x, double y, double z )
+{
+    int ix = (int)ceil( x ), iy = (int)ceil( y );
+    int xOff = ix % noiseSize.x, yOff = iy % noiseSize.y;
+    int xI = ix / noiseSize.x, yI = iy / noiseSize.y;
+    if( ix < 0 )
+        xI--;
+    if( iy < 0 )
+        yI--;
+    int key = ((xI & 0xFFFF) << 16) | (yI & 0xFFFF);
+    if( !cache.has( key ) )
+        cache.put( key, RCPointer<Noise>::of( noiseSupplier( key + seed ) ) );
+    return cache.get( key )->getNoise( (xOff + 1 - (ix - x)) / noiseSize.x, (yOff + 1 - (iy - y)) / noiseSize.y, z );
+}
+
+double NoiseInterpolator::getNoise( double x, double y, double z )
+{
+    const double weights[ 6 ] = { 0.32, 0.17, 0.09, 0.05, 0.03, 0.02 };
+    double sum = 0;
+    for( int xi = -5; xi <= 5; xi++ )
+    {
+        for( int yi = -5; yi <= 5; yi++ )
+            sum += getRealNoise( x + xi, y + yi, z ) * weights[ abs( xi ) ] * weights[ abs( yi ) ];
+    }
+    return sum;
+}
+
+int NoiseInterpolator::getSeed() const
+{
+    return seed;
+}

+ 21 - 0
FactoryCraft/NoiseInterpolator.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include "Noise.h"
+#include "Punkt.h"
+#include "Cache.h"
+#include "RCPointer.h"
+
+class NoiseInterpolator : public Noise
+{
+    Framework::Punkt noiseSize;
+    Framework::Cache<int, Framework::RCPointer<Noise>> cache;
+    std::function<Noise* (int)> noiseSupplier;
+    int seed;
+
+    double getRealNoise( double x, double y, double z );
+
+public:
+    NoiseInterpolator( int seed, std::function<Noise* (int)> noiseSupplier, int width, int height );
+    double getNoise( double x, double y, double z ) override;
+    int getSeed() const override;
+};

+ 5 - 1
FactoryCraft/PerlinNoise.cpp

@@ -1,4 +1,5 @@
 #include "PerlinNoise.h"
+#include "Constants.h"
 
 #include <random>
 #include <algorithm>
@@ -21,8 +22,11 @@ int PerlinNoise::getSeed() const
     return seed;
 }
 
-double PerlinNoise::getNoise( double x, double y, double z ) const
+double PerlinNoise::getNoise( double x, double y, double z )
 {
+    x = (double)((int)x % (CHUNK_SIZE * 10)) / (CHUNK_SIZE * 10);
+    y = (double)((int)y % (CHUNK_SIZE * 10)) / (CHUNK_SIZE * 10);
+    z = (double)((int)z % (CHUNK_SIZE * 10)) / (CHUNK_SIZE * 10);
     // Find the unit cube that contains the point
     int X = (int)floor( x ) & 255;
     int Y = (int)floor( y ) & 255;

+ 1 - 1
FactoryCraft/PerlinNoise.h

@@ -13,7 +13,7 @@ public:
     PerlinNoise( int seed );
 
     int getSeed() const override;
-    double getNoise( double x, double y, double z ) const override;
+    double getNoise( double x, double y, double z ) override;
 
 private:
     inline double fade( double t ) const;

+ 51 - 18
FactoryCraft/Player.cpp

@@ -13,6 +13,7 @@ Player::Player( Framework::Vec3<float> location, int dimensionId, int entityId )
     thirst = 10;
     maxThirst = 10;
     keyState = 0;
+    jumping = 0;
 }
 
 void Player::setName( Framework::Text name )
@@ -27,28 +28,24 @@ const char* Player::getName() const
 
 void Player::tick( const Dimension* zDimension, Game* zGame )
 {
+    speed = { 0, 0, speed.z };
     if( (keyState | Key::MOVE_FRONT) == keyState )
-        location += {faceDir.x * 0.05f, faceDir.y * 0.05f, 0};
+        speed += {faceDir.x * 1.5f, faceDir.y * 1.5f, 0};
     if( (keyState | Key::MOVE_BACK) == keyState )
-        location += {-faceDir.x * 0.05f, -faceDir.y * 0.05f, 0};
+        speed += {-faceDir.x * 1.5f, -faceDir.y * 1.5f, 0};
     if( (keyState | Key::MOVE_RIGHT) == keyState )
     {
-        Vec2<float> right = Vec2<float>( faceDir ).CW90();
-        location += {right.x * 0.05f, right.y * 0.05f, 0};
+        Vec3<float> right = Vec3<float>( faceDir ).rotateZ( (float)PI / 2.f );
+        speed += {right.x * 1.5f, right.y * 1.5f, 0};
     }
     if( (keyState | Key::MOVE_LEFT) == keyState )
     {
-        Vec2<float> left = Vec2<float>( faceDir ).CCW90();
-        location += {left.x * 0.05f, left.y * 0.05f, 0};
+        Vec3<float> left = Vec3<float>( faceDir ).rotateZ( -(float)PI / 2.f );
+        speed += {left.x * 1.5f, left.y * 1.5f, 0};
     }
-    if( (keyState | Key::MOVE_UP) == keyState )
-        location += {0, 0, 0.05f};
-    if( (keyState | Key::MOVE_DOWN) == keyState )
-        location += {0, 0, -0.05f};
-    if( (keyState | Key::ROTATE_LEFT) == keyState )
-        faceDir = faceDir.rotation( -0.05f );
-    if( (keyState | Key::ROTATE_RIGHT) == keyState )
-        faceDir = faceDir.rotation( 0.05f );
+    if( (keyState | Key::MOVE_DOWN) == keyState && !jumping )
+        speed.z = -1.5f;
+    return Entity::tick( zDimension, zGame );
 }
 
 void Player::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse )
@@ -74,7 +71,9 @@ void Player::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse
             keyState = keyState & ~Key::MOVE_RIGHT;
             break;
         case 4:
-            keyState = keyState & ~Key::MOVE_UP;
+            if( gravityMultiplier == 0.f )
+                speed.z = 0;
+            keyState = keyState & ~Key::MOVE_DOWN;
             break;
         case 5:
             keyState = keyState & ~Key::ROTATE_LEFT;
@@ -83,7 +82,9 @@ void Player::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse
             keyState = keyState & ~Key::ROTATE_RIGHT;
             break;
         case 7:
-            keyState = keyState & ~Key::MOVE_DOWN;
+            if( gravityMultiplier == 0.f )
+                speed.z = 0;
+            keyState = keyState & ~Key::MOVE_UP;
             break;
         }
         break;
@@ -104,7 +105,7 @@ void Player::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse
             keyState = keyState | Key::MOVE_RIGHT;
             break;
         case 4:
-            keyState = keyState | Key::MOVE_UP;
+            keyState = keyState | Key::MOVE_DOWN;
             break;
         case 5:
             keyState = keyState | Key::ROTATE_LEFT;
@@ -113,13 +114,45 @@ void Player::api( Framework::StreamReader* zRequest, NetworkResponse* zResponse
             keyState = keyState | Key::ROTATE_RIGHT;
             break;
         case 7:
-            keyState = keyState | Key::MOVE_DOWN;
+            if( (keyState | Key::MOVE_UP) != keyState )
+            {
+                if( gravityMultiplier > 0 )
+                {
+                    if( jumping )
+                    {
+                        // TODO: check if flight is enabled
+                        gravityMultiplier = 0;
+                        jumping = 0;
+                        speed.z = 1.5f;
+                    }
+                    else
+                    {
+                        jumping = 1;
+                        speed.z = 5.f;
+                    }
+                }
+                else
+                    speed.z = 1.5f;
+            }
+            keyState = keyState | Key::MOVE_UP;
             break;
         }
         break;
+        case 2
+            :
+                zRequest->lese( (char*)&faceDir.x, 4 );
+                zRequest->lese( (char*)&faceDir.y, 4 );
+                zRequest->lese( (char*)&faceDir.z, 4 );
     }
 }
 
+void Player::onFall( float collisionSpeed )
+{
+    Entity::onFall( collisionSpeed );
+    gravityMultiplier = 1.f;
+    jumping = 0;
+}
+
 PlayerEntityType::PlayerEntityType()
     : EntityType( ID )
 {}

+ 2 - 0
FactoryCraft/Player.h

@@ -22,6 +22,7 @@ public:
     };
 private:
     Framework::Text name;
+    bool jumping;
     __int64 keyState;
 
 public:
@@ -31,6 +32,7 @@ public:
     void tick( const Dimension* zDimension, Game* zGame ) override;
 
     void api( Framework::StreamReader* zRequest, NetworkResponse* zResponse ) override;
+    void onFall( float collisionSpeed ) override;
 
     friend PlayerEntityType;
 };

+ 2 - 1
FactoryCraft/WorldGenerator.cpp

@@ -3,13 +3,14 @@
 #include "Game.h"
 #include "PerlinNoise.h"
 #include "AddChunkUpdate.h"
+#include "NoiseInterpolator.h"
 
 using namespace Framework;
 
 WorldGenerator::WorldGenerator( int seed, Game* zGame )
     : Thread(),
     zGame( zGame ),
-    noise( new PerlinNoise( seed ) ),
+    noise( new NoiseInterpolator( seed, []( int s ) {return new PerlinNoise( s ); }, CHUNK_SIZE * 10, CHUNK_SIZE * 10 ) ),
     exit( 0 )
 {
     start();

+ 1 - 1
FactoryCraft/WorldUpdate.cpp

@@ -36,7 +36,7 @@ int WorldUpdate::distanceTo( int x, int y ) const
         xDist = 0;
     if( y >= minAffected.y && y <= maxAffected.y )
         yDist = 0;
-    return sqrt( xDist * xDist + yDist * yDist );
+    return (int)sqrt( xDist * xDist + yDist * yDist );
 }