예제 #1
0
        private void load(GamebosuConfigManager config)
        {
            Rate.BindValueChanged(updateValue, true);

            lockClockRate = config?.GetBindable <bool>(GamebosuSetting.LockClockRate);
            lockClockRate?.BindValueChanged(e => State.Value = e.NewValue ? Visibility.Hidden : Visibility.Visible, true);
        }
예제 #2
0
        protected override void LoadComplete()
        {
            rooms.CollectionChanged  += roomsChanged;
            roomManager.RoomsUpdated += updateSorting;

            rooms.BindTo(roomManager.Rooms);

            Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true);
        }
예제 #3
0
 private void load(GameplayClock gameplayClock)
 {
     // if in a gameplay context, pause sample playback when gameplay is paused.
     gameplayClockPaused = gameplayClock?.IsPaused.GetBoundCopy();
     gameplayClockPaused?.BindValueChanged(paused =>
     {
         if (requestedPlaying)
         {
             if (paused.NewValue)
             {
                 stop();
             }
             // it's not easy to know if a sample has finished playing (to end).
             // to keep things simple only resume playing looping samples.
             else if (Looping)
             {
                 play();
             }
         }
     });
 }
예제 #4
0
        protected override void LoadComplete()
        {
            base.LoadComplete();

            areaOffset.BindTo(tabletHandler.AreaOffset);
            areaOffset.BindValueChanged(val =>
            {
                offsetX.Value = val.NewValue.X;
                offsetY.Value = val.NewValue.Y;
            }, true);

            offsetX.BindValueChanged(val => areaOffset.Value = new Vector2(val.NewValue, areaOffset.Value.Y));
            offsetY.BindValueChanged(val => areaOffset.Value = new Vector2(areaOffset.Value.X, val.NewValue));

            areaSize.BindTo(tabletHandler.AreaSize);
            areaSize.BindValueChanged(val =>
            {
                sizeX.Value = val.NewValue.X;
                sizeY.Value = val.NewValue.Y;
            }, true);

            sizeX.BindValueChanged(val =>
            {
                areaSize.Value = new Vector2(val.NewValue, areaSize.Value.Y);

                aspectRatioApplication?.Cancel();
                aspectRatioApplication = Schedule(() => applyAspectRatio(sizeX));
            });

            sizeY.BindValueChanged(val =>
            {
                areaSize.Value = new Vector2(areaSize.Value.X, val.NewValue);

                aspectRatioApplication?.Cancel();
                aspectRatioApplication = Schedule(() => applyAspectRatio(sizeY));
            });

            updateAspectRatio();
            aspectRatio.BindValueChanged(aspect =>
            {
                aspectRatioApplication?.Cancel();
                aspectRatioApplication = Schedule(() => forceAspectRatio(aspect.NewValue));
            });

            tablet.BindTo(tabletHandler.Tablet);
            tablet.BindValueChanged(val =>
            {
                Scheduler.AddOnce(toggleVisibility);

                var tab = val.NewValue;

                bool tabletFound = tab != null;
                if (!tabletFound)
                {
                    return;
                }

                offsetX.MaxValue = tab.Size.X;
                offsetX.Default  = tab.Size.X / 2;
                sizeX.Default    = sizeX.MaxValue = tab.Size.X;

                offsetY.MaxValue = tab.Size.Y;
                offsetY.Default  = tab.Size.Y / 2;
                sizeY.Default    = sizeY.MaxValue = tab.Size.Y;

                areaSize.Default = new Vector2(sizeX.Default, sizeY.Default);
            }, true);
        }
예제 #5
0
            protected override void LoadComplete()
            {
                base.LoadComplete();

                selectedGroup.BindValueChanged(group => { Selected = controlGroup == group.NewValue; }, true);
            }
예제 #6
0
 public UpdateableBeatmapBackgroundSprite()
 {
     Beatmap.BindValueChanged(b => Model = b.NewValue);
 }
예제 #7
0
        protected override void LoadComplete()
        {
            base.LoadComplete();

            Metadata.BindValueChanged(onMetadataChanged, true);
        }
예제 #8
0
 public LocalisationManager(Bindable <string> locale)
 {
     preferUnicode = new Bindable <bool>(true);
     configLocale  = locale;
     configLocale.BindValueChanged(updateLocale);
 }
예제 #9
0
        private void load()
        {
            try
            {
                using (var str = File.OpenRead(typeof(OsuGameBase).Assembly.Location))
                    VersionHash = str.ComputeMD5Hash();
            }
            catch
            {
                // special case for android builds, which can't read DLLs from a packed apk.
                // should eventually be handled in a better way.
                VersionHash = $"{Version}-{RuntimeInfo.OS}".ComputeMD5Hash();
            }

            Resources.AddStore(new DllResourceStore(OsuResources.ResourceAssembly));

            dependencies.Cache(contextFactory = new DatabaseContextFactory(Storage));

            dependencies.CacheAs(Storage);

            var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore <byte[]>(Resources, @"Textures")));

            largeStore.AddStore(Host.CreateTextureLoaderStore(new OnlineStore()));
            dependencies.Cache(largeStore);

            dependencies.CacheAs(this);
            dependencies.CacheAs(LocalConfig);

            AddFont(Resources, @"Fonts/osuFont");

            AddFont(Resources, @"Fonts/Torus-Regular");
            AddFont(Resources, @"Fonts/Torus-Light");
            AddFont(Resources, @"Fonts/Torus-SemiBold");
            AddFont(Resources, @"Fonts/Torus-Bold");

            AddFont(Resources, @"Fonts/Noto-Basic");
            AddFont(Resources, @"Fonts/Noto-Hangul");
            AddFont(Resources, @"Fonts/Noto-CJK-Basic");
            AddFont(Resources, @"Fonts/Noto-CJK-Compatibility");
            AddFont(Resources, @"Fonts/Noto-Thai");

            AddFont(Resources, @"Fonts/Venera-Light");
            AddFont(Resources, @"Fonts/Venera-Bold");
            AddFont(Resources, @"Fonts/Venera-Black");

            Audio.Samples.PlaybackConcurrency = SAMPLE_CONCURRENCY;

            runMigrations();

            dependencies.Cache(SkinManager = new SkinManager(Storage, contextFactory, Host, Audio, new NamespacedResourceStore <byte[]>(Resources, "Skins/Legacy")));
            dependencies.CacheAs <ISkinSource>(SkinManager);

            // needs to be done here rather than inside SkinManager to ensure thread safety of CurrentSkinInfo.
            SkinManager.ItemRemoved.BindValueChanged(weakRemovedInfo =>
            {
                if (weakRemovedInfo.NewValue.TryGetTarget(out var removedInfo))
                {
                    Schedule(() =>
                    {
                        // check the removed skin is not the current user choice. if it is, switch back to default.
                        if (removedInfo.ID == SkinManager.CurrentSkinInfo.Value.ID)
                        {
                            SkinManager.CurrentSkinInfo.Value = SkinInfo.Default;
                        }
                    });
                }
            });

            EndpointConfiguration endpoints = UseDevelopmentServer ? (EndpointConfiguration) new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration();

            MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl;

            dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints, VersionHash));

            dependencies.CacheAs(spectatorStreaming = new SpectatorStreamingClient(endpoints));
            dependencies.CacheAs(multiplayerClient  = new MultiplayerClient(endpoints));

            var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);

            dependencies.Cache(RulesetStore = new RulesetStore(contextFactory, Storage));
            dependencies.Cache(FileStore    = new FileStore(contextFactory, Storage));

            // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
            dependencies.Cache(ScoreManager   = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => DifficultyCache, LocalConfig));
            dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap, true));

            // this should likely be moved to ArchiveModelManager when another case appers where it is necessary
            // to have inter-dependent model managers. this could be obtained with an IHasForeign<T> interface to
            // allow lookups to be done on the child (ScoreManager in this case) to perform the cascading delete.
            List <ScoreInfo> getBeatmapScores(BeatmapSetInfo set)
            {
                var beatmapIds = BeatmapManager.QueryBeatmaps(b => b.BeatmapSetInfoID == set.ID).Select(b => b.ID).ToList();

                return(ScoreManager.QueryScores(s => beatmapIds.Contains(s.Beatmap.ID)).ToList());
            }

            BeatmapManager.ItemRemoved.BindValueChanged(i =>
            {
                if (i.NewValue.TryGetTarget(out var item))
                {
                    ScoreManager.Delete(getBeatmapScores(item), true);
                }
            });

            BeatmapManager.ItemUpdated.BindValueChanged(i =>
            {
                if (i.NewValue.TryGetTarget(out var item))
                {
                    ScoreManager.Undelete(getBeatmapScores(item), true);
                }
            });

            dependencies.Cache(DifficultyCache = new BeatmapDifficultyCache());
            AddInternal(DifficultyCache);

            dependencies.Cache(UserCache = new UserLookupCache());
            AddInternal(UserCache);

            var scorePerformanceManager = new ScorePerformanceCache();

            dependencies.Cache(scorePerformanceManager);
            AddInternal(scorePerformanceManager);

            dependencies.Cache(KeyBindingStore    = new KeyBindingStore(contextFactory, RulesetStore));
            dependencies.Cache(SettingsStore      = new SettingsStore(contextFactory));
            dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore));
            dependencies.Cache(new SessionStatics());
            dependencies.Cache(new OsuColour());

            RegisterImportHandler(BeatmapManager);
            RegisterImportHandler(ScoreManager);
            RegisterImportHandler(SkinManager);

            // drop track volume game-wide to leave some head-room for UI effects / samples.
            // this means that for the time being, gameplay sample playback is louder relative to the audio track, compared to stable.
            // we may want to revisit this if users notice or complain about the difference (consider this a bit of a trial).
            Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, globalTrackVolumeAdjust);

            Beatmap = new NonNullableBindable <WorkingBeatmap>(defaultBeatmap);

            dependencies.CacheAs <IBindable <WorkingBeatmap> >(Beatmap);
            dependencies.CacheAs(Beatmap);

            FileStore.Cleanup();

            // add api components to hierarchy.
            if (API is APIAccess apiAccess)
            {
                AddInternal(apiAccess);
            }
            AddInternal(spectatorStreaming);
            AddInternal(multiplayerClient);

            AddInternal(RulesetConfigCache);

            var globalInput = new GlobalInputManager(this)
            {
                RelativeSizeAxes = Axes.Both,
                Child            = MenuCursorContainer = new MenuCursorContainer {
                    RelativeSizeAxes = Axes.Both
                }
            };

            MenuCursorContainer.Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor)
            {
                RelativeSizeAxes = Axes.Both
            };

            base.Content.Add(CreateScalingContainer().WithChild(globalInput));

            KeyBindingStore.Register(globalInput.GlobalBindings);
            dependencies.Cache(globalInput.GlobalBindings);

            PreviewTrackManager previewTrackManager;

            dependencies.Cache(previewTrackManager = new PreviewTrackManager());
            Add(previewTrackManager);

            AddInternal(MusicController = new MusicController());
            dependencies.CacheAs(MusicController);

            Ruleset.BindValueChanged(onRulesetChanged);
        }
예제 #10
0
        private void load(IAPIProvider api, NotificationOverlay notifications)
        {
            SpriteIcon icon;

            AddRange(new Drawable[]
            {
                icon = new SpriteIcon
                {
                    Anchor = Anchor.Centre,
                    Origin = Anchor.Centre,
                    Icon   = FontAwesome.Regular.Heart,
                    Size   = new Vector2(18),
                    Shadow = false,
                },
                loading = new DimmedLoadingLayer(0.8f, 0.5f),
            });

            Action = () =>
            {
                if (loading.State.Value == Visibility.Visible)
                {
                    return;
                }

                // guaranteed by disabled state above.
                Debug.Assert(BeatmapSet.Value.OnlineBeatmapSetID != null);

                loading.Show();

                request?.Cancel();

                request = new PostBeatmapFavouriteRequest(BeatmapSet.Value.OnlineBeatmapSetID.Value, favourited.Value ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite);

                request.Success += () =>
                {
                    favourited.Toggle();
                    loading.Hide();
                };

                request.Failure += e =>
                {
                    notifications?.Post(new SimpleNotification
                    {
                        Text = e.Message,
                        Icon = FontAwesome.Solid.Times,
                    });

                    loading.Hide();
                };

                api.Queue(request);
            };

            favourited.ValueChanged += favourited => icon.Icon = favourited.NewValue ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart;

            localUser.BindTo(api.LocalUser);
            localUser.BindValueChanged(_ => updateEnabled());

            // must be run after setting the Action to ensure correct enabled state (setting an Action forces a button to be enabled).
            BeatmapSet.BindValueChanged(setInfo =>
            {
                updateEnabled();
                favourited.Value = setInfo.NewValue?.OnlineInfo?.HasFavourited ?? false;
            }, true);
        }
예제 #11
0
 private void load()
 {
     // todo: when friending/unfriending is implemented, the APIAccess.Friends list should be updated accordingly.
     User.BindValueChanged(user => SetValue(user.NewValue?.FollowerCount ?? 0), true);
 }
예제 #12
0
        private void load(OverlayColourProvider colourProvider, TextureStore textures)
        {
            Container <Drawable> hiddenDetailContainer;
            Container <Drawable> expandedDetailContainer;

            InternalChildren = new Drawable[]
            {
                new Box
                {
                    RelativeSizeAxes = Axes.Both,
                    Colour           = colourProvider.Background4
                },
                new FillFlowContainer
                {
                    AutoSizeAxes     = Axes.X,
                    RelativeSizeAxes = Axes.Y,
                    Direction        = FillDirection.Horizontal,
                    Padding          = new MarginPadding {
                        Vertical = 10
                    },
                    Margin = new MarginPadding {
                        Left = UserProfileOverlay.CONTENT_X_MARGIN
                    },
                    Spacing  = new Vector2(10, 0),
                    Children = new Drawable[]
                    {
                        new AddFriendButton
                        {
                            RelativeSizeAxes = Axes.Y,
                            User             = { BindTarget = User }
                        },
                        new MessageUserButton
                        {
                            User = { BindTarget = User }
                        },
                        // Disabled temporarily, Will be available
                        // after peppy improves the watch stream system
                        // (Supports watch to stable players gameplay.)

                        /*new SpectatePlayerButton
                         * {
                         *  RelativeSizeAxes = Axes.Y,
                         *  User = { BindTarget = User }
                         * },*/
                    }
                },
                new Container
                {
                    Anchor           = Anchor.CentreRight,
                    Origin           = Anchor.CentreRight,
                    RelativeSizeAxes = Axes.Y,
                    Padding          = new MarginPadding {
                        Vertical = 10
                    },
                    Width = UserProfileOverlay.CONTENT_X_MARGIN,
                    Child = new ExpandDetailsButton
                    {
                        RelativeSizeAxes = Axes.Y,
                        Anchor           = Anchor.Centre,
                        Origin           = Anchor.Centre,
                        DetailsVisible   = { BindTarget = DetailsVisible }
                    },
                },
                new Container
                {
                    Anchor       = Anchor.CentreRight,
                    Origin       = Anchor.CentreRight,
                    AutoSizeAxes = Axes.Both,
                    Margin       = new MarginPadding {
                        Right = UserProfileOverlay.CONTENT_X_MARGIN
                    },
                    Children = new Drawable[]
                    {
                        new LevelBadge
                        {
                            Anchor = Anchor.CentreRight,
                            Origin = Anchor.CentreRight,
                            Size   = new Vector2(40),
                            User   = { BindTarget = User }
                        },
                        expandedDetailContainer = new Container
                        {
                            Anchor = Anchor.CentreRight,
                            Origin = Anchor.CentreRight,
                            Width  = 200,
                            Height = 6,
                            Margin = new MarginPadding {
                                Right = 50
                            },
                            Child = new LevelProgressBar
                            {
                                RelativeSizeAxes = Axes.Both,
                                User             = { BindTarget = User }
                            }
                        },
                        hiddenDetailContainer = new FillFlowContainer
                        {
                            Direction    = FillDirection.Horizontal,
                            Anchor       = Anchor.CentreRight,
                            Origin       = Anchor.CentreRight,
                            Width        = 200,
                            AutoSizeAxes = Axes.Y,
                            Alpha        = 0,
                            Spacing      = new Vector2(10, 0),
                            Margin       = new MarginPadding {
                                Right = 50
                            },
                            Children = new[]
                            {
                                hiddenDetailGlobal = new OverlinedInfoContainer
                                {
                                    Title      = "全球排名",
                                    LineColour = colourProvider.Highlight1
                                },
                                hiddenDetailCountry = new OverlinedInfoContainer
                                {
                                    Title      = "國家排名",
                                    LineColour = colourProvider.Highlight1
                                },
                            }
                        }
                    }
                }
            };

            DetailsVisible.BindValueChanged(visible =>
            {
                hiddenDetailContainer.FadeTo(visible.NewValue ? 0 : 1, 200, Easing.OutQuint);
                expandedDetailContainer.FadeTo(visible.NewValue ? 1 : 0, 200, Easing.OutQuint);
            });

            User.BindValueChanged(user => updateDisplay(user.NewValue));
        }
예제 #13
0
        private void load(Storage storage, FrameworkConfigManager frameworkConfig)
        {
            Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));

            AddFont(Resources, @"Resources/Fonts/Aquatico-Regular");
            AddFont(Resources, @"Resources/Fonts/Aquatico-Light");

            Textures.AddStore(new TextureLoaderStore(new ResourceStore <byte[]>(new StorageBackedResourceStore(storage))));

            this.storage = storage;

            windowSize = frameworkConfig.GetBindable <Size>(FrameworkSetting.WindowedSize);
            windowSize.BindValueChanged(size => ScheduleAfterChildren(() =>
            {
                var minWidth = (int)(size.NewValue.Height / 9f * 16 + 400);

                heightWarning.Alpha = size.NewValue.Width < minWidth ? 1 : 0;
            }), true);

            readBracket();

            ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value);

            dependencies.CacheAs <MatchIPCInfo>(ipc = new FileBasedIPC());
            Add(ipc);

            AddRange(new[]
            {
                new TourneyButton
                {
                    Text    = "Save Changes",
                    Width   = 140,
                    Height  = 50,
                    Depth   = float.MinValue,
                    Anchor  = Anchor.BottomRight,
                    Origin  = Anchor.BottomRight,
                    Padding = new MarginPadding(10),
                    Action  = SaveChanges,
                },
                heightWarning = new Container
                {
                    Masking      = true,
                    CornerRadius = 5,
                    Depth        = float.MinValue,
                    Anchor       = Anchor.Centre,
                    Origin       = Anchor.Centre,
                    AutoSizeAxes = Axes.Both,
                    Children     = new Drawable[]
                    {
                        new Box
                        {
                            Colour           = Color4.Red,
                            RelativeSizeAxes = Axes.Both,
                        },
                        new OsuSpriteText
                        {
                            Text    = "Please make the window wider",
                            Font    = OsuFont.Default.With(weight: "bold"),
                            Colour  = Color4.White,
                            Padding = new MarginPadding(20)
                        }
                    }
                },
            });
        }
예제 #14
0
 protected override void LoadComplete()
 {
     Scope.BindValueChanged(onScopeChanged, true);
     Country.BindValueChanged(onCountryChanged, true);
     base.LoadComplete();
 }
예제 #15
0
 protected override void LoadComplete()
 {
     hue.BindValueChanged(h => fill.Colour = Colour4.FromHSV(h.NewValue, 1, 1), true);
 }
예제 #16
0
 protected override void LoadComplete()
 {
     base.LoadComplete();
     state.BindValueChanged(updateState, true);
 }
예제 #17
0
        private void load()
        {
            Resources.AddStore(new DllResourceStore(@"osu.Game.Resources.dll"));

            dependencies.Cache(contextFactory = new DatabaseContextFactory(Storage));

            var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore <byte[]>(Resources, @"Textures")));

            largeStore.AddStore(Host.CreateTextureLoaderStore(new OnlineStore()));
            dependencies.Cache(largeStore);

            dependencies.CacheAs(this);
            dependencies.Cache(LocalConfig);

            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/osuFont"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Medium"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-MediumItalic"));

            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-Basic"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-Hangul"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-CJK-Basic"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Noto-CJK-Compatibility"));

            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Regular"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-RegularItalic"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-SemiBold"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-SemiBoldItalic"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Bold"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-BoldItalic"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Light"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-LightItalic"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-Black"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Exo2.0-BlackItalic"));

            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Light"));
            Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Medium"));

            runMigrations();

            dependencies.Cache(SkinManager = new SkinManager(Storage, contextFactory, Host, Audio, new NamespacedResourceStore <byte[]>(Resources, "Skins/Legacy")));
            dependencies.CacheAs <ISkinSource>(SkinManager);

            if (API == null)
            {
                API = new APIAccess(LocalConfig);
            }

            dependencies.CacheAs(API);

            var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);

            dependencies.Cache(RulesetStore = new RulesetStore(contextFactory));
            dependencies.Cache(FileStore    = new FileStore(contextFactory, Storage));

            // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
            dependencies.Cache(ScoreManager   = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host));
            dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap));

            // this should likely be moved to ArchiveModelManager when another case appers where it is necessary
            // to have inter-dependent model managers. this could be obtained with an IHasForeign<T> interface to
            // allow lookups to be done on the child (ScoreManager in this case) to perform the cascading delete.
            List <ScoreInfo> getBeatmapScores(BeatmapSetInfo set)
            {
                var beatmapIds = BeatmapManager.QueryBeatmaps(b => b.BeatmapSetInfoID == set.ID).Select(b => b.ID).ToList();

                return(ScoreManager.QueryScores(s => beatmapIds.Contains(s.Beatmap.ID)).ToList());
            }

            BeatmapManager.ItemRemoved += i => ScoreManager.Delete(getBeatmapScores(i), true);
            BeatmapManager.ItemAdded   += i => ScoreManager.Undelete(getBeatmapScores(i), true);

            dependencies.Cache(KeyBindingStore    = new KeyBindingStore(contextFactory, RulesetStore));
            dependencies.Cache(SettingsStore      = new SettingsStore(contextFactory));
            dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore));
            dependencies.Cache(new SessionStatics());
            dependencies.Cache(new OsuColour());

            fileImporters.Add(BeatmapManager);
            fileImporters.Add(ScoreManager);
            fileImporters.Add(SkinManager);

            // tracks play so loud our samples can't keep up.
            // this adds a global reduction of track volume for the time being.
            Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8));

            beatmap = new NonNullableBindable <WorkingBeatmap>(defaultBeatmap);
            beatmap.BindValueChanged(b => ScheduleAfterChildren(() =>
            {
                // compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
                if (b.OldValue?.TrackLoaded == true && b.OldValue?.Track != b.NewValue?.Track)
                {
                    b.OldValue.RecycleTrack();
                }
            }));

            dependencies.CacheAs <IBindable <WorkingBeatmap> >(beatmap);
            dependencies.CacheAs(beatmap);

            FileStore.Cleanup();

            if (API is APIAccess apiAcces)
            {
                AddInternal(apiAcces);
            }
            AddInternal(RulesetConfigCache);

            GlobalActionContainer globalBinding;

            MenuCursorContainer = new MenuCursorContainer {
                RelativeSizeAxes = Axes.Both
            };
            MenuCursorContainer.Child = globalBinding = new GlobalActionContainer(this)
            {
                RelativeSizeAxes = Axes.Both,
                Child            = content = new OsuTooltipContainer(MenuCursorContainer.Cursor)
                {
                    RelativeSizeAxes = Axes.Both
                }
            };

            base.Content.Add(new ScalingContainer(ScalingMode.Everything)
            {
                Child = MenuCursorContainer
            });

            KeyBindingStore.Register(globalBinding);
            dependencies.Cache(globalBinding);

            PreviewTrackManager previewTrackManager;

            dependencies.Cache(previewTrackManager = new PreviewTrackManager());
            Add(previewTrackManager);
        }
예제 #18
0
        public TranslateEditSection()
        {
            Padding = new MarginPadding(10);

            var columnDimensions = new[]
            {
                new Dimension(GridSizeMode.Absolute, 200),
                new Dimension(GridSizeMode.Absolute, column_spacing),
                new Dimension(GridSizeMode.Absolute, 400),
                new Dimension(GridSizeMode.Absolute, column_spacing),
                new Dimension()
            };

            Child = new FillFlowContainer
            {
                RelativeSizeAxes = Axes.X,
                AutoSizeAxes     = Axes.Y,
                Children         = new Drawable[]
                {
                    new GridContainer
                    {
                        Name          = "LanguageSelection",
                        RowDimensions = new[]
                        {
                            new Dimension(GridSizeMode.AutoSize)
                        },
                        ColumnDimensions = columnDimensions,
                        RelativeSizeAxes = Axes.X,
                        AutoSizeAxes     = Axes.Y,
                        Content          = new Drawable[][]
                        {
                            new[]
                            {
                                null,
                                null,
                                null,
                                null,
                                new GridContainer
                                {
                                    RelativeSizeAxes = Axes.X,
                                    AutoSizeAxes     = Axes.Y,
                                    ColumnDimensions = new[]
                                    {
                                        new Dimension(GridSizeMode.Distributed),
                                        new Dimension(GridSizeMode.Absolute, column_spacing),
                                        new Dimension(GridSizeMode.Absolute, 50),
                                        new Dimension(GridSizeMode.Absolute, column_spacing),
                                        new Dimension(GridSizeMode.Absolute, 50),
                                    },
                                    RowDimensions = new[]
                                    {
                                        new Dimension(GridSizeMode.AutoSize),
                                    },
                                    Content = new[]
                                    {
                                        new Drawable[]
                                        {
                                            languageDropdown = new LanguageDropdown
                                            {
                                                RelativeSizeAxes = Axes.X,
                                            },
                                            null,
                                            new IconButton
                                            {
                                                Y      = 5,
                                                Icon   = FontAwesome.Solid.Plus,
                                                Action = () =>
                                                {
                                                    LanguageSelectionDialog.Show();
                                                }
                                            },
                                            null,
                                            new IconButton
                                            {
                                                Y      = 5,
                                                Icon   = FontAwesome.Solid.Trash,
                                                Action = () =>
                                                {
                                                    var currentLanguage = languageDropdown.Current.Value;

                                                    if (translateManager.LanguageContainsTranslateAmount(currentLanguage) > 0)
                                                    {
                                                        DialogOverlay.Push(new DeleteLanguagePopupDialog(currentLanguage, isOk =>
                                                        {
                                                            if (isOk)
                                                            {
                                                                translateManager.RemoveLanguage(currentLanguage);
                                                            }
                                                        }));
                                                    }
                                                    else
                                                    {
                                                        translateManager.RemoveLanguage(currentLanguage);
                                                    }
                                                }
                                            },
                                        }
                                    }
                                }
                            },
                        }
                    },
                    new Container
                    {
                        RelativeSizeAxes = Axes.X,
                        AutoSizeAxes     = Axes.Y,
                        Children         = new[]
                        {
                            new GridContainer
                            {
                                Name          = "Background",
                                RowDimensions = new[]
                                {
                                    new Dimension(GridSizeMode.AutoSize)
                                },
                                ColumnDimensions = columnDimensions,
                                RelativeSizeAxes = Axes.Both,
                                Content          = new[]
                                {
                                    new[]
                                    {
                                        new CornerBackground
                                        {
                                            Alpha = 0,
                                        },
                                        null,
                                        null,
                                        null,
                                        null,
                                    },
                                    new[]
                                    {
                                        timeSectionBackground = new CornerBackground
                                        {
                                            RelativeSizeAxes = Axes.Both
                                        },
                                        null,
                                        lyricSectionBackground = new CornerBackground
                                        {
                                            RelativeSizeAxes = Axes.Both
                                        },
                                        null,
                                        null,
                                    },
                                }
                            },
                            translateGrid = new GridContainer
                            {
                                Name             = "Translates",
                                ColumnDimensions = columnDimensions,
                                RelativeSizeAxes = Axes.X,
                                AutoSizeAxes     = Axes.Y,
                            }
                        }
                    }
                },
            };

            NewLanguage.BindValueChanged(e =>
            {
                translateManager.AddLanguage(e.NewValue);
            });
        }
예제 #19
0
 protected override void LoadComplete()
 {
     base.LoadComplete();
     type.BindValueChanged(typeChanged, true);
 }
예제 #20
0
        private void load(OsuConfigManager config, OsuColour colours, ChannelManager channelManager)
        {
            const float padding = 5;

            Children = new Drawable[]
            {
                channelSelectionContainer = new Container
                {
                    RelativeSizeAxes = Axes.Both,
                    Height           = 1f - DEFAULT_HEIGHT,
                    Masking          = true,
                    Children         = new[]
                    {
                        ChannelSelectionOverlay = new ChannelSelectionOverlay
                        {
                            RelativeSizeAxes = Axes.Both,
                        },
                    },
                },
                chatContainer = new Container
                {
                    Name             = @"chat container",
                    Anchor           = Anchor.BottomLeft,
                    Origin           = Anchor.BottomLeft,
                    RelativeSizeAxes = Axes.Both,
                    Height           = DEFAULT_HEIGHT,
                    Children         = new[]
                    {
                        new Container
                        {
                            Name             = @"chat area",
                            RelativeSizeAxes = Axes.Both,
                            Padding          = new MarginPadding {
                                Top = TAB_AREA_HEIGHT
                            },
                            Children = new Drawable[]
                            {
                                chatBackground = new Box
                                {
                                    RelativeSizeAxes = Axes.Both,
                                },
                                currentChannelContainer = new Container <DrawableChannel>
                                {
                                    RelativeSizeAxes = Axes.Both,
                                    Padding          = new MarginPadding
                                    {
                                        Bottom = textbox_height
                                    },
                                },
                                new Container
                                {
                                    Anchor           = Anchor.BottomLeft,
                                    Origin           = Anchor.BottomLeft,
                                    RelativeSizeAxes = Axes.X,
                                    Height           = textbox_height,
                                    Padding          = new MarginPadding
                                    {
                                        Top    = padding * 2,
                                        Bottom = padding * 2,
                                        Left   = ChatLine.LEFT_PADDING + padding * 2,
                                        Right  = padding * 2,
                                    },
                                    Children = new Drawable[]
                                    {
                                        textbox = new FocusedTextBox
                                        {
                                            RelativeSizeAxes     = Axes.Both,
                                            Height               = 1,
                                            PlaceholderText      = "type your message",
                                            OnCommit             = postMessage,
                                            ReleaseFocusOnCommit = false,
                                            HoldFocus            = true,
                                        }
                                    }
                                },
                                loading = new LoadingAnimation(),
                            }
                        },
                        tabsArea = new TabsArea
                        {
                            Children = new Drawable[]
                            {
                                tabBackground = new Box
                                {
                                    RelativeSizeAxes = Axes.Both,
                                    Colour           = Color4.Black,
                                },
                                new SpriteIcon
                                {
                                    Icon   = FontAwesome.Solid.Comments,
                                    Anchor = Anchor.CentreLeft,
                                    Origin = Anchor.CentreLeft,
                                    Size   = new Vector2(20),
                                    Margin = new MarginPadding(10),
                                },
                                ChannelTabControl = CreateChannelTabControl().With(d =>
                                {
                                    d.Anchor           = Anchor.BottomLeft;
                                    d.Origin           = Anchor.BottomLeft;
                                    d.RelativeSizeAxes = Axes.Both;
                                    d.OnRequestLeave   = channelManager.LeaveChannel;
                                    d.IsSwitchable     = true;
                                }),
                            }
                        },
                    },
                },
            };

            ChannelTabControl.Current.ValueChanged += current => channelManager.CurrentChannel.Value = current.NewValue;
            ChannelTabControl.ChannelSelectorActive.ValueChanged += active => ChannelSelectionOverlay.State.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden;
            ChannelSelectionOverlay.State.ValueChanged           += state =>
            {
                // Propagate the visibility state to ChannelSelectorActive
                ChannelTabControl.ChannelSelectorActive.Value = state.NewValue == Visibility.Visible;

                if (state.NewValue == Visibility.Visible)
                {
                    textbox.HoldFocus = false;
                    if (1f - ChatHeight.Value < channel_selection_min_height)
                    {
                        this.TransformBindableTo(ChatHeight, 1f - channel_selection_min_height, 800, Easing.OutQuint);
                    }
                }
                else
                {
                    textbox.HoldFocus = true;
                }
            };

            ChannelSelectionOverlay.OnRequestJoin  = channel => channelManager.JoinChannel(channel);
            ChannelSelectionOverlay.OnRequestLeave = channelManager.LeaveChannel;

            ChatHeight = config.GetBindable <float>(OsuSetting.ChatDisplayHeight);
            ChatHeight.BindValueChanged(height =>
            {
                chatContainer.Height             = height.NewValue;
                channelSelectionContainer.Height = 1f - height.NewValue;
                tabBackground.FadeTo(height.NewValue == 1f ? 1f : 0.8f, 200);
            }, true);

            chatBackground.Colour = colours.ChatBlue;

            this.channelManager = channelManager;

            loading.Show();

            // This is a relatively expensive (and blocking) operation.
            // Scheduling it ensures that it won't be performed unless the user decides to open chat.
            // TODO: Refactor OsuFocusedOverlayContainer / OverlayContainer to support delayed content loading.
            Schedule(() =>
            {
                // TODO: consider scheduling bindable callbacks to not perform when overlay is not present.
                channelManager.JoinedChannels.ItemsAdded   += onChannelAddedToJoinedChannels;
                channelManager.JoinedChannels.ItemsRemoved += onChannelRemovedFromJoinedChannels;
                foreach (Channel channel in channelManager.JoinedChannels)
                {
                    ChannelTabControl.AddChannel(channel);
                }

                channelManager.AvailableChannels.ItemsAdded   += availableChannelsChanged;
                channelManager.AvailableChannels.ItemsRemoved += availableChannelsChanged;
                ChannelSelectionOverlay.UpdateAvailableChannels(channelManager.AvailableChannels);

                currentChannel = channelManager.CurrentChannel.GetBoundCopy();
                currentChannel.BindValueChanged(currentChannelChanged, true);
            });
        }
예제 #21
0
 private void load()
 {
     User.BindValueChanged(user => SetValue(user.NewValue?.MappingFollowerCount ?? 0), true);
 }
예제 #22
0
 protected override void LoadComplete()
 {
     base.LoadComplete();
     beatDivisor.BindValueChanged(val => Text = $"1/{val.NewValue}", true);
 }
예제 #23
0
 protected override void LoadComplete()
 {
     base.LoadComplete();
     Active.BindValueChanged(_ => updateDim(), true);
     FinishTransforms();
 }
예제 #24
0
 public UpdateableBeatmapBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover)
 {
     Beatmap.BindValueChanged(b => Model = b.NewValue);
     this.beatmapSetCoverType            = beatmapSetCoverType;
 }
예제 #25
0
        private void load(OverlayColourProvider colourProvider, TextureStore textures)
        {
            Container <Drawable> hiddenDetailContainer;
            Container <Drawable> expandedDetailContainer;

            InternalChildren = new Drawable[]
            {
                new Box
                {
                    RelativeSizeAxes = Axes.Both,
                    Colour           = colourProvider.Background4
                },
                new FillFlowContainer
                {
                    AutoSizeAxes     = Axes.X,
                    RelativeSizeAxes = Axes.Y,
                    Direction        = FillDirection.Horizontal,
                    Padding          = new MarginPadding {
                        Vertical = 10
                    },
                    Margin = new MarginPadding {
                        Left = UserProfileOverlay.CONTENT_X_MARGIN
                    },
                    Spacing  = new Vector2(10, 0),
                    Children = new Drawable[]
                    {
                        new FollowersButton
                        {
                            User = { BindTarget = User }
                        },
                        new MappingSubscribersButton
                        {
                            User = { BindTarget = User }
                        },
                        new MessageUserButton
                        {
                            User = { BindTarget = User }
                        },
                    }
                },
                new Container
                {
                    Anchor           = Anchor.CentreRight,
                    Origin           = Anchor.CentreRight,
                    RelativeSizeAxes = Axes.Y,
                    Padding          = new MarginPadding {
                        Vertical = 10
                    },
                    Width = UserProfileOverlay.CONTENT_X_MARGIN,
                    Child = new ExpandDetailsButton
                    {
                        Anchor         = Anchor.Centre,
                        Origin         = Anchor.Centre,
                        DetailsVisible = { BindTarget = DetailsVisible }
                    },
                },
                new Container
                {
                    Anchor       = Anchor.CentreRight,
                    Origin       = Anchor.CentreRight,
                    AutoSizeAxes = Axes.Both,
                    Margin       = new MarginPadding {
                        Right = UserProfileOverlay.CONTENT_X_MARGIN
                    },
                    Children = new Drawable[]
                    {
                        new LevelBadge
                        {
                            Anchor = Anchor.CentreRight,
                            Origin = Anchor.CentreRight,
                            Size   = new Vector2(40),
                            User   = { BindTarget = User }
                        },
                        expandedDetailContainer = new Container
                        {
                            Anchor = Anchor.CentreRight,
                            Origin = Anchor.CentreRight,
                            Width  = 200,
                            Height = 6,
                            Margin = new MarginPadding {
                                Right = 50
                            },
                            Child = new LevelProgressBar
                            {
                                RelativeSizeAxes = Axes.Both,
                                User             = { BindTarget = User }
                            }
                        },
                        hiddenDetailContainer = new FillFlowContainer
                        {
                            Direction    = FillDirection.Horizontal,
                            Anchor       = Anchor.CentreRight,
                            Origin       = Anchor.CentreRight,
                            Width        = 200,
                            AutoSizeAxes = Axes.Y,
                            Alpha        = 0,
                            Spacing      = new Vector2(10, 0),
                            Margin       = new MarginPadding {
                                Right = 50
                            },
                            Children = new[]
                            {
                                hiddenDetailGlobal = new OverlinedInfoContainer
                                {
                                    Title      = UsersStrings.ShowRankGlobalSimple,
                                    LineColour = colourProvider.Highlight1
                                },
                                hiddenDetailCountry = new OverlinedInfoContainer
                                {
                                    Title      = UsersStrings.ShowRankCountrySimple,
                                    LineColour = colourProvider.Highlight1
                                },
                            }
                        }
                    }
                }
            };

            DetailsVisible.BindValueChanged(visible =>
            {
                hiddenDetailContainer.FadeTo(visible.NewValue ? 0 : 1, 200, Easing.OutQuint);
                expandedDetailContainer.FadeTo(visible.NewValue ? 1 : 0, 200, Easing.OutQuint);
            });

            User.BindValueChanged(user => updateDisplay(user.NewValue));
        }
예제 #26
0
        private void load(OsuRulesetConfigManager config)
        {
            config?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail);

            showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true);
        }
예제 #27
0
 protected override void LoadComplete()
 {
     beatmap.BindValueChanged(beatmapChanged, true);
     beatmap.BindDisabledChanged(beatmapDisabledChanged, true);
     base.LoadComplete();
 }
예제 #28
0
        protected override void LoadComplete()
        {
            base.LoadComplete();

            SelectedScore.BindValueChanged(selectedScoreChanged, true);
        }
예제 #29
0
 private void load(TauRulesetConfigManager config)
 {
     config?.BindWith(TauRulesetSettings.BeatSize, size);
     size.BindValueChanged(value => Size = new Vector2(value.NewValue), true);
 }
예제 #30
0
        private void load(ReadableKeyCombinationProvider keyCombinationProvider)
        {
            try
            {
                using (var str = File.OpenRead(typeof(OsuGameBase).Assembly.Location))
                    VersionHash = str.ComputeMD5Hash();
            }
            catch
            {
                // special case for android builds, which can't read DLLs from a packed apk.
                // should eventually be handled in a better way.
                VersionHash = $"{Version}-{RuntimeInfo.OS}".ComputeMD5Hash();
            }

            Resources.AddStore(new DllResourceStore(OsuResources.ResourceAssembly));

            if (Storage.Exists(DatabaseContextFactory.DATABASE_NAME))
            {
                dependencies.Cache(EFContextFactory = new DatabaseContextFactory(Storage));
            }

            dependencies.Cache(realm = new RealmAccess(Storage, CLIENT_DATABASE_FILENAME, Host.UpdateThread, EFContextFactory));

            dependencies.CacheAs <RulesetStore>(RulesetStore = new RealmRulesetStore(realm, Storage));
            dependencies.CacheAs <IRulesetStore>(RulesetStore);

            Decoder.RegisterDependencies(RulesetStore);

            // Backup is taken here rather than in EFToRealmMigrator to avoid recycling realm contexts
            // after initial usages below. It can be moved once a direction is established for handling re-subscription.
            // See https://github.com/ppy/osu/pull/16547 for more discussion.
            if (EFContextFactory != null)
            {
                const string backup_folder = "backups";

                string migration = $"before_final_migration_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}";

                EFContextFactory.CreateBackup(Path.Combine(backup_folder, $"client.{migration}.db"));
                realm.CreateBackup(Path.Combine(backup_folder, $"client.{migration}.realm"));

                using (var source = Storage.GetStream("collection.db"))
                {
                    if (source != null)
                    {
                        using (var destination = Storage.CreateFileSafely(Path.Combine(backup_folder, $"collection.{migration}.db")))
                            source.CopyTo(destination);
                    }
                }
            }

            dependencies.CacheAs(Storage);

            var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore <byte[]>(Resources, @"Textures")));

            largeStore.AddStore(Host.CreateTextureLoaderStore(new OnlineStore()));
            dependencies.Cache(largeStore);

            dependencies.CacheAs(this);
            dependencies.CacheAs(LocalConfig);

            InitialiseFonts();

            Audio.Samples.PlaybackConcurrency = SAMPLE_CONCURRENCY;

            dependencies.Cache(SkinManager = new SkinManager(Storage, realm, Host, Resources, Audio, Scheduler));
            dependencies.CacheAs <ISkinSource>(SkinManager);

            EndpointConfiguration endpoints = CreateEndpoints();

            MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl;

            dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints, VersionHash));

            dependencies.CacheAs(spectatorClient   = new OnlineSpectatorClient(endpoints));
            dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(endpoints));

            var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);

            // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
            dependencies.Cache(ScoreManager   = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, () => difficultyCache, LocalConfig));
            dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true));

            dependencies.Cache(BeatmapDownloader = new BeatmapModelDownloader(BeatmapManager, API));
            dependencies.Cache(ScoreDownloader   = new ScoreModelDownloader(ScoreManager, API));

            dependencies.Cache(difficultyCache = new BeatmapDifficultyCache());
            AddInternal(difficultyCache);

            dependencies.Cache(userCache = new UserLookupCache());
            AddInternal(userCache);

            dependencies.Cache(beatmapCache = new BeatmapLookupCache());
            AddInternal(beatmapCache);

            var scorePerformanceManager = new ScorePerformanceCache();

            dependencies.Cache(scorePerformanceManager);
            AddInternal(scorePerformanceManager);

            dependencies.CacheAs <IRulesetConfigCache>(rulesetConfigCache = new RulesetConfigCache(realm, RulesetStore));

            var powerStatus = CreateBatteryInfo();

            if (powerStatus != null)
            {
                dependencies.CacheAs(powerStatus);
            }

            dependencies.Cache(SessionStatics = new SessionStatics());
            dependencies.Cache(new OsuColour());

            RegisterImportHandler(BeatmapManager);
            RegisterImportHandler(ScoreManager);
            RegisterImportHandler(SkinManager);

            // drop track volume game-wide to leave some head-room for UI effects / samples.
            // this means that for the time being, gameplay sample playback is louder relative to the audio track, compared to stable.
            // we may want to revisit this if users notice or complain about the difference (consider this a bit of a trial).
            Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, globalTrackVolumeAdjust);

            Beatmap = new NonNullableBindable <WorkingBeatmap>(defaultBeatmap);

            dependencies.CacheAs <IBindable <WorkingBeatmap> >(Beatmap);
            dependencies.CacheAs(Beatmap);

            // add api components to hierarchy.
            if (API is APIAccess apiAccess)
            {
                AddInternal(apiAccess);
            }
            AddInternal(spectatorClient);
            AddInternal(multiplayerClient);

            AddInternal(rulesetConfigCache);

            GlobalActionContainer globalBindings;

            base.Content.Add(new SafeAreaContainer
            {
                SafeAreaOverrideEdges = SafeAreaOverrideEdges,
                RelativeSizeAxes      = Axes.Both,
                Child = CreateScalingContainer().WithChildren(new Drawable[]
                {
                    (MenuCursorContainer = new MenuCursorContainer
                    {
                        RelativeSizeAxes = Axes.Both
                    }).WithChild(content = new OsuTooltipContainer(MenuCursorContainer.Cursor)
                    {
                        RelativeSizeAxes = Axes.Both
                    }),
                    // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything.
                    globalBindings = new GlobalActionContainer(this)
                })
            });

            KeyBindingStore = new RealmKeyBindingStore(realm, keyCombinationProvider);
            KeyBindingStore.Register(globalBindings, RulesetStore.AvailableRulesets);

            dependencies.Cache(globalBindings);

            PreviewTrackManager previewTrackManager;

            dependencies.Cache(previewTrackManager = new PreviewTrackManager(BeatmapManager.BeatmapTrackStore));
            Add(previewTrackManager);

            AddInternal(MusicController = new MusicController());
            dependencies.CacheAs(MusicController);

            Ruleset.BindValueChanged(onRulesetChanged);
            Beatmap.BindValueChanged(onBeatmapChanged);
        }