示例#1
0
        public void AddCallback(TDelegate dlg)
        {
            if (m_CannotMutateCallbacksArray)
            {
                if (m_CallbacksToAdd.Contains(dlg))
                {
                    return;
                }
                var removeIndex = m_CallbacksToRemove.IndexOf(dlg);
                if (removeIndex != -1)
                {
                    m_CallbacksToRemove.RemoveAtByMovingTailWithCapacity(removeIndex);
                }
                m_CallbacksToAdd.AppendWithCapacity(dlg);
                return;
            }

            if (!m_Callbacks.Contains(dlg))
            {
                m_Callbacks.AppendWithCapacity(dlg, capacityIncrement: 4);
            }
        }
示例#2
0
        public void RemoveCallback(TDelegate dlg)
        {
            if (m_CannotMutateCallbacksArray)
            {
                if (m_CallbacksToRemove.Contains(dlg))
                {
                    return;
                }
                var addIndex = m_CallbacksToAdd.IndexOf(dlg);
                if (addIndex != -1)
                {
                    m_CallbacksToAdd.RemoveAtByMovingTailWithCapacity(addIndex);
                }
                m_CallbacksToRemove.AppendWithCapacity(dlg);
                return;
            }

            var index = m_Callbacks.IndexOf(dlg);

            if (index >= 0)
            {
                m_Callbacks.RemoveAtWithCapacity(index);
            }
        }
        /// <summary>
        /// Resolve and add all bindings and actions from the given map.
        /// </summary>
        /// <param name="map"></param>
        /// <exception cref="Exception"></exception>
        public void AddActionMap(InputActionMap map)
        {
            Debug.Assert(map != null);

            // Keep track of indices for this map.
            var bindingStartIndex     = totalBindingCount;
            var controlStartIndex     = totalControlCount;
            var interactionStartIndex = totalInteractionCount;
            var processorStartIndex   = totalProcessorCount;
            var compositeStartIndex   = totalCompositeCount;
            var actionStartIndex      = totalActionCount;

            // Allocate binding states.
            var bindingsInThisMap     = map.m_Bindings;
            var bindingCountInThisMap = bindingsInThisMap != null ? bindingsInThisMap.Length : 0;

            totalBindingCount += bindingCountInThisMap;
            ArrayHelpers.GrowBy(ref bindingStates, totalBindingCount);

            ////TODO: make sure composite objects get all the bindings they need
            ////TODO: handle case where we have bindings resolving to the same control
            ////      (not so clear cut what to do there; each binding may have a different interaction setup, for example)
            var currentCompositeBindingIndex = InputActionMapState.kInvalidIndex;
            var currentCompositeIndex        = InputActionMapState.kInvalidIndex;
            var bindingMaskOnThisMap         = map.m_BindingMask;
            var actionsInThisMap             = map.m_Actions;
            var actionCountInThisMap         = actionsInThisMap != null ? actionsInThisMap.Length : 0;

            for (var n = 0; n < bindingCountInThisMap; ++n)
            {
                var unresolvedBinding = bindingsInThisMap[n];
                var bindingIndex      = bindingStartIndex + n;

                // Set binding state to defaults.
                bindingStates[bindingIndex].mapIndex = totalMapCount;
                bindingStates[bindingIndex].compositeOrCompositeBindingIndex = InputActionMapState.kInvalidIndex;
                bindingStates[bindingIndex].actionIndex = InputActionMapState.kInvalidIndex;

                // Skip binding if it is disabled (path is empty string).
                var path = unresolvedBinding.effectivePath;
                if (unresolvedBinding.path == "")
                {
                    continue;
                }

                // Skip binding if it doesn't match with our binding mask (might be empty).
                if (!bindingMask.Matches(ref unresolvedBinding))
                {
                    continue;
                }

                // Skip binding if it doesn't match the binding mask on the map (might be empty).
                if (!bindingMaskOnThisMap.Matches(ref unresolvedBinding))
                {
                    continue;
                }

                // Try to find action.
                // NOTE: Technically, we allow individual bindings of composites to trigger actions independent
                //       of the action triggered by the composite.
                var actionIndex = InputActionMapState.kInvalidIndex;
                var actionName  = unresolvedBinding.action;
                if (!string.IsNullOrEmpty(actionName))
                {
                    actionIndex = map.TryGetActionIndex(actionName);
                }
                else if (map.m_SingletonAction != null)
                {
                    // Special-case for singleton actions that don't have names.
                    actionIndex = 0;
                }

                // Skip binding if it doesn't match the binding mask on the action (might be empty).
                if (actionIndex != InputActionMapState.kInvalidIndex &&
                    !map.m_Actions[actionIndex].m_BindingMask.Matches(ref unresolvedBinding))
                {
                    continue;
                }

                // Instantiate processors.
                var firstProcessorIndex = 0;
                var numProcessors       = 0;
                var processors          = unresolvedBinding.effectiveProcessors;
                if (!string.IsNullOrEmpty(processors))
                {
                    firstProcessorIndex = ResolveProcessors(processors);
                    if (processors != null)
                    {
                        numProcessors = totalProcessorCount - firstProcessorIndex;
                    }
                }

                // Instantiate interactions.
                var firstInteractionIndex = 0;
                var numInteractions       = 0;
                var interactions          = unresolvedBinding.effectiveInteractions;
                if (!string.IsNullOrEmpty(interactions))
                {
                    firstInteractionIndex = ResolveInteractions(interactions);
                    if (interactionStates != null)
                    {
                        numInteractions = totalInteractionCount - firstInteractionIndex;
                    }
                }

                ////TODO: allow specifying parameters for composite on its path (same way as parameters work for interactions)
                // If it's the start of a composite chain, create the composite.
                if (unresolvedBinding.isComposite)
                {
                    ////REVIEW: what to do about interactions on composites?

                    // Instantiate. For composites, the path is the name of the composite.
                    var composite = InstantiateBindingComposite(unresolvedBinding.path);
                    currentCompositeIndex =
                        ArrayHelpers.AppendWithCapacity(ref composites, ref totalCompositeCount, composite);
                    currentCompositeBindingIndex = bindingIndex;
                    bindingStates[bindingIndex]  = new InputActionMapState.BindingState
                    {
                        actionIndex = actionIndex,
                        compositeOrCompositeBindingIndex = currentCompositeIndex,
                        processorStartIndex   = firstProcessorIndex,
                        processorCount        = numProcessors,
                        interactionCount      = numInteractions,
                        interactionStartIndex = firstInteractionIndex,
                        mapIndex = totalMapCount,
                    };

                    // The composite binding entry itself does not resolve to any controls.
                    // It creates a composite binding object which is then populated from
                    // subsequent bindings.
                    continue;
                }

                // If we've reached the end of a composite chain, finish
                // off the current composite.
                if (!unresolvedBinding.isPartOfComposite &&
                    currentCompositeBindingIndex != InputActionMapState.kInvalidIndex)
                {
                    currentCompositeBindingIndex = InputActionMapState.kInvalidIndex;
                    currentCompositeIndex        = InputActionMapState.kInvalidIndex;
                }

                // Look up controls.
                var firstControlIndex = totalControlCount;
                if (controls == null)
                {
                    controls = new InputControl[10];
                }
                var resolvedControls = new ArrayOrListWrapper <InputControl>(controls, totalControlCount);
                var numControls      = InputSystem.GetControls(path, ref resolvedControls);
                controls          = resolvedControls.array;
                totalControlCount = resolvedControls.count;

                // Add unique devices.
                for (var i = 0; i < numControls; ++i)
                {
                    var control     = controls[firstControlIndex + i];
                    var device      = control.device;
                    var deviceIndex = 0;
                    for (; deviceIndex < totalDeviceCount; ++deviceIndex)
                    {
                        if (devices[deviceIndex] == device)
                        {
                            break;
                        }
                    }

                    if (deviceIndex == totalDeviceCount)
                    {
                        devices.AppendWithCapacity(device, 4);
                        ++totalDeviceCount;
                    }
                }

                // Add entry for resolved binding.
                bindingStates[bindingIndex] = new InputActionMapState.BindingState
                {
                    controlStartIndex                = firstControlIndex,
                    controlCount                     = numControls,
                    interactionStartIndex            = firstInteractionIndex,
                    interactionCount                 = numInteractions,
                    processorStartIndex              = firstProcessorIndex,
                    processorCount                   = numProcessors,
                    isPartOfComposite                = unresolvedBinding.isPartOfComposite,
                    actionIndex                      = actionIndex,
                    compositeOrCompositeBindingIndex = currentCompositeBindingIndex,
                    mapIndex = totalMapCount,
                };

                // If the binding is part of a composite, pass the resolve controls
                // on to the composite.
                if (unresolvedBinding.isPartOfComposite && currentCompositeBindingIndex != InputActionMapState.kInvalidIndex && numControls != 0)
                {
                    ////REVIEW: what should we do when a single binding in a composite resolves to multiple controls?
                    ////        if the composite has more than one bindable control, it's not readily apparent how we would group them
                    if (numControls > 1)
                    {
                        throw new NotImplementedException("Handling case where single binding in composite resolves to multiple controls");
                    }

                    // Make sure the binding is named. The name determines what in the composite
                    // to bind to.
                    if (string.IsNullOrEmpty(unresolvedBinding.name))
                    {
                        throw new Exception(string.Format(
                                                "Binding that is part of composite '{0}' is missing a name",
                                                composites[currentCompositeIndex]));
                    }

                    // Install the control on the binding.
                    BindControlInComposite(composites[currentCompositeIndex], unresolvedBinding.name,
                                           controls[firstControlIndex]);
                }
            }

            // Set up control to binding index mapping.
            var controlCountInThisMap = totalControlCount - controlStartIndex;

            ArrayHelpers.GrowBy(ref controlIndexToBindingIndex, controlCountInThisMap);
            for (var i = 0; i < bindingCountInThisMap; ++i)
            {
                var numControls = bindingStates[bindingStartIndex + i].controlCount;
                var startIndex  = bindingStates[bindingStartIndex + i].controlStartIndex;
                for (var n = 0; n < numControls; ++n)
                {
                    controlIndexToBindingIndex[startIndex + n] = i;
                }
            }

            // Store indices for map.
            var numMaps  = totalMapCount;
            var mapIndex = ArrayHelpers.AppendWithCapacity(ref maps, ref numMaps, map);

            ArrayHelpers.AppendWithCapacity(ref mapIndices, ref totalMapCount, new InputActionMapState.ActionMapIndices
            {
                actionStartIndex      = actionStartIndex,
                actionCount           = actionCountInThisMap,
                controlStartIndex     = controlStartIndex,
                controlCount          = controlCountInThisMap,
                bindingStartIndex     = bindingStartIndex,
                bindingCount          = bindingCountInThisMap,
                interactionStartIndex = interactionStartIndex,
                interactionCount      = totalInteractionCount - interactionStartIndex,
                processorStartIndex   = processorStartIndex,
                processorCount        = totalProcessorCount - processorStartIndex,
                compositeStartIndex   = compositeStartIndex,
                compositeCount        = totalCompositeCount - compositeStartIndex,
            });
            map.m_MapIndexInState = mapIndex;

            // Allocate action states.
            if (actionCountInThisMap > 0)
            {
                // Assign action indices.
                var actions = map.m_Actions;
                for (var i = 0; i < actionCountInThisMap; ++i)
                {
                    actions[i].m_ActionIndex = totalActionCount + i;
                }

                ArrayHelpers.GrowBy(ref actionStates, actionCountInThisMap);
                totalActionCount += actionCountInThisMap;
                for (var i = 0; i < actionCountInThisMap; ++i)
                {
                    actionStates[i].mapIndex = mapIndex;
                }
            }
        }