Skip to content

Crash: IndexOutOfRangeException in SystemRenderPlayerEffects.onBeforeRender when maxDynamicLights = 0 and a dynamic light appears #60

Description

@Petyok

Optimum version: 0.3.14 (built from source via install-linux.sh)
Game version: 1.22.7 (Stable), Linux x64 (Arch, kernel 7.1.9), Mesa 26.2.1, Intel HD 6000

Summary

Client crashes with IndexOutOfRangeException in SystemRenderPlayerEffects.onBeforeRender the moment any dynamic light source appears (e.g. lighting a torch), when the vanilla setting maxDynamicLights is 0 (as set by the low-end graphics presets).

Crash

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Vintagestory.Client.NoObf.SystemRenderPlayerEffects.onBeforeRender(Single dt)
   at Vintagestory.Client.NoObf.ClientMain.MainRenderLoop(Single dt)
   ...

Root cause

In patches/VintagestoryLib/Vintagestory.Client.NoObf/SystemRenderPlayerEffects.cs.patch, the alloc-free K-nearest selection (B3) does not handle maxDynLights == 0:

if (array.Length > maxDynLights)            // 1 > 0 → true
{
    if (_lightScratch == null || _lightScratch.Length < maxDynLights)
    {
        _lightScratch = new Entity[maxDynLights];       // new Entity[0]
        _lightScratchDistSq = new double[maxDynLights]; // new double[0]
    }
    _lightScratchCount = 0;
    for (int i = 0; i < array.Length; i++)
    {
        ...
        if (_lightScratchCount < maxDynLights)  // 0 < 0 → false
        { ... }
        else
        {
            int farthest = 0;
            double farthestDist = _lightScratchDistSq[0];  // ← throws: zero-length array

With maxDynLights = 0 the first entity that passes HasLight goes straight to the eviction branch and reads _lightScratchDistSq[0] from a zero-length array.

Repro: set maxDynamicLights: 0 in clientsettings.json, join any world, light a torch (or approach any glowing entity) → instant crash to desktop. 100% reproducible.

Suggested fix

Guard the selection branch, preserving vanilla semantics for 0 (no dynamic lights rendered):

if (maxDynLights > 0 && array.Length > maxDynLights)
{
    ...
}
else if (maxDynLights == 0)
{
    array = Array.Empty<Entity>();
}

Workaround for affected users until then: set maxDynamicLights to ≥ 1.

Thanks for Optimum — on a 15W Broadwell laptop with HD 6000 it took the package temperature from thermal-throttle city (100°C+) down to a stable ~80°C with FSR at 0.67. Great work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions