Forráskód Böngészése

send entity events only to interested clients

Kolja Strohm 7 hónapja
szülő
commit
89a5dea21d

+ 0 - 42
FactoryCraft/AddEntityUpdate.cpp

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

+ 0 - 19
FactoryCraft/AddEntityUpdate.h

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

+ 5 - 14
FactoryCraft/Animal.cpp

@@ -1,6 +1,6 @@
 #include "Animal.h"
 
-#include "AddEntityUpdate.h"
+#include "Dimension.h"
 #include "Game.h"
 #include "ItemEntity.h"
 #include "ItemStack.h"
@@ -37,19 +37,10 @@ void Animal::onDeath()
                               ->createItemStack(amount);
                     if (spawnedItems)
                     {
-                        ItemEntity* itemEntity
-                            = (ItemEntity*)Game::INSTANCE
-                                  ->zEntityType(EntityTypeEnum::ITEM)
-                                  ->createEntity(location
-                                                     + Framework::Vec3<float>(
-                                                         0.5f, 0.5f, 0.5f),
-                                      getDimensionId(),
-                                      Game::INSTANCE->getNextEntityId());
-                        itemEntity->unsaveAddItem(
-                            spawnedItems, NO_DIRECTION, 0);
-                        spawnedItems->release();
-                        Game::INSTANCE->requestWorldUpdate(
-                            new AddEntityUpdate(itemEntity, getDimensionId()));
+                        Game::INSTANCE->spawnItem(
+                            location + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
+                            getDimensionId(),
+                            spawnedItems);
                     }
                 }
             }

+ 18 - 28
FactoryCraft/BasicBlocks.cpp

@@ -1,11 +1,10 @@
 #include "BasicBlocks.h"
 
-#include "AddEntityUpdate.h"
 #include "Game.h"
 #include "ItemEntity.h"
+#include "ItemStack.h"
 #include "ModelInfo.h"
 #include "TreeSeblingBlock.h"
-#include "ItemStack.h"
 
 BasicBlock::BasicBlock(int typeId, Framework::Vec3<int> pos, int dimensionId)
     : BasicBlock(typeId, pos, dimensionId, false)
@@ -233,18 +232,10 @@ void AdditionalItemSpawningBlock::onDestroy()
                           ->createItemStack(amount);
                 if (spawnedItems)
                 {
-                    ItemEntity* itemEntity
-                        = (ItemEntity*)Game::INSTANCE
-                              ->zEntityType(EntityTypeEnum::ITEM)
-                              ->createEntity(location
-                                                 + Framework::Vec3<float>(
-                                                     0.5f, 0.5f, 0.5f),
-                                  getDimensionId(),
-                                  Game::INSTANCE->getNextEntityId());
-                    itemEntity->unsaveAddItem(spawnedItems, NO_DIRECTION, 0);
-                    spawnedItems->release();
-                    Game::INSTANCE->requestWorldUpdate(
-                        new AddEntityUpdate(itemEntity, getDimensionId()));
+                    Game::INSTANCE->spawnItem(
+                        location + Framework::Vec3<float>(0.5f, 0.5f, 0.5f),
+                        getDimensionId(),
+                        spawnedItems);
                 }
             }
         }
@@ -365,20 +356,19 @@ JSONObjectValidationBuilder*
 AdditionalItemSpawningBlockTypeFactory::addToValidator(
     JSONObjectValidationBuilder* builder) const
 {
-    return super.addToValidator(
-        builder->withRequiredAttribute("spawns",
-            Framework::JSON::Validator::JSONValidator::buildForArray()
-                ->addAcceptedObjectInArray()
-                ->withRequiredString("itemType")
-                ->finishString()
-                ->withRequiredNumber("chance")
-                ->finishNumber()
-                ->withRequiredNumber("min")
-                ->finishNumber()
-                ->withRequiredNumber("max")
-                ->finishNumber()
-                ->finishObject()
-                ->finishArray()));
+    return super.addToValidator(builder->withRequiredAttribute("spawns",
+        Framework::JSON::Validator::JSONValidator::buildForArray()
+            ->addAcceptedObjectInArray()
+            ->withRequiredString("itemType")
+            ->finishString()
+            ->withRequiredNumber("chance")
+            ->finishNumber()
+            ->withRequiredNumber("min")
+            ->finishNumber()
+            ->withRequiredNumber("max")
+            ->finishNumber()
+            ->finishObject()
+            ->finishArray()));
 }
 
 Framework::Text AdditionalItemSpawningBlockTypeFactory::getTypeToken() const

+ 22 - 3
FactoryCraft/BiomGenerator.cpp

@@ -1,7 +1,8 @@
 #include "BiomGenerator.h"
 
-#include "AddEntityUpdate.h"
 #include "Constants.h"
+#include "Dimension.h"
+#include "Entity.h"
 #include "Game.h"
 #include "JNoise.h"
 
@@ -94,8 +95,15 @@ void BiomGenerator::generateEntities(
             Entity* entity = entityGen->generate(
                 Framework::Vec3<float>((float)x, (float)y, (float)z),
                 dimensionId);
-            Game::INSTANCE->requestWorldUpdate(
-                new AddEntityUpdate(entity, dimensionId));
+            Dimension* dimension = Game::INSTANCE->zDimension(dimensionId);
+            if (dimension)
+            {
+                dimension->addEntity(entity);
+            }
+            else
+            {
+                entity->release();
+            }
         }
     }
 }
@@ -175,6 +183,17 @@ BiomGenerator::getGeneratorRules() const
     return rules;
 }
 
+void BiomGenerator::addEntityGenerator(EntityGenerator* generator)
+{
+    entityGenerators.add(generator);
+}
+
+const Framework::RCArray<EntityGenerator>&
+BiomGenerator::getEntityGenerators() const
+{
+    return entityGenerators;
+}
+
 BiomGeneratorFactory::BiomGeneratorFactory()
     : TypeFactory()
 {}

+ 0 - 1
FactoryCraft/Block.cpp

@@ -1,6 +1,5 @@
 #include "Block.h"
 
-#include "AddEntityUpdate.h"
 #include "Dimension.h"
 #include "Game.h"
 #include "Inventory.h"

+ 48 - 1
FactoryCraft/Chunk.cpp

@@ -1169,4 +1169,51 @@ void Chunk::setLightData(
 int Chunk::getBlockTypeAt(Framework::Vec3<int> location) const
 {
     return blockIds[index(location)];
-}
+}
+
+void Chunk::onEntityEnters(Entity* zEntity, Chunk* lastChunk)
+{
+    NetworkMessage* msg = 0;
+    for (InformationObserver* observer : observers)
+    {
+        if (!lastChunk || !lastChunk->hasObserver(zEntity->getId()))
+        {
+            if (!msg)
+            {
+                msg = new NetworkMessage();
+                msg->addEntityMessage(zEntity);
+                if (msg->isEmpty()) break;
+            }
+            observer->sendMessage(msg);
+        }
+    }
+    if (msg) msg->release();
+}
+
+void Chunk::onEntityLeaves(Entity* zEntity, Chunk* zNextChunk)
+{
+    NetworkMessage* msg = 0;
+    for (InformationObserver* observer : observers)
+    {
+        if (!zNextChunk || !zNextChunk->hasObserver(zEntity->getId()))
+        {
+            if (!msg)
+            {
+                msg = new NetworkMessage();
+                msg->removeEntityMessage(zEntity);
+                if (msg->isEmpty()) break;
+            }
+            observer->sendMessage(msg);
+        }
+    }
+    if (msg) msg->release();
+}
+
+bool Chunk::hasObserver(int entityId) const
+{
+    for (InformationObserver* observer : observers)
+    {
+        if (observer->getEntityId() == entityId) return 1;
+    }
+    return 0;
+}

+ 3 - 0
FactoryCraft/Chunk.h

@@ -89,6 +89,9 @@ public:
     void setLightData(
         Framework::Vec3<int> location, unsigned char* data, bool foreground);
     int getBlockTypeAt(Framework::Vec3<int> location) const;
+    void onEntityEnters(Entity* zEntity, Chunk* lastChunk);
+    void onEntityLeaves(Entity* zEntity, Chunk* zNextChunk);
+    bool hasObserver(int entityId) const;
 
     inline static int index(Framework::Vec3<int> localLocation)
     {

+ 1 - 1
FactoryCraft/Constants.h

@@ -19,5 +19,5 @@
 #define MAX_TICKS_PER_SECOND  20
 
 #ifndef OUT
-#    define OUT00
+#    define OUT
 #endif

+ 60 - 18
FactoryCraft/Entity.cpp

@@ -4,7 +4,6 @@
 
 #include "BlockType.h"
 #include "Dimension.h"
-#include "EntityRemovedUpdate.h"
 #include "Game.h"
 #include "ItemSkill.h"
 #include "ItemStack.h"
@@ -218,6 +217,8 @@ Entity::Entity(
     int typeId, Framework::Vec3<float> location, int dimensionId, int entityId)
     : Inventory(location, dimensionId, true),
       chatSecurityLevel(0),
+      lastChunkCenter(0, 0),
+      lastDimensionId(-1),
       speed(0, 0, 0),
       faceDir(1, 0, 0),
       target(0),
@@ -233,8 +234,16 @@ void Entity::onDeath()
 {
     if (!removed)
     {
-        Game::INSTANCE->requestWorldUpdate(
-            new EntityRemovedUpdate(id, dimensionId, location));
+        Dimension* dim = Game::INSTANCE->zDimension(dimensionId);
+        if (dim)
+        {
+            Chunk* chunk = dim->zChunk(lastChunkCenter);
+            if (chunk)
+            {
+                chunk->onEntityLeaves(this, 0);
+            }
+            dim->removeEntity(id);
+        }
         removed = 1;
     }
 }
@@ -389,22 +398,29 @@ void Entity::addMovementFrame(MovementFrame& frame)
     cs.lock();
     movements.add(frame);
     cs.unlock();
-    NetworkMessage* message = new NetworkMessage();
-    message->addressEntity(this);
-    char* msg = new char[37];
-    msg[0] = 0;
-    *(float*)(msg + 1) = frame.direction.x;
-    *(float*)(msg + 5) = frame.direction.y;
-    *(float*)(msg + 9) = frame.direction.z;
-    *(float*)(msg + 13) = frame.targetPosition.x;
-    *(float*)(msg + 17) = frame.targetPosition.y;
-    *(float*)(msg + 21) = frame.targetPosition.z;
-    *(int*)(msg + 25) = frame.movementFlags;
-    *(double*)(msg + 29) = frame.duration;
-    message->setMessage(msg, 37);
-    Game::INSTANCE->broadcastMessage(message);
+    Dimension* dim = Game::INSTANCE->zDimension(lastDimensionId);
+    if (dim)
+    {
+        Chunk* chunk = dim->zChunk(lastChunkCenter);
+        if (chunk)
+        {
+            NetworkMessage* message = new NetworkMessage();
+            message->addressEntity(this);
+            char* msg = new char[37];
+            msg[0] = 0;
+            *(float*)(msg + 1) = frame.direction.x;
+            *(float*)(msg + 5) = frame.direction.y;
+            *(float*)(msg + 9) = frame.direction.z;
+            *(float*)(msg + 13) = frame.targetPosition.x;
+            *(float*)(msg + 17) = frame.targetPosition.y;
+            *(float*)(msg + 21) = frame.targetPosition.z;
+            *(int*)(msg + 25) = frame.movementFlags;
+            *(double*)(msg + 29) = frame.duration;
+            message->setMessage(msg, 37);
+            chunk->notifyObservers(message);
+        }
+    }
     faceDir = frame.direction;
-    // TODO implement subscription system to notify only interested clients
 }
 
 void Entity::calculateTarget(Framework::Vec3<float> basePos,
@@ -658,6 +674,32 @@ void Entity::tick(const Dimension* zDimension)
         }
     }
     time.messungStart();
+    Framework::Punkt chunkCenter
+        = Game::INSTANCE->getChunkCenter((int)location.x, (int)location.y);
+    if (dimensionId != lastDimensionId || chunkCenter != lastChunkCenter)
+    {
+        Dimension* lastDimension = Game::INSTANCE->zDimension(lastDimensionId);
+        Dimension* currentDimension = Game::INSTANCE->zDimension(dimensionId);
+        Chunk* zCurrentChunk
+            = currentDimension ? currentDimension->zChunk(chunkCenter) : 0;
+        Chunk* zLastChunk
+            = lastDimension ? lastDimension->zChunk(lastChunkCenter) : 0;
+        if (lastDimensionId != -1)
+        {
+            if (zLastChunk)
+            {
+                zLastChunk->onEntityLeaves(
+                    this, lastDimensionId == dimensionId ? zCurrentChunk : 0);
+            }
+        }
+        if (zCurrentChunk)
+        {
+            zCurrentChunk->onEntityEnters(
+                this, lastDimensionId == dimensionId ? zLastChunk : 0);
+        }
+        lastDimensionId = dimensionId;
+        lastChunkCenter = chunkCenter;
+    }
 }
 
 void Entity::api(Framework::StreamReader* zRequest,

+ 2 - 0
FactoryCraft/Entity.h

@@ -57,6 +57,8 @@ private:
     float currentHP;
     float thirst;
     int chatSecurityLevel;
+    Framework::Punkt lastChunkCenter;
+    int lastDimensionId;
 
 protected:
     float maxHP;

+ 0 - 22
FactoryCraft/EntityRemovedUpdate.cpp

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

+ 0 - 19
FactoryCraft/EntityRemovedUpdate.h

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

+ 2 - 6
FactoryCraft/FactoryCraft.vcxproj

@@ -106,11 +106,11 @@
     <ClInclude Include="FactorizeNoise.h" />
     <ClInclude Include="FlattenNoise.h" />
     <ClInclude Include="FluidContainer.h" />
+    <ClInclude Include="GameClient.h" />
     <ClInclude Include="GeneratorRule.h" />
     <ClInclude Include="BlockTypeGeneratorRule.h" />
     <ClInclude Include="Chest.h" />
     <ClInclude Include="ChunkMap.h" />
-    <ClInclude Include="AddEntityUpdate.h" />
     <ClInclude Include="Area.h" />
     <ClInclude Include="BasicBlocks.h" />
     <ClInclude Include="BasicItems.h" />
@@ -131,7 +131,6 @@
     <ClInclude Include="Effect.h" />
     <ClInclude Include="EffectFactory.h" />
     <ClInclude Include="Entity.h" />
-    <ClInclude Include="EntityRemovedUpdate.h" />
     <ClInclude Include="EntityType.h" />
     <ClInclude Include="FastNoiseLite.h" />
     <ClInclude Include="FastNoiseWrapper.h" />
@@ -199,11 +198,9 @@
     <ClInclude Include="UIDialog.h" />
     <ClInclude Include="WorldGenerator.h" />
     <ClInclude Include="WorldLoader.h" />
-    <ClInclude Include="WorldUpdate.h" />
     <ClInclude Include="WormCaveGenerator.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="AddEntityUpdate.cpp" />
     <ClCompile Include="Animal.cpp" />
     <ClCompile Include="AnimalAI.cpp" />
     <ClCompile Include="Area.cpp" />
@@ -234,7 +231,6 @@
     <ClCompile Include="DoLaterHandler.cpp" />
     <ClCompile Include="Entity.cpp" />
     <ClCompile Include="EntityGenerator.cpp" />
-    <ClCompile Include="EntityRemovedUpdate.cpp" />
     <ClCompile Include="EntityType.cpp" />
     <ClCompile Include="FactorizeNoise.cpp" />
     <ClCompile Include="FastNoiseWrapper.cpp" />
@@ -242,6 +238,7 @@
     <ClCompile Include="FluidBlock.cpp" />
     <ClCompile Include="FluidContainer.cpp" />
     <ClCompile Include="Game.cpp" />
+    <ClCompile Include="GameClient.cpp" />
     <ClCompile Include="GeneratedStructure.cpp" />
     <ClCompile Include="GeneratorTemplate.cpp" />
     <ClCompile Include="GeneratorRule.cpp" />
@@ -301,7 +298,6 @@
     <ClCompile Include="UIDialog.cpp" />
     <ClCompile Include="WorldGenerator.cpp" />
     <ClCompile Include="WorldLoader.cpp" />
-    <ClCompile Include="WorldUpdate.cpp" />
     <ClCompile Include="WormCaveGenerator.cpp" />
   </ItemGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+ 6 - 21
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -28,9 +28,6 @@
     <Filter Include="world\ticking">
       <UniqueIdentifier>{03a72d46-51b8-4f26-b04a-f5f4d4f5af6e}</UniqueIdentifier>
     </Filter>
-    <Filter Include="world\update">
-      <UniqueIdentifier>{05bf4218-e0cd-4d0d-bd7b-eaea87023838}</UniqueIdentifier>
-    </Filter>
     <Filter Include="world\loader">
       <UniqueIdentifier>{12fac988-c4d8-4db8-b4a8-1c025f117866}</UniqueIdentifier>
     </Filter>
@@ -177,9 +174,6 @@
     <ClInclude Include="TickOrganizer.h">
       <Filter>world\ticking</Filter>
     </ClInclude>
-    <ClInclude Include="WorldUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="EntityType.h">
       <Filter>entities</Filter>
     </ClInclude>
@@ -207,12 +201,6 @@
     <ClInclude Include="ItemEntity.h">
       <Filter>entities</Filter>
     </ClInclude>
-    <ClInclude Include="AddEntityUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
-    <ClInclude Include="EntityRemovedUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="GeneratorTemplate.h">
       <Filter>world\generator\templates</Filter>
     </ClInclude>
@@ -426,6 +414,9 @@
     <ClInclude Include="NeutralAnimalAI.h">
       <Filter>entities\animals</Filter>
     </ClInclude>
+    <ClInclude Include="GameClient.h">
+      <Filter>game</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -470,9 +461,6 @@
     <ClCompile Include="WorldLoader.cpp">
       <Filter>world\loader</Filter>
     </ClCompile>
-    <ClCompile Include="WorldUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="Dimension.cpp">
       <Filter>world</Filter>
     </ClCompile>
@@ -518,12 +506,6 @@
     <ClCompile Include="ItemEntity.cpp">
       <Filter>entities</Filter>
     </ClCompile>
-    <ClCompile Include="AddEntityUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
-    <ClCompile Include="EntityRemovedUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="GeneratedStructure.cpp">
       <Filter>world\generator\templates</Filter>
     </ClCompile>
@@ -728,5 +710,8 @@
     <ClCompile Include="NeutralAnimalAI.cpp">
       <Filter>entities\animals</Filter>
     </ClCompile>
+    <ClCompile Include="GameClient.cpp">
+      <Filter>game</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 33 - 346
FactoryCraft/Game.cpp

@@ -2,12 +2,10 @@
 
 #include <Logging.h>
 
-#include "AddEntityUpdate.h"
 #include "AsynchronCall.h"
 #include "Chat.h"
 #include "Dimension.h"
 #include "Entity.h"
-#include "EntityRemovedUpdate.h"
 #include "ItemEntity.h"
 #include "JsonUtils.h"
 #include "MultiblockTree.h"
@@ -30,316 +28,11 @@ using namespace Framework;
 Framework::ConsoleHandler* Game::consoleHandler = 0;
 Framework::InputLine* Game::consoleInput = 0;
 
-GameClient::GameClient(Player* zPlayer, FCKlient* client)
-    : Thread(),
-      zPlayer(zPlayer),
-      client(client),
-      viewDistance(DEFAULT_VIEW_DISTANCE),
-      first(1),
-      online(1),
-      finished(0),
-      backgroundFinished(0),
-      foregroundFinished(0)
-{
-    new AsynchronCall("Game Client Updates", [this]() {
-        while (online)
-        {
-            other.lock();
-            if (updateQueue.hat(0))
-            {
-                WorldUpdate* update = updateQueue.get(0);
-                updateQueue.remove(0);
-                other.unlock();
-                background.lock();
-                this->client->zBackgroundWriter()->schreibe(
-                    (char*)&Message::WORLD_UPDATE, 1);
-                update->writeAndCheck(this->client->zBackgroundWriter());
-                background.unlock();
-                update->release();
-            }
-            else
-            {
-                other.unlock();
-                updateSync.wait();
-            }
-        }
-        finished = 1;
-    });
-    start();
-}
-
-GameClient::~GameClient()
-{
-    online = 0;
-    updateSync.notify();
-    emptyForegroundQueueSync.notifyAll();
-    emptyBackgroundQueueSync.notifyAll();
-    foregroundQueueSync.notify();
-    backgroundQueueSync.notify();
-    while (!finished || !foregroundFinished || !backgroundFinished)
-        Sleep(100);
-    client->release();
-}
-
-void GameClient::thread()
-{
-    new AsynchronCall("Game Client Background", [this]() {
-        while (online)
-        {
-            queueCs.lock();
-            if (backgroundQueue.hat(0))
-            {
-                NetworkMessage* message = backgroundQueue.get(0);
-                backgroundQueue.remove(0);
-                queueCs.unlock();
-                background.lock();
-                message->writeTo(client->zBackgroundWriter());
-                background.unlock();
-                message->release();
-            }
-            else
-            {
-                queueCs.unlock();
-                emptyBackgroundQueueSync.notifyAll();
-                while (!backgroundQueueSync.wait(1000))
-                {
-                    emptyBackgroundQueueSync.notifyAll();
-                }
-            }
-        }
-        backgroundFinished = 1;
-    });
-    while (online)
-    {
-        queueCs.lock();
-        if (foregroundQueue.hat(0))
-        {
-            NetworkMessage* message = foregroundQueue.get(0);
-            foregroundQueue.remove(0);
-            queueCs.unlock();
-            foreground.lock();
-            message->writeTo(client->zForegroundWriter());
-            foreground.unlock();
-            message->release();
-        }
-        else
-        {
-            queueCs.unlock();
-            emptyForegroundQueueSync.notifyAll();
-            while (!foregroundQueueSync.wait(1000))
-            {
-                emptyForegroundQueueSync.notifyAll();
-            }
-        }
-    }
-    foregroundFinished = 1;
-}
-
-void GameClient::sendWorldUpdate(WorldUpdate* update)
-{
-    bool add = 0;
-    if (zPlayer->getDimensionId() == update->getAffectedDimension())
-    {
-        auto pos = (Vec3<int>)zPlayer->getPosition();
-        int dist = update->distanceTo(pos.x, pos.y);
-        if (dist < viewDistance * CHUNK_SIZE)
-        {
-            other.lock();
-            updateQueue.add(update);
-            other.unlock();
-            updateSync.notify();
-            add = 1;
-        }
-    }
-    if (!add) update->release();
-}
-
-void GameClient::reply()
-{
-    other.lock();
-    for (auto req : requests)
-        Game::INSTANCE->api(req, this);
-    requests.leeren();
-    other.unlock();
-    if (first)
-    {
-        foreground.lock();
-        int id = zPlayer->getId();
-        client->zForegroundWriter()->schreibe(
-            (char*)&Message::POSITION_UPDATE, 1);
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        id = zPlayer->getDimensionId();
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        client->zForegroundWriter()->schreibe((char*)&Message::API_MESSAGE, 1);
-        int len = 10;
-        client->zForegroundWriter()->schreibe((char*)&len, 4);
-        client->zForegroundWriter()->schreibe("\1", 1);
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        client->zForegroundWriter()->schreibe("\6", 1);
-        float gravity = Game::INSTANCE->zDimension(zPlayer->getDimensionId())
-                            ->getGravity();
-        client->zForegroundWriter()->schreibe((char*)&gravity, 4);
-        foreground.unlock();
-        first = 0;
-    }
-}
-
-void GameClient::logout()
-{
-    online = 0;
-    updateSync.notify();
-    emptyForegroundQueueSync.notifyAll();
-    emptyBackgroundQueueSync.notifyAll();
-    foregroundQueueSync.notify();
-    backgroundQueueSync.notify();
-}
-
-void GameClient::addMessage(StreamReader* reader)
-{
-    short len = 0;
-    reader->lese((char*)&len, 2);
-    InMemoryBuffer* buffer = new InMemoryBuffer();
-    char* tmp = new char[len];
-    reader->lese(tmp, len);
-    buffer->schreibe(tmp, len);
-    delete[] tmp;
-    other.lock();
-    requests.add(buffer);
-    other.unlock();
-}
-
-bool GameClient::isOnline() const
-{
-    return online;
-}
-
-void GameClient::sendResponse(NetworkMessage* response)
-{
-    queueCs.lock();
-    if (response->isUseBackground())
-    {
-        if (backgroundQueue.getEintragAnzahl() > 20)
-        {
-            queueCs.unlock();
-            while (!emptyBackgroundQueueSync.wait(1000))
-            {
-                backgroundQueueSync.notify();
-            }
-            queueCs.lock();
-        }
-        backgroundQueue.add(response);
-        queueCs.unlock();
-        backgroundQueueSync.notify();
-    }
-    else
-    {
-        if (foregroundQueue.getEintragAnzahl() > 100)
-        {
-            queueCs.unlock();
-            Framework::Logging::warning()
-                << "Game paused because nework connection to "
-                << zPlayer->getName() << " is to slow.";
-            ZeitMesser m;
-            m.messungStart();
-            while (foregroundQueue.getEintragAnzahl() > 0)
-            {
-                foregroundQueueSync.notify();
-                emptyForegroundQueueSync.wait(100);
-            }
-            m.messungEnde();
-            Framework::Logging::warning()
-                << "Game resumed after " << m.getSekunden() << " seconds.";
-            queueCs.lock();
-        }
-        foregroundQueue.add(response);
-        queueCs.unlock();
-        foregroundQueueSync.notify();
-    }
-}
-
-Player* GameClient::zEntity() const
-{
-    return zPlayer;
-}
-
-void GameClient::sendTypes()
-{
-    foreground.lock();
-    int count = 0;
-    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zBlockType(i)) count++;
-    }
-    client->zForegroundWriter()->schreibe((char*)&count, 4);
-    for (int i = 0; i < Game::INSTANCE->getBlockTypeCount(); i++)
-    {
-        const BlockType* t = Game::INSTANCE->zBlockType(i);
-        if (t)
-        {
-            t->writeTypeInfo(client->zForegroundWriter());
-        }
-    }
-    count = 0;
-    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zItemType(i)) count++;
-    }
-    client->zForegroundWriter()->schreibe((char*)&count, 4);
-    for (int i = 0; i < Game::INSTANCE->getItemTypeCount(); i++)
-    {
-        const ItemType* t = Game::INSTANCE->zItemType(i);
-        if (t)
-        {
-            int id = t->getId();
-            client->zForegroundWriter()->schreibe((char*)&id, 4);
-            char len = (char)t->getName().getLength();
-            client->zForegroundWriter()->schreibe((char*)&len, 1);
-            client->zForegroundWriter()->schreibe(t->getName().getText(), len);
-            short tlen = (short)t->getTooltipUIML().getLength();
-            client->zForegroundWriter()->schreibe((char*)&tlen, 2);
-            client->zForegroundWriter()->schreibe(
-                t->getTooltipUIML().getText(), tlen);
-            if (t->zModel())
-            {
-                t->zModel()->writeTo(client->zForegroundWriter());
-            }
-            else
-            {
-                ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
-                    .writeTo(client->zForegroundWriter());
-            }
-        }
-    }
-    count = 0;
-    for (int i = 0; i < Game::INSTANCE->getEntityTypeCount(); i++)
-    {
-        if (Game::INSTANCE->zEntityType(i)) count++;
-    }
-    client->zForegroundWriter()->schreibe((char*)&count, 4);
-    for (int i = 0; i < count; i++)
-    {
-        const EntityType* t = Game::INSTANCE->zEntityType(i);
-        int id = t->getId();
-        client->zForegroundWriter()->schreibe((char*)&id, 4);
-        if (t->zModel())
-        {
-            t->zModel()->writeTo(client->zForegroundWriter());
-        }
-        else
-        {
-            ModelInfo("", Framework::RCArray<Framework::Text>(), false, 1.f)
-                .writeTo(client->zForegroundWriter());
-        }
-    }
-    foreground.unlock();
-}
-
 Game::Game(Framework::Text name, Framework::Text worldsDir)
     : Thread(),
       name(name),
       typeRegistry(new TypeRegistry()),
       dimensions(new RCArray<Dimension>()),
-      updates(new RCArray<WorldUpdate>()),
       clients(new RCArray<GameClient>()),
       questManager(new QuestManager()),
       ticker(new TickOrganizer()),
@@ -382,7 +75,6 @@ Game::Game(Framework::Text name, Framework::Text worldsDir)
 Game::~Game()
 {
     dimensions->release();
-    updates->release();
     clients->release();
     generator->release();
     loader->release();
@@ -707,10 +399,14 @@ void Game::thread()
                 Dimension* dim
                     = zDimension(player->zEntity()->getDimensionId());
                 dim->removeSubscriptions(player->zEntity());
-                this->requestWorldUpdate(
-                    new EntityRemovedUpdate(player->zEntity()->getId(),
-                        player->zEntity()->getDimensionId(),
-                        player->zEntity()->getPosition()));
+                Chunk* chunk = dim->zChunk(
+                    getChunkCenter((int)player->zEntity()->getLocation().x,
+                        (int)player->zEntity()->getLocation().y));
+                if (chunk)
+                {
+                    chunk->onEntityLeaves(player->zEntity(), 0);
+                }
+                dim->removeEntity(player->zEntity()->getId());
             }
             else
             {
@@ -748,30 +444,6 @@ void Game::thread()
         waitForLock.messungEnde();
         waitTotal += waitForLock.getSekunden();
         worldUpdates.messungStart();
-        while (updates->hat(0))
-        {
-            WorldUpdate* update = updates->z(0);
-            for (auto client : *clients)
-                client->sendWorldUpdate(
-                    dynamic_cast<WorldUpdate*>(update->getThis()));
-            if (!zDimension(update->getAffectedDimension()))
-            {
-                Dimension* dim = generator->createDimension(
-                    update->getAffectedDimension());
-                if (dim)
-                    addDimension(dim);
-                else
-                {
-                    Framework::Logging::error()
-                        << "could not create dimension "
-                        << update->getAffectedDimension()
-                        << ". No Factory was provided.";
-                }
-            }
-            if (zDimension(update->getAffectedDimension()))
-                update->onUpdate(zDimension(update->getAffectedDimension()));
-            updates->remove(0);
-        }
         worldUpdates.messungEnde();
         cs.unlock();
         clientReply.messungStart();
@@ -984,14 +656,6 @@ void Game::sendMessage(NetworkMessage* response, Entity* zTargetPlayer)
     response->release();
 }
 
-bool Game::requestWorldUpdate(WorldUpdate* update)
-{
-    cs.lock();
-    updates->add(update);
-    cs.unlock();
-    return 1;
-}
-
 bool Game::checkPlayer(Framework::Text name, Framework::Text secret)
 {
     if (playerRegister->checkSecret(name, secret))
@@ -1096,7 +760,18 @@ GameClient* Game::addPlayer(FCKlient* client, Framework::Text name)
         player->setPosition(
             {player->getPosition().x, player->getPosition().y, (float)h + 2.f});
     }
-    requestWorldUpdate(new AddEntityUpdate(player, player->getDimensionId()));
+    Dimension* zDim = zDimension(player->getDimensionId());
+    if (zDim)
+    {
+        zDim->addEntity(player);
+    }
+    else
+    {
+        Framework::Logging::error()
+            << "could not add player to dimension "
+            << (int)player->getDimensionId() << ". Dimension not loaded.";
+        player->release();
+    }
     chat->addObserver(gameClient->zEntity()->getId());
     chat->broadcastMessage(name + " joined the game.", Chat::CHANNEL_INFO);
     cs.unlock();
@@ -1158,7 +833,19 @@ void Game::spawnItem(
                   location, dimensionId, Game::INSTANCE->getNextEntityId());
     itemEntity->unsaveAddItem(stack, NO_DIRECTION, 0);
     stack->release();
-    requestWorldUpdate(new AddEntityUpdate(itemEntity, dimensionId));
+    Dimension* dim = zDimension(dimensionId);
+    if (dim)
+    {
+        dim->addEntity(itemEntity);
+    }
+    else
+    {
+        Framework::Logging::error()
+            << "could not spawn item entity in dimension " << dimensionId
+            << ". Dimension not loaded.";
+        itemEntity->release();
+        return;
+    }
 }
 
 Framework::Either<Block*, int> Game::zBlockAt(

+ 2 - 54
FactoryCraft/Game.h

@@ -10,12 +10,11 @@
 #include <Thread.h>
 
 #include "Area.h"
+#include "Constants.h"
+#include "GameClient.h"
 #include "NetworkMessage.h"
 #include "TypeRegistry.h"
-#include "WorldUpdate.h"
 
-class FCKlient;
-class Player;
 class QuestManager;
 class TickOrganizer;
 class WorldGenerator;
@@ -31,55 +30,6 @@ class BlockType;
 class ItemType;
 class Item;
 
-class GameClient : public Framework::Thread
-{
-private:
-    Player* zPlayer;
-    FCKlient* client;
-    Framework::Critical background;
-    Framework::Critical foreground;
-    Framework::Critical other;
-    Framework::Synchronizer updateSync;
-    Framework::RCArray<Framework::InMemoryBuffer> requests;
-    Framework::RCArray<WorldUpdate> updateQueue;
-    Framework::RCArray<NetworkMessage> backgroundQueue;
-    Framework::RCArray<NetworkMessage> foregroundQueue;
-    Framework::Synchronizer foregroundQueueSync;
-    Framework::Synchronizer backgroundQueueSync;
-    Framework::Critical queueCs;
-    Framework::Synchronizer emptyForegroundQueueSync;
-    Framework::Synchronizer emptyBackgroundQueueSync;
-    int viewDistance;
-    bool first;
-    bool online;
-    bool finished;
-    bool backgroundFinished;
-    bool foregroundFinished;
-
-public:
-    GameClient(Player* zPlayer, FCKlient* client);
-    ~GameClient();
-
-    void thread() override;
-    void sendWorldUpdate(WorldUpdate* update);
-    void reply();
-    void logout();
-    void addMessage(Framework::StreamReader* reader);
-    bool isOnline() const;
-    void sendResponse(NetworkMessage* response);
-    Player* zEntity() const;
-    void sendTypes();
-
-    class Message
-    {
-    public:
-        inline static const unsigned char TERMINATE = 1;
-        inline static const unsigned char WORLD_UPDATE = 2;
-        inline static const unsigned char API_MESSAGE = 3;
-        inline static const unsigned char POSITION_UPDATE = 4;
-    };
-};
-
 class Game : public virtual Framework::Thread
 {
 public:
@@ -90,7 +40,6 @@ private:
     Framework::Text name;
     TypeRegistry* typeRegistry;
     Framework::RCArray<Dimension>* dimensions;
-    Framework::RCArray<WorldUpdate>* updates;
     Framework::RCArray<GameClient>* clients;
     Framework::Array<std::function<void()>> actions;
     QuestManager* questManager;
@@ -134,7 +83,6 @@ public:
         int dimensionId, Framework::Vec3<int> location);
     void broadcastMessage(NetworkMessage* response);
     void sendMessage(NetworkMessage* response, Entity* zTargetPlayer);
-    bool requestWorldUpdate(WorldUpdate* update);
     bool checkPlayer(Framework::Text name, Framework::Text secret);
     bool existsPlayer(Framework::Text name);
     Framework::Text createPlayer(Framework::Text name);

+ 268 - 0
FactoryCraft/GameClient.cpp

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

+ 56 - 0
FactoryCraft/GameClient.h

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

+ 0 - 1
FactoryCraft/Grass.cpp

@@ -1,6 +1,5 @@
 #include "Grass.h"
 
-#include "AddEntityUpdate.h"
 #include "Game.h"
 #include "ItemEntity.h"
 

+ 45 - 0
FactoryCraft/NetworkMessage.cpp

@@ -8,6 +8,7 @@
 #include "ChunkMap.h"
 #include "Dimension.h"
 #include "Entity.h"
+#include "EntityType.h"
 #include "Game.h"
 
 NetworkMessage::NetworkMessage()
@@ -238,6 +239,50 @@ void NetworkMessage::syncTime(
     *(double*)(message + 24) = dayLength;
 }
 
+void NetworkMessage::addEntityMessage(const Entity* zEntity)
+{
+    Dimension* dim = Game::INSTANCE->zDimension(zEntity->getDimensionId());
+    if (dim)
+    {
+        addressDimension(dim);
+        Framework::InMemoryBuffer buffer;
+        int id = zEntity->zType()->getId();
+        buffer.schreibe("\x7", 1); // add entity
+        buffer.schreibe((char*)&id, 4);
+        id = zEntity->getId();
+        buffer.schreibe((char*)&id, 4);
+        Framework::Vec3<float> pos = zEntity->getPosition();
+        buffer.schreibe((char*)&pos.x, 4);
+        buffer.schreibe((char*)&pos.y, 4);
+        buffer.schreibe((char*)&pos.z, 4);
+        float maxSpeed = zEntity->getMaxSpeed();
+        buffer.schreibe((char*)&maxSpeed, 4);
+        float gravityMultiplier = zEntity->getGravityMultiplier();
+        buffer.schreibe((char*)&gravityMultiplier, 4);
+        float jumpSpeed = zEntity->getJumpSpeed();
+        buffer.schreibe((char*)&jumpSpeed, 4);
+        bool special = !zEntity->hasDefaultModel();
+        buffer.schreibe((char*)&special, 1);
+        if (special) zEntity->zSpecialModel()->writeTo(&buffer);
+        msgLength = (int)buffer.getSize();
+        message = new char[msgLength];
+        buffer.lese(message, (int)buffer.getSize());
+    }
+}
+
+void NetworkMessage::removeEntityMessage(const Entity* zEntity)
+{
+    Dimension* dim = Game::INSTANCE->zDimension(zEntity->getDimensionId());
+    if (dim)
+    {
+        addressDimension(dim);
+        msgLength = 5;
+        message = new char[5];
+        message[0] = '\x8';
+        *(int*)(message + 1) = zEntity->getId();
+    }
+}
+
 void NetworkMessage::writeTo(Framework::StreamWriter* zWriter) const
 {
     int total = msgLength + addressLength;

+ 2 - 0
FactoryCraft/NetworkMessage.h

@@ -55,6 +55,8 @@ public:
         double nightLength,
         double transitionLength,
         double dayLength);
+    void addEntityMessage(const Entity* zEntity);
+    void removeEntityMessage(const Entity* zEntity);
 
     void writeTo(Framework::StreamWriter* zWriter) const;
     bool isBroadcast() const;

+ 0 - 30
FactoryCraft/WorldUpdate.cpp

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

+ 0 - 35
FactoryCraft/WorldUpdate.h

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

+ 2 - 6
Windows Version/Windows Version.vcxproj

@@ -157,7 +157,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     </CustomBuildStep>
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClCompile Include="..\FactoryCraft\AddEntityUpdate.cpp" />
     <ClCompile Include="..\FactoryCraft\Animal.cpp" />
     <ClCompile Include="..\FactoryCraft\AnimalAI.cpp" />
     <ClCompile Include="..\FactoryCraft\Area.cpp" />
@@ -188,7 +187,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\DoLaterHandler.cpp" />
     <ClCompile Include="..\FactoryCraft\Entity.cpp" />
     <ClCompile Include="..\FactoryCraft\EntityGenerator.cpp" />
-    <ClCompile Include="..\FactoryCraft\EntityRemovedUpdate.cpp" />
     <ClCompile Include="..\FactoryCraft\EntityType.cpp" />
     <ClCompile Include="..\FactoryCraft\FactorizeNoise.cpp" />
     <ClCompile Include="..\FactoryCraft\FastNoiseWrapper.cpp" />
@@ -196,6 +194,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\FluidBlock.cpp" />
     <ClCompile Include="..\FactoryCraft\FluidContainer.cpp" />
     <ClCompile Include="..\FactoryCraft\Game.cpp" />
+    <ClCompile Include="..\FactoryCraft\GameClient.cpp" />
     <ClCompile Include="..\FactoryCraft\GeneratedStructure.cpp" />
     <ClCompile Include="..\FactoryCraft\GeneratorTemplate.cpp" />
     <ClCompile Include="..\FactoryCraft\GeneratorRule.cpp" />
@@ -255,7 +254,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\UIDialog.cpp" />
     <ClCompile Include="..\FactoryCraft\WorldGenerator.cpp" />
     <ClCompile Include="..\FactoryCraft\WorldLoader.cpp" />
-    <ClCompile Include="..\FactoryCraft\WorldUpdate.cpp" />
     <ClCompile Include="..\FactoryCraft\WormCaveGenerator.cpp" />
   </ItemGroup>
   <ItemGroup>
@@ -269,11 +267,11 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\FactorizeNoise.h" />
     <ClInclude Include="..\FactoryCraft\FlattenNoise.h" />
     <ClInclude Include="..\FactoryCraft\FluidContainer.h" />
+    <ClInclude Include="..\FactoryCraft\GameClient.h" />
     <ClInclude Include="..\FactoryCraft\GeneratorRule.h" />
     <ClInclude Include="..\FactoryCraft\BlockTypeGeneratorRule.h" />
     <ClInclude Include="..\FactoryCraft\Chest.h" />
     <ClInclude Include="..\FactoryCraft\ChunkMap.h" />
-    <ClInclude Include="..\FactoryCraft\AddEntityUpdate.h" />
     <ClInclude Include="..\FactoryCraft\Area.h" />
     <ClInclude Include="..\FactoryCraft\BasicBlocks.h" />
     <ClInclude Include="..\FactoryCraft\BasicItems.h" />
@@ -294,7 +292,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\Effect.h" />
     <ClInclude Include="..\FactoryCraft\EffectFactory.h" />
     <ClInclude Include="..\FactoryCraft\Entity.h" />
-    <ClInclude Include="..\FactoryCraft\EntityRemovedUpdate.h" />
     <ClInclude Include="..\FactoryCraft\EntityType.h" />
     <ClInclude Include="..\FactoryCraft\FastNoiseLite.h" />
     <ClInclude Include="..\FactoryCraft\FastNoiseWrapper.h" />
@@ -362,7 +359,6 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\UIDialog.h" />
     <ClInclude Include="..\FactoryCraft\WorldGenerator.h" />
     <ClInclude Include="..\FactoryCraft\WorldLoader.h" />
-    <ClInclude Include="..\FactoryCraft\WorldUpdate.h" />
     <ClInclude Include="..\FactoryCraft\WormCaveGenerator.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 6 - 21
Windows Version/Windows Version.vcxproj.filters

@@ -28,9 +28,6 @@
     <Filter Include="world\ticking">
       <UniqueIdentifier>{03a72d46-51b8-4f26-b04a-f5f4d4f5af6e}</UniqueIdentifier>
     </Filter>
-    <Filter Include="world\update">
-      <UniqueIdentifier>{05bf4218-e0cd-4d0d-bd7b-eaea87023838}</UniqueIdentifier>
-    </Filter>
     <Filter Include="world\loader">
       <UniqueIdentifier>{12fac988-c4d8-4db8-b4a8-1c025f117866}</UniqueIdentifier>
     </Filter>
@@ -153,9 +150,6 @@
     <ClCompile Include="..\FactoryCraft\WorldLoader.cpp">
       <Filter>world\loader</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\WorldUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\Dimension.cpp">
       <Filter>world</Filter>
     </ClCompile>
@@ -198,12 +192,6 @@
     <ClCompile Include="..\FactoryCraft\ItemEntity.cpp">
       <Filter>entities</Filter>
     </ClCompile>
-    <ClCompile Include="..\FactoryCraft\AddEntityUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
-    <ClCompile Include="..\FactoryCraft\EntityRemovedUpdate.cpp">
-      <Filter>world\update</Filter>
-    </ClCompile>
     <ClCompile Include="..\FactoryCraft\GeneratedStructure.cpp">
       <Filter>world\generator\templates</Filter>
     </ClCompile>
@@ -411,6 +399,9 @@
     <ClCompile Include="..\FactoryCraft\NeutralAnimalAI.cpp">
       <Filter>entities\animals</Filter>
     </ClCompile>
+    <ClCompile Include="..\FactoryCraft\GameClient.cpp">
+      <Filter>game</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\FactoryCraft\Chunk.h">
@@ -473,9 +464,6 @@
     <ClInclude Include="..\FactoryCraft\TickOrganizer.h">
       <Filter>world\ticking</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\WorldUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\EntityType.h">
       <Filter>entities</Filter>
     </ClInclude>
@@ -503,12 +491,6 @@
     <ClInclude Include="..\FactoryCraft\ItemEntity.h">
       <Filter>entities</Filter>
     </ClInclude>
-    <ClInclude Include="..\FactoryCraft\AddEntityUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
-    <ClInclude Include="..\FactoryCraft\EntityRemovedUpdate.h">
-      <Filter>world\update</Filter>
-    </ClInclude>
     <ClInclude Include="..\FactoryCraft\GeneratorTemplate.h">
       <Filter>world\generator\templates</Filter>
     </ClInclude>
@@ -728,5 +710,8 @@
     <ClInclude Include="..\FactoryCraft\NeutralAnimalAI.h">
       <Filter>entities\animals</Filter>
     </ClInclude>
+    <ClInclude Include="..\FactoryCraft\GameClient.h">
+      <Filter>game</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>