11-10-2022 07:35 AM
In the unity oculus interaction SDK there is a bug in the PointableCanvasModule
This is the ADB log
15:37:50.067 Unity InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.Collections.Generic.Dictionary`2+ValueCollection+Enumerator[TKey,TValue].MoveNext ()
at Oculus.Interaction.PointableCanvasModule.Process () [0x00000]
at UnityEngine.EventSystems.EventSystem.Update () [0x00000]
The result is the menu items are no longer selectable and the user has a stuck menu
Offending code:
public class PointableCanvasModule : PointerInputModule
////...
public override void Process()
{
foreach (Pointer pointer in _pointersForDeletion)
{
ProcessPointer(pointer, true);
}
_pointersForDeletion.Clear();
// when pointers/hand rays are added: InvalidOperationException: Collection was modified
foreach (Pointer pointer in _pointerMap.Values)
{
ProcessPointer(pointer);
}
}
Proposed fix
var pointers = new List<Pointer>();
pointers.AddRange(_pointerMap.Values);
foreach (Pointer pointer in pointers)
ProcessPointer(pointer);
11-10-2022 11:11 AM
Created workaround by adding the below class and using that instead of the standard PointableCanvasModule
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Oculus.Interaction
{
public class PointableCanvasModulePatched : PointableCanvasModule
{
/// <summary>
/// Patch for bug https://forums.oculusvr.com/t5/Unity-VR-Development/Pointable-Canvas-menu-in-Unity-stops-working-when-user-uses-both/td-p/997121
/// Requires members accessed in this method to manually be made non-private
/// </summary>
public override void Process()
{
// Clone deleted pointers into in a local array to prevent
// InvalidOperationException: Collection was modified; enumeration operation may not execute.
var pointersToLoopOver = _pointersForDeletion.ToArray();
// Clear the deleted pointers list so it can start collecting newly delete pointers if those occur as a side effect to this method
_pointersForDeletion.Clear();
foreach (Pointer pointer in pointersToLoopOver)
ProcessPointer(pointer, forceRelease: true);
// Clone current pointers into a local array to prevent
// InvalidOperationException: Collection was modified; enumeration operation may not execute.
pointersToLoopOver = _pointerMap.Values.ToArray();
foreach (Pointer pointer in pointersToLoopOver)
ProcessPointer(pointer);
}
}
}