|
@@ -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;
|
|
|
}
|