Browse Source

calculate light levels for red, green and blue lights

Kolja Strohm 2 years ago
parent
commit
dd2d41b6c5

+ 1 - 1
FactoryCraft/BasicBlock.cpp

@@ -15,7 +15,7 @@ void BasicBlock::onPostTick()
 
 
 BasicBlockType::BasicBlockType(int typeId, int itemTypeId, ModelInfo model)
-	: BlockType(typeId, 0, model, 1, 100),
+	: BlockType(typeId, 0, model, 1, 100, 0),
 	itemType(itemTypeId),
 	transparent(0),
 	passable(0),

+ 12 - 0
FactoryCraft/Block.cpp

@@ -28,6 +28,7 @@ Block::Block(const BlockType* zType, ItemType* zTool, Framework::Vec3<int> pos,
 	interactable = 0;
 	deadAndRemoved = 0;
 	memset(zNeighbours, 0, sizeof(Block*) * 6);
+	memset(lightEmisionColor, 0, 3);
 }
 
 Block::~Block()
@@ -229,6 +230,17 @@ bool Block::isDeadAndRemoved() const
 	return deadAndRemoved;
 }
 
+const unsigned char* Block::getLightEmisionColor() const
+{
+	return lightEmisionColor;
+}
+
+void Block::filterPassingLight(unsigned char rgb[3]) const
+{
+	if (!transparent) // let no light pass intransparent blocks
+		memset(rgb, 0, 3);
+}
+
 
 BasicBlockItem::BasicBlockItem(const ItemType* zType, const BlockType* zPlacedBlockType, const char* name)
 	: Item(zType, name)

+ 4 - 0
FactoryCraft/Block.h

@@ -9,6 +9,7 @@
 #include <Trie.h>
 #include <Vec3.h>
 #include <Either.h>
+#include <VecN.h>
 
 #define CONST_BLOCK(maybeBlock, type) (maybeBlock ? maybeBlock : StaticRegistry<BlockType>::INSTANCE.zElement((int)type)->zDefault())
 
@@ -45,6 +46,7 @@ protected:
 	bool interactable;
 	bool transmissionRequested;
 	bool deadAndRemoved;
+	unsigned char lightEmisionColor[3];
 
 	/// <summary>
 	/// executes block specific things
@@ -89,6 +91,8 @@ public:
 	bool isVisible() const;
 	void setHP(float hp);
 	bool isDeadAndRemoved() const;
+	const unsigned char* getLightEmisionColor() const;
+	virtual void filterPassingLight(unsigned char rgb[3]) const;
 
 	friend BlockType;
 };

+ 7 - 1
FactoryCraft/BlockType.cpp

@@ -6,12 +6,13 @@
 using namespace Framework;
 
 BlockType::BlockType(int id, Block* defaultBlock,
-	ModelInfo model, bool needsClientInstance, int initialMaxHP)
+	ModelInfo model, bool needsClientInstance, int initialMaxHP, bool lightSource)
 	: ReferenceCounter(),
 	id(id),
 	model(model),
 	initialMaxHP(initialMaxHP),
 	needsClientInstance(needsClientInstance),
+	lightSource(lightSource),
 	defaultBlock(defaultBlock)
 {
 	StaticRegistry<BlockType>::INSTANCE.registerT(this, id);
@@ -138,6 +139,11 @@ int BlockType::getInitialMaxHP() const
 	return initialMaxHP;
 }
 
+bool BlockType::isLightSource() const
+{
+	return lightSource;
+}
+
 
 const Block* getDefaultBlock(Either<Block*, int> b)
 {

+ 3 - 1
FactoryCraft/BlockType.h

@@ -18,10 +18,11 @@ private:
 	const ModelInfo model;
 	int initialMaxHP;
 	const bool needsClientInstance;
+	bool lightSource;
 
 protected:
 	Block* defaultBlock;
-	BlockType(int id, Block* defaultBlock, ModelInfo model, bool needsClientInstance, int initialMaxHP);
+	BlockType(int id, Block* defaultBlock, ModelInfo model, bool needsClientInstance, int initialMaxHP, bool lightSource);
 	virtual ~BlockType();
 
 	virtual void loadSuperBlock(Block* zBlock, Framework::StreamReader* zReader) const;
@@ -41,6 +42,7 @@ public:
 	const ModelInfo& getModel() const;
 	int getId() const;
 	int getInitialMaxHP() const;
+	bool isLightSource() const;
 };
 
 const Block* getDefaultBlock(Framework::Either<Block*, int> b);

+ 150 - 29
FactoryCraft/Chunk.cpp

@@ -14,8 +14,10 @@ Chunk::Chunk(Framework::Punkt location, int dimensionId)
 {
 	blocks = new Block * [CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
 	blockIds = new unsigned short[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT];
+	lightData = new unsigned char[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6];
 	memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*));
 	memset(blockIds, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(unsigned short));
+	memset(lightData, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * 6);
 	zNeighbours[0] = 0;
 	zNeighbours[1] = 0;
 	zNeighbours[2] = 0;
@@ -37,6 +39,29 @@ Chunk::~Chunk()
 	}
 	delete[] blocks;
 	delete[] blockIds;
+	delete[] lightData;
+}
+
+void Chunk::addLightSource(int index)
+{
+	for (int i : lightSources)
+	{
+		if (i == index)
+			return;
+	}
+	lightSources.add(index);
+}
+
+void Chunk::removeLightSource(int index)
+{
+	for (auto i = lightSources.begin(); i; i++)
+	{
+		if (i.val() == index)
+		{
+			i.remove();
+			return;
+		}
+	}
 }
 
 Framework::Either<Block*, int> Chunk::zBlockNeighbor(Framework::Vec3<int> location)
@@ -125,6 +150,65 @@ void Chunk::api(Framework::StreamReader* zRequest, Entity* zSource)
 	}
 }
 
+void Chunk::initializeLightning()
+{
+	unsigned char dayLight[6] = { 255, 255, 255, 0, 0, 0 };
+	unsigned char noLight[6] = { 0, 0, 0, 0, 0, 0 };
+	while (true)
+	{
+		bool changes = false;
+		for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
+		{
+			for (int x = 0; x < CHUNK_SIZE; x++)
+			{
+				for (int y = 0; y < CHUNK_SIZE; y++)
+				{
+					int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
+					unsigned char* light = getLightData(Vec3<int>(x, y, z));
+					unsigned char newLight[6] = { 0, 0, 0, 0, 0, 0 };
+					for (int i = 0; i < 6; i++)
+					{
+						unsigned char* neighborLeight;
+						Vec3<int> neighborPos = Vec3<int>(x, y, z) + getDirection(getDirectionFromIndex(i));
+						if (neighborPos.z < 0 || neighborPos.x < 0 || neighborPos.y < 0 || neighborPos.x >= CHUNK_SIZE || neighborPos.y >= CHUNK_SIZE)
+						{
+							neighborLeight = noLight;
+						}
+						else if (neighborPos.z >= WORLD_HEIGHT)
+						{
+							neighborLeight = dayLight;
+						}
+						else
+						{
+							neighborLeight = getLightData(Vec3<int>(x, y, neighborPos.z));
+						}
+						for (int j = 0; j < 3; j++)
+							newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : neighborLeight[j] - 16);
+						for (int j = 3; j < 6; j++)
+							newLight[j] = (unsigned char)MAX(newLight[j], neighborLeight[j] - 16);
+					}
+					const Block* current = blocks[index] ? blocks[index] : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->zDefault();
+					// add own light emission
+					for (int j = 3; j < 6; j++)
+						newLight[j] = (unsigned char)MAX(newLight[j], current->getLightEmisionColor()[j - 3]);
+					current->filterPassingLight(newLight);
+					current->filterPassingLight(newLight + 3);
+					for (int i = 0; i < 6; i++)
+					{
+						if (newLight[i] != light[i])
+						{
+							memcpy(light, newLight, 6);
+						}
+					}
+
+				}
+			}
+		}
+		if (!changes)
+			break;
+	}
+}
+
 Framework::Either<Block*, int> Chunk::zBlockAt(Framework::Vec3<int> location) const
 {
 	int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
@@ -175,14 +259,17 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
 	assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT&& index >= 0);
 	Block* old = blocks[index];
 	bool change = 0;
+	bool wasLightSource = old ? old->zBlockType()->isLightSource() : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->isLightSource();
+	bool isLightSource = 0;
 	if (block)
 	{
 		change = blockIds[index] != (unsigned short)block->zBlockType()->getId();
 		blockIds[index] = (unsigned short)block->zBlockType()->getId();
+		isLightSource = block->zBlockType()->isLightSource();
 	}
 	else
 	{
-		change = blocks[index] != 0;
+		change = old != 0;
 	}
 	blocks[index] = block;
 	Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
@@ -219,6 +306,17 @@ void Chunk::putBlockAt(Framework::Vec3<int> location, Block* block)
 		old->release();
 	if (change)
 	{
+		if (isLightSource != wasLightSource)
+		{
+			if (isLightSource)
+				addLightSource(index);
+			else
+				removeLightSource(index);
+		}
+		if (added)
+		{
+			Game::INSTANCE->updateLightning(getDimensionId(), Vec3<int>(location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z));
+		}
 		char msg[9];
 		msg[0] = 0; // set block
 		*(int*)(msg + 1) = index;
@@ -234,33 +332,49 @@ void Chunk::putBlockTypeAt(Framework::Vec3<int> location, int type)
 {
 	int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z;
 	assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
-	blockIds[index] = (unsigned short)type;
-	Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
-	if (neighbor.isA())
-		((Block*)neighbor)->setNeighbourType(SOUTH, type);
-	neighbor = zBlockNeighbor(location + getDirection(EAST));
-	if (neighbor.isA())
-		((Block*)neighbor)->setNeighbourType(WEST, type);
-	neighbor = zBlockNeighbor(location + getDirection(SOUTH));
-	if (neighbor.isA())
-		((Block*)neighbor)->setNeighbourType(NORTH, type);
-	neighbor = zBlockNeighbor(location + getDirection(WEST));
-	if (neighbor.isA())
-		((Block*)neighbor)->setNeighbourType(EAST, type);
-	neighbor = zBlockNeighbor(location + getDirection(TOP));
-	if (neighbor.isA())
-		((Block*)neighbor)->setNeighbourType(BOTTOM, type);
-	neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
-	if (neighbor.isA())
-		((Block*)neighbor)->setNeighbourType(TOP, type);
-	char msg[9];
-	msg[0] = 0; // set block
-	*(int*)(msg + 1) = index;
-	*(int*)(msg + 5) = type;
-	NetworkMessage message;
-	message.addressChunck(this);
-	message.setMessage(msg, 9, 0);
-	notifyObservers(message);
+	bool wasLightSource = StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->isLightSource();
+	bool isLightSource = StaticRegistry<BlockType>::INSTANCE.zElement(type)->isLightSource();
+	if (blockIds[index] != (unsigned short)type)
+	{
+		blockIds[index] = (unsigned short)type;
+		Either<Block*, int> neighbor = zBlockNeighbor(location + getDirection(NORTH));
+		if (neighbor.isA())
+			((Block*)neighbor)->setNeighbourType(SOUTH, type);
+		neighbor = zBlockNeighbor(location + getDirection(EAST));
+		if (neighbor.isA())
+			((Block*)neighbor)->setNeighbourType(WEST, type);
+		neighbor = zBlockNeighbor(location + getDirection(SOUTH));
+		if (neighbor.isA())
+			((Block*)neighbor)->setNeighbourType(NORTH, type);
+		neighbor = zBlockNeighbor(location + getDirection(WEST));
+		if (neighbor.isA())
+			((Block*)neighbor)->setNeighbourType(EAST, type);
+		neighbor = zBlockNeighbor(location + getDirection(TOP));
+		if (neighbor.isA())
+			((Block*)neighbor)->setNeighbourType(BOTTOM, type);
+		neighbor = zBlockNeighbor(location + getDirection(BOTTOM));
+		if (neighbor.isA())
+			((Block*)neighbor)->setNeighbourType(TOP, type);
+		if (isLightSource != wasLightSource)
+		{
+			if (isLightSource)
+				addLightSource(index);
+			else
+				removeLightSource(index);
+		}
+		if (added)
+		{
+			Game::INSTANCE->updateLightning(getDimensionId(), Vec3<int>(location.x + this->location.x - CHUNK_SIZE / 2, location.y + this->location.y - CHUNK_SIZE / 2, location.z));
+		}
+		char msg[9];
+		msg[0] = 0; // set block
+		*(int*)(msg + 1) = index;
+		*(int*)(msg + 5) = type;
+		NetworkMessage message;
+		message.addressChunck(this);
+		message.setMessage(msg, 9, 0);
+		notifyObservers(message);
+	}
 }
 
 void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
@@ -350,9 +464,9 @@ void Chunk::load(Framework::StreamReader* zReader)
 			putBlockAt(pos, StaticRegistry<BlockType>::INSTANCE.zElement(id)->loadBlock(Framework::Vec3<int>(pos.x + location.x - CHUNK_SIZE / 2, pos.y + location.y - CHUNK_SIZE / 2, pos.z), zReader));
 		else
 			putBlockTypeAt(pos, id);
-
 		zReader->lese((char*)&id, 2);
 	}
+	initializeLightning();
 }
 
 void Chunk::save(Framework::StreamWriter* zWriter)
@@ -530,4 +644,11 @@ void Chunk::setAdded()
 bool Chunk::hasObservers() const
 {
 	return observers.getEintragAnzahl() > 0;
+}
+
+unsigned char* Chunk::getLightData(Framework::Vec3<int> location) const
+{
+	int index = ((location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z) * 6;
+	assert(index < CHUNK_SIZE* CHUNK_SIZE* WORLD_HEIGHT);
+	return lightData + index;
 }

+ 7 - 0
FactoryCraft/Chunk.h

@@ -21,6 +21,11 @@ private:
 	bool added;
 	Framework::Critical cs;
 	Framework::Array<int> observers;
+	Framework::Array<int> lightSources;
+	unsigned char* lightData;
+
+	void addLightSource(int index);
+	void removeLightSource(int index);
 
 public:
 	Chunk(Framework::Punkt location, int dimensionId);
@@ -31,6 +36,7 @@ public:
 	void addObserver(Entity* zEntity);
 	void removeObserver(Entity* zEntity);
 	void api(Framework::StreamReader* zRequest, Entity* zSource);
+	void initializeLightning();
 
 	Framework::Either<Block*, int> zBlockAt(Framework::Vec3<int> cLocation) const;
 	const Block* zBlockConst(Framework::Vec3<int> location) const;
@@ -50,4 +56,5 @@ public:
 	void prepareRemove();
 	void setAdded();
 	bool hasObservers() const;
+	unsigned char* getLightData(Framework::Vec3<int> location) const;
 };

+ 168 - 2
FactoryCraft/Dimension.cpp

@@ -2,16 +2,20 @@
 #include "Constants.h"
 #include "Datei.h"
 #include "Game.h"
+#include "NoBlock.h"
 
 using namespace Framework;
 
 
 Dimension::Dimension(int id)
-	: dimensionId(id),
+	: Thread(),
+	dimensionId(id),
 	gravity(9.8f),
 	chunks(new Trie<Chunk>()),
 	entities(new RCArray<Entity>())
-{}
+{
+	start();
+}
 
 Dimension::~Dimension()
 {
@@ -64,6 +68,110 @@ void Dimension::tickEntities()
 	}
 }
 
+void Dimension::thread()
+{
+	// light calculation
+	int index = 0;
+	ZeitMesser messer;
+	messer.messungStart();
+	double time = 0;
+	while (true)
+	{
+		lightCs.lock();
+		if (!lightUpdateQueue.getEintragAnzahl())
+		{
+			lightCs.unlock();
+			messer.messungEnde();
+			time += messer.getSekunden();
+			Sleep(500);
+			messer.messungStart();
+			continue;
+		}
+		Vec3<int> position = lightUpdateQueue.get(0);
+		lightUpdateQueue.remove(0);
+		lightCs.unlock();
+		// TODO: do not remove chunks while light calculation
+		Chunk* chunk = zChunk(Game::INSTANCE->getChunkCenter(position.x, position.y));
+		if (position.z >= 0 && position.z < WORLD_HEIGHT)
+		{
+			if (chunk)
+			{
+				int x = position.x % CHUNK_SIZE;
+				int y = position.y % CHUNK_SIZE;
+				if (x < 0)
+					x += CHUNK_SIZE;
+				if (y < 0)
+					y += CHUNK_SIZE;
+				unsigned char* light = chunk->getLightData(Vec3<int>(x, y, position.z));
+				unsigned char dayLight[6] = { 255, 255, 255, 0, 0, 0 };
+				unsigned char noLight[6] = { 0, 0, 0, 0, 0, 0 };
+				unsigned char newLight[6] = { 0, 0, 0, 0, 0, 0 };
+				// add neighbor light emission
+				for (int i = 0; i < 6; i++)
+				{
+					unsigned char* neighborLeight;
+					Vec3<int> neighborPos = position + getDirection(getDirectionFromIndex(i));
+					if (neighborPos.z < 0)
+					{
+						neighborLeight = noLight;
+					}
+					else if (neighborPos.z >= WORLD_HEIGHT)
+					{
+						neighborLeight = dayLight;
+					}
+					else
+					{
+						Chunk* neighborChunk = zChunk(Game::INSTANCE->getChunkCenter(neighborPos.x, neighborPos.y));
+						x = neighborPos.x % CHUNK_SIZE;
+						y = neighborPos.y % CHUNK_SIZE;
+						if (x < 0)
+							x += CHUNK_SIZE;
+						if (y < 0)
+							y += CHUNK_SIZE;
+						if (neighborChunk)
+							neighborLeight = neighborChunk->getLightData(Vec3<int>(x, y, neighborPos.z));
+						else
+							neighborLeight = noLight;
+					}
+					for (int j = 0; j < 3; j++)
+						newLight[j] = (unsigned char)MAX(newLight[j], i == getDirectionIndex(TOP) ? neighborLeight[j] : neighborLeight[j] - 16);
+					for (int j = 3; j < 6; j++)
+						newLight[j] = (unsigned char)MAX(newLight[j], neighborLeight[j] - 16);
+				}
+				const Block* current = zBlockOrDefault(position);
+				if (!current)
+					current = &NoBlock::INSTANCE;
+				// add own light emission
+				for (int j = 3; j < 6; j++)
+					newLight[j] = (unsigned char)MAX(newLight[j], current->getLightEmisionColor()[j - 3]);
+				current->filterPassingLight(newLight);
+				current->filterPassingLight(newLight + 3);
+				for (int i = 0; i < 6; i++)
+				{
+					if (newLight[i] != light[i])
+					{
+						memcpy(light, newLight, 6);
+						for (int j = 0; j < 6; j++)
+							updateLightning(position + getDirection(getDirectionFromIndex(j)));
+						break;
+					}
+				}
+			}
+		}
+		index++;
+		if (index > 100000)
+		{
+			messer.messungEnde();
+			time += messer.getSekunden();
+			std::cout << "100000 light updates needed " << time << " seconds\n";
+			time = 0;
+			index = 0;
+			Sleep(250);
+			messer.messungStart();
+		}
+	}
+}
+
 void Dimension::getAddrOf(Punkt cPos, char* addr) const
 {
 	*(int*)addr = cPos.x;
@@ -121,6 +229,22 @@ Block* Dimension::zRealBlockInstance(Framework::Vec3<int> location)
 	return 0;
 }
 
+const Block* Dimension::zBlockOrDefault(Framework::Vec3<int> location)
+{
+	Chunk* c = zChunk(Game::INSTANCE->getChunkCenter(location.x, location.y));
+	if (c)
+	{
+		int x = location.x % CHUNK_SIZE;
+		int y = location.y % CHUNK_SIZE;
+		if (x < 0)
+			x += CHUNK_SIZE;
+		if (y < 0)
+			y += CHUNK_SIZE;
+		return c->zBlockConst(Vec3<int>(x, y, location.z));
+	}
+	return 0;
+}
+
 void Dimension::placeBlock(Framework::Vec3<int> location, Framework::Either<Block*, int> block)
 {
 	Chunk* c = zChunk(Game::getChunkCenter(location.x, location.y));
@@ -151,6 +275,7 @@ void Dimension::addEntity(Entity* entity)
 
 void Dimension::setChunk(Chunk* chunk, Punkt center)
 {
+	chunkCs.lock();
 	char addr[8];
 	getAddrOfWorld(center, addr);
 	Chunk* old = chunks->z(addr, 8);
@@ -170,6 +295,10 @@ 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);
@@ -177,7 +306,9 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 	{
 		zChunk->setNeighbor(WEST, chunk);
 		if (chunk)
+		{
 			chunk->setNeighbor(EAST, zChunk);
+		}
 	}
 	getAddrOfWorld(center + Punkt(-CHUNK_SIZE, 0), addr);
 	zChunk = chunks->z(addr, 8);
@@ -203,6 +334,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 		if (chunk)
 			chunk->setNeighbor(NORTH, zChunk);
 	}
+	updateLightAtChunkBorders(center);
 	if (chunk)
 	{
 		cs.lock();
@@ -231,6 +363,7 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 		}
 		cs.unlock();
 	}
+	chunkCs.unlock();
 }
 
 void Dimension::save(Text worldDir) const
@@ -296,6 +429,7 @@ float Dimension::getGravity() const
 
 void Dimension::removeOldChunks()
 {
+	chunkCs.lock();
 	Array<int> removed;
 	int index = 0;
 	for (Chunk* chunk : chunkList)
@@ -321,6 +455,7 @@ void Dimension::removeOldChunks()
 		chunk->prepareRemove();
 		setChunk(0, chunk->getCenter());
 	}
+	chunkCs.unlock();
 }
 
 Entity* Dimension::zEntity(int id)
@@ -370,4 +505,35 @@ void Dimension::removeSubscriptions(Entity* zEntity)
 {
 	for (Chunk* chunk : chunkList)
 		chunk->removeObserver(zEntity);
+}
+
+void Dimension::updateLightning(Vec3<int> location)
+{
+	lightCs.lock();
+	lightUpdateQueue.add(location, 0);
+	lightCs.unlock();
+}
+
+void Dimension::updateLightAtChunkBorders(Punkt chunkCenter)
+{
+	lightCs.lock();
+	if (lightUpdateQueue.getEintragAnzahl() > 300000)
+	{
+		std::cout << "warning: light calculation queue is over 300000 blocks long";
+	}
+	for (int i = WORLD_HEIGHT - 1; i >= 0; i--)
+	{
+		for (int j = 0; j < CHUNK_SIZE; j++)
+		{
+			updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 - 1, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
+			updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
+			updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 8 - 1, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
+			updateLightning(Vec3<int>(chunkCenter.x + CHUNK_SIZE / 8, chunkCenter.y - CHUNK_SIZE / 8 + j, i));
+			updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y - CHUNK_SIZE / 8 - 1, i));
+			updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y - CHUNK_SIZE / 8, i));
+			updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y + CHUNK_SIZE / 8 - 1, i));
+			updateLightning(Vec3<int>(chunkCenter.x - CHUNK_SIZE / 8 + j, chunkCenter.y + CHUNK_SIZE / 8, i));
+		}
+	}
+	lightCs.unlock();
 }

+ 10 - 1
FactoryCraft/Dimension.h

@@ -2,6 +2,7 @@
 
 #include <Punkt.h>
 #include <InMemoryBuffer.h>
+#include <Thread.h>
 
 #include "Chunk.h"
 #include "NetworkMessage.h"
@@ -13,18 +14,21 @@ struct RequestQueue
 	int sourceId;
 };
 
-class Dimension : public virtual Framework::ReferenceCounter
+class Dimension : public Framework::Thread
 {
 private:
 	int dimensionId;
 	float gravity;
 	Framework::Trie<Chunk>* chunks;
 	Framework::Array<Chunk*> chunkList;
+	Framework::Critical chunkCs;
 	Framework::RCArray<Entity>* entities;
 	Framework::Array<RequestQueue> waitingRequests;
 	Framework::Critical cs;
 	void getAddrOf(Framework::Punkt cPos, char* addr) const;
 	void getAddrOfWorld(Framework::Punkt wPos, char* addr) const;
+	Framework::Array<Framework::Vec3<int>> lightUpdateQueue;
+	Framework::Critical lightCs;
 
 public:
 	Dimension(int id);
@@ -33,8 +37,11 @@ public:
 	void api(Framework::InMemoryBuffer* zRequest, NetworkMessage* zResponse, Entity* zSource);
 	void tickEntities();
 
+	void thread() override;
+
 	Framework::Either<Block*, int> zBlock(Framework::Vec3<int> location);
 	Block* zRealBlockInstance(Framework::Vec3<int> location);
+	const Block* zBlockOrDefault(Framework::Vec3<int> location);
 	void placeBlock(Framework::Vec3<int> location, Framework::Either<Block*, int> block);
 	void addEntity(Entity* entity);
 	void setChunk(Chunk* chunk, Framework::Punkt center);
@@ -48,4 +55,6 @@ public:
 	Entity* zNearestEntity(Framework::Vec3<float> pos, std::function<bool(Entity*)> filter);
 	void removeEntity(int id);
 	void removeSubscriptions(Entity* zEntity);
+	void updateLightning(Framework::Vec3<int> location);
+	void updateLightAtChunkBorders(Framework::Punkt chunkCenter);
 };

+ 7 - 0
FactoryCraft/Game.cpp

@@ -386,6 +386,13 @@ void Game::api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin)
 	}
 }
 
+void Game::updateLightning(int dimensionId, Vec3<int> location)
+{
+	Dimension* zDim = zDimension(dimensionId);
+	if (zDim)
+		zDim->updateLightning(location);
+}
+
 void Game::broadcastMessage(NetworkMessage* zResponse)
 {
 	for (auto client : *clients)

+ 1 - 0
FactoryCraft/Game.h

@@ -84,6 +84,7 @@ public:
 	~Game();
 	void initialize();
 	void api(Framework::InMemoryBuffer* zRequest, GameClient* zOrigin);
+	void updateLightning(int dimensionId, Vec3<int> location);
 	void broadcastMessage(NetworkMessage* zResponse);
 	void sendMessage(NetworkMessage* zResponse, Entity* zTargetPlayer);
 	bool requestWorldUpdate(WorldUpdate* update);

+ 2 - 2
FactoryCraft/NoBlock.cpp

@@ -21,11 +21,11 @@ const NoBlock NoBlock::INSTANCE;
 
 
 NoBlockBlockType::NoBlockBlockType()
-	: BlockType(ID, 0, ModelInfo("", "", 0), 0, 1)
+	: BlockType(ID, 0, ModelInfo("", "", 0), 0, 1, 0)
 {}
 
 NoBlockBlockType::NoBlockBlockType(int id)
-	: BlockType(id, 0, ModelInfo("", "", 0), 0, 1)
+	: BlockType(id, 0, ModelInfo("", "", 0), 0, 1, 0)
 {}
 
 Block* NoBlockBlockType::createBlock(Framework::Vec3<int> position) const

+ 2 - 0
FactoryCraft/NoBlock.h

@@ -30,6 +30,8 @@ protected:
 	virtual void saveBlock(Block* zBlock, Framework::StreamWriter* zWriter) const override;
 	virtual Item* getItemFromBlock(Block* zBlock) const override;
 	virtual Block* createBlockAt(Framework::Vec3<int> position, Item* zUsedItem) const override;
+
+public:
 	virtual const Block* zDefault() const override;
 };
 REGISTER(NoBlockBlockType, BlockType)

+ 1 - 0
FactoryCraft/WorldGenerator.cpp

@@ -47,6 +47,7 @@ void WorldGenerator::thread()
 				if (!Game::INSTANCE->doesChunkExist(x, y, next.dimensionId))
 				{
 					Chunk* generatedChunk = StaticRegistry<DimensionGenerator>::INSTANCE.zElement(next.dimensionId)->generateChunk(seed, x, y);
+					generatedChunk->initializeLightning();
 					generatedChunk->removeUnusedBlocks();
 					Dimension* dim = Game::INSTANCE->zDimension(next.dimensionId);
 					if (!dim)