cancel
Showing results for 
Search instead for 
Did you mean: 

Pointable Canvas menu in Unity stops working when user uses both hands or controllers

riesvriend
Level 2

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);

 

 

1 REPLY 1

riesvriend
Level 2

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);
        }
    }
}