mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-31 18:31:04 +00:00
Sort out incorrect logic in MeshUpdateQueue::addBlock()
This commit is contained in:
parent
1d53ec4892
commit
54d48decad
2 changed files with 58 additions and 27 deletions
|
@ -29,6 +29,8 @@ void QueuedMeshUpdate::retrieveBlocks(Map *map, u16 cell_size)
|
||||||
assert(map_blocks.size() == total); // must not change
|
assert(map_blocks.size() == total); // must not change
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
v3s16 pos;
|
v3s16 pos;
|
||||||
|
// order is not important, but it must be consistent
|
||||||
|
// note the extra margin!
|
||||||
for (pos.X = p.X - 1; pos.X <= p.X + cell_size; pos.X++)
|
for (pos.X = p.X - 1; pos.X <= p.X + cell_size; pos.X++)
|
||||||
for (pos.Z = p.Z - 1; pos.Z <= p.Z + cell_size; pos.Z++)
|
for (pos.Z = p.Z - 1; pos.Z <= p.Z + cell_size; pos.Z++)
|
||||||
for (pos.Y = p.Y - 1; pos.Y <= p.Y + cell_size; pos.Y++) {
|
for (pos.Y = p.Y - 1; pos.Y <= p.Y + cell_size; pos.Y++) {
|
||||||
|
@ -43,6 +45,20 @@ void QueuedMeshUpdate::retrieveBlocks(Map *map, u16 cell_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QueuedMeshUpdate::checkSkip(u16 cell_size)
|
||||||
|
{
|
||||||
|
bool all_air = true;
|
||||||
|
const v3s16 p_max = p + v3s16(cell_size);
|
||||||
|
assert(!map_blocks.empty());
|
||||||
|
for (auto *block : map_blocks) {
|
||||||
|
// ignore extra margin
|
||||||
|
if (block && block->getPos() >= p && block->getPos() < p_max) {
|
||||||
|
all_air &= block->isAir();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all_air;
|
||||||
|
}
|
||||||
|
|
||||||
void QueuedMeshUpdate::dropBlocks()
|
void QueuedMeshUpdate::dropBlocks()
|
||||||
{
|
{
|
||||||
for (auto *block : map_blocks) {
|
for (auto *block : map_blocks) {
|
||||||
|
@ -52,6 +68,19 @@ void QueuedMeshUpdate::dropBlocks()
|
||||||
map_blocks.clear();
|
map_blocks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct DroppingDeleter {
|
||||||
|
void operator() (QueuedMeshUpdate *q) {
|
||||||
|
if (q)
|
||||||
|
q->dropBlocks();
|
||||||
|
delete q;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simple helper to avoid messing up the refcounting
|
||||||
|
using UnqueuedMeshUpdate = std::unique_ptr<QueuedMeshUpdate, DroppingDeleter>;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MeshUpdateQueue
|
MeshUpdateQueue
|
||||||
*/
|
*/
|
||||||
|
@ -76,17 +105,15 @@ MeshUpdateQueue::~MeshUpdateQueue()
|
||||||
bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server,
|
bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server,
|
||||||
bool urgent, bool from_neighbor)
|
bool urgent, bool from_neighbor)
|
||||||
{
|
{
|
||||||
// FIXME: with cell_size > 1 there isn't a "main block" and this check is
|
// If block that causes update does not exist, skip.
|
||||||
// probably incorrect and broken
|
if (!map->getBlockNoCreateNoEx(p))
|
||||||
MapBlock *main_block = map->getBlockNoCreateNoEx(p);
|
|
||||||
if (!main_block)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MeshGrid mesh_grid = m_client->getMeshGrid();
|
const MeshGrid mesh_grid = m_client->getMeshGrid();
|
||||||
|
|
||||||
// Mesh is placed at the corner block of a chunk
|
// Mesh is placed at the corner block of a chunk
|
||||||
// (where all coordinate are divisible by the chunk size)
|
// (where all coordinate are divisible by the chunk size)
|
||||||
v3s16 mesh_position = mesh_grid.getMeshPos(p);
|
const v3s16 mesh_position = mesh_grid.getMeshPos(p);
|
||||||
|
|
||||||
MutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
|
|
||||||
|
@ -113,21 +140,9 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Air blocks won't suddenly become visible due to a neighbor update, so
|
Grab the relevant blocks first
|
||||||
skip those.
|
|
||||||
Note: this can be extended with more precise checks in the future
|
|
||||||
*/
|
*/
|
||||||
if (from_neighbor && mesh_grid.cell_size == 1 && main_block->isAir()) {
|
UnqueuedMeshUpdate q{new QueuedMeshUpdate()};
|
||||||
assert(!ack_block_to_server);
|
|
||||||
m_urgents.erase(mesh_position);
|
|
||||||
g_profiler->add("MeshUpdateQueue: updates skipped", 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Add the block
|
|
||||||
*/
|
|
||||||
QueuedMeshUpdate *q = new QueuedMeshUpdate;
|
|
||||||
q->p = mesh_position;
|
q->p = mesh_position;
|
||||||
if (ack_block_to_server)
|
if (ack_block_to_server)
|
||||||
q->ack_list.push_back(p);
|
q->ack_list.push_back(p);
|
||||||
|
@ -135,7 +150,21 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server,
|
||||||
q->crack_pos = m_client->getCrackPos();
|
q->crack_pos = m_client->getCrackPos();
|
||||||
q->urgent = urgent;
|
q->urgent = urgent;
|
||||||
q->retrieveBlocks(map, mesh_grid.cell_size);
|
q->retrieveBlocks(map, mesh_grid.cell_size);
|
||||||
m_queue.push_back(q);
|
|
||||||
|
/*
|
||||||
|
Air blocks won't suddenly become visible due to a neighbor update, so
|
||||||
|
skip those.
|
||||||
|
Note: this can be extended with more precise checks in the future
|
||||||
|
*/
|
||||||
|
if (from_neighbor && q->checkSkip(mesh_grid.cell_size)) {
|
||||||
|
assert(!ack_block_to_server);
|
||||||
|
m_urgents.erase(mesh_position);
|
||||||
|
g_profiler->add("MeshUpdateQueue: updates skipped", 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put into queue, pointer moved from `q`.
|
||||||
|
m_queue.push_back(q.release());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -186,12 +215,7 @@ void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
|
||||||
|
|
||||||
data->fillBlockDataBegin(q->p);
|
data->fillBlockDataBegin(q->p);
|
||||||
|
|
||||||
v3s16 pos;
|
for (auto *block : q->map_blocks) {
|
||||||
int i = 0;
|
|
||||||
for (pos.X = q->p.X - 1; pos.X <= q->p.X + mesh_grid.cell_size; pos.X++)
|
|
||||||
for (pos.Z = q->p.Z - 1; pos.Z <= q->p.Z + mesh_grid.cell_size; pos.Z++)
|
|
||||||
for (pos.Y = q->p.Y - 1; pos.Y <= q->p.Y + mesh_grid.cell_size; pos.Y++) {
|
|
||||||
MapBlock *block = q->map_blocks[i++];
|
|
||||||
if (block)
|
if (block)
|
||||||
block->copyTo(data->m_vmanip);
|
block->copyTo(data->m_vmanip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,13 @@ struct QueuedMeshUpdate
|
||||||
* @note not done by destructor, since this is only safe on main thread
|
* @note not done by destructor, since this is only safe on main thread
|
||||||
*/
|
*/
|
||||||
void dropBlocks();
|
void dropBlocks();
|
||||||
|
/**
|
||||||
|
* Check if the blocks that would comprise the mesh are all air, so the
|
||||||
|
* update can be skipped entirely.
|
||||||
|
* @param cell_size mesh grid cell size
|
||||||
|
* @return (true = all air)
|
||||||
|
*/
|
||||||
|
bool checkSkip(u16 cell_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue