Ver código fonte

fix block updates in a chunk were send to the client before the chunk itself

Kolja Strohm 1 ano atrás
pai
commit
09061cb99f

+ 25 - 13
FactoryCraft/Chunk.cpp

@@ -240,14 +240,13 @@ void Chunk::notifyObservers(NetworkMessage* msg)
 {
     Array<int> remove;
     int index = 0;
-    for (int id : observers)
+    for (InformationObserver* observer : observers)
     {
-        Entity* zE = Game::INSTANCE->zEntity(id);
-        if (!zE)
+        if (!observer->sendMessage(
+                dynamic_cast<NetworkMessage*>(msg->getThis())))
+        {
             remove.add(index, 0);
-        else
-            Game::INSTANCE->sendMessage(
-                dynamic_cast<NetworkMessage*>(msg->getThis()), zE);
+        }
         index++;
     }
     for (int i : remove)
@@ -257,13 +256,14 @@ void Chunk::notifyObservers(NetworkMessage* msg)
 
 void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
 {
-    for (int id : observers)
+    for (InformationObserver* observer : observers)
     {
-        if (id == zEntity->getId()) return;
+        if (observer->getEntityId() == zEntity->getId()) return;
     }
     int id = zEntity->getId();
-    observers.add(id);
-    laterHandler.addTodo([this, id]() {
+    InformationObserver* observer = new InformationObserver(id);
+    observers.add(observer);
+    laterHandler.addTodo([this, id, observer]() {
         InMemoryBuffer buffer;
         buffer.schreibe("\4", 1);
         buffer.schreibe((char*)&location.x, 4);
@@ -280,6 +280,17 @@ void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
         Entity* e = Game::INSTANCE->zEntity(id);
         if (e)
         {
+            Punkt p = location;
+            int dimId = dimensionId;
+            msg->setOnAfterSend([this, p, dimId, observer]() {
+                // check if chunk is still loaded
+                if (Game::INSTANCE->zDimension(dimId)
+                    && Game::INSTANCE->zDimension(dimId)->zChunk(p) == this)
+                {
+                    // send all waiting messages to the observer
+                    observer->setReady();
+                }
+            });
             Game::INSTANCE->sendMessage(msg, e);
         }
         else
@@ -290,9 +301,9 @@ void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
 void Chunk::removeObserver(Entity* zEntity)
 {
     int index = 0;
-    for (int id : observers)
+    for (InformationObserver* observer : observers)
     {
-        if (id == zEntity->getId())
+        if (observer->getEntityId() == zEntity->getId())
         {
             observers.remove(index);
             return;
@@ -424,7 +435,8 @@ void Chunk::instantiateBlock(Framework::Vec3<int> location)
                 ->createBlockAt(
                     {location.x + this->location.x - CHUNK_SIZE / 2,
                         location.y + this->location.y - CHUNK_SIZE / 2,
-                        location.z}, dimensionId,
+                        location.z},
+                    dimensionId,
                     0));
 }
 

+ 2 - 1
FactoryCraft/Chunk.h

@@ -10,6 +10,7 @@
 #include "DoLaterHandler.h"
 #include "Tickable.h"
 #include "Constants.h"
+#include "InformationObserver.h"
 
 class ChunkMap;
 
@@ -26,7 +27,7 @@ private:
         Framework::Vec3<int> location);
     bool added;
     Framework::Critical cs;
-    Framework::Array<int> observers;
+    Framework::RCArray<InformationObserver> observers;
     Framework::Array<int> lightSources;
     Framework::Array<Block*> tickSources;
     unsigned char* lightData;

+ 1 - 0
FactoryCraft/Dimension.cpp

@@ -482,6 +482,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
         removedChunksCs.unlock();
     }
     if (chunk) chunk->onLoaded();
+    laterHandler.execute();
     updateLightAtChunkBorders(center);
 }
 

+ 63 - 0
FactoryCraft/InformationObserver.cpp

@@ -0,0 +1,63 @@
+#include "InformationObserver.h"
+
+#include "Game.h"
+
+InformationObserver::InformationObserver(int entityId)
+    : ReferenceCounter(),
+      entityId(entityId),
+      ready(false)
+{}
+
+InformationObserver::~InformationObserver()
+{
+    cs.lock();
+    waitingMessages.leeren();
+    cs.unlock();
+}
+
+int InformationObserver::getEntityId() const
+{
+    return entityId;
+}
+
+bool InformationObserver::sendMessage(NetworkMessage* message)
+{
+    cs.lock();
+    if (ready)
+    {
+        cs.unlock();
+        Entity* e = Game::INSTANCE->zEntity(entityId);
+        if (e)
+        {
+            Game::INSTANCE->sendMessage(message, e);
+            return 1;
+        }
+        else
+        {
+            message->release();
+            return 0;
+        }
+    }
+    else
+    {
+        waitingMessages.add(message);
+        cs.unlock();
+        return 1;
+    }
+}
+
+void InformationObserver::setReady()
+{
+    cs.lock();
+    ready = 1;
+    Entity* e = Game::INSTANCE->zEntity(entityId);
+    if (e)
+    {
+        for (NetworkMessage* msg : waitingMessages)
+        {
+            Game::INSTANCE->sendMessage(dynamic_cast<NetworkMessage*>(msg->getThis()), e);
+        }
+    }
+    waitingMessages.leeren();
+    cs.unlock();
+}

+ 23 - 0
FactoryCraft/InformationObserver.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include "NetworkMessage.h"
+
+#include <Array.h>
+#include <Critical.h>
+
+class InformationObserver : public Framework::ReferenceCounter
+{
+private:
+	Framework::RCArray<NetworkMessage> waitingMessages;
+    bool ready;
+    int entityId;
+    Framework::Critical cs;
+
+public:
+    InformationObserver(int entityId);
+	~InformationObserver();
+
+	int getEntityId() const;
+	bool sendMessage(NetworkMessage* message);
+    void setReady();
+};

+ 10 - 1
FactoryCraft/NetworkMessage.cpp

@@ -5,7 +5,8 @@
 #include "Game.h"
 
 NetworkMessage::NetworkMessage()
-    : Framework::ReferenceCounter()
+    : Framework::ReferenceCounter(),
+      onAfterSend(0)
 {
     address = 0;
     addressLength = 0;
@@ -21,6 +22,13 @@ NetworkMessage::~NetworkMessage()
     delete[] address;
 }
 
+void NetworkMessage::setOnAfterSend(std::function<void()> onAfterSend)
+{
+    if (this->onAfterSend)
+        throw "Illegal State exception: onAfterSend was already set";
+    this->onAfterSend = onAfterSend;
+}
+
 void NetworkMessage::addressChunck(const Chunk* zChunk)
 {
     delete[] address;
@@ -193,6 +201,7 @@ void NetworkMessage::writeTo(Framework::StreamWriter* zWriter) const
         zWriter->schreibe((char*)&total, 4);
         zWriter->schreibe(address, addressLength);
         zWriter->schreibe(message, msgLength);
+        if (onAfterSend) onAfterSend();
     }
 }
 

+ 4 - 2
FactoryCraft/NetworkMessage.h

@@ -1,9 +1,9 @@
 #pragma once
 
+#include <Punkt.h>
 #include <ReferenceCounter.h>
 #include <Vec3.h>
 #include <Writer.h>
-#include <Punkt.h>
 
 class Chunk;
 class Block;
@@ -23,11 +23,13 @@ private:
     char* message;
     int msgLength;
     bool useBackground;
+    std::function<void()> onAfterSend;
 
 public:
     NetworkMessage();
     virtual ~NetworkMessage();
 
+    void setOnAfterSend(std::function<void()> onAfterSend);
     void addressChunck(const Chunk* zChunk);
     void addressEntity(const Entity* zEntity);
     void addressBlock(const Block* zBlock);
@@ -38,7 +40,7 @@ public:
     void sendChatMessage(ChatMessage* zMsg);
     void sendChatOptions(ChatObserver* zOptions);
     void sendMap(ChunkMap* zMap);
-    void sendPlayerPositions(char *msg, int length);
+    void sendPlayerPositions(char* msg, int length);
     void setUseBackground();
     void sendToAll();
     void animateBlockBone(int dimensionId,

+ 2 - 0
Windows Version/Windows Version.vcxproj

@@ -195,6 +195,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClCompile Include="..\FactoryCraft\GrantCommand.cpp" />
     <ClCompile Include="..\FactoryCraft\Grass.cpp" />
     <ClCompile Include="..\FactoryCraft\Hoe.cpp" />
+    <ClCompile Include="..\FactoryCraft\InformationObserver.cpp" />
     <ClCompile Include="..\FactoryCraft\Inventory.cpp" />
     <ClCompile Include="..\FactoryCraft\Item.cpp" />
     <ClCompile Include="..\FactoryCraft\ItemEntity.cpp" />
@@ -285,6 +286,7 @@ copy ..\..\..\..\..\Allgemein\Framework\x64\release\Framework.dll Framework.dll<
     <ClInclude Include="..\FactoryCraft\Grass.h" />
     <ClInclude Include="..\FactoryCraft\Chat.h" />
     <ClInclude Include="..\FactoryCraft\Hoe.h" />
+    <ClInclude Include="..\FactoryCraft\InformationObserver.h" />
     <ClInclude Include="..\FactoryCraft\Inventory.h" />
     <ClInclude Include="..\FactoryCraft\Item.h" />
     <ClInclude Include="..\FactoryCraft\ItemEntity.h" />

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

@@ -354,6 +354,9 @@
     <ClCompile Include="..\FactoryCraft\NegateNoise.cpp">
       <Filter>world\generator\noise</Filter>
     </ClCompile>
+    <ClCompile Include="..\FactoryCraft\InformationObserver.cpp">
+      <Filter>server\response</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\FactoryCraft\Chunk.h">
@@ -626,5 +629,8 @@
     <ClInclude Include="..\FactoryCraft\NegateNoise.h">
       <Filter>world\generator\noise</Filter>
     </ClInclude>
+    <ClInclude Include="..\FactoryCraft\InformationObserver.h">
+      <Filter>server\response</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>