Performance optimizations: sound caching, renderer culling, entity and lighting improvements

- Sound engine: cache filesystem probe results to avoid repeated file existence checks; add MA_SOUND_FLAG_DECODE for pre-decoded playback
- Level renderer: column-level frustum culling, compact visible chunk lists to skip empty iteration, lightweight second-pass render path, early-out for non-dirty chunks, scaled recheck period at high render distances
- Entity: cache shared_from_this() to reduce reference counting overhead in move() and checkInsideTiles()
- Level: skip checkLight() when tile light properties unchanged; enable entity locking on all platforms (not just Vita)
- LevelChunk: only rescan min height when the minimum column changes; defer lightGap processing
- LivingEntity: use raw pointer cast instead of dynamic_pointer_cast; cache friction tile lookup
- ServerPlayerGameMode: return whether block was destroyed to avoid redundant tile update packets
This commit is contained in:
Revela
2026-03-18 17:22:04 -05:00
parent 80ba2e0762
commit 0ba923f085
12 changed files with 311 additions and 170 deletions
+14 -20
View File
@@ -817,8 +817,9 @@ void LevelChunk::recalcHeight(int x, int yStart, int z)
{
minHeight = y;
}
else
else if (yOld == minHeight)
{
// Only rescan when the column that was at the minimum changed height
int min = Level::maxBuildHeight - 1;
for (int _x = 0; _x < 16; _x++)
for (int _z = 0; _z < 16; _z++)
@@ -886,11 +887,16 @@ void LevelChunk::recalcHeight(int x, int yStart, int z)
if (!level->dimension->hasCeiling)
{
PIXBeginNamedEvent(0,"Light gaps");
lightGap(xOffs - 1, zOffs, y1, y2);
lightGap(xOffs + 1, zOffs, y1, y2);
lightGap(xOffs, zOffs - 1, y1, y2);
lightGap(xOffs, zOffs + 1, y1, y2);
lightGap(xOffs, zOffs, y1, y2);
// Flag columns for gap rechecking — processed by recheckGaps() on next tick
auto flagGap = [&](int wx, int wz) {
LevelChunk *c = level->getChunkAt(wx, wz);
if (c && !c->isEmpty()) c->lightGaps(wx & 15, wz & 15);
};
flagGap(xOffs - 1, zOffs);
flagGap(xOffs + 1, zOffs);
flagGap(xOffs, zOffs - 1);
flagGap(xOffs, zOffs + 1);
flagGap(xOffs, zOffs);
PIXEndNamedEvent();
}
@@ -1643,10 +1649,7 @@ void LevelChunk::getEntities(shared_ptr<Entity> except, AABB *bb, vector<shared_
if (yc0 < 0) yc0 = 0;
if (yc1 >= ENTITY_BLOCKS_LENGTH) yc1 = ENTITY_BLOCKS_LENGTH - 1;
#ifndef __PSVITA__
// AP - RW critical sections are expensive so enter once in Level::getEntities
EnterCriticalSection(&m_csEntities);
#endif
// Lock is now always held by Level::getEntities()
for (int yc = yc0; yc <= yc1; yc++)
{
vector<shared_ptr<Entity> > *entities = entityBlocks[yc];
@@ -1671,9 +1674,6 @@ void LevelChunk::getEntities(shared_ptr<Entity> except, AABB *bb, vector<shared_
}
}
}
#ifndef __PSVITA__
LeaveCriticalSection(&m_csEntities);
#endif
}
void LevelChunk::getEntitiesOfClass(const type_info& ec, AABB *bb, vector<shared_ptr<Entity> > &es, const EntitySelector *selector)
@@ -1698,10 +1698,7 @@ void LevelChunk::getEntitiesOfClass(const type_info& ec, AABB *bb, vector<shared
yc1 = 0;
}
#ifndef __PSVITA__
// AP - RW critical sections are expensive so enter once in Level::getEntitiesOfClass
EnterCriticalSection(&m_csEntities);
#endif
// Lock is now always held by Level::getEntitiesOfClass()
for (int yc = yc0; yc <= yc1; yc++)
{
vector<shared_ptr<Entity> > *entities = entityBlocks[yc];
@@ -1729,9 +1726,6 @@ void LevelChunk::getEntitiesOfClass(const type_info& ec, AABB *bb, vector<shared
// 4J - note needs to be equivalent to baseClass.isAssignableFrom(e.getClass())
}
}
#ifndef __PSVITA__
LeaveCriticalSection(&m_csEntities);
#endif
}
int LevelChunk::countEntities()