public ConnectionInfoManagementViewModel() { AddNewItemCommand = IsItemEditing.Inverse().ToReactiveCommand(); AddNewItemCommand.Subscribe(() => { SelectedItem.Value = null; EditingItem.Value = new T(); if (IsGroupSelected?.Value == true) { EditingItem.Value.GroupName = SelectedGroup.Value?.Name; } IsItemEditing.Value = true; }).AddTo(Disposable); ConnectCommand.Subscribe(async item => await ConfirmConnect(item)).AddTo(Disposable); IsItemSelected = SelectedItem.Select(x => x != null).ToReadOnlyReactiveProperty(); IsNotItemEditing = IsItemEditing.Inverse().ToReadOnlyReactiveProperty(); SelectedItem.Subscribe(x => { EditingItem.Value = SelectedItem.Value; IsItemEditing.Value = false; }).AddTo(Disposable); StartEditCommand = IsItemSelected .CombineLatest(IsItemEditing.Inverse(), (a, b) => a && b) .ToReactiveCommand(); StartEditCommand.Subscribe(() => { EditingItem.Value = SelectedItem.Value.CloneDeep(); IsItemEditing.Value = true; }).AddTo(Disposable); ReplicateCommand = IsItemSelected .CombineLatest(IsItemEditing.Inverse(), (a, b) => a && b) .ToReactiveCommand(); ReplicateCommand.Subscribe(() => { var replicated = SelectedItem.Value.CloneDeep(); replicated.Id = -1; SelectedItem.Value = null; EditingItem.Value = replicated; IsItemEditing.Value = true; }).AddTo(Disposable); RemoveCommand = IsItemSelected .CombineLatest(IsItemEditing.Inverse(), (a, b) => a && b) .ToAsyncReactiveCommand(); RemoveCommand.Subscribe(async() => { if (await Remove(SelectedItem.Value)) { Items.Remove(SelectedItem.Value); // Renew Windows JumpList JumpListHelper.RenewJumpList(await MainWindow.DbContext.EnumerateAllConnectionInfos()); } }).AddTo(Disposable); DiscardChangesCommand = IsItemEditing.ToReactiveCommand(); DiscardChangesCommand.Subscribe(() => { EditingItem.Value = SelectedItem.Value ?? new T(); IsItemEditing.Value = false; }).AddTo(Disposable); SaveChangesCommand = IsItemEditing.ToReactiveCommand(); SaveChangesCommand.Subscribe(async() => { var selectedItem = SelectedItem.Value; var item = EditingItem.Value; try { var(result, resultItem) = await Save(item); if (resultItem == null) { return; // FAILED } item = resultItem; // Replace with the saved item if (result) // ADDED { Items.Add(item); } else // UPDATED { var oldItem = Items.FirstOrDefault(x => x.Id == item.Id); if (oldItem != null) { var index = Items.IndexOf(oldItem); if (index >= 0) { Items.RemoveAt(index); Items.Insert(index, item); } } } // Renew Windows JumpList JumpListHelper.RenewJumpList(await MainWindow.DbContext.EnumerateAllConnectionInfos()); } catch (OperationCanceledException) // User manually canceled { return; } SelectedItem.Value = item; IsItemEditing.Value = false; }).AddTo(Disposable); // Connection info filterings FilterText .Throttle(TimeSpan.FromMilliseconds(500)) .ObserveOnDispatcher() .Subscribe(_ => RefreshCollectionView()) .AddTo(Disposable); SelectedGroup .ObserveOnDispatcher() .Subscribe(_ => RefreshCollectionView()) .AddTo(Disposable); // If any group is selected or not (except for "All") IsGroupSelected = SelectedGroup .Select(x => x?.Name != AllGroupName) .ToReadOnlyReactivePropertySlim() .AddTo(Disposable); // Group list extraction on connection info events Observable.CombineLatest( // When Add, Remove or Update Items.CollectionChangedAsObservable() .Select(_ => Unit.Default) .StartWith(Unit.Default), // When GroupName property in each element changed Items.ObserveElementPropertyChanged() .Where(x => x.EventArgs.PropertyName == nameof(ConnectionInfoBase.GroupName)) .Select(_ => Unit.Default) .StartWith(Unit.Default) ) .Throttle(TimeSpan.FromMilliseconds(500)) // Once 500 ms .ObserveOnDispatcher() .Subscribe(_ => { var selectedGroup = SelectedGroup.Value; // Reload group list Groups.Clear(); EnumerateGroups().ToList().ForEach(Groups.Add); // Reset selected group SelectedGroup.Value = (selectedGroup is null) ? Groups.FirstOrDefault() : selectedGroup; }) .AddTo(Disposable); }
public TournamentRunner() { SceneLoader instance = SceneLoader.Instance; Singleton <PropertyManager> .Instance.AddRootContext(this); PFIDsUsed.Add("D1E872B9C9DA0648"); LoggedInPlayfab = (from id in PersistentSingleton <PlayFabService> .Instance.LoggedOnPlayerId.StartWith(string.Empty) select id != string.Empty).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); TimeTillTournament = TickerService.MasterTicksSlow.CombineLatest(ServerTimeService.IsSynced, (long tick, bool sync) => (!sync) ? (-1) : GetTimeTillTournament()).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); TimeTillTournamentClock = (from time in TimeTillTournament.DistinctUntilChanged() select(time <= 0) ? string.Empty : TextUtils.FormatSecondsShortWithDays(time)).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); (from till in TimeTillTournament where till == 0 select till).Subscribe(delegate { ResetIfDifferentDevice(); }).AddTo(instance); TournamentAccessable = TimeTillTournament.CombineLatest(PlayerData.Instance.TournamentIdCurrent, TournamentFetched, ConnectivityService.InternetConnectionAvailable, (long time, int id, bool fetched, bool connected) => connected && time == 0 && id < 0 && fetched).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); CurrentlyInTournament = (from id in PlayerData.Instance.TournamentIdCurrent select id >= 0 && CheckIfSameDevice()).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); (from should in TournamentFetched.CombineLatest(TimeTillTournament, FetchAttempt, LoggedInPlayfab, (bool fetched, long till, int attempt, bool loggedIn) => !fetched && attempt == 0 && till == 0) where should select should).Subscribe(delegate { TryToFetchTournament(); }).AddTo(instance); (from timestamp in PlayerData.Instance.TournamentTimeStamp where timestamp + 10000000L * (long)PersistentSingleton <GameSettings> .Instance.TournamentDurationSeconds >= ServerTimeService.NowTicks() && ServerTimeService.NowTicks() >= timestamp && CheckIfSameDevice() select timestamp).Subscribe(delegate { TournamentRuns.SetValueAndForceNotify(LoadTournamentRuns()); TournamentActive.SetValueAndForceNotify(value: true); }).AddTo(instance); TimeTillTournamentEnd = (from should in TickerService.MasterTicks.CombineLatest(ServerTimeService.IsSynced, PlayerData.Instance.TournamentIdCurrent, (long tick, bool sync, int id) => sync && id >= 0 && CheckIfSameDevice()) where should select should into _ select GetTimeTillTournamentEnd()).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); TournamentEndClock = (from time in TimeTillTournamentEnd.DistinctUntilChanged() select(time <= 0) ? string.Empty : TextUtils.FormatSecondsShort(time)).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); TournamentEnded = TimeTillTournamentEnd.CombineLatest(PlayerData.Instance.TournamentIdCurrent, (long time, int id) => time < 0 && id >= 0).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); (from ended in TournamentEnded where ended select ended).Subscribe(delegate { LoadTournamentEndedValues(); }).AddTo(instance); TournamentWorldReached = (from world in PlayerData.Instance.MainChunk select world >= 70).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); DisplayNameGiven = (from name in PlayerData.Instance.DisplayName select name != string.Empty).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); TournamentsUnlocked = PlayerData.Instance.LifetimePrestiges.CombineLatest(PlayerData.Instance.LifetimeChunk, (int prest, int chunk) => prest > 0 || chunk >= 45).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); (from unlocked in TournamentsUnlocked.Pairwise() where !unlocked.Previous && unlocked.Current select unlocked).Subscribe(delegate { BindingManager.Instance.TournamentUnlockedParent.ShowInfo(); }).AddTo(instance); PlayerData.Instance.Medals.Take(1).Subscribe(delegate { TryToBuyTrophy(showUnlocking: false); }).AddTo(instance); PlayerData.Instance.Trophies.Subscribe(delegate(int trophies) { CalculateTrophiesMultiplier(trophies); }).AddTo(instance); InternetConnectionAvailable = (from avail in ConnectivityService.InternetConnectionAvailable select(avail)).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); }
public BossBattleRunner() { Singleton <PropertyManager> .Instance.AddRootContext(this); SceneLoader instance = SceneLoader.Instance; BossMaxDuration = (from duration in Singleton <CumulativeBonusRunner> .Instance.BonusMult[7] select PersistentSingleton <GameSettings> .Instance.BossDurationSeconds + duration.ToInt()).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); UniRx.IObservable <long> left2 = (from dead in (from health in BossCurrentHP select health <= BigDouble.ZERO).DistinctUntilChanged() select(!dead) ? TickerService.MasterTicks : Observable.Never <long>()).Switch(); (from tuple in left2.CombineLatest(BossBattlePaused, (long ticks, bool paused) => new { ticks, paused }) where !tuple.paused select tuple).Subscribe(tuple => { if (ElapsedTime.Value < 864000000000L) { ElapsedTime.Value += tuple.ticks; } }).AddTo(instance); BattleSecondsLeft = (from left in ElapsedTime.CombineLatest(BossMaxDuration, (long elapsed, int dur) => dur - (int)(elapsed / 10000000)) select Mathf.Max(0, left)).TakeUntilDestroy(instance).ToReactiveProperty(); BattleSecondsLeftNormalized = (from secs in BattleSecondsLeft select(float) secs / (float)BossMaxDuration.Value).ToReadOnlyReactiveProperty(); UniRx.IObservable <bool> source = from secs in BattleSecondsLeft.Skip(1) select secs <= 0 into ranOut where ranOut select ranOut; UniRx.IObservable <bool> observable = from killed in (from health in BossCurrentHP select health <= BigDouble.ZERO).DistinctUntilChanged() where killed select killed; observable.Subscribe(delegate { PlayerData.Instance.BossFailedLastTime.Value = false; PersistentSingleton <MainSaver> .Instance.PleaseSave("boss_killed_chunk_" + Singleton <WorldRunner> .Instance.CurrentChunk.Value.Index + "_prestige_" + PlayerData.Instance.LifetimePrestiges.Value); }).AddTo(instance); (from order in Singleton <PrestigeRunner> .Instance.PrestigeTriggered select order == PrestigeOrder.PrestigeStart).Subscribe(delegate { if (BossBattleActive.Value) { ElapsedTime.Value = 85536000000000L; } PlayerData.Instance.BossFailedLastTime.Value = false; }).AddTo(instance); (from seq in Singleton <WorldRunner> .Instance.MapSequence where seq select seq).Subscribe(delegate { PlayerData.Instance.BossFailedLastTime.Value = false; }).AddTo(instance); UniRx.IObservable <bool> observable2 = (from pair in Singleton <ChunkRunner> .Instance.AllBlockAmount.Pairwise() select pair.Current == 1 && pair.Previous > 1).CombineLatest(Singleton <ChunkRunner> .Instance.BossBlock, (bool cleared, BossBlockController boss) => cleared && boss != null).StartWith(value: false); (from activated in observable2 where activated select activated).Subscribe(delegate { StartCountdown(); }).AddTo(instance); BossBattleActive = (from secs in BattleSecondsLeft select secs > 0).CombineLatest(observable2, (bool time, bool block) => time && block).DistinctUntilChanged().TakeUntilDestroy(instance) .ToReadOnlyReactiveProperty(); BossLevelActive = (from boss in Singleton <ChunkRunner> .Instance.BossBlock select boss != null).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); (from pair in BossLevelActive.Pairwise() select pair.Current&& !pair.Previous into start where start select start).Subscribe(delegate { StartBossLevel(); }).AddTo(instance); BossPreludeActive = BossLevelActive.CombineLatest(Singleton <ChunkRunner> .Instance.AllBlockAmount, (bool level, int blocks) => level && blocks > 1).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); BossFailedActive = BossLevelActive.CombineLatest(BossPreludeActive, BossBattleActive, (bool level, bool prelude, bool battle) => level && !prelude && !battle).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); TryBossAvailable = PlayerData.Instance.BossFailedLastTime.CombineLatest(BossLevelActive, (bool failed, bool active) => failed && !active).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); BossBattlePending = TryBossAvailable.CombineLatest(BossLevelActive, (bool avail, bool level) => avail || level).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); BossSuccessNotification = (from _ in observable select Observable.Merge(new UniRx.IObservable <bool>[2] { Observable.Return <bool>(value: true), Observable.Return <bool>(value: false).Delay(TimeSpan.FromSeconds(10.0)) })).Switch().TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); BossFailedNotification = (from _ in source select Observable.Merge(new UniRx.IObservable <bool>[2] { Observable.Return <bool>(value: true), Observable.Return <bool>(value: false).Delay(TimeSpan.FromSeconds(10.0)) })).Switch().TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); BossBattleResult = (from _ in source select false).Merge(observable).StartWith(value: false).ToSequentialReadOnlyReactiveProperty(); BossFullHP = (from chunk in Singleton <WorldRunner> .Instance.CurrentChunk select ChunkRunner.IsLastChunkForNode(chunk.Index)).Select(delegate(bool last) { BiomeConfig value = Singleton <WorldRunner> .Instance.CurrentBiomeConfig.Value; return((!last) ? value.MiniBossHP : value.BossHP); }).CombineLatest(Singleton <DrJellyRunner> .Instance.DrJellyBattle, (BigDouble hp, bool dr) => (!dr) ? hp : (hp * PersistentSingleton <GameSettings> .Instance.DrJellyHpMult)).TakeUntilDestroy(instance) .ToReadOnlyReactiveProperty(); BossHealthNormalized = (from hp in BossFullHP select(!(hp > new BigDouble(1.0))) ? new BigDouble(1.0) : hp).CombineLatest(BossCurrentHP, (BigDouble full, BigDouble current) => (current / full).ToFloat()).TakeUntilDestroy(instance).ToReadOnlyReactiveProperty(); (from result in BossBattleResult.Skip(1) where !result select result).Subscribe(delegate { AudioController.Instance.QueueEvent(new AudioEvent("BossSequenceFailed", AUDIOEVENTACTION.Play)); }).AddTo(instance); (from result in BossBattleResult.Skip(1) where result select result).Subscribe(delegate { PlayerData.Instance.RetryLevelNumber.Value = 0; }).AddTo(instance); if (PersistentSingleton <GameAnalytics> .Instance != null) { BossBattleResult.Subscribe(delegate(bool result) { PersistentSingleton <GameAnalytics> .Instance.BossBattleResult.Value = result; }).AddTo(instance); } }
// FIXME: VMでやることじゃない public AxisStandardViewModel( INativeWindowManager nativeWindowManager, IScreenManager screenManager, IAudioManager audioManager, IVersionRepository versionRepository, ISettingService settingService) { settings = settingService.Instance(); Vertical = BindSettings(settings.Vertical, nameof(settings.Vertical)); Horizontal = BindSettings(settings.Horizontal, nameof(settings.Horizontal)); WindowFittingStandard = BindSettings(settings.WindowFittingStandard, nameof(settings.WindowFittingStandard)); MuteCondition = BindSettings(settings.MuteCondition, nameof(settings.MuteCondition)); TargetApplicationName = BindSettings(settings.TargetApplicationName, nameof(TargetApplicationName)); LatestVersion = new ReactiveProperty <string>(""); UseCurrentVerticalUserSetting = BindSettings(settings.UseCurrentVerticalUserSetting, nameof(settings.UseCurrentVerticalUserSetting), ReactivePropertyMode.RaiseLatestValueOnSubscribe); UseCurrentHorizontalUserSetting = BindSettings(settings.UseCurrentHorizontalUserSetting, nameof(settings.UseCurrentHorizontalUserSetting), ReactivePropertyMode.RaiseLatestValueOnSubscribe); UserDefinedVerticalWindowRect = BindSettings(settings.UserDefinedVerticalWindowRect, nameof(settings.UserDefinedVerticalWindowRect)); UserDefinedHorizontalWindowRect = BindSettings(settings.UserDefinedHorizontalWindowRect, nameof(settings.UserDefinedHorizontalWindowRect)); IsMostTop = BindSettings(settings.IsMostTop, nameof(settings.IsMostTop)); IsRemoveBorder = BindSettings(settings.IsRemoveBorder, nameof(settings.IsRemoveBorder)); // FIXME: PollingじゃなくてGlobalHookとかでやりたい targetWindowHandle = Observable.Interval(TimeSpan.FromSeconds(5)) .CombineLatest(TargetApplicationName) .Select(x => nativeWindowManager.GetWindowHandle(x.Second)) .Distinct() .ToReadOnlyReactiveProperty(); // FIXME: TargetApplicationNameが変わってもThreadが変わって動かなくなるわ… Disposable.Add(TargetApplicationName.Subscribe(x => nativeWindowManager.SetHook(x))); Disposable.Add(targetWindowHandle.Subscribe(x => nativeWindowManager.SetTargetProcessHandler(x))); var observableBorderChanged = Observable.FromEventPattern(nativeWindowManager, nameof(nativeWindowManager.OnBorderChanged)).StartWith(new object[] { null }); var observableOnMoveChanged = Observable.FromEventPattern(nativeWindowManager, nameof(nativeWindowManager.OnMoveOrSizeChanged)).Throttle(TimeSpan.FromMilliseconds(200)).StartWith(new object[] { null }); var windowRect = targetWindowHandle .CombineLatest( observableOnMoveChanged, observableBorderChanged.Delay(TimeSpan.FromMilliseconds(500)) ) .Select(x => { if (x.First == IntPtr.Zero) { return(WindowRect.Empty, WindowRect.Empty); } var windowClientRectPair = nativeWindowManager.GetWindowRect(x.First); var(r, _) = windowClientRectPair; if (r.IsEmpty) { return(WindowRect.Empty, WindowRect.Empty); } return(windowClientRectPair); }); Disposable.Add(UseCurrentHorizontalUserSetting.Subscribe(x => { if (!x) { return; } var handle = targetWindowHandle.Value; if (handle == IntPtr.Zero) { return; } var(r, _) = nativeWindowManager.GetWindowRect(handle); if (r.IsEmpty) { UserDefinedHorizontalWindowRect.Value = WindowRect.Empty; return; } UserDefinedHorizontalWindowRect.Value = r; return; })); Disposable.Add(UseCurrentVerticalUserSetting.Subscribe(x => { if (!x) { return; } var handle = targetWindowHandle.Value; if (handle == IntPtr.Zero) { return; } var(r, _) = nativeWindowManager.GetWindowRect(handle); if (r.IsEmpty) { UserDefinedVerticalWindowRect.Value = WindowRect.Empty; return; } UserDefinedVerticalWindowRect.Value = r; return; })); Disposable.Add(targetWindowHandle.CombineLatest( MuteCondition, Observable.CombineLatest( Observable.FromEventPattern <bool>(nativeWindowManager, nameof(nativeWindowManager.OnForeground)) .Select(x => x.EventArgs.ToDefaultableBooleanLike()).StartWith(DefaultableBooleanLike.Default), Observable.FromEventPattern <bool>(nativeWindowManager, nameof(nativeWindowManager.OnMinimized)) .Select(x => x.EventArgs.ToDefaultableBooleanLike()).StartWith(DefaultableBooleanLike.Default) ) .DistinctUntilChanged() .Select(x => { var maybeForeground = x[0]; var maybeMinimized = x[1]; return((maybeForeground, maybeMinimized) switch { (DefaultableBooleanLike.Default, DefaultableBooleanLike.Default) => ApplicationState.Foreground, (DefaultableBooleanLike.Default, DefaultableBooleanLike.True) => ApplicationState.Minimized, (DefaultableBooleanLike.Default, DefaultableBooleanLike.False) => ApplicationState.Background, (DefaultableBooleanLike.True, DefaultableBooleanLike.Default) => ApplicationState.Foreground, (DefaultableBooleanLike.True, DefaultableBooleanLike.True) => ApplicationState.Minimized, (DefaultableBooleanLike.True, DefaultableBooleanLike.False) => ApplicationState.Foreground, (DefaultableBooleanLike.False, DefaultableBooleanLike.Default) => ApplicationState.Background, (DefaultableBooleanLike.False, DefaultableBooleanLike.True) => ApplicationState.Minimized, (DefaultableBooleanLike.False, DefaultableBooleanLike.False) => ApplicationState.Background }); })