Globally cascading sunlight x3
parent
9dfa361833
commit
41bb678eec
|
@ -11,7 +11,7 @@
|
|||
#include "../util/net/PacketView.h"
|
||||
|
||||
Server::Server(unsigned short port, const std::string& subgame) :
|
||||
seed(27),
|
||||
seed(69),
|
||||
port(port),
|
||||
config(defs),
|
||||
defs(subgame, seed),
|
||||
|
|
|
@ -59,32 +59,33 @@ void ServerWorld::update(double delta) {
|
|||
auto finished = genStream->update();
|
||||
generatedChunks = static_cast<int>(finished->size());
|
||||
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> changed {};
|
||||
|
||||
for (auto& mb : *finished) {
|
||||
for (const auto& chunk : mb.chunks) dimension.setChunk(chunk);
|
||||
dimension.calculateEdgeLight(mb.pos);
|
||||
dimension.getMapBlock(mb.pos)->generated = true;
|
||||
|
||||
unsigned long long mapBlockIntegrity = dimension.getMapBlockIntegrity(mb.pos);
|
||||
for (auto& client : clientList.clients) {
|
||||
if (client->hasPlayer) {
|
||||
auto playerMapBlock = Space::MapBlock::world::fromBlock(client->getPos());
|
||||
|
||||
std::pair<glm::ivec3, glm::ivec3> bounds = {
|
||||
{playerMapBlock.x - MB_GEN_H, playerMapBlock.y - MB_GEN_V, playerMapBlock.z - MB_GEN_H},
|
||||
{playerMapBlock.x + MB_GEN_H, playerMapBlock.y + MB_GEN_V, playerMapBlock.z + MB_GEN_H}};
|
||||
|
||||
if (isInBounds(mb.pos, bounds) && client->getMapBlockIntegrity(mb.pos) < mapBlockIntegrity) {
|
||||
client->setMapBlockIntegrity(mb.pos, mapBlockIntegrity);
|
||||
|
||||
//TODO: Replace with sendMapBlock
|
||||
for (int i = 0; i < 64; i++) {
|
||||
sendChunk(dimension.getMapBlock(mb.pos)->operator[](i)->pos, *client);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& chunk : mb.chunks) {
|
||||
changed.insert(chunk->pos);
|
||||
dimension.setChunk(chunk);
|
||||
}
|
||||
|
||||
auto resend = dimension.calculateEdgeLight(mb.pos);
|
||||
changed.insert(resend.begin(), resend.end());
|
||||
|
||||
dimension.getMapBlock(mb.pos)->generated = true;
|
||||
}
|
||||
|
||||
for (auto& chunk : changed) {
|
||||
for (auto& client : clientList.clients) {
|
||||
if (!client->hasPlayer) continue;
|
||||
|
||||
auto myChunk = Space::Chunk::world::fromBlock(client->getPos());
|
||||
|
||||
std::pair<glm::ivec3, glm::ivec3> bounds = {
|
||||
{myChunk.x - CHUNK_SEND_H, myChunk.y - CHUNK_SEND_V, myChunk.z - CHUNK_SEND_H},
|
||||
{myChunk.x + CHUNK_SEND_H, myChunk.y + CHUNK_SEND_V, myChunk.z + CHUNK_SEND_H}};
|
||||
|
||||
if (isInBounds(chunk, bounds)) sendChunk(dimension.getChunk(chunk), *client);
|
||||
}
|
||||
}
|
||||
|
||||
// Send the # of generated chunks to the client (debug),
|
||||
// and trigger new chunks to be generated if a player has changed MapBlocks.
|
||||
|
@ -135,7 +136,7 @@ void ServerWorld::changedChunks(ServerClient& client) {
|
|||
unsigned int mapBlocksGenerating = 0;
|
||||
|
||||
for (const auto &c : generateOrder) {
|
||||
glm::vec3 mapBlockPos = mapBlock + c;
|
||||
glm::ivec3 mapBlockPos = mapBlock + c;
|
||||
if (!isInBounds(mapBlockPos, oldBounds)) {
|
||||
auto existing = dimension.getMapBlock(mapBlockPos);
|
||||
if (existing != nullptr && existing->generated) {
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
class ServerWorld : public World {
|
||||
public:
|
||||
const static int MB_GEN_H = 2;
|
||||
const static int MB_GEN_V = 2;
|
||||
const static int MB_GEN_H = 2, MB_GEN_V = 2;
|
||||
const static int CHUNK_SEND_H = 8, CHUNK_SEND_V = 8;
|
||||
|
||||
explicit ServerWorld(unsigned int seed, ServerGame& game, ClientList& clients);
|
||||
|
||||
|
|
|
@ -16,64 +16,39 @@ bool Dimension::setBlock(glm::ivec3 pos, unsigned int block) {
|
|||
if (oldLight.x + oldLight.y + oldLight.z != 0) removeBlockLight(pos);
|
||||
if (newLight.x + newLight.y + newLight.z != 0) addBlockLight(pos, newLight);
|
||||
|
||||
if (def.lightPropagates) reflowLightThroughTransparent(pos);
|
||||
if (!def.lightPropagates && getLight(pos, chunk.get()).w != 0) reflowSunlightAroundSolid(pos);
|
||||
if (def.lightPropagates) reflowLight(pos);
|
||||
if (!def.lightPropagates && getLight(pos, chunk.get()).w != 0) removeSunlight(pos);
|
||||
|
||||
propogateRemoveNodes();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dimension::calculateEdgeLight(glm::ivec3 mbPos) {
|
||||
// for (auto i = 0; i < 64; i++) {
|
||||
// glm::ivec3 l = Space::Chunk::fromIndex(i);
|
||||
// glm::ivec3 chunkPos = mbPos * 4 + l;
|
||||
//
|
||||
// auto edges = std::array<bool, 6> { l.x == 0, l.y == 0, l.z == 0,
|
||||
// l.x == Space::MAPBLOCK_SIZE - 1, l.y == Space::MAPBLOCK_SIZE - 1, l.z == Space::MAPBLOCK_SIZE - 1};
|
||||
//
|
||||
// // Pull light from above
|
||||
// if (edges[4]) {
|
||||
// if (!getChunk(chunkPos + glm::ivec3 {0, 1, 0})) continue;
|
||||
// auto chunk = getChunk(chunkPos).get();
|
||||
//
|
||||
// for (unsigned int j = 0; j < 16; j++) {
|
||||
// for (unsigned int k = 0; k < 16; k++) {
|
||||
// glm::ivec3 belowPos = chunkPos * 16 + glm::ivec3 {j, 15, k};
|
||||
// glm::ivec3 abovePos = belowPos + glm::ivec3 {0, 1, 0};
|
||||
//
|
||||
// unsigned int lightAbove = getLight(abovePos).w;
|
||||
// unsigned int lightBelow = getLight(belowPos).w;
|
||||
// if (lightBelow > lightAbove) {
|
||||
// unsigned int ind = Space::Block::index(belowPos);
|
||||
// lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, lightBelow, chunk);
|
||||
// chunk->setSunlight(ind, 0);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Push light below
|
||||
// if (edges[1]) {
|
||||
// auto belowChunk = getChunk(chunkPos + glm::ivec3 {0, -1, 0}).get();
|
||||
// if (!belowChunk) continue;
|
||||
//
|
||||
// for (unsigned int j = 0; j < 16; j++) {
|
||||
// for (unsigned int k = 0; k < 16; k++) {
|
||||
// glm::ivec3 abovePos = chunkPos * 16 + glm::ivec3 {j, 0, k};
|
||||
// glm::ivec3 belowPos = abovePos + glm::ivec3 {0, -1, 0};
|
||||
//
|
||||
// unsigned int lightAbove = getLight(abovePos).w;
|
||||
// unsigned int lightBelow = getLight(belowPos).w;
|
||||
// if (lightBelow > lightAbove) {
|
||||
// unsigned int ind = Space::Block::index(belowPos);
|
||||
// lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, lightBelow, belowChunk);
|
||||
// belowChunk->setSunlight(ind, 0);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::calculateEdgeLight(glm::ivec3 mbPos) {
|
||||
bool ypos = mapBlockGenerated(mbPos + glm::ivec3 {0, 1, 0});
|
||||
bool yneg = mapBlockGenerated(mbPos + glm::ivec3 {0, -1, 0});
|
||||
bool xpos = mapBlockGenerated(mbPos + glm::ivec3 {1, 0, 0});
|
||||
bool xneg = mapBlockGenerated(mbPos + glm::ivec3 {-1, 0, 0});
|
||||
bool zpos = mapBlockGenerated(mbPos + glm::ivec3 {0, 0, 1});
|
||||
bool zneg = mapBlockGenerated(mbPos + glm::ivec3 {0, 0, -1});
|
||||
|
||||
propogateRemoveNodes();
|
||||
for (unsigned int i = 0; i < 64; i++) {
|
||||
glm::ivec3 l = Space::Chunk::fromIndex(i);
|
||||
glm::ivec3 chunkPos = mbPos * 4 + l;
|
||||
|
||||
auto self = getChunk(chunkPos);
|
||||
|
||||
if (yneg && l.y == 0) calculateVerticalEdge(self, getChunk(chunkPos + glm::ivec3 {0, -1, 0}));
|
||||
else if (ypos && l.y == 3) calculateVerticalEdge(getChunk(chunkPos + glm::ivec3 {0, 1, 0}), self);
|
||||
|
||||
if (xpos && l.x == 3) calculateHorizontalEdge(self, getChunk(chunkPos + glm::ivec3 {1, 0, 0}));
|
||||
if (xneg && l.x == 0) calculateHorizontalEdge(self, getChunk(chunkPos + glm::ivec3 {-1, 0, 0}));
|
||||
|
||||
if (zpos && l.z == 3) calculateHorizontalEdge(self, getChunk(chunkPos + glm::ivec3 {0, 0, 1}));
|
||||
if (zneg && l.z == 0) calculateHorizontalEdge(self, getChunk(chunkPos + glm::ivec3 {0, 0, -1}));
|
||||
}
|
||||
|
||||
return propogateRemoveNodes();
|
||||
}
|
||||
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateAddNodes() {
|
||||
|
@ -152,7 +127,9 @@ std::unordered_set<glm::ivec3, Vec::ivec3> Dimension::propogateRemoveNodes() {
|
|||
}
|
||||
}
|
||||
|
||||
propogateAddNodes(); //TODO: Merge returned chunks with our list
|
||||
auto otherChunksUpdated = propogateAddNodes();
|
||||
chunksUpdated.insert(otherChunksUpdated.begin(), otherChunksUpdated.end());
|
||||
|
||||
return chunksUpdated;
|
||||
}
|
||||
|
||||
|
@ -166,6 +143,37 @@ glm::ivec4 Dimension::getLight(glm::ivec3 worldPos, BlockChunk *chunk) {
|
|||
return (oChunk ? oChunk->getLight(Space::Block::index(worldPos)) : glm::ivec4 {});
|
||||
}
|
||||
|
||||
void Dimension::calculateHorizontalEdge(std::shared_ptr<BlockChunk> a, std::shared_ptr<BlockChunk> b) {
|
||||
for (unsigned int j = 0; j < 256; j++) {
|
||||
glm::ivec3 diff = a->pos - b->pos;
|
||||
|
||||
glm::ivec3 aPos = {
|
||||
(diff.x == 0 ? j % 16 : diff.x == 1 ? 0 : 15), j / 16,
|
||||
(diff.z == 0 ? j % 16 : diff.z == 1 ? 0 : 15) };
|
||||
glm::ivec3 bPos = {
|
||||
(diff.x == 0 ? j % 16 : diff.x == 1 ? 15 : 0), j / 16,
|
||||
(diff.z == 0 ? j % 16 : diff.z == 1 ? 15 : 0) };
|
||||
|
||||
auto lightA = a->getSunlight(Space::Block::index(aPos));
|
||||
auto lightB = b->getSunlight(Space::Block::index(bPos));
|
||||
|
||||
if (lightA > lightB + 1) setSunlight(b->pos * 16 + bPos, lightA - 1);
|
||||
else if (lightB > lightA + 1) setSunlight(a->pos * 16 + aPos, lightB - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Dimension::calculateVerticalEdge(std::shared_ptr<BlockChunk> above, std::shared_ptr<BlockChunk> below) {
|
||||
for (unsigned int j = 0; j < 256; j++) {
|
||||
unsigned int xx = j / 16;
|
||||
unsigned int zz = j % 16;
|
||||
|
||||
auto lightAbove = above->getSunlight(Space::Block::index({xx, 0, zz}));
|
||||
auto lightBelow = below->getSunlight(Space::Block::index({xx, 15, zz}));
|
||||
|
||||
if (lightBelow > lightAbove) removeSunlight(below->pos * 16 + glm::ivec3{xx, 15, zz});
|
||||
}
|
||||
}
|
||||
|
||||
void Dimension::addBlockLight(glm::ivec3 pos, glm::ivec3 light) {
|
||||
auto startChunk = getChunk(Space::Chunk::world::fromBlock(pos));
|
||||
auto ind = Space::Block::index(pos);
|
||||
|
@ -174,7 +182,6 @@ void Dimension::addBlockLight(glm::ivec3 pos, glm::ivec3 light) {
|
|||
lightAddQueue[0].emplace(ind, startChunk.get());
|
||||
lightAddQueue[1].emplace(ind, startChunk.get());
|
||||
lightAddQueue[2].emplace(ind, startChunk.get());
|
||||
propogateAddNodes();
|
||||
}
|
||||
|
||||
void Dimension::removeBlockLight(glm::ivec3 pos) {
|
||||
|
@ -187,10 +194,9 @@ void Dimension::removeBlockLight(glm::ivec3 pos) {
|
|||
lightRemoveQueue[0].emplace(ind, val.x, startChunk.get());
|
||||
lightRemoveQueue[1].emplace(ind, val.y, startChunk.get());
|
||||
lightRemoveQueue[2].emplace(ind, val.z, startChunk.get());
|
||||
propogateRemoveNodes();
|
||||
}
|
||||
|
||||
void Dimension::reflowLightThroughTransparent(glm::ivec3 pos) {
|
||||
void Dimension::reflowLight(glm::ivec3 pos) {
|
||||
glm::ivec4 placeLight {};
|
||||
const static std::array<glm::ivec3, 6> checks = { glm::ivec3 {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1} };
|
||||
|
||||
|
@ -214,15 +220,21 @@ void Dimension::reflowLightThroughTransparent(glm::ivec3 pos) {
|
|||
lightAddQueue[1].emplace(ind, chunk.get());
|
||||
lightAddQueue[2].emplace(ind, chunk.get());
|
||||
lightAddQueue[3].emplace(ind, chunk.get());
|
||||
|
||||
propogateAddNodes();
|
||||
}
|
||||
|
||||
void Dimension::reflowSunlightAroundSolid(glm::ivec3 pos) {
|
||||
auto startChunk = getChunk(Space::Chunk::world::fromBlock(pos));
|
||||
auto ind = Space::Block::index(pos);
|
||||
unsigned int light = startChunk->getSunlight(ind);
|
||||
startChunk->setSunlight(ind, 0);
|
||||
lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, light, startChunk.get());
|
||||
propogateRemoveNodes();
|
||||
void Dimension::removeSunlight(glm::ivec3 pos) {
|
||||
auto chunk = getChunk(Space::Chunk::world::fromBlock(pos));
|
||||
unsigned int ind = Space::Block::index(pos);
|
||||
unsigned int light = chunk->getSunlight(ind);
|
||||
|
||||
chunk->setSunlight(ind, 0);
|
||||
lightRemoveQueue[SUNLIGHT_CHANNEL].emplace(ind, light, chunk.get());
|
||||
}
|
||||
|
||||
void Dimension::setSunlight(glm::ivec3 pos, unsigned char level) {
|
||||
auto chunk = getChunk(Space::Chunk::world::fromBlock(pos));
|
||||
unsigned int ind = Space::Block::index(pos);
|
||||
|
||||
chunk->setSunlight(ind, level);
|
||||
lightAddQueue[SUNLIGHT_CHANNEL].emplace(ind, chunk.get());
|
||||
}
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
class Dimension : public DimensionBase {
|
||||
public:
|
||||
typedef std::unordered_set<glm::ivec3, Vec::ivec3> relitChunks;
|
||||
|
||||
Dimension(DefinitionAtlas& defs) : DimensionBase(defs) {}
|
||||
|
||||
// Override setBlock to update lighting.
|
||||
|
@ -21,24 +23,27 @@ public:
|
|||
|
||||
// Calculate light propogation around MapBlock edges,
|
||||
// Called after a new mapblock is inserted into the dimension.
|
||||
void calculateEdgeLight(glm::ivec3 mbPos);
|
||||
relitChunks calculateEdgeLight(glm::ivec3 mbPos);
|
||||
|
||||
protected:
|
||||
virtual std::unordered_set<glm::ivec3, Vec::ivec3> propogateAddNodes();
|
||||
virtual std::unordered_set<glm::ivec3, Vec::ivec3> propogateRemoveNodes();
|
||||
virtual relitChunks propogateAddNodes();
|
||||
virtual relitChunks propogateRemoveNodes();
|
||||
|
||||
private:
|
||||
// Helper methods to speed up light propagation.
|
||||
// Lighting functions
|
||||
|
||||
static inline bool containsWorldPos(BlockChunk* chunk, glm::ivec3 pos);
|
||||
inline glm::ivec4 getLight(glm::ivec3 worldPos, BlockChunk* chunk = nullptr);
|
||||
|
||||
// Add and remove block light sources.
|
||||
void calculateHorizontalEdge(std::shared_ptr<BlockChunk> a, std::shared_ptr<BlockChunk> b);
|
||||
void calculateVerticalEdge(std::shared_ptr<BlockChunk> above, std::shared_ptr<BlockChunk> below);
|
||||
|
||||
inline void addBlockLight(glm::ivec3 pos, glm::ivec3 light);
|
||||
inline void removeBlockLight(glm::ivec3 pos);
|
||||
|
||||
// Special methods to recalculate lights after world manipulation.
|
||||
inline void reflowLightThroughTransparent(glm::ivec3 pos);
|
||||
inline void reflowSunlightAroundSolid(glm::ivec3 pos);
|
||||
inline void reflowLight(glm::ivec3 pos);
|
||||
inline void removeSunlight(glm::ivec3 pos);
|
||||
inline void setSunlight(glm::ivec3 pos, unsigned char level);
|
||||
|
||||
struct LightAddNode {
|
||||
LightAddNode(unsigned short index, BlockChunk* chunk) : index(index), chunk(chunk) {};
|
||||
|
|
|
@ -29,6 +29,11 @@ void DimensionBase::removeMapBlock(glm::ivec3 pos) {
|
|||
if (region->count == 0) removeRegion(Space::Region::world::fromMapBlock(pos));
|
||||
}
|
||||
|
||||
bool DimensionBase::mapBlockGenerated(glm::ivec3 mapBlockPosition) {
|
||||
auto mb = getMapBlock(mapBlockPosition);
|
||||
return mb && mb->generated;
|
||||
}
|
||||
|
||||
std::shared_ptr<BlockChunk> DimensionBase::getChunk(glm::ivec3 chunkPosition) {
|
||||
auto mapBlock = getMapBlock(Space::MapBlock::world::fromChunk(chunkPosition));
|
||||
if (!mapBlock) return nullptr;
|
||||
|
@ -77,4 +82,4 @@ std::shared_ptr<MapBlock> DimensionBase::getOrCreateMapBlock(glm::ivec3 mapBlock
|
|||
if ((*region)[index] != nullptr) return (*region)[index];
|
||||
(*region).set(index, std::make_shared<MapBlock>(mapBlockPosition));
|
||||
return (*region)[index];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ public:
|
|||
std::shared_ptr<MapBlock> getMapBlock(glm::ivec3 mapBlockPosition);
|
||||
virtual void removeMapBlock(glm::ivec3 pos);
|
||||
|
||||
bool mapBlockGenerated(glm::ivec3 mapBlockPosition);
|
||||
|
||||
std::shared_ptr<BlockChunk> getChunk(glm::ivec3 chunkPosition);
|
||||
virtual void setChunk(std::shared_ptr<BlockChunk> chunk);
|
||||
virtual void removeChunk(glm::ivec3 pos);
|
||||
|
|
Loading…
Reference in New Issue