Improve random Chunk lookup in client
This commit is contained in:
parent
5b25027e51
commit
3b4f29f53f
@ -25,9 +25,6 @@ SOFTWARE.
|
||||
#ifndef POLYGUN_WORLD_CHUNK_MANAGER_BASE_HPP
|
||||
#define POLYGUN_WORLD_CHUNK_MANAGER_BASE_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "common/math/rect3d.hpp"
|
||||
|
||||
namespace polygun::world {
|
||||
@ -45,9 +42,6 @@ namespace polygun::world {
|
||||
math::Rect3D get_node_bbox(const math::Vector3i& node_pos);
|
||||
|
||||
virtual Chunk& get_chunk(const math::Vector3i& pos) = 0;
|
||||
|
||||
protected:
|
||||
std::vector<std::unique_ptr<Chunk>> m_loaded_chunks;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -68,8 +68,10 @@ namespace polygun::world {
|
||||
private:
|
||||
engine::Engine* m_engine;
|
||||
engine::TextureAtlas& m_texture_atlas;
|
||||
math::Rect3D m_loaded_area;
|
||||
int m_chunk_cache;
|
||||
std::vector<math::Vector3i> m_pending_chunks;
|
||||
Chunk** m_loaded_chunks;
|
||||
Chunk m_dummy_chunk;
|
||||
unsigned m_updated_chunks;
|
||||
renderer::Shader* m_greedy_chunk_shader;
|
||||
@ -77,7 +79,7 @@ namespace polygun::world {
|
||||
network::NetworkManager* m_network_manager;
|
||||
|
||||
private:
|
||||
Chunk* get_loaded_chunk(const math::Vector3i& pos);
|
||||
void unload_all_chunks();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,8 @@ ChunkManager::ChunkManager(Server& server) :
|
||||
m_map_read_only(true),
|
||||
m_last_write(time(nullptr)),
|
||||
m_map_chunk_count(0),
|
||||
m_map_chunk_headers_array_offset(0)
|
||||
m_map_chunk_headers_array_offset(0),
|
||||
m_loaded_chunks()
|
||||
{}
|
||||
|
||||
ChunkManager::~ChunkManager() {
|
||||
|
@ -27,7 +27,9 @@ SOFTWARE.
|
||||
|
||||
#include "common/world/chunk_manager_base.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace polygun::server {
|
||||
class Server;
|
||||
@ -50,6 +52,7 @@ namespace polygun::server {
|
||||
time_t m_last_write;
|
||||
uint32_t m_map_chunk_count;
|
||||
uint64_t m_map_chunk_headers_array_offset;
|
||||
std::vector<std::unique_ptr<world::Chunk>> m_loaded_chunks;
|
||||
|
||||
private:
|
||||
void load_header();
|
||||
|
Loading…
x
Reference in New Issue
Block a user