Преглед изворни кода

add torches and improved light sytsem

Kolja Strohm пре 2 година
родитељ
комит
bb7b5010d5

+ 20 - 0
FactoryCraft/BasicBlock.cpp

@@ -272,4 +272,24 @@ Item* BasaltBlockItemType::createItem() const
 	BasicBlockItem* item = new BasicBlockItem(this, BasaltBlockType::INSTANCE, "Basalt");
 	initializeItem(item, 0, 0, 100, 100, 2.f, 0, 1);
 	return item;
+}
+
+// Pine Wood
+PineBlockType::PineBlockType()
+	: BasicBlockType(ID, PineBlockItemType::ID, ModelInfo("cube", "blocks.ltdb/pine.png", 6))
+{
+	hardness = 1.4f;
+	defaultBlock = createBlockAt({ 0, 0, 0 }, 0);
+}
+
+
+PineBlockItemType::PineBlockItemType()
+	: BasicBlockItemType(ID, "Pine", 0, 0, ModelInfo("itemCube", "blocks.ltdb/pine.png", 6))
+{}
+
+Item* PineBlockItemType::createItem() const
+{
+	BasicBlockItem* item = new BasicBlockItem(this, PineBlockType::INSTANCE, "Pine");
+	initializeItem(item, 0, 0, 100, 100, 1.4f, 0, 1);
+	return item;
 }

+ 23 - 1
FactoryCraft/BasicBlocks.h

@@ -279,4 +279,26 @@ class BasaltBlockType : public BasicBlockType
 protected:
 	BasaltBlockType();
 };
-REGISTER(BasaltBlockType, BlockType)
+REGISTER(BasaltBlockType, BlockType)
+
+// Pine
+class PineBlockItemType : public BasicBlockItemType
+{
+	REGISTRABLE(PineBlockItemType)
+
+protected:
+	PineBlockItemType();
+
+public:
+	virtual Item* createItem() const override;
+};
+REGISTER(PineBlockItemType, ItemType)
+
+class PineBlockType : public BasicBlockType
+{
+	REGISTRABLE(PineBlockType)
+
+protected:
+	PineBlockType();
+};
+REGISTER(PineBlockType, BlockType)

+ 21 - 0
FactoryCraft/BasicItems.cpp

@@ -0,0 +1,21 @@
+#include "BasicItems.h"
+#include "ModelInfo.h"
+
+WoodStickItemType::WoodStickItemType()
+	: ItemType(ID, "WoodenStick", 0, 0, ModelInfo("items.m3/stick", "items.ltdb/stick.png", 1))
+{}
+
+Item* WoodStickItemType::createItem() const
+{
+	return createBasicItem("Wooden Stick", 1.f, 1.f, 10.f, 10.f, 0, 0, 0, 1, 0, 50);
+}
+
+
+ResinItemType::ResinItemType()
+	: ItemType(ID, "Resin", 0, 0, ModelInfo("itemCube", "items.ltdb/resin.png", 6))
+{}
+
+Item* ResinItemType::createItem() const
+{
+	return createBasicItem("Resin", 1.f, 1.f, 10.f, 10.f, 0, 0, 0, 1, 0, 50);
+}

+ 28 - 0
FactoryCraft/BasicItems.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "ItemType.h"
+
+class WoodStickItemType : public ItemType
+{
+	REGISTRABLE(WoodStickItemType)
+
+protected:
+	WoodStickItemType();
+
+public:
+	Item* createItem() const override;
+};
+REGISTER(WoodStickItemType, ItemType)
+
+
+class ResinItemType : public ItemType
+{
+	REGISTRABLE(ResinItemType)
+
+protected:
+	ResinItemType();
+
+public:
+	Item* createItem() const override;
+};
+REGISTER(ResinItemType, ItemType)

+ 2 - 0
FactoryCraft/BlockType.cpp

@@ -39,6 +39,7 @@ void BlockType::loadSuperBlock(Block* zBlock, Framework::StreamReader* zReader)
 		zBlock->zTool = StaticRegistry<ItemType>::INSTANCE.zElement(effectiveToolId);
 	else
 		zBlock->zTool = 0;
+	zReader->lese((char*)&zBlock->interactable, 1);
 }
 
 void BlockType::saveSuperBlock(Block* zBlock, Framework::StreamWriter* zWriter) const
@@ -52,6 +53,7 @@ void BlockType::saveSuperBlock(Block* zBlock, Framework::StreamWriter* zWriter)
 	zWriter->schreibe((char*)&zBlock->speedModifier, 4);
 	int effectiveToolId = zBlock->zTool ? zBlock->zTool->getId() : -1;
 	zWriter->schreibe((char*)&effectiveToolId, 4);
+	zWriter->schreibe((char*)&zBlock->interactable, 1);
 }
 
 void BlockType::createSuperBlock(Block* zBlock, Item* zItem) const

+ 44 - 45
FactoryCraft/Chunk.cpp

@@ -84,13 +84,19 @@ void Chunk::sendLightToClient(Framework::StreamWriter* zWriter)
 							int bi = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z;
 							int type = blockIds[bi];
 							needSend |= type != NoBlockBlockType::ID && type != AirBlockBlockType::ID;
-							if (needSend)
-								break;
 						}
 						else
 						{
-							needSend = 1; // TODO: check if the block is visible
+							if (i < 4 && zNeighbours[i])
+							{
+								Vec3<int> offset = getDirection(getDirectionFromIndex(i)) * 16;
+								int bi = ((pos.x - offset.x) * CHUNK_SIZE + (pos.y - offset.y)) * WORLD_HEIGHT + (pos.z - offset.z);
+								int type = zNeighbours[i]->blockIds[bi];
+								needSend |= type != NoBlockBlockType::ID && type != AirBlockBlockType::ID;
+							}
 						}
+						if (needSend)
+							break;
 					}
 				}
 				if (needSend)
@@ -158,6 +164,7 @@ void Chunk::addObserver(Entity* zEntity, DoLaterHandler& laterHandler)
 			sendLightToClient(&buffer);
 			NetworkMessage* msg = new NetworkMessage();
 			msg->addressDimension();
+			std::cout << "chunk size: " << buffer.getSize() << "b\n";
 			char* message = new char[buffer.getSize()];
 			buffer.lese(message, (int)buffer.getSize());
 			msg->setMessage(message, (int)buffer.getSize());
@@ -239,7 +246,7 @@ void Chunk::initializeLightning()
 						for (int j = 0; j < 3; j++)
 							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], (unsigned char)((float)neighborLeight[j] * 0.8f));
+							newLight[j] = (unsigned char)MAX(newLight[j], (unsigned char)((float)neighborLeight[j] * 0.85f));
 					}
 					const Block* current = blocks[index] ? blocks[index] : StaticRegistry<BlockType>::INSTANCE.zElement(blockIds[index])->zDefault();
 					// add own light emission
@@ -534,58 +541,49 @@ void Chunk::setNeighbor(Direction dir, Chunk* zChunk)
 
 void Chunk::load(Framework::StreamReader* zReader)
 {
-	unsigned short id = 0;
-	zReader->lese((char*)&id, 2);
-	Framework::Vec3<int> pos;
-	bool d = 0;
-	while (id)
+	for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
 	{
-		zReader->lese((char*)&pos.x, 4);
-		zReader->lese((char*)&pos.y, 4);
-		zReader->lese((char*)&pos.z, 4);
-		zReader->lese((char*)&d, 1);
-		if (d)
-			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);
+		unsigned short blockType;
+		zReader->lese((char*)&blockType, 2);
+		if (blockType)
+		{
+			Framework::Vec3<int> pos = Framework::Vec3<int>((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT);
+			bool d;
+			zReader->lese((char*)&d, 1);
+			if (d)
+			{
+				putBlockAt(pos, StaticRegistry<BlockType>::INSTANCE.zElement(blockType)->loadBlock(Framework::Vec3<int>(pos.x + location.x - CHUNK_SIZE / 2, pos.y + location.y - CHUNK_SIZE / 2, pos.z), zReader));
+			}
+			else
+			{
+				putBlockTypeAt(pos, blockType);
+			}
+		}
 	}
 	initializeLightning();
 }
 
 void Chunk::save(Framework::StreamWriter* zWriter)
 {
-	for (int x = 0; x < CHUNK_SIZE; x++)
+	for (int index = 0; index < WORLD_HEIGHT * CHUNK_SIZE * CHUNK_SIZE; index++)
 	{
-		for (int y = 0; y < CHUNK_SIZE; y++)
+		unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
+		zWriter->schreibe((char*)&blockType, 2);
+		if (blockType)
 		{
-			for (int z = 0; z < WORLD_HEIGHT; z++)
+			if (blocks[index])
 			{
-				int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
-				unsigned short blockType = blocks[index] ? (unsigned short)blocks[index]->zBlockType()->getId() : blockIds[index];
-				if (blockType)
-				{
-					zWriter->schreibe((char*)&blockType, 2);
-					zWriter->schreibe((char*)&x, 4);
-					zWriter->schreibe((char*)&y, 4);
-					zWriter->schreibe((char*)&z, 4);
-					if (blocks[index])
-					{
-						bool d = 1;
-						zWriter->schreibe((char*)&d, 1);
-						StaticRegistry<BlockType>::INSTANCE.zElement(blockType)->saveBlock(blocks[index], zWriter);
-					}
-					else
-					{
-						bool d = 0;
-						zWriter->schreibe((char*)&d, 1);
-					}
-				}
+				bool d = 1;
+				zWriter->schreibe((char*)&d, 1);
+				StaticRegistry<BlockType>::INSTANCE.zElement(blockType)->saveBlock(blocks[index], zWriter);
+			}
+			else
+			{
+				bool d = 0;
+				zWriter->schreibe((char*)&d, 1);
 			}
 		}
 	}
-	unsigned short end = 0;
-	zWriter->schreibe((char*)&end, 2);
 }
 
 void Chunk::sendToClient(Framework::StreamWriter* zWriter)
@@ -735,7 +733,7 @@ unsigned char* Chunk::getLightData(Framework::Vec3<int> location) const
 	return lightData + index;
 }
 
-void Chunk::setLightData(Framework::Vec3<int> location, unsigned char* data)
+void Chunk::setLightData(Framework::Vec3<int> location, unsigned char* data, bool foreground)
 {
 	int index = ((location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z) * 6;
 	memcpy(lightData + index, data, 6);
@@ -769,7 +767,8 @@ void Chunk::setLightData(Framework::Vec3<int> location, unsigned char* data)
 		*(int*)(message + 1) = index / 6;
 		memcpy(message + 5, data, 6);
 		msg->setMessage(message, 11);
-		msg->setUseBackground();
+		if (!foreground)
+			msg->setUseBackground();
 		notifyObservers(msg);
 	}
 }

+ 1 - 1
FactoryCraft/Chunk.h

@@ -59,5 +59,5 @@ public:
 	void setAdded();
 	bool hasObservers() const;
 	unsigned char* getLightData(Framework::Vec3<int> location) const;
-	void setLightData(Framework::Vec3<int> location, unsigned char* data);
+	void setLightData(Framework::Vec3<int> location, unsigned char* data, bool foreground);
 };

+ 76 - 27
FactoryCraft/Dimension.cpp

@@ -76,6 +76,7 @@ void Dimension::thread()
 	ZeitMesser messer;
 	messer.messungStart();
 	double time = 0;
+	bool isForeground = 0;
 	Framework::Array<Framework::Vec3<int>> internalLightUpdateQueue;
 	while (true)
 	{
@@ -87,12 +88,33 @@ void Dimension::thread()
 		}
 		else
 		{
+			removedChunksCs.lock();
+			if (removedChunks.getEintragAnzahl() > 0)
+			{
+				Chunk* removedChunk = removedChunks.z(0);
+				removedChunksCs.unlock();
+				Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + getDimensionId() + "/";
+				filePath.appendHex(removedChunk->getCenter().x);
+				filePath += "_";
+				filePath.appendHex(removedChunk->getCenter().y);
+				filePath += ".chunk";
+				Datei d;
+				d.setDatei(filePath);
+				d.erstellen();
+				d.open(Datei::Style::schreiben);
+				removedChunk->save(&d);
+				d.close();
+				removedChunksCs.lock();
+				removedChunks.remove(0);
+			}
+			removedChunksCs.unlock();
 			if (priorizedLightUpdateQueue.getEintragAnzahl())
 			{
 				prioLightCs.lock();
 				position = priorizedLightUpdateQueue.get(0);
 				priorizedLightUpdateQueue.remove(0);
 				prioLightCs.unlock();
+				isForeground = 1;
 			}
 			else
 			{
@@ -108,10 +130,9 @@ void Dimension::thread()
 				position = lightUpdateQueue.get(0);
 				lightUpdateQueue.remove(0);
 				lightCs.unlock();
+				isForeground = 0;
 			}
-
 		}
-		// 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)
 		{
@@ -157,7 +178,7 @@ void Dimension::thread()
 					for (int j = 0; j < 3; j++)
 						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], (unsigned char)((float)neighborLeight[j] * 0.8f));
+						newLight[j] = (unsigned char)MAX(newLight[j], (unsigned char)((float)neighborLeight[j] * 0.85f));
 				}
 				const Block* current = zBlockOrDefault(position);
 				if (!current)
@@ -171,7 +192,7 @@ void Dimension::thread()
 				{
 					if (newLight[i] != light[i])
 					{
-						chunk->setLightData(Vec3<int>(x, y, position.z), newLight);
+						chunk->setLightData(Vec3<int>(x, y, position.z), newLight, isForeground);
 						for (int j = 0; j < 6; j++)
 							internalLightUpdateQueue.add(position + getDirection(getDirectionFromIndex(j)), 0);
 						break;
@@ -299,9 +320,10 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 	chunkCs.lock();
 	char addr[8];
 	getAddrOfWorld(center, addr);
-	Chunk* old = chunks->z(addr, 8);
+	Chunk* old = chunks->get(addr, 8);
 	if (old)
 	{
+		old->prepareRemove();
 		for (int i = 0; i < chunkList.getEintragAnzahl(); i++)
 		{
 			if (chunkList.get(i) == old)
@@ -381,6 +403,12 @@ void Dimension::setChunk(Chunk* chunk, Punkt center)
 		cs.unlock();
 	}
 	chunkCs.unlock();
+	if (old)
+	{
+		removedChunksCs.lock();
+		removedChunks.add(old);
+		removedChunksCs.unlock();
+	}
 	updateLightAtChunkBorders(center);
 }
 
@@ -435,9 +463,49 @@ int Dimension::getDimensionId() const
 	return dimensionId;
 }
 
-bool Dimension::hasChunck(int x, int y) const
+bool Dimension::hasChunck(int x, int y)
 {
-	return zChunk(Punkt(x, y));
+	if (zChunk(Punkt(x, y)))
+		return 1;
+	removedChunksCs.lock();
+	for (Chunk* c : removedChunks)
+	{
+		if (c->getCenter().x == x && c->getCenter().y == y)
+		{
+			removedChunksCs.unlock();
+			return 1;
+		}
+	}
+	removedChunksCs.unlock();
+	return 0;
+}
+
+bool Dimension::reviveChunk(int x, int y)
+{
+	chunkCs.lock();
+	if (zChunk(Punkt(x, y)))
+	{
+		chunkCs.unlock();
+		return 1;
+	}
+	removedChunksCs.lock();
+	int index = 0;
+	for (Iterator<Chunk*> i = removedChunks.begin(); i; i++)
+	{
+		if (i->getCenter().x == x && i->getCenter().y == y)
+		{
+			setChunk(dynamic_cast<Chunk*>(i->getThis()), Punkt(x, y));
+			if (index > 0)
+				i.remove();
+			removedChunksCs.unlock();
+			chunkCs.unlock();
+			return 1;
+		}
+		index++;
+	}
+	removedChunksCs.unlock();
+	chunkCs.unlock();
+	return 0;
 }
 
 float Dimension::getGravity() const
@@ -448,32 +516,13 @@ float Dimension::getGravity() const
 void Dimension::removeOldChunks()
 {
 	chunkCs.lock();
-	Array<int> removed;
 	int index = 0;
 	for (Chunk* chunk : chunkList)
 	{
 		if (!chunk->hasObservers())
-			removed.add(index, 0);
+			setChunk(0, chunk->getCenter());
 		index++;
 	}
-	for (int i : removed)
-	{
-		Chunk* chunk = chunkList.get(i);
-		// TODO: save chunk in a seperate thread?
-		Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + getDimensionId() + "/";
-		filePath.appendHex(chunk->getCenter().x);
-		filePath += "_";
-		filePath.appendHex(chunk->getCenter().y);
-		filePath += ".chunk";
-		Datei d;
-		d.setDatei(filePath);
-		d.erstellen();
-		d.open(Datei::Style::schreiben);
-		chunk->save(&d);
-		d.close();
-		chunk->prepareRemove();
-		setChunk(0, chunk->getCenter());
-	}
 	chunkCs.unlock();
 }
 

+ 4 - 1
FactoryCraft/Dimension.h

@@ -31,6 +31,8 @@ private:
 	Framework::Array<Framework::Vec3<int>> priorizedLightUpdateQueue;
 	Framework::Critical lightCs;
 	Framework::Critical prioLightCs;
+	Framework::RCArray<Chunk> removedChunks;
+	Framework::Critical removedChunksCs;
 
 public:
 	Dimension(int id);
@@ -49,7 +51,8 @@ public:
 	void setChunk(Chunk* chunk, Framework::Punkt center);
 	void save(Framework::Text worldDir) const;
 	int getDimensionId() const;
-	bool hasChunck(int x, int y) const;
+	bool hasChunck(int x, int y);
+	bool reviveChunk(int x, int y);
 	Chunk* zChunk(Framework::Punkt wPos) const;
 	float getGravity() const;
 	void removeOldChunks();

+ 4 - 0
FactoryCraft/FactoryCraft.vcxproj

@@ -95,6 +95,7 @@
     <ClInclude Include="AddEntityUpdate.h" />
     <ClInclude Include="Area.h" />
     <ClInclude Include="BasicBlocks.h" />
+    <ClInclude Include="BasicItems.h" />
     <ClInclude Include="BiomGenerator.h" />
     <ClInclude Include="Block.h" />
     <ClInclude Include="BlockType.h" />
@@ -122,6 +123,7 @@
     <ClInclude Include="ItemSlot.h" />
     <ClInclude Include="ItemStack.h" />
     <ClInclude Include="ItemType.h" />
+    <ClInclude Include="LightSources.h" />
     <ClInclude Include="ModelInfo.h" />
     <ClInclude Include="NetworkMessage.h" />
     <ClInclude Include="Noise.h" />
@@ -150,6 +152,7 @@
     <ClCompile Include="AddEntityUpdate.cpp" />
     <ClCompile Include="Area.cpp" />
     <ClCompile Include="BasicBlock.cpp" />
+    <ClCompile Include="BasicItems.cpp" />
     <ClCompile Include="BiomGenerator.cpp" />
     <ClCompile Include="Block.cpp" />
     <ClCompile Include="BlockType.cpp" />
@@ -174,6 +177,7 @@
     <ClCompile Include="ItemSlot.cpp" />
     <ClCompile Include="ItemStack.cpp" />
     <ClCompile Include="ItemType.cpp" />
+    <ClCompile Include="LightSources.cpp" />
     <ClCompile Include="ModelInfo.cpp" />
     <ClCompile Include="NetworkMessage.cpp" />
     <ClCompile Include="NoBlock.cpp" />

+ 12 - 0
FactoryCraft/FactoryCraft.vcxproj.filters

@@ -222,6 +222,12 @@
     <ClInclude Include="DoLaterHandler.h">
       <Filter>server</Filter>
     </ClInclude>
+    <ClInclude Include="BasicItems.h">
+      <Filter>inventory\items</Filter>
+    </ClInclude>
+    <ClInclude Include="LightSources.h">
+      <Filter>world\blocks</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Server.cpp">
@@ -371,5 +377,11 @@
     <ClCompile Include="DoLaterHandler.cpp">
       <Filter>server</Filter>
     </ClCompile>
+    <ClCompile Include="BasicItems.cpp">
+      <Filter>inventory\items</Filter>
+    </ClCompile>
+    <ClCompile Include="LightSources.cpp">
+      <Filter>world\blocks</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 6 - 3
FactoryCraft/Game.cpp

@@ -18,7 +18,9 @@ GameClient::GameClient(Player* zPlayer, FCKlient* client)
 	viewDistance(DEFAULT_VIEW_DISTANCE),
 	first(1),
 	online(1),
-	finished(0)
+	finished(0),
+	backgroundFinished(0),
+	foregroundFinished(0)
 {
 	new AsynchronCall("Game Client Updates", [this]()
 		{
@@ -55,7 +57,7 @@ GameClient::~GameClient()
 	emptyBackgroundQueueSync.notifyAll();
 	foregroundQueueSync.notify();
 	backgroundQueueSync.notify();
-	while (!finished)
+	while (!finished ||!backgroundFinished || !backgroundFinished)
 		Sleep(100);
 	client->release();
 }
@@ -84,7 +86,7 @@ void GameClient::thread()
 					backgroundQueueSync.wait();
 				}
 			}
-			finished = 1;
+			backgroundFinished = 1;
 		});
 	while (online)
 	{
@@ -106,6 +108,7 @@ void GameClient::thread()
 			foregroundQueueSync.wait();
 		}
 	}
+	foregroundFinished = 1;
 }
 
 void GameClient::sendWorldUpdate(WorldUpdate* update)

+ 2 - 0
FactoryCraft/Game.h

@@ -41,6 +41,8 @@ private:
 	bool first;
 	bool online;
 	bool finished;
+	bool backgroundFinished;
+	bool foregroundFinished;
 
 public:
 	GameClient(Player* zPlayer, FCKlient* client);

+ 1 - 0
FactoryCraft/GrasslandBiom.cpp

@@ -12,6 +12,7 @@ GrasslandBiom::GrasslandBiom()
 	addTemplateGenerator(new TreeTemplate(0.02f, BirchBlockType::INSTANCE, LeavesBlockType::INSTANCE, 8, 15));
 	addTemplateGenerator(new TreeTemplate(0.01f, BeechBlockType::INSTANCE, LeavesBlockType::INSTANCE, 8, 13));
 	addTemplateGenerator(new TreeTemplate(0.005f, OakBlockType::INSTANCE, LeavesBlockType::INSTANCE, 10, 15));
+	addTemplateGenerator(new TreeTemplate(0.0025f, PineBlockType::INSTANCE, LeavesBlockType::INSTANCE, 15, 24));
 	heightNoise = 0;
 }
 

+ 1 - 1
FactoryCraft/Inventory.cpp

@@ -400,7 +400,7 @@ void Inventory::notyObservers(NetworkMessage* msg)
 		if (e)
 		{
 			msg->addressGui(observer.getSecond());
-			Game::INSTANCE->sendMessage(dynamic_cast<NetworkMessage*>(msg->getThis()), e);
+			Game::INSTANCE->sendMessage(msg->clone(), e);
 		}
 		else
 			toDelete.add(index, 0);

+ 140 - 0
FactoryCraft/LightSources.cpp

@@ -0,0 +1,140 @@
+#include "LightSources.h"
+
+LightSourceItem::LightSourceItem(const ItemType* zType, const BlockType* zPlacedBlockType, const char* name)
+	: BasicBlockItem(zType, zPlacedBlockType, name),
+	color(0XFFFFFFFF)
+{}
+
+bool LightSourceItem::canBeStackedWith(const Item* zItem) const
+{
+	const LightSourceItem* other = dynamic_cast<const LightSourceItem*>(zItem);
+	return BasicBlockItem::canBeStackedWith(zItem) && other->color == color;
+}
+
+
+LightSourceItemType::LightSourceItemType(int id, const char* name, const ModelInfo model)
+	:BasicBlockItemType(id, name, 0, 0, model)
+{}
+
+void LightSourceItemType::loadSuperItem(Item* zItem, Framework::StreamReader* zReader) const
+{
+	LightSourceItem* item = dynamic_cast<LightSourceItem*>(zItem);
+	zReader->lese((char*)&item->color, 4);
+	BasicBlockItemType::loadSuperItem(zItem, zReader);
+}
+
+void LightSourceItemType::saveSuperItem(const Item* zItem, Framework::StreamWriter* zWriter) const
+{
+	const LightSourceItem* item = dynamic_cast<const LightSourceItem*>(zItem);
+	zWriter->schreibe((char*)&item->color, 4);
+	BasicBlockItemType::saveSuperItem(zItem, zWriter);
+}
+
+void LightSourceItemType::initializeItem(LightSourceItem* zItem, int color, bool transparent, bool passable, float hp, float maxHP, float hardness, int toolId, float speedModifier) const
+{
+	zItem->color = color;
+	BasicBlockItemType::initializeItem(zItem, transparent, passable, hp, maxHP, hardness, toolId, speedModifier);
+}
+
+
+BasicLightSource::BasicLightSource(const BlockType* zType, Framework::Vec3<int> pos)
+	: Block(zType, 0, pos, 0)
+{}
+
+void BasicLightSource::setLight(int light)
+{
+	lightEmisionColor[0] = (unsigned char)((light >> 16) & 0xFF);
+	lightEmisionColor[1] = (unsigned char)((light >> 8) & 0xFF);
+	lightEmisionColor[2] = (unsigned char)(light & 0xFF);
+}
+
+bool BasicLightSource::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
+{
+	return 0;
+}
+
+void BasicLightSource::onPostTick()
+{}
+
+
+BasicLightSourceBlockType::BasicLightSourceBlockType(int typeId, int itemTypeId, ModelInfo model)
+	: BlockType(typeId, 0, model, 1, 1, 1),
+	itemType(itemTypeId),
+	transparent(1),
+	passable(1),
+	hardness(1.f),
+	interactable(1)
+{}
+
+void BasicLightSourceBlockType::createSuperBlock(Block* zBlock, Item* zItem) const
+{
+	if (zItem)
+	{
+		BlockType::createSuperBlock(zBlock, zItem);
+		dynamic_cast<BasicLightSource*>(zBlock)->setLight(dynamic_cast<LightSourceItem*>(zItem)->color);
+	}
+	else
+	{
+		BasicLightSource* block = dynamic_cast<BasicLightSource*>(zBlock);
+		if (!block)
+			throw "BasicLightSourceBlockType::createSuperBlock was called with a block witch is not an instance of BasicLightSource";
+		block->transparent = transparent;
+		block->passable = passable;
+		block->hp = (float)getInitialMaxHP();
+		block->maxHP = (float)getInitialMaxHP();
+		block->hardness = hardness;
+		block->zTool = 0;
+		block->speedModifier = 1;
+		block->interactable = interactable;
+		block->setLight(color);
+	}
+}
+
+void BasicLightSourceBlockType::loadSuperBlock(Block* zBlock, Framework::StreamReader* zReader) const
+{
+	BlockType::loadSuperBlock(zBlock, zReader);
+	BasicLightSource* block = dynamic_cast<BasicLightSource*>(zBlock);
+	if (!block)
+		throw "BasicLightSourceBlockType::loadSuperBlock was called with a block witch is not an instance of BasicLightSource";
+	zReader->lese((char*)&block->lightEmisionColor, 4);
+}
+
+void BasicLightSourceBlockType::saveSuperBlock(Block* zBlock, Framework::StreamWriter* zWriter) const
+{
+	BlockType::saveSuperBlock(zBlock, zWriter);
+	BasicLightSource* block = dynamic_cast<BasicLightSource*>(zBlock);
+	if (!block)
+		throw "BasicLightSourceBlockType::saveSuperBlock was called with a block witch is not an instance of BasicLightSource";
+	zWriter->schreibe((char*)&block->lightEmisionColor, 4);
+}
+
+Block* BasicLightSourceBlockType::createBlock(Framework::Vec3<int> position) const
+{
+	return new BasicLightSource(this, position);
+}
+
+Item* BasicLightSourceBlockType::createItem() const
+{
+	return StaticRegistry<ItemType>::INSTANCE.zElement(itemType)->createItem();
+}
+
+
+TorchBlockItemType::TorchBlockItemType()
+	: LightSourceItemType(ID, "Torch", ModelInfo("items.m3/stick", "blocks.ltdb/torch.png", 6))
+{}
+
+Item* TorchBlockItemType::createItem() const
+{
+	LightSourceItem* item = new LightSourceItem(this, TorchBlockType::INSTANCE, "Torch");
+	initializeItem(item, 0x00F69A54);
+	return item;
+}
+
+
+TorchBlockType::TorchBlockType()
+	: BasicLightSourceBlockType(ID, TorchBlockItemType::ID, ModelInfo("blocks.m3/torch", "blocks.ltdb/torch.png", 6))
+{
+	hardness = 0.f;
+	color = 0x00F69A54;
+	defaultBlock = createBlockAt({ 0, 0, 0 }, 0);
+}

+ 86 - 0
FactoryCraft/LightSources.h

@@ -0,0 +1,86 @@
+#pragma once
+
+#include "BlockType.h"
+#include "BasicBlocks.h"
+#include "Block.h"
+
+class BasicLightSourceBlockType;
+class LightSourceItemType;
+
+class LightSourceItem : public BasicBlockItem
+{
+protected:
+	int color;
+
+public:
+	LightSourceItem(const ItemType* zType, const BlockType* zPlacedBlockType, const char* name);
+	virtual bool canBeStackedWith(const Item* zItem) const override;
+
+	friend LightSourceItemType;
+	friend BasicLightSourceBlockType;
+};
+
+class LightSourceItemType : public BasicBlockItemType
+{
+protected:
+	LightSourceItemType(int id, const char* name, const ModelInfo model);
+	virtual void loadSuperItem(Item* zItem, Framework::StreamReader* zReader) const override;
+	virtual void saveSuperItem(const Item* zItem, Framework::StreamWriter* zWriter) const override;
+	void initializeItem(LightSourceItem* zItem, int color, bool transparent = 1, bool passable = 1, float hp = 1, float maxHP = 1, float hardness = 0, int toolId = 0, float speedModifier = 1) const;
+};
+
+class BasicLightSource : public Block
+{
+protected:
+	void setLight(int light);
+
+public:
+	BasicLightSource(const BlockType* zType, Framework::Vec3<int> pos);
+	virtual bool onTick(TickQueue* zQueue, int numTicks, bool& blocked) override;
+	virtual void onPostTick() override;
+
+	friend BasicLightSourceBlockType;
+};
+
+class BasicLightSourceBlockType : public BlockType
+{
+private:
+	int itemType;
+
+protected:
+	bool transparent;
+	bool passable;
+	float hardness;
+	bool interactable;
+	int color;
+
+	BasicLightSourceBlockType(int typeId, int itemTypeId, ModelInfo model);
+	virtual void createSuperBlock(Block* zBlock, Item* zItem) const override;
+	virtual void loadSuperBlock(Block* zBlock, Framework::StreamReader* zReader) const override;
+	virtual void saveSuperBlock(Block* zBlock, Framework::StreamWriter* zWriter) const override;
+
+public:
+	virtual Block* createBlock(Framework::Vec3<int> position) const override;
+	virtual Item* createItem() const override;
+};
+
+class TorchBlockItemType : public LightSourceItemType
+{
+	REGISTRABLE(TorchBlockItemType)
+
+protected:
+	TorchBlockItemType();
+
+public:
+	virtual Item* createItem() const override;
+};
+REGISTER(TorchBlockItemType, ItemType)
+
+class TorchBlockType : public BasicLightSourceBlockType
+{
+	REGISTRABLE(TorchBlockType)
+
+protected:
+	TorchBlockType();
+};
+REGISTER(TorchBlockType, BlockType)

+ 14 - 0
FactoryCraft/NetworkMessage.cpp

@@ -127,4 +127,18 @@ bool NetworkMessage::isEmpty() const
 bool NetworkMessage::isUseBackground() const
 {
 	return useBackground;
+}
+
+NetworkMessage* NetworkMessage::clone() const
+{
+	NetworkMessage* result = new NetworkMessage();
+	result->message = new char[(int)msgLength];
+	memcpy(result->message, message, (int)msgLength);
+	result->msgLength = msgLength;
+	result->address = new char[(int)addressLength];
+	memcpy(result->address, address, (int)addressLength);
+	result->addressLength = addressLength;
+	result->broadcast = broadcast;
+	result->useBackground = useBackground;
+	return result;
 }

+ 1 - 0
FactoryCraft/NetworkMessage.h

@@ -36,4 +36,5 @@ public:
 	bool isBroadcast() const;
 	bool isEmpty() const;
 	bool isUseBackground() const;
+	NetworkMessage* clone() const;
 };

+ 4 - 1
FactoryCraft/StaticInitializerOrder.cpp

@@ -27,6 +27,9 @@ bool initialized_##c##_##typ = StaticRegistry<typ>::INSTANCE.info(c::ID);
 // item skills
 #include "PlayerHand.h"
 #include "StoneTool.h"
+#include "BasicItems.h"
 // world updates
 #include "AddEntityUpdate.h"
-#include "EntityRemovedUpdate.h"
+#include "EntityRemovedUpdate.h"
+
+#include "LightSources.h"

+ 7 - 1
FactoryCraft/WorldLoader.cpp

@@ -67,7 +67,13 @@ void WorldLoader::thread()
 		{
 			for (int y = start.y; yDir < 0 ? y >= end.y : y <= end.y; y += CHUNK_SIZE * yDir)
 			{
-				if (!Game::INSTANCE->isChunkLoaded(x, y, next.dimensionId))
+				Dimension* zDim = Game::INSTANCE->zDimension(next.dimensionId);
+				bool revived = 0;
+				if (!zDim->zChunk(Punkt(x, y)) && zDim->hasChunck(x, y))
+				{
+					revived = zDim->reviveChunk(x, y);
+				}
+				if (!revived && !Game::INSTANCE->isChunkLoaded(x, y, next.dimensionId))
 				{
 					Datei* file = new Datei();
 					Text filePath = Game::INSTANCE->getWorldDirectory() + "/dim/" + next.dimensionId + "/";