/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using UnityEngine; namespace Oculus.Interaction.Input { public interface IDataSource { int CurrentDataVersion { get; } void MarkInputDataRequiresUpdate(); event Action InputDataAvailable; } public interface IDataSource : IDataSource { TData GetData(); } public abstract class DataSource : MonoBehaviour, IDataSource where TData : class, ICopyFrom, new() { public bool Started => _started; protected bool _started = false; private bool _requiresUpdate = true; [Flags] public enum UpdateModeFlags { Manual = 0, UnityUpdate = 1 << 0, UnityFixedUpdate = 1 << 1, UnityLateUpdate = 1 << 2, AfterPreviousStep = 1 << 3 } [Header("Update")] [SerializeField] private UpdateModeFlags _updateMode; public UpdateModeFlags UpdateMode => _updateMode; [SerializeField, Interface(typeof(IDataSource))] [Optional(OptionalAttribute.Flag.DontHide)] private UnityEngine.Object _updateAfter; private IDataSource UpdateAfter; private int _currentDataVersion; protected bool UpdateModeAfterPrevious => (_updateMode & UpdateModeFlags.AfterPreviousStep) != 0; // Notifies that new data is available for query via GetData() method. // Do not use this event if you are reading data from a `Oculus.Interaction.Input.Hand` object, // instead, use the `Updated` event on that class. public event Action InputDataAvailable = delegate { }; public virtual int CurrentDataVersion => _currentDataVersion; #region Unity Lifecycle protected virtual void Start() { this.BeginStart(ref _started); if (_updateAfter != null) { UpdateAfter = _updateAfter as IDataSource; this.AssertField(UpdateAfter, nameof(UpdateAfter)); } this.EndStart(ref _started); } protected virtual void OnEnable() { if (_started) { if (UpdateModeAfterPrevious && UpdateAfter != null) { UpdateAfter.InputDataAvailable += MarkInputDataRequiresUpdate; } } } protected virtual void OnDisable() { if (_started) { if (UpdateAfter != null) { UpdateAfter.InputDataAvailable -= MarkInputDataRequiresUpdate; } } } protected virtual void Update() { if ((_updateMode & UpdateModeFlags.UnityUpdate) != 0) { MarkInputDataRequiresUpdate(); } } protected virtual void FixedUpdate() { if ((_updateMode & UpdateModeFlags.UnityFixedUpdate) != 0) { MarkInputDataRequiresUpdate(); } } protected virtual void LateUpdate() { if ((_updateMode & UpdateModeFlags.UnityLateUpdate) != 0) { MarkInputDataRequiresUpdate(); } } #endregion protected void ResetUpdateAfter(IDataSource updateAfter, UpdateModeFlags updateMode) { bool wasActive = isActiveAndEnabled; if (isActiveAndEnabled) { OnDisable(); } _updateMode = updateMode; UpdateAfter = updateAfter; _requiresUpdate = true; _currentDataVersion += 1; if (wasActive) { OnEnable(); } } public TData GetData() { if (RequiresUpdate()) { UpdateData(); _requiresUpdate = false; } return DataAsset; } protected bool RequiresUpdate() { return _requiresUpdate; } /// /// Marks the DataAsset stored as outdated, which means it will be /// re-processed JIT during the next call to GetData. /// public virtual void MarkInputDataRequiresUpdate() { _requiresUpdate = true; _currentDataVersion += 1; InputDataAvailable(); } protected abstract void UpdateData(); /// /// Returns the current DataAsset, without performing any updates. /// /// /// Null if no call to GetData has been made since this data source was initialized. /// protected abstract TData DataAsset { get; } #region Inject public void InjectAllDataSource(UpdateModeFlags updateMode, IDataSource updateAfter) { InjectUpdateMode(updateMode); InjectUpdateAfter(updateAfter); } public void InjectUpdateMode(UpdateModeFlags updateMode) { _updateMode = updateMode; } public void InjectUpdateAfter(IDataSource updateAfter) { _updateAfter = updateAfter as UnityEngine.Object; UpdateAfter = updateAfter; } #endregion } }