public MainPage()
        {
            InitializeComponent();
            SizeChanged += OnThisSizeChanged;

            gridContact.MouseEnter += GridOnMouseEnter;
            gridLead.MouseEnter += GridOnMouseEnter;
            gridActivity.MouseEnter += GridOnMouseEnter;

            gridContact.GotFocus += DataGridGotFocus;
            gridLead.GotFocus += DataGridGotFocus;
            gridActivity.GotFocus += DataGridGotFocus;

            if (Database != null)
                gridContact.ItemsSource = Database.GetTable<Contact>().ToObservableCollection(); // Load all contacts

            Delayer.DelayMilliseconds = 300;
            var contactDelayer = new Delayer();
            gridContact.SelectionChanged += (sender, e) => contactDelayer.Action = RefreshLeads;
            var activityDelayer = new Delayer();
            gridLead.SelectionChanged += (sender, e) => activityDelayer.Action = RefreshActivities;

            gridContact.SelectionChanged += (sender, e) => CheckButtons();
            gridLead.SelectionChanged += (sender, e) => CheckButtons();
            CheckButtons();

            detailDelayer = new Delayer();
        }
        /// <summary>
        /// Paste the data to the current foreground window.
        /// </summary>
        /// <param name="message">The message to show.</param>
        private void PasteData(Message message)
        {
            Requires.NotNull(message.Values, nameof(message.Values));

            var delayer = new Delayer <object>(TimeSpan.FromMilliseconds(200));

            delayer.Action += (sender, args) =>
            {
                var clipboardService            = ServiceLocator.GetService <ClipboardService>();
                var mouseAndKeyboardHookService = ServiceLocator.GetService <MouseAndKeyboardHookService>();
                mouseAndKeyboardHookService.Pause();
                clipboardService.Pause();

                ServiceLocator.GetService <DataService>().CopyData((DataEntry)message.Values.First());
                clipboardService.Paste();

                delayer         = new Delayer <object>(TimeSpan.FromMilliseconds(300));
                delayer.Action += (sender2, args2) =>
                {
                    mouseAndKeyboardHookService.Resume();
                    clipboardService.Resume();
                };
                delayer.ResetAndTick();
            };
            delayer.ResetAndTick();
        }
예제 #3
0
    public void Awake()
    {
        if (HackDisableShadowsObjects == null)
        {
            HackDisableShadowsObjects = new GameObject[0];
        }

        QueuedScreenRecoils = new Delayer <Vector3>();

        CosmeticSpring                   = new ThrottledRotationalSpring(Quaternion.identity);
        CosmeticSpring.Damping           = 0.0000001f;
        CosmeticSpring.Strength          = 900f;
        CosmeticSpring.ImpulseQueueLimit = 1;

        Relay.Instance.OptionsMenu.OnFOVOptionChanged += ReceiveFOVChanged;
        BaseFieldOfView = Relay.Instance.OptionsMenu.FOVOptionValue;
        Relay.Instance.OptionsMenu.OnExteriorViewOptionChanged += ReceiveExteriorViewOptionChanged;

        // Used for view bob and jump/landing etc
        YSpring          = new ScalarSpring(0f);
        YSpring.Strength = 800f;
        YSpring.Damping  = 0.000000000001f;

        ViewBobSpring          = new RotationalSpring(Quaternion.identity);
        ViewBobSpring.Strength = 500f;
        ViewBobSpring.Damping  = 0.0000001f;
    }
        /// <summary>
        /// Resume the hooking with the specified delay.
        /// </summary>
        /// <param name="delay">The delay before resuming.</param>
        internal void DelayedResume(TimeSpan delay)
        {
            var delayedHooking = new Delayer <object>(delay);

            delayedHooking.Action += (sender, args) => Resume();
            delayedHooking.ResetAndTick();
        }
        public MainPage()
        {
            InitializeComponent();
            SizeChanged += OnThisSizeChanged;

            gridContact.MouseEnter  += GridOnMouseEnter;
            gridLead.MouseEnter     += GridOnMouseEnter;
            gridActivity.MouseEnter += GridOnMouseEnter;

            gridContact.GotFocus  += DataGridGotFocus;
            gridLead.GotFocus     += DataGridGotFocus;
            gridActivity.GotFocus += DataGridGotFocus;

            if (Database != null)
            {
                gridContact.ItemsSource = Database.GetTable <Contact>().ToObservableCollection(); // Load all contacts
            }
            Delayer.DelayMilliseconds = 300;
            var contactDelayer = new Delayer();

            gridContact.SelectionChanged += (sender, e) => contactDelayer.Action = RefreshLeads;
            var activityDelayer = new Delayer();

            gridLead.SelectionChanged += (sender, e) => activityDelayer.Action = RefreshActivities;

            gridContact.SelectionChanged += (sender, e) => CheckButtons();
            gridLead.SelectionChanged    += (sender, e) => CheckButtons();
            CheckButtons();

            detailDelayer = new Delayer();
        }
    private static void LoadDelayer(GameObject LoadedObject, SavedDelayer save)
    {
        Delayer delayer = LoadedObject.GetComponent <Delayer>();

        delayer.Output.On  = save.OutputOn;
        delayer.DelayCount = save.DelayCount;
    }
예제 #7
0
        private void ExecuteHideBarButtonCommand()
        {
            if (_mouseAndKeyboardHookService != null)
            {
                if (Settings.Default.ClosePasteBarWhenMouseIsAway)
                {
                    _mouseAndKeyboardHookService.MouseAction -= MouseAndKeyboardHookService_MouseAction;
                }

                if (Settings.Default.ClosePasteBarWithHotKey)
                {
                    _mouseAndKeyboardHookService.UnregisterHotKey(Consts.PasteShortcutName);
                    _mouseAndKeyboardHookService.HotKeyDetected -= MouseAndKeyboardHookService_HotKeyDetected;
                }
                _mouseAndKeyboardHookService.Pause();
            }

            Logger.Instance.Information($"The paste bar window has been hidden.");

            MessengerInstance.Send(new ComponentModel.Messages.Message(), MessageIdentifiers.HidePasteBarWindow);
            var delayer = new Delayer <object>(TimeSpan.FromMilliseconds(200));

            delayer.Action += (sender, args) =>
            {
                _mouseAndKeyboardHookService = null;
                _canCloseIfMouseMovesAway    = false;
                if (!string.IsNullOrEmpty(SearchQueryString) || SearchType != SearchType.All)
                {
                    SearchQueryString = string.Empty;
                    SearchType        = SearchType.All;
                    Search();
                }
            };
            delayer.ResetAndTick();
        }
예제 #8
0
        private void ExecuteSearchCommand()
        {
            if (IgnoreSearch)
            {
                return;
            }

            IgnoreSearch = true;

            var delayer = new Delayer <object>(TimeSpan.FromMilliseconds(250));

            delayer.Action += (sender, args) =>
            {
                IgnoreSearch = false;
            };
            delayer.ResetAndTick();

            var delayer2 = new Delayer <object>(TimeSpan.FromMilliseconds(10));

            delayer2.Action += (sender, args) =>
            {
                Logger.Instance.Information("Search in the paste bar started.");
                Search();
                RaisePropertyChanged(nameof(NoSearchResult));
            };
            delayer2.ResetAndTick();

            if (CoreHelper.IsUnitTesting())
            {
                Task.Delay(50).Wait();
                DispatcherHelper.DoEvents();
            }
        }
예제 #9
0
        public void Delayer()
        {
            var actionCalled = false;

            DispatcherUtil.ExecuteOnDispatcherThread(() =>
            {
                var delayer     = new Delayer <string>(TimeSpan.FromMilliseconds(100));
                delayer.Action += (sender, args) =>
                {
                    if (args.Data == "hello")
                    {
                        actionCalled = true;
                    }
                };

                Assert.IsFalse(actionCalled);
                delayer.ResetAndTick("hello");

                Task.Delay(100).Wait();
                DispatcherUtil.DoEvents();
                Assert.IsFalse(actionCalled);
            }, 1);

            Task.Delay(100).Wait();
            DispatcherUtil.DoEvents();
            Assert.IsTrue(actionCalled);
        }
예제 #10
0
        private void ExecuteExitCommand()
        {
            Logger.Instance.Information("Exit menu from icon in the task bar clicked.");
            HideNotifyIcon();

            var delayer = new Delayer <object>(TimeSpan.FromMilliseconds(300));

            delayer.Action += (o, args) =>
            {
                if (MessageBox.Show(Language.MainWindow.Message_Quit, Language.MainWindow.ApplicationTitle, MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                {
                    if (CoreHelper.IsUnitTesting())
                    {
                        throw new OperationCanceledException("Unable to quit a unit test");
                    }

                    _pasteBarMustBeRecreatedAutomatically = false;
                    _pasteBarWindow.Close();
                    Application.Current.Shutdown(0);
                }
                else
                {
                    Logger.Instance.Information("Exit has been canceled.");
                    ShowNotifyIcon();
                }
            };
            delayer.ResetAndTick();
        }
예제 #11
0
        /// <summary>
        /// Display on the screen the paste bare with an animation.
        /// </summary>
        internal void DisplayBar()
        {
            var delayer = new Delayer <object>(TimeSpan.FromMilliseconds(250));

            delayer.Action += (sender, args) =>
            {
                if (Settings.Default.ClosePasteBarWhenMouseIsAway && !CoreHelper.IsUnitTesting())
                {
                    _mouseAndKeyboardHookService              = ServiceLocator.GetService <MouseAndKeyboardHookService>();
                    _mouseAndKeyboardHookService.MouseAction += MouseAndKeyboardHookService_MouseAction;
                    _mouseAndKeyboardHookService.Resume();
                }

                if (Settings.Default.ClosePasteBarWithHotKey && !CoreHelper.IsUnitTesting())
                {
                    if (_mouseAndKeyboardHookService == null)
                    {
                        _mouseAndKeyboardHookService = ServiceLocator.GetService <MouseAndKeyboardHookService>();
                    }
                    _mouseAndKeyboardHookService.HotKeyDetected += MouseAndKeyboardHookService_HotKeyDetected;
                    _mouseAndKeyboardHookService.RegisterHotKey(Consts.PasteShortcutName, Settings.Default.KeyboardShortcut.Cast <Key>().ToArray());
                    _mouseAndKeyboardHookService.Resume();
                    Logger.Instance.Information($"The keyboard is listened. The expecting shortcut is {JsonConvert.SerializeObject(Settings.Default.KeyboardShortcut.Cast<Key>().ToArray())}.");
                }
            };
            delayer.ResetAndTick();
        }
예제 #12
0
파일: Entity.cs 프로젝트: tech-bear/Rhisis
 /// <summary>
 /// Creates a new <see cref="Entity"/> instance.
 /// </summary>
 /// <param name="context"></param>
 protected Entity(IContext context)
 {
     this.Id      = RandomHelper.GenerateUniqueId();
     this.Context = context;
     this.Object  = new ObjectComponent();
     this.Delayer = new Delayer();
 }
예제 #13
0
    private static void LoadDelayer(GameObject LoadedObject, SavedObject save)
    {
        object[] data    = save.CustomDataArray;
        Delayer  delayer = LoadedObject.GetComponent <Delayer>();

        delayer.Input.On   = (bool)data[0];
        delayer.Output.On  = (bool)data[1];
        delayer.DelayCount = (int)data[2];
    }
예제 #14
0
 public void Awake()
 {
     if (_instance != null)
     {
         Logger.Warning("Delayer should only be attached once.");
         return;
     }
     _instance = this;
 }
예제 #15
0
        public void Delayer_Should_Delay_With_The_Given_Time(int seconds)
        {
            var affector = new Delayer(TimeSpan.FromSeconds(seconds));

            var t = new ExecutionTimer();

            t.Aggregate(() => affector.Affect());

            Assert.InRange(t.Total, seconds - 1, seconds + 1);
        }
예제 #16
0
        internal static SearchProvider CreateProvider()
        {
            List <string> itemNames = new List <string>();
            List <string> shortcuts = new List <string>();

            GetMenuInfo(itemNames, shortcuts);

            System.Threading.Tasks.Task.Run(() => BuildMenus(itemNames));

            queryEngine = new QueryEngine <MenuData>(k_QueryEngineOptions);
            queryEngine.SetFilter("id", m => m.path)
            .AddOrUpdatePropositionData(label: "Menu Path", replacement: "id:create/", help: "Filter by menu path.", priority: 9999);
            queryEngine.SetSearchDataCallback(m => m.words, s => Utils.FastToLower(s), StringComparison.Ordinal);

            debounce = Delayer.Debounce(_ => TriggerBackgroundUpdate(itemNames, shortcuts));

            Menu.menuChanged -= OnMenuChanged;
            Menu.menuChanged += OnMenuChanged;

            return(new SearchProvider(type, displayName)
            {
                priority = 80,
                filterId = "m:",
                showDetailsOptions = ShowDetailsOptions.ListView | ShowDetailsOptions.Actions,

                onEnable = () => shortcutIds = ShortcutManager.instance.GetAvailableShortcutIds().ToArray(),
                onDisable = () => shortcutIds = new string[0],

                fetchItems = FetchItems,

                fetchLabel = (item, context) =>
                {
                    if (item.label == null)
                    {
                        var menuName = Utils.GetNameFromPath(item.id);
                        var enabled = Menu.GetEnabled(item.id);
                        var @checked = Menu.GetChecked(item.id);
                        item.label = $"{menuName}{(enabled ? "" : " (disabled)")} {(@checked ? "\u2611" : "")}";
                    }
                    return item.label;
                },

                fetchDescription = (item, context) =>
                {
                    if (string.IsNullOrEmpty(item.description))
                    {
                        item.description = GetMenuDescription(item.id);
                    }
                    return item.description;
                },

                fetchThumbnail = (item, context) => Icons.shortcut,
                fetchPropositions = (context, options) => FetchPropositions(context, options)
            });
        }
예제 #17
0
        public void Delayer_DelayWithNullTestKitBase_ThrowsArgumentNullException()
        {
            //arrange
            Delayer sut = CreateDelayer();

            //act
            Action act = () => sut.Delay(null, TimeSpan.Zero);

            //assert
            act.Should().Throw <ArgumentNullException>();
        }
예제 #18
0
        /// <summary>
        /// Initialize the <see cref="_delayedTextChangedTimer"/> each time that the text change
        /// </summary>
        private void InitializeDelayedTextChangedTimer()
        {
            _delayedTextChangedTimer?.Stop();

            if (_delayedTextChangedTimer == null)
            {
                _delayedTextChangedTimer         = new Delayer <object>(TimeSpan.FromMilliseconds(DelayedTextChangedTimeout));
                _delayedTextChangedTimer.Action += DelayedTextChangedTimer_Tick;
            }

            _delayedTextChangedTimer.ResetAndTick();
        }
예제 #19
0
        private void MouseAndKeyboardHookService_MouseAction(object sender, MouseHookEventArgs e)
        {
            var mustClose    = false;
            var activeScreen = Screen.FromPoint(new System.Drawing.Point(Cursor.Position.X, Cursor.Position.Y));
            var screen       = SystemInfoHelper.GetAllScreenInfos().Single(s => s.DeviceName == activeScreen.DeviceName);

            switch (Settings.Default.PasteBarPosition)
            {
            case PasteBarPosition.Top:
                if (e.Coords.Y - screen.Bounds.Top >= screen.Bounds.Bottom / 2)
                {
                    if (_canCloseIfMouseMovesAway)
                    {
                        mustClose = true;
                    }
                }
                else
                {
                    _canCloseIfMouseMovesAway = true;
                }
                break;

            case PasteBarPosition.Bottom:
                if (e.Coords.Y - screen.Bounds.Top <= screen.Bounds.Bottom / 2)
                {
                    if (_canCloseIfMouseMovesAway)
                    {
                        mustClose = true;
                    }
                }
                else
                {
                    _canCloseIfMouseMovesAway = true;
                }
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (mustClose)
            {
                if (_mouseAndKeyboardHookService != null)
                {
                    _mouseAndKeyboardHookService.MouseAction -= MouseAndKeyboardHookService_MouseAction;
                }
                Logger.Instance.Information($"Mouse moves away from the paste bar.");

                var delayer = new Delayer <object>(TimeSpan.FromMilliseconds(10));
                delayer.Action += (o, args) => HideBarButtonCommand?.Execute(null);
                delayer.ResetAndTick();
            }
        }
예제 #20
0
        static void Main(string[] args)
        {
            ConsoleUI ui = new ConsoleUI();
            var       displayFormatter = new DisplayFormatter();
            var       inputConverter   = new InputConverter();
            var       displayDelayer   = new Delayer(milliSecDelay: 1100);
            var       fileReader       = new FileReader();

            Game life = new Game(ui, displayFormatter, inputConverter, displayDelayer, fileReader);

            life.Run();
        }
예제 #21
0
        public static bool RunEvery(float seconds)
        {
            if ((delayer = listDelays.Find(d => d.LifeTime == seconds)) == null)
            {
                listDelays.Add(new Delayer(seconds));
            }
            else if (delayer.CurrentTime == 0.0f)
            {
                return(true);
            }

            return(false);
        }
예제 #22
0
        static void TesterRepeateDemo()
        {
            var delayer = new Delayer <int>().SetDelayTimeInMiliseconds(50);
            var printer = new Print <int>(delayer);

            printer.OldDataKeepCount = 2;
            printer.SetTextWriter(System.IO.TextWriter.Null);

            var tester = new RepeateTester <int>(printer).SetShowProgerss(true).SetRepetitionCount(21);

            tester.RunSync();
            tester.RunAsync();
        }
예제 #23
0
        private void ExecutePasteCommand(DataEntry dataEntry)
        {
            var delayer = new Delayer <DataEntry>(TimeSpan.FromMilliseconds(200));

            delayer.Action += (sender, args) =>
            {
                Logger.Instance.Information("Paste command activated.");
                Requires.NotNull(args.Data, nameof(args.Data));
                HideBarButtonCommand.Execute(null);
                MessengerInstance.Send(new ComponentModel.Messages.Message(args.Data), MessageIdentifiers.PasteData);
            };
            delayer.ResetAndTick(dataEntry);
        }
예제 #24
0
        private void MouseAndKeyboardHookService_HotKeyDetected(object sender, HotKeyEventArgs e)
        {
            if (_mouseAndKeyboardHookService != null)
            {
                _mouseAndKeyboardHookService.HotKeyDetected -= MouseAndKeyboardHookService_HotKeyDetected;
            }
            Logger.Instance.Information($"The keyboard shortcut has hit.");
            e.Handled = true;

            var delayer = new Delayer <object>(TimeSpan.FromMilliseconds(10));

            delayer.Action += (o, args) => HideBarButtonCommand?.Execute(null);
            delayer.ResetAndTick();
        }
        public void Jump()
        {
            if (CurrentContact == Contact.None)
            {
                return;
            }

            CurrentContact = Contact.None;
            _velocity     += Up * _parameters.JumpVelocity;

            _updateContact = false;
            Delayer.ExecuteAfter(() => _updateContact = true, 0.2f);

            OnContactLost();
        }
예제 #26
0
        private void ExecuteCopyCommand(DataEntry dataEntry)
        {
            var delayer = new Delayer <DataEntry>(TimeSpan.FromMilliseconds(200));

            delayer.Action += (sender, args) =>
            {
                Logger.Instance.Information("Copy command activated.");
                Requires.NotNull(args.Data, nameof(args.Data));

                _mouseAndKeyboardHookService?.Pause();
                _dataService.CopyData(args.Data);
                _mouseAndKeyboardHookService?.Resume();
            };
            delayer.ResetAndTick(dataEntry);
        }
예제 #27
0
        void RunPhysics()
        {
            DateTime lastUpdate = DateTime.UtcNow;
            Delayer  delayer    = new Delayer(TimeSpan.FromMilliseconds(25));

            while (true)
            {
                delayer.Delay();

                DateTime now      = DateTime.UtcNow;
                TimeSpan duration = now - lastUpdate;
                lastUpdate = now;

                physics.DoPhysics(duration);
            }
        }
예제 #28
0
        public PropertyDatabase(string filePath, bool autoBackgroundUpdate, double backgroundUpdateDebounceInSeconds = k_DefaultBackgroundUpdateDebounceInSeconds)
        {
            this.filePath        = filePath;
            stringTableFilePath  = GetStringTablePath(filePath);
            m_LocalVolatileStore = new PropertyDatabaseVolatileMemoryStore();
            m_LocalStore         = new PropertyDatabaseMemoryStore();
            m_FileStore          = new PropertyDatabaseFileStore(filePath);
            m_StringTable        = new PropertyStringTable(stringTableFilePath, 30);

            // Do not allow automatic background updates while running tests. The writing of the file
            // causes an assembly leak during the test Unity.IntegrationTests.Scripting.AssemblyReloadTest.AssemblyReloadDoesntLeakAssemblies
            // on MacOs. I haven't found out why exactly does the writing of a file causes an assembly to be held, so instead I deactivate
            // the automatic update during tests.
            this.autoBackgroundUpdate = autoBackgroundUpdate && !Utils.IsRunningTests();

            m_Debounce = Delayer.Debounce(_ => TriggerPropertyDatabaseBackgroundUpdate(), backgroundUpdateDebounceInSeconds);
        }
예제 #29
0
    public void DoWork()
    {
        int snapshot = m_iSharedData;

        Delayer.Delay(Delayer.RandomShortDelay(m_rng));
        m_iSharedData++;
        Delayer.Delay(Delayer.RandomShortDelay(m_rng));
        if (m_iSharedData != snapshot + 1)
        {
            Error = true;
            Console.WriteLine("Failure!!!");
        }
        if (m_iSharedData == m_iRequestedEntries)
        {
            m_Event.Set();
        }
    }
예제 #30
0
    //
    // Click for pressDuration seconds
    //  a good visual pressDuration is 0.33f
    public virtual void Click(float pressDuration = 0)
    {
        if (!(isActiveAndEnabled && Interactable))
        {
            // button must be active and interactable to click
            return;
        }

        // show button as pressed
        _showAsPressed = true;
        UpdateButton();

        void unpressCallback()
        {
            //
            // invoke and unpress button

            onClickEvent?.Invoke(this);

            // SkipPointerUp skips returning to the normal ("Up") state after
            //  clicking, which is useful with tab menus or button toggles,
            //  otherwise you see the normal state flicker.
            _showAsPressed = SkipPointerUp;
            UpdateButton();
        }

        if (waitForClickSound && pressDuration == 0 && Enabled)
        {
            SoundHelper.Play(clickSound, unpressCallback);
        }
        else
        {
            if (clickSound && Enabled)
            {
                clickSound?.Play();
            }
            if (pressDuration > 0)
            {
                Delayer.Delay(pressDuration, unpressCallback);
            }
            else
            {
                unpressCallback();
            }
        }
    }
예제 #31
0
        public void Delayer_DelayWithNegativeDuration_DoesNotDelay()
        {
            //arrange
            TimeSpan duration = TimeSpan.FromSeconds(TestHelper.GenerateNumberBetween(-1000, -1));
            Delayer  sut      = CreateDelayer();

            //act
            Action act = () => sut.Delay(TestKit, duration);

            //assert
            TimeSpan  expected  = TimeSpan.Zero;
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();
            act();
            stopwatch.Stop();
            stopwatch.Elapsed.Should().BeCloseTo(expected, 250);
        }
    public void Awake()
    {
		bulletsLeft = BurstCount;
        playerCamera = GetComponentInChildren<CameraScript>();
        weaponIndicator = Camera.main.GetComponent<WeaponIndicatorScript>();
        targets = weaponIndicator.Targets;
        playerScript = GetComponent<PlayerScript>();

        GunRecoilThrotter = new Throttler<float>();
        GunRecoilThrotter.MinimumTimeBetweenItems = 0.09f;
        GunRecoilSpring = new ScalarSpring(0f);
        GunRecoilSpring.Strength = 2000f;
        GunRecoilSpring.Damping = 0.00000000001f;
        ReloaderSpring = new ScalarSpring(0f);
        ReloaderSpring.Strength = 200f;
        ReloaderSpring.Damping = 0.00000001f;
        ReloaderDelayer = new Delayer<float>();
        ReloaderDelayer.DelayTime = 0.25f;
    }
예제 #33
0
    public void Awake()
    {
        if (HackDisableShadowsObjects == null)
            HackDisableShadowsObjects = new GameObject[0];

        QueuedScreenRecoils = new Delayer<Vector3>();

        CosmeticSpring = new ThrottledRotationalSpring(Quaternion.identity);
        CosmeticSpring.Damping = 0.0000001f;
        CosmeticSpring.Strength = 900f;
        CosmeticSpring.ImpulseQueueLimit = 1;

        Relay.Instance.OptionsMenu.OnFOVOptionChanged += ReceiveFOVChanged;
        BaseFieldOfView = Relay.Instance.OptionsMenu.FOVOptionValue;
        Relay.Instance.OptionsMenu.OnExteriorViewOptionChanged += ReceiveExteriorViewOptionChanged;

        // Used for view bob and jump/landing etc
        YSpring = new ScalarSpring(0f);
        YSpring.Strength = 800f;
        YSpring.Damping = 0.000000000001f;

        ViewBobSpring = new RotationalSpring(Quaternion.identity);
        ViewBobSpring.Strength = 500f;
        ViewBobSpring.Damping = 0.0000001f;
    }