|
|
|
|
@@ -24,6 +24,8 @@ SOFTWARE.
|
|
|
|
|
|
|
|
|
|
#include "game/world/chunk_manager.hpp"
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
|
|
#include "common/network/network_manager.hpp"
|
|
|
|
|
#include "game/engine/engine.hpp"
|
|
|
|
|
#include "game/engine/game_config.hpp"
|
|
|
|
|
@@ -31,6 +33,10 @@ SOFTWARE.
|
|
|
|
|
#include "game/renderer/shader.hpp"
|
|
|
|
|
#include "game/world/local_player.hpp"
|
|
|
|
|
|
|
|
|
|
// TODO: Load this from GameConfig
|
|
|
|
|
#define VIEW_RANGE 2
|
|
|
|
|
#define VIEW_AREA_SIZE VIEW_RANGE*2
|
|
|
|
|
|
|
|
|
|
using namespace polygun::world;
|
|
|
|
|
|
|
|
|
|
ChunkManager::ChunkManager(engine::Engine* engine, engine::TextureAtlas& texture_atlas) :
|
|
|
|
|
@@ -38,14 +44,17 @@ ChunkManager::ChunkManager(engine::Engine* engine, engine::TextureAtlas& texture
|
|
|
|
|
world::ChunkManagerBase(),
|
|
|
|
|
m_engine(engine),
|
|
|
|
|
m_texture_atlas(texture_atlas),
|
|
|
|
|
m_loaded_area(math::Rect3D::with_center(math::Vector3f(0), math::Vector3f(VIEW_AREA_SIZE))),
|
|
|
|
|
m_chunk_cache(-1),
|
|
|
|
|
m_pending_chunks(),
|
|
|
|
|
m_loaded_chunks(new Chunk*[VIEW_AREA_SIZE*VIEW_AREA_SIZE*VIEW_AREA_SIZE]),
|
|
|
|
|
m_dummy_chunk(engine, this, 0.0f),
|
|
|
|
|
m_updated_chunks(0),
|
|
|
|
|
m_greedy_chunk_shader(engine->get_master_renderer()->create_shader()),
|
|
|
|
|
m_chunk_shader(engine->get_master_renderer()->create_shader()),
|
|
|
|
|
m_network_manager(nullptr)
|
|
|
|
|
{
|
|
|
|
|
memset(m_loaded_chunks, 0, VIEW_AREA_SIZE*VIEW_AREA_SIZE*VIEW_AREA_SIZE*sizeof(Chunk*));
|
|
|
|
|
m_greedy_chunk_shader->load_from_file("greedy_chunk");
|
|
|
|
|
m_chunk_shader->load_from_file("chunk");
|
|
|
|
|
}
|
|
|
|
|
@@ -53,6 +62,8 @@ ChunkManager::ChunkManager(engine::Engine* engine, engine::TextureAtlas& texture
|
|
|
|
|
ChunkManager::~ChunkManager() {
|
|
|
|
|
delete m_chunk_shader;
|
|
|
|
|
delete m_greedy_chunk_shader;
|
|
|
|
|
unload_all_chunks();
|
|
|
|
|
delete[] m_loaded_chunks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChunkManager::on_packet(network::NetworkPacket& packet) {
|
|
|
|
|
@@ -68,12 +79,15 @@ void ChunkManager::on_packet(network::NetworkPacket& packet) {
|
|
|
|
|
if(it==m_pending_chunks.end())
|
|
|
|
|
break;
|
|
|
|
|
m_pending_chunks.erase(it);
|
|
|
|
|
std::unique_ptr<Chunk> chunk = std::make_unique<Chunk>(m_engine, this, m_texture_atlas.get_texture_unit_size(), false);
|
|
|
|
|
if(!m_loaded_area.contains(pos.convert<float>()))
|
|
|
|
|
break;
|
|
|
|
|
Chunk* const chunk = new Chunk(m_engine, this, m_texture_atlas.get_texture_unit_size(), false);
|
|
|
|
|
chunk->set_pos(pos);
|
|
|
|
|
chunk->set_modified(true);
|
|
|
|
|
packet.read(chunk.get());
|
|
|
|
|
m_loaded_chunks.push_back(std::move(chunk));
|
|
|
|
|
packet.read(chunk);
|
|
|
|
|
LOG_VERBOSE("Received data for chunk at %d %d %d", pos[0], pos[1], pos[2]);
|
|
|
|
|
pos-=m_loaded_area.get_pos().convert<int>();
|
|
|
|
|
m_loaded_chunks[pos[2]*VIEW_AREA_SIZE*VIEW_AREA_SIZE+pos[1]*VIEW_AREA_SIZE+pos[0]] = chunk;
|
|
|
|
|
m_updated_chunks++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -108,29 +122,75 @@ void ChunkManager::on_packet(network::NetworkPacket& packet) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ChunkManager::on_local_player_move(const LocalPlayer& player) {
|
|
|
|
|
// TODO: Make sure that chunk visible by other local players won't get unloaded
|
|
|
|
|
math::Vector3f pos = player.get_position();
|
|
|
|
|
pos[0] = std::floor(pos[0]/Chunk::CHUNK_SIZE);
|
|
|
|
|
pos[1] = std::floor(pos[1]/Chunk::CHUNK_SIZE);
|
|
|
|
|
pos[2] = std::floor(pos[2]/Chunk::CHUNK_SIZE);
|
|
|
|
|
// TODO: Load this from GameConfig
|
|
|
|
|
const unsigned VIEW_RANGE = 2;
|
|
|
|
|
for(int x = pos[0]-VIEW_RANGE; x<=pos[0]+VIEW_RANGE; x++) {
|
|
|
|
|
for(int y = pos[1]-VIEW_RANGE; y<=pos[1]+VIEW_RANGE; y++) {
|
|
|
|
|
for(int z = pos[2]-VIEW_RANGE; z<=pos[2]+VIEW_RANGE; z++) {
|
|
|
|
|
request_chunk(math::Vector3i{x, y, z});
|
|
|
|
|
const math::Rect3D new_loaded_area = math::Rect3D::with_center(pos, math::Vector3f(VIEW_AREA_SIZE));
|
|
|
|
|
const math::Vector3i diff = new_loaded_area.get_pos().convert<int>()-m_loaded_area.get_pos().convert<int>();
|
|
|
|
|
m_loaded_area = new_loaded_area;
|
|
|
|
|
|
|
|
|
|
acquire();
|
|
|
|
|
if(std::abs(diff[0])>=VIEW_AREA_SIZE || std::abs(diff[1])>=VIEW_AREA_SIZE || std::abs(diff[2])>=VIEW_AREA_SIZE)
|
|
|
|
|
unload_all_chunks();
|
|
|
|
|
else {
|
|
|
|
|
if(diff[0]!=0) {
|
|
|
|
|
const int start = diff[0]>0?diff[0]:(VIEW_AREA_SIZE+diff[0]-1);
|
|
|
|
|
const int end = diff[0]>0?VIEW_AREA_SIZE:0;
|
|
|
|
|
for(int x = start; diff[0]>0?(x<end):(x>=end); x+=diff[0]) {
|
|
|
|
|
for(int y = 0; y<VIEW_AREA_SIZE; y++) {
|
|
|
|
|
for(int z = 0; z<VIEW_AREA_SIZE; z++) {
|
|
|
|
|
Chunk*& old_chunk_ptr = m_loaded_chunks[z*VIEW_AREA_SIZE*VIEW_AREA_SIZE+y*VIEW_AREA_SIZE+x-diff[0]];
|
|
|
|
|
if(old_chunk_ptr)
|
|
|
|
|
delete old_chunk_ptr;
|
|
|
|
|
Chunk*& moved_chunk_ptr = m_loaded_chunks[z*VIEW_AREA_SIZE*VIEW_AREA_SIZE+y*VIEW_AREA_SIZE+x];
|
|
|
|
|
old_chunk_ptr = moved_chunk_ptr;
|
|
|
|
|
moved_chunk_ptr = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(diff[1]!=0) {
|
|
|
|
|
const int start = diff[1]>0?diff[1]:(VIEW_AREA_SIZE+diff[1]-1);
|
|
|
|
|
const int end = diff[1]>0?VIEW_AREA_SIZE:0;
|
|
|
|
|
for(int x = 0; x<VIEW_AREA_SIZE; x++) {
|
|
|
|
|
for(int y = start; diff[1]>0?(y<end):(y>=end); y+=diff[1]) {
|
|
|
|
|
for(int z = 0; z<VIEW_AREA_SIZE; z++) {
|
|
|
|
|
Chunk*& old_chunk_ptr = m_loaded_chunks[z*VIEW_AREA_SIZE*VIEW_AREA_SIZE+(y-diff[1])*VIEW_AREA_SIZE+x];
|
|
|
|
|
if(old_chunk_ptr)
|
|
|
|
|
delete old_chunk_ptr;
|
|
|
|
|
Chunk*& moved_chunk_ptr = m_loaded_chunks[z*VIEW_AREA_SIZE*VIEW_AREA_SIZE+y*VIEW_AREA_SIZE+x];
|
|
|
|
|
old_chunk_ptr = moved_chunk_ptr;
|
|
|
|
|
moved_chunk_ptr = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(diff[2]!=0) {
|
|
|
|
|
const int start = diff[2]>0?diff[2]:(VIEW_AREA_SIZE+diff[2]-1);
|
|
|
|
|
const int end = diff[2]>0?VIEW_AREA_SIZE:0;
|
|
|
|
|
for(int x = 0; x<VIEW_AREA_SIZE; x++) {
|
|
|
|
|
for(int y = 0; y<VIEW_AREA_SIZE; y++) {
|
|
|
|
|
for(int z = start; diff[2]>0?(z<end):(z>=end); z+=diff[2]) {
|
|
|
|
|
Chunk*& old_chunk_ptr = m_loaded_chunks[(z-diff[2])*VIEW_AREA_SIZE*VIEW_AREA_SIZE+y*VIEW_AREA_SIZE+x];
|
|
|
|
|
if(old_chunk_ptr)
|
|
|
|
|
delete old_chunk_ptr;
|
|
|
|
|
Chunk*& moved_chunk_ptr = m_loaded_chunks[z*VIEW_AREA_SIZE*VIEW_AREA_SIZE+y*VIEW_AREA_SIZE+x];
|
|
|
|
|
old_chunk_ptr = moved_chunk_ptr;
|
|
|
|
|
moved_chunk_ptr = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// TODO: Make sure that chunk visible by other local players won't get unloaded
|
|
|
|
|
// FIXME: Chunk unloading is not symmertical
|
|
|
|
|
acquire();
|
|
|
|
|
for(size_t i = 0; i<m_loaded_chunks.size(); i++) {
|
|
|
|
|
const Chunk& chunk = *m_loaded_chunks[i];
|
|
|
|
|
if(std::abs(pos[0]-chunk.get_pos()[0])>VIEW_RANGE || std::abs(pos[1]-chunk.get_pos()[1])>VIEW_RANGE || std::abs(pos[2]-chunk.get_pos()[2])>VIEW_RANGE) {
|
|
|
|
|
if(static_cast<size_t>(m_chunk_cache)==i)
|
|
|
|
|
m_chunk_cache = -1;
|
|
|
|
|
m_loaded_chunks.erase(m_loaded_chunks.begin()+i);
|
|
|
|
|
i--;
|
|
|
|
|
for(int x = 0; x<VIEW_AREA_SIZE; x++) {
|
|
|
|
|
for(int y = 0; y<VIEW_AREA_SIZE; y++) {
|
|
|
|
|
for(int z = 0; z<VIEW_AREA_SIZE; z++) {
|
|
|
|
|
if(!m_loaded_chunks[z*VIEW_AREA_SIZE*VIEW_AREA_SIZE+y*VIEW_AREA_SIZE+x])
|
|
|
|
|
request_chunk(math::Vector3i{x, y, z}+m_loaded_area.get_pos().convert<int>());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
release();
|
|
|
|
|
@@ -138,12 +198,14 @@ void ChunkManager::on_local_player_move(const LocalPlayer& player) {
|
|
|
|
|
|
|
|
|
|
void ChunkManager::update_chunks() {
|
|
|
|
|
acquire();
|
|
|
|
|
for(std::unique_ptr<Chunk>& chunk : m_loaded_chunks) {
|
|
|
|
|
if(chunk->is_modified()) {
|
|
|
|
|
for(unsigned i = 0; i<VIEW_AREA_SIZE*VIEW_AREA_SIZE*VIEW_AREA_SIZE; i++) {
|
|
|
|
|
Chunk* const chunk = m_loaded_chunks[i];
|
|
|
|
|
if(chunk && chunk->is_modified()) {
|
|
|
|
|
chunk->generate_mesh();
|
|
|
|
|
chunk->set_modified(false);
|
|
|
|
|
m_updated_chunks--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
release();
|
|
|
|
|
}
|
|
|
|
|
@@ -152,8 +214,9 @@ void ChunkManager::render() {
|
|
|
|
|
acquire();
|
|
|
|
|
renderer::MeshRenderer* const mesh_renderer = m_engine->get_mesh_renderer();
|
|
|
|
|
mesh_renderer->set_shader(engine::GameConfig::get().m_meshing_mode==engine::GameConfig::MeshingMode::MESHING_MODE_GREEDY?m_greedy_chunk_shader:m_chunk_shader);
|
|
|
|
|
for(std::unique_ptr<Chunk>& chunk : m_loaded_chunks) {
|
|
|
|
|
if(!chunk->has_mesh())
|
|
|
|
|
for(unsigned i = 0; i<VIEW_AREA_SIZE*VIEW_AREA_SIZE*VIEW_AREA_SIZE; i++) {
|
|
|
|
|
Chunk* const chunk = m_loaded_chunks[i];
|
|
|
|
|
if(!chunk || !chunk->has_mesh())
|
|
|
|
|
continue;
|
|
|
|
|
mesh_renderer->translate(chunk->get_pos().convert<float>()*math::Vector3f(Chunk::CHUNK_SIZE));
|
|
|
|
|
chunk->render(m_texture_atlas.get_atlas_texture());
|
|
|
|
|
@@ -178,14 +241,6 @@ void ChunkManager::try_fill_node(const math::Vector3i& from, const math::Vector3
|
|
|
|
|
|
|
|
|
|
void ChunkManager::request_chunk(const math::Vector3i& pos) {
|
|
|
|
|
acquire();
|
|
|
|
|
std::vector<std::unique_ptr<Chunk>>::iterator it = std::find_if(m_loaded_chunks.begin(), m_loaded_chunks.end(), [pos](const std::unique_ptr<Chunk>& chunk) {
|
|
|
|
|
return chunk->get_pos()==pos;
|
|
|
|
|
});
|
|
|
|
|
if(it!=m_loaded_chunks.end()) {
|
|
|
|
|
release();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<math::Vector3i>::iterator it2 = std::find(m_pending_chunks.begin(), m_pending_chunks.end(), pos);
|
|
|
|
|
if(it2!=m_pending_chunks.end()) {
|
|
|
|
|
release();
|
|
|
|
|
@@ -201,22 +256,26 @@ void ChunkManager::request_chunk(const math::Vector3i& pos) {
|
|
|
|
|
|
|
|
|
|
Chunk& ChunkManager::get_chunk(const math::Vector3i& pos) {
|
|
|
|
|
acquire();
|
|
|
|
|
Chunk* const chunk = get_loaded_chunk(pos);
|
|
|
|
|
release();
|
|
|
|
|
if(!chunk)
|
|
|
|
|
|
|
|
|
|
if(!m_loaded_area.contains(pos.convert<float>())) {
|
|
|
|
|
release();
|
|
|
|
|
return m_dummy_chunk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const math::Vector3i local_chunk_pos = pos-m_loaded_area.get_pos().convert<int>();
|
|
|
|
|
Chunk* chunk = m_loaded_chunks[local_chunk_pos[2]*VIEW_AREA_SIZE*VIEW_AREA_SIZE+local_chunk_pos[1]*VIEW_AREA_SIZE+local_chunk_pos[0]];
|
|
|
|
|
if(!chunk)
|
|
|
|
|
chunk = &m_dummy_chunk;
|
|
|
|
|
|
|
|
|
|
release();
|
|
|
|
|
return *chunk;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Chunk* ChunkManager::get_loaded_chunk(const math::Vector3i& pos) {
|
|
|
|
|
if(m_chunk_cache>=0 && m_loaded_chunks[m_chunk_cache]->get_pos()==pos)
|
|
|
|
|
return m_loaded_chunks[m_chunk_cache].get();
|
|
|
|
|
std::vector<std::unique_ptr<Chunk>>::iterator it = std::find_if(m_loaded_chunks.begin(), m_loaded_chunks.end(), [pos](const std::unique_ptr<Chunk>& chunk) {
|
|
|
|
|
return chunk->get_pos()==pos;
|
|
|
|
|
});
|
|
|
|
|
if(it!=m_loaded_chunks.end()) {
|
|
|
|
|
m_chunk_cache = m_loaded_chunks.end()-it;
|
|
|
|
|
return it->get();
|
|
|
|
|
void ChunkManager::unload_all_chunks() {
|
|
|
|
|
for(size_t i = 0; i<VIEW_AREA_SIZE*VIEW_AREA_SIZE*VIEW_AREA_SIZE; i++) {
|
|
|
|
|
if(m_loaded_chunks[i]) {
|
|
|
|
|
delete m_loaded_chunks[i];
|
|
|
|
|
m_loaded_chunks[i] = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|