@@ -17,6 +17,13 @@ class Chunk { | |||
public: | |||
using RelPos = TilePos; | |||
// What does this chunk want the world gen to do after a tick? | |||
enum class TickAction { | |||
DEACTIVATE, | |||
DELETE, | |||
NOTHING, | |||
}; | |||
Chunk(ChunkPos pos): pos_(pos) { | |||
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]); | |||
} | |||
@@ -30,10 +37,11 @@ public: | |||
void compress(); | |||
void decompress(); | |||
void draw(const Context &ctx, Win &win); | |||
void tick(float dt); | |||
TickAction tick(float dt); | |||
bool keepActive(); // Returns true if chunk was inactive | |||
bool isActive() { return deactivate_timer_ > 0; } | |||
bool keepActive(); // Returns true if chunk was inactive | |||
void markModified() { is_modified_ = true; } | |||
ChunkPos pos_; | |||
@@ -51,6 +59,7 @@ private: | |||
ssize_t compressed_size_ = -1; // -1 if not compressed, a positive number if compressed | |||
bool need_render_ = false; | |||
float deactivate_timer_ = DEACTIVATE_INTERVAL; | |||
bool is_modified_ = false; | |||
CPtr<SDL_Texture, SDL_DestroyTexture> texture_; | |||
}; |
@@ -2,6 +2,7 @@ | |||
#include <zlib.h> | |||
#include <stdint.h> | |||
#include <assert.h> | |||
#include "log.h" | |||
#include "Clock.h" | |||
@@ -57,11 +58,11 @@ void Chunk::compress() { | |||
info | |||
<< "Compressed chunk " << pos_ << " from " | |||
<< CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID) << " bytes " | |||
<< "to " << destlen << " bytes."; | |||
<< "to " << destlen << " bytes"; | |||
} else if (ret == Z_BUF_ERROR) { | |||
info | |||
<< "Didn't compress chunk " << pos_ << " " | |||
<< "because compressing it would've made it bigger."; | |||
<< "because compressing it would've made it bigger"; | |||
} else { | |||
warn << "Chunk compression error: " << ret << " (Out of memory?)"; | |||
} | |||
@@ -153,14 +154,18 @@ void Chunk::draw(const Context &ctx, Win &win) { | |||
texture_.get(), &rect); | |||
} | |||
void Chunk::tick(float dt) { | |||
if (deactivate_timer_ <= 0) | |||
return; | |||
Chunk::TickAction Chunk::tick(float dt) { | |||
assert(isActive()); | |||
deactivate_timer_ -= dt; | |||
if (deactivate_timer_ <= 0) { | |||
compress(); | |||
if (is_modified_) | |||
return TickAction::DEACTIVATE; | |||
else | |||
return TickAction::DELETE; | |||
} | |||
return TickAction::NOTHING; | |||
} | |||
bool Chunk::keepActive() { |
@@ -28,7 +28,12 @@ static Chunk::RelPos relPos(TilePos pos) { | |||
} | |||
Context WorldPlane::getContext() { | |||
return { .game = *world_->game_, .world = *world_, .plane = *this, .resources = world_->resources_ }; | |||
return { | |||
.game = *world_->game_, | |||
.world = *world_, | |||
.plane = *this, | |||
.resources = world_->resources_ | |||
}; | |||
} | |||
Entity *WorldPlane::spawnEntity(const std::string &name, const SRF ¶ms) { | |||
@@ -81,7 +86,11 @@ void WorldPlane::setTileID(TilePos pos, Tile::ID id) { | |||
Chunk &chunk = getChunk(chunkPos(pos)); | |||
Chunk::RelPos rp = relPos(pos); | |||
chunk.setTileID(rp, id, world_->getTileByID(id).image_.texture_.get()); | |||
Tile::ID old = chunk.getTileID(rp); | |||
if (id != old) { | |||
chunk.setTileID(rp, id, world_->getTileByID(id).image_.texture_.get()); | |||
chunk.markModified(); | |||
} | |||
if (active_chunks_.find(&chunk) == active_chunks_.end()) { | |||
active_chunks_.insert(&chunk); | |||
@@ -210,10 +219,28 @@ void WorldPlane::tick(float dt) { | |||
for (auto &ent: entities_) | |||
ent->tick(getContext(), dt); | |||
for (auto &chunk: active_chunks_) | |||
chunk->tick(dt); | |||
std::erase_if(active_chunks_, [](Chunk *chunk) { return !chunk->isActive(); }); | |||
auto iter = active_chunks_.begin(); | |||
auto last = active_chunks_.end(); | |||
while (iter != last) { | |||
auto &chunk = *iter; | |||
auto action = chunk->tick(dt); | |||
switch (action) { | |||
case Chunk::TickAction::DEACTIVATE: | |||
info << "Compressing inactive modified chunk " << chunk->pos_; | |||
chunk->compress(); | |||
iter = active_chunks_.erase(iter); | |||
break; | |||
case Chunk::TickAction::DELETE: | |||
info << "Deleting inactive unmodified chunk " << chunk->pos_; | |||
chunks_.erase(chunk->pos_); | |||
iter = active_chunks_.erase(iter); | |||
break; | |||
case Chunk::TickAction::NOTHING: | |||
++iter; | |||
break; | |||
} | |||
} | |||
} | |||
void WorldPlane::debugBox(TilePos pos) { |