浏览代码

fixed lagging while chunk generation

Kolja Strohm 2 年之前
父节点
当前提交
a212c2aa0d

+ 36 - 29
FactoryCraft/Chunk.cpp

@@ -1,4 +1,5 @@
 #include <InMemoryBuffer.h>
+#include <AsynchronCall.h>
 
 #include "Chunk.h"
 #include "Constants.h"
@@ -64,7 +65,7 @@ void Chunk::removeLightSource(int index)
 	}
 }
 
-void Chunk::sendLightToClient(Entity* zPlayer)
+void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
 {
 	for (int z = 0; z < WORLD_HEIGHT; z++)
 	{
@@ -94,19 +95,15 @@ void Chunk::sendLightToClient(Entity* zPlayer)
 				}
 				if (needSend)
 				{
-					NetworkMessage msg;
-					msg.addressChunck(this);
-					char message[11];
-					message[0] = 1;
 					int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
-					*(int*)(message + 1) = index;
-					memcpy(message + 5, lightData + index * 6, 6);
-					msg.setMessage(message, 11, 0);
-					Game::INSTANCE->sendMessage(&msg, zPlayer);
+					zWriter->schreibe((char*)&index, 4);
+					zWriter->schreibe((char*)(lightData + index * 6), 6);
 				}
 			}
 		}
 	}
+	int end = -1;
+	zWriter->schreibe((char*)&end, 4);
 }
 
 Framework::Either<Block*, int> Chunk::zBlockNeighbor(Framework::Vec3<int> location)
@@ -141,27 +138,35 @@ void Chunk::notifyObservers(NetworkMessage& msg)
 		observers.remove(i);
 }
 
-void Chunk::addObserver(Entity* zEntity)
+void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
 {
 	for (int id : observers)
 	{
 		if (id == zEntity->getId())
 			return;
 	}
-	observers.add(zEntity->getId());
-	InMemoryBuffer buffer;
-	buffer.schreibe("\4", 1);
-	buffer.schreibe((char*)&location.x, 4);
-	buffer.schreibe((char*)&location.y, 4);
-	sendToClient(&buffer);
-	NetworkMessage msg;
-	msg.addressDimension();
-	char* message = new char[buffer.getSize()];
-	buffer.lese(message, (int)buffer.getSize());
-	msg.setMessage(message, (int)buffer.getSize(), 1);
-	msg.setUseBackground();
-	Game::INSTANCE->sendMessage(&msg, zEntity);
-	sendLightToClient(zEntity);
+	int id = zEntity->getId();
+	observers.add(id);
+	laterHandler.addTodo([this, id]()
+		{
+			InMemoryBuffer buffer;
+			buffer.schreibe("\4", 1);
+			buffer.schreibe((char*)&location.x, 4);
+			buffer.schreibe((char*)&location.y, 4);
+			sendToClient(&buffer);
+			sendLightToClient(&buffer);
+			NetworkMessage msg;
+			msg.addressDimension();
+			char* message = new char[buffer.getSize()];
+			buffer.lese(message, (int)buffer.getSize());
+			msg.setMessage(message, (int)buffer.getSize(), 1);
+			msg.setUseBackground();
+			Entity* e = Game::INSTANCE->zEntity(id);
+			if (e)
+			{
+				Game::INSTANCE->sendMessage(&msg, e);
+			}
+		});
 }
 
 void Chunk::removeObserver(Entity* zEntity)
@@ -178,7 +183,7 @@ void Chunk::removeObserver(Entity* zEntity)
 	}
 }
 
-void Chunk::api(Framework::StreamReader* zRequest, Entity* zSource)
+void Chunk::api(Framework::StreamReader* zRequest, Entity* zSource, DoLaterHandler& laterHandler)
 {
 	// TODO: answer api messages
 	char type;
@@ -187,7 +192,7 @@ void Chunk::api(Framework::StreamReader* zRequest, Entity* zSource)
 	{
 	case 0:
 		// register observer
-		addObserver(zSource);
+		addObserver(zSource, laterHandler);
 		break;
 	case 1:
 		// unsubscribe
@@ -226,12 +231,12 @@ void Chunk::initializeLightning()
 						}
 						else
 						{
-							neighborLeight = getLightData(Vec3<int>(x, y, neighborPos.z));
+							neighborLeight = getLightData(neighborPos);
 						}
 						for (int j = 0; j < 3; j++)
-							newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : neighborLeight[j] - 16);
+							newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : (unsigned char)((float)neighborLeight[j] * 0.8f));
 						for (int j = 3; j < 6; j++)
-							newLight[j] = (unsigned char)MAX(newLight[j], neighborLeight[j] - 16);
+							newLight[j] = (unsigned char)MAX(newLight[j], (unsigned char)((float)neighborLeight[j] * 0.8f));
 					}
 					const Block* current = blocks[index] ? blocks[index] : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->zDefault();
 					// add own light emission
@@ -245,6 +250,7 @@ void Chunk::initializeLightning()
 						{
 							changes = 1;
 							memcpy(light, newLight, 6);
+							break;
 						}
 					}
 
@@ -732,6 +738,7 @@ void Chunk::setLightData(Framework::Vec3<int> location, unsigned char* data)
 		*(int*)(message + 1) = index / 6;
 		memcpy(message + 5, data, 6);
 		msg.setMessage(message, 11, 0);
+		msg.setUseBackground();
 		notifyObservers(msg);
 	}
 }

+ 4 - 3
FactoryCraft/Chunk.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "Block.h"
+#include "DoLaterHandler.h"
 
 #include <Vec3.h>
 #include <Array.h>
@@ -26,7 +27,7 @@ private:
 
 	void addLightSource(int index);
 	void removeLightSource(int index);
-	void sendLightToClient(Entity* zPlayer);
+	void sendLightToClient(Framework::StreamWriter* zWriter);
 
 public:
 	Chunk(Framework::Punkt location, int dimensionId);
@@ -34,9 +35,9 @@ public:
 	~Chunk();
 
 	void notifyObservers(NetworkMessage& msg);
-	void addObserver(Entity* zEntity);
+	void addObserver(Entity* zEntity, DoLaterHandler& laterHandler);
 	void removeObserver(Entity* zEntity);
-	void api(Framework::StreamReader* zRequest, Entity* zSource);
+	void api(Framework::StreamReader* zRequest, Entity* zSource, DoLaterHandler& laterHandler);
 	void initializeLightning();
 
 	Framework::Either<Block*, int> zBlockAt(Framework::Vec3<int> cLocation) const;

+ 8 - 9
FactoryCraft/Dimension.cpp

@@ -25,6 +25,7 @@ Dimension::~Dimension()
 
 void Dimension::api(Framework::InMemoryBuffer* zRequest, NetworkMessage* zResponse, Entity* zSource)
 {
+	DoLaterHandler laterHandler;
 	char type;
 	zRequest->lese(&type, 1);
 	switch (type)
@@ -44,7 +45,7 @@ void Dimension::api(Framework::InMemoryBuffer* zRequest, NetworkMessage* zRespon
 		}
 		else
 		{
-			cC->api(zRequest, zSource);
+			cC->api(zRequest, zSource, laterHandler);
 		}
 		cs.unlock();
 		break;
@@ -134,9 +135,9 @@ void Dimension::thread()
 							neighborLeight = noLight;
 					}
 					for (int j = 0; j < 3; j++)
-						newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : neighborLeight[j] - 16);
+						newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : (unsigned char)((float)neighborLeight[j] * 0.8f));
 					for (int j = 3; j < 6; j++)
-						newLight[j] = (unsigned char)MAX(newLight[j], neighborLeight[j] - 16);
+						newLight[j] = (unsigned char)MAX(newLight[j], (unsigned char)((float)neighborLeight[j] * 0.8f));
 				}
 				const Block* current = zBlockOrDefault(position);
 				if (!current)
@@ -295,10 +296,6 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 	{
 		chunkList.add(chunk);
 		chunk->setAdded();
-		if (chunkList.getEintragAnzahl() == 0)
-		{
-			updateLightning(Vec3<int>(chunk->getCenter().x, chunk->getCenter().y, WORLD_HEIGHT - 1));
-		}
 	}
 	getAddrOfWorld(center + Punkt(CHUNK_SIZE, 0), addr);
 	Chunk* zChunk = chunks->z(addr, 8);
@@ -334,7 +331,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 		if (chunk)
 			chunk->setNeighbor(NORTH, zChunk);
 	}
-	updateLightAtChunkBorders(center);
+	DoLaterHandler laterHandler;
 	if (chunk)
 	{
 		cs.lock();
@@ -346,7 +343,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 			{
 				if (iterator.val().chunkCenter == chunk->getCenter())
 				{
-					chunk->api(iterator.val().request, zE);
+					chunk->api(iterator.val().request, zE, laterHandler);
 					iterator.val().request->release();
 					iterator.remove();
 					continue;
@@ -364,6 +361,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 		cs.unlock();
 	}
 	chunkCs.unlock();
+	updateLightAtChunkBorders(center);
 }
 
 void Dimension::save(Text worldDir) const
@@ -449,6 +447,7 @@ void Dimension::removeOldChunks()
 		filePath += ".chunk";
 		Datei d;
 		d.setDatei(filePath);
+		d.erstellen();
 		d.open(Datei::Style::schreiben);
 		chunk->save(&d);
 		d.close();

+ 28 - 0
FactoryCraft/DoLaterHandler.cpp

@@ -0,0 +1,28 @@
+#include "DoLaterHandler.h"
+
+
+DoLaterHandler::DoLaterHandler()
+{
+	action = []() {};
+}
+
+DoLaterHandler::~DoLaterHandler()
+{
+	action();
+}
+
+void DoLaterHandler::addTodo(std::function<void()> newAction)
+{
+	std::function<void()> oldAction = action;
+	this->action = [oldAction, newAction]()
+	{
+		oldAction();
+		newAction();
+	};
+}
+
+void DoLaterHandler::execute()
+{
+	action();
+	action = []() {};
+}

+ 15 - 0
FactoryCraft/DoLaterHandler.h

@@ -0,0 +1,15 @@
+#pragma once
+
+#include <functional>
+
+class DoLaterHandler
+{
+private:
+	std::function<void()> action;
+
+public:
+	DoLaterHandler();
+	~DoLaterHandler();
+	void addTodo(std::function<void()> action);
+	void execute();
+};

+ 2 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -102,6 +102,7 @@
     <ClInclude Include="Constants.h" />
     <ClInclude Include="CraftingStorage.h" />
     <ClInclude Include="DimensionGenerator.h" />
+    <ClInclude Include="DoLaterHandler.h" />
     <ClInclude Include="Effect.h" />
     <ClInclude Include="EffectFactory.h" />
     <ClInclude Include="Entity.h" />
@@ -156,6 +157,7 @@
     <ClCompile Include="CraftingStorage.cpp" />
     <ClCompile Include="Dimension.cpp" />
     <ClCompile Include="DimensionGenerator.cpp" />
+    <ClCompile Include="DoLaterHandler.cpp" />
     <ClCompile Include="Entity.cpp" />
     <ClCompile Include="EntityRemovedUpdate.cpp" />
     <ClCompile Include="EntityType.cpp" />

+ 6 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -219,6 +219,9 @@
     <ClInclude Include="ModelInfo.h">
       <Filter>static</Filter>
     </ClInclude>
+    <ClInclude Include="DoLaterHandler.h">
+      <Filter>server</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -365,5 +368,8 @@
     <ClCompile Include="ModelInfo.cpp">
       <Filter>static</Filter>
     </ClCompile>
+    <ClCompile Include="DoLaterHandler.cpp">
+      <Filter>server</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 27 - 0
FactoryCraft/Game.cpp

@@ -235,13 +235,24 @@ void Game::initialize()
 
 void Game::thread()
 {
+	ZeitMesser waitForLock;
+	ZeitMesser removeOldClients;
+	ZeitMesser tickEntities;
+	ZeitMesser worldUpdates;
+	ZeitMesser clientReply;
+	ZeitMesser removeOldChunks;
 	ZeitMesser m;
 	while (!stop)
 	{
 		m.messungStart();
 		ticker->nextTick();
 		Array<int> removed;
+		double waitTotal = 0;
+		waitForLock.messungStart();
 		cs.lock();
+		waitForLock.messungEnde();
+		waitTotal += waitForLock.getSekunden();
+		removeOldClients.messungStart();
 		int index = 0;
 		for (auto player : *clients)
 		{
@@ -264,10 +275,17 @@ void Game::thread()
 		}
 		for (auto i : removed)
 			clients->remove(i);
+		removeOldClients.messungEnde();
 		cs.unlock();
+		tickEntities.messungStart();
 		for (auto dim : *dimensions)
 			dim->tickEntities();
+		tickEntities.messungEnde();
+		waitForLock.messungStart();
 		cs.lock();
+		waitForLock.messungEnde();
+		waitTotal += waitForLock.getSekunden();
+		worldUpdates.messungStart();
 		while (updates->hat(0))
 		{
 			WorldUpdate* update = updates->z(0);
@@ -278,12 +296,20 @@ void Game::thread()
 			update->onUpdate(zDimension(update->getAffectedDimension()));
 			updates->remove(0);
 		}
+		worldUpdates.messungEnde();
 		cs.unlock();
+		clientReply.messungStart();
 		for (auto client : *clients)
 			client->reply();
+		clientReply.messungEnde();
+		waitForLock.messungStart();
 		cs.lock();
+		waitForLock.messungEnde();
+		waitTotal += waitForLock.getSekunden();
+		removeOldChunks.messungStart();
 		for (auto dim : *dimensions)
 			dim->removeOldChunks();
+		removeOldChunks.messungEnde();
 		cs.unlock();
 		m.messungEnde();
 		double sec = m.getSekunden();
@@ -308,6 +334,7 @@ void Game::thread()
 		else
 		{
 			std::cout << "WARNING: tick needed " << sec << " seconds. The game will run sower then normal.\n";
+			std::cout << "waiting: " << waitTotal << "\nremoveOldClients: " << removeOldClients.getSekunden() << "\ntickEntities:" << tickEntities.getSekunden() << "\nworldUpdates: " << worldUpdates.getSekunden() << "\nclientReply: " << clientReply.getSekunden() << "\nremoveOldChunks:" << removeOldChunks.getSekunden() << "\n";
 		}
 	}
 	save();