Example #1
0
        private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache)
        {
            Colour = colours.BlueLighter;

            if (gameplayState != null)
            {
                performanceCalculator = gameplayState.Ruleset.CreatePerformanceCalculator();
                clonedMods            = gameplayState.Mods.Select(m => m.DeepClone()).ToArray();

                scoreInfo = new ScoreInfo(gameplayState.Score.ScoreInfo.BeatmapInfo, gameplayState.Score.ScoreInfo.Ruleset)
                {
                    Mods = clonedMods
                };

                var gameplayWorkingBeatmap = new GameplayWorkingBeatmap(gameplayState.Beatmap);
                difficultyCache.GetTimedDifficultyAttributesAsync(gameplayWorkingBeatmap, gameplayState.Ruleset, clonedMods, loadCancellationSource.Token)
                .ContinueWith(task => Schedule(() =>
                {
                    timedAttributes = task.GetResultSafely();

                    IsValid = true;

                    if (lastJudgement != null)
                    {
                        onJudgementChanged(lastJudgement);
                    }
                }), TaskContinuationOptions.OnlyOnRanToCompletion);
            }
        }
Example #2
0
        private void load()
        {
            InterpretedDifficulty.Default = BeatmapDifficultyCache.GetDifficultyRating(EditorBeatmap.BeatmapInfo.StarRating);
            InterpretedDifficulty.SetDefault();

            Child = new Container
            {
                RelativeSizeAxes = Axes.Both,
                Child            = new GridContainer
                {
                    RelativeSizeAxes = Axes.Both,
                    ColumnDimensions = new[]
                    {
                        new Dimension(),
                        new Dimension(GridSizeMode.Absolute, 250),
                    },
                    Content = new[]
                    {
                        new Drawable[]
                        {
                            IssueList = new IssueList(),
                            new IssueSettings(),
                        },
                    }
                }
            };
        }
Example #3
0
        private void load(SkinManager skinManager, IBeatmap beatmap, BeatmapDifficultyCache difficultyCache)
        {
            RegisterPool <TouchHold, DrawableTouchHold>(2);

            // handle colouring of playfield elements
            beatmapDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo);

            skin = skinManager.CurrentSkin.GetBoundCopy();
            sentakkiRulesetConfig?.BindWith(SentakkiRulesetSettings.RingColor, ringColor);
        }
Example #4
0
        private void load([CanBeNull] IBindable <WorkingBeatmap> workingBeatmap, [CanBeNull] BeatmapDifficultyCache difficultyCache)
        {
            if (workingBeatmap == null || difficultyCache == null)
            {
                return;
            }

            var beatmapDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo).Value;

            LoadComponentAsync(new BeatmapInfoWedge(workingBeatmap.Value, mods.Value, beatmapDifficulty ?? new StarDifficulty()), Add);
        }
Example #5
0
        private void load(BeatmapDifficultyCache beatmapDifficultyCache)
        {
            var beatmap  = score.Beatmap;
            var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
            var creator  = metadata.Author?.Username;

            var topStatistics = new List <StatisticDisplay>
            {
                new AccuracyStatistic(score.Accuracy),
                new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out var missCount) || missCount == 0),
                new PerformanceStatistic(score),
            };

            var bottomStatistics = new List <HitResultStatistic>();

            foreach (var result in score.GetStatisticsForDisplay())
            {
                bottomStatistics.Add(new HitResultStatistic(result));
            }

            statisticDisplays.AddRange(topStatistics);
            statisticDisplays.AddRange(bottomStatistics);

            var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).Result;

            InternalChildren = new Drawable[]
            {
                new FillFlowContainer
                {
                    RelativeSizeAxes = Axes.Both,
                    Direction        = FillDirection.Vertical,
                    Spacing          = new Vector2(20),
                    Children         = new Drawable[]
                    {
                        new FillFlowContainer
                        {
                            Anchor           = Anchor.TopCentre,
                            Origin           = Anchor.TopCentre,
                            RelativeSizeAxes = Axes.X,
                            AutoSizeAxes     = Axes.Y,
                            Direction        = FillDirection.Vertical,
                            Children         = new Drawable[]
                            {
                                new OsuSpriteText
                                {
                                    Anchor   = Anchor.TopCentre,
                                    Origin   = Anchor.TopCentre,
                                    Text     = new LocalisedString((metadata.TitleUnicode, metadata.Title)),
                                    Font     = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold),
                                    MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2,
                                    Truncate = true,
                                },
Example #6
0
        public ScoreManager(RulesetStore rulesets, Func <BeatmapManager> beatmaps, Storage storage, RealmAccess realm, Scheduler scheduler,
                            BeatmapDifficultyCache difficultyCache = null, OsuConfigManager configManager = null)
            : base(storage, realm)
        {
            this.scheduler       = scheduler;
            this.difficultyCache = difficultyCache;
            this.configManager   = configManager;

            scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm)
            {
                PostNotification = obj => PostNotification?.Invoke(obj)
            };
        }
Example #7
0
        private void load(BeatmapDifficultyCache difficultyCache)
        {
            var metadata = beatmap.BeatmapInfo.Metadata;

            AutoSizeAxes = Axes.Both;
            Children     = new Drawable[]
            {
                new FillFlowContainer
                {
                    AutoSizeAxes = Axes.Both,
                    Origin       = Anchor.TopCentre,
                    Anchor       = Anchor.TopCentre,
                    Direction    = FillDirection.Vertical,
                    Children     = new[]
Example #8
0
        private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache)
        {
            Colour = colours.BlueLighter;

            if (gameplayState != null)
            {
                clonedMods = gameplayState.Mods.Select(m => m.DeepClone()).ToArray();

                var gameplayWorkingBeatmap = new GameplayWorkingBeatmap(gameplayState.Beatmap);
                difficultyCache.GetTimedDifficultyAttributesAsync(gameplayWorkingBeatmap, gameplayState.Ruleset, clonedMods, loadCancellationSource.Token)
                .ContinueWith(r => Schedule(() =>
                {
                    timedAttributes = r.Result;
                    IsValid         = true;
                    if (lastJudgement != null)
                    {
                        onJudgementChanged(lastJudgement);
                    }
                }), TaskContinuationOptions.OnlyOnRanToCompletion);
            }
        }
Example #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();

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

            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);

            MenuCursorContainer = new MenuCursorContainer {
                RelativeSizeAxes = Axes.Both
            };

            GlobalActionContainer globalBindings;

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

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

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

            PreviewTrackManager previewTrackManager;

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

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

            Ruleset.BindValueChanged(onRulesetChanged);
        }
Example #10
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", 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.GetStream(Path.Combine(backup_folder, $"collection.{migration}.db"), FileAccess.Write, FileMode.CreateNew))
                            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 = UseDevelopmentServer ? (EndpointConfiguration) new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration();

            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);
        }
Example #11
0
        private void load(BeatmapDifficultyCache beatmapDifficultyCache)
        {
            var    beatmap  = score.BeatmapInfo;
            var    metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
            string creator  = metadata.Author.Username;

            var topStatistics = new List <StatisticDisplay>
            {
                new AccuracyStatistic(score.Accuracy),
                new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0),
                new PerformanceStatistic(score),
            };

            var bottomStatistics = new List <HitResultStatistic>();

            foreach (var result in score.GetStatisticsForDisplay())
            {
                bottomStatistics.Add(new HitResultStatistic(result));
            }

            statisticDisplays.AddRange(topStatistics);
            statisticDisplays.AddRange(bottomStatistics);

            var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely();

            AddInternal(new FillFlowContainer
            {
                RelativeSizeAxes = Axes.Both,
                Direction        = FillDirection.Vertical,
                Spacing          = new Vector2(20),
                Children         = new Drawable[]
                {
                    new FillFlowContainer
                    {
                        Anchor           = Anchor.TopCentre,
                        Origin           = Anchor.TopCentre,
                        RelativeSizeAxes = Axes.X,
                        AutoSizeAxes     = Axes.Y,
                        Direction        = FillDirection.Vertical,
                        Children         = new Drawable[]
                        {
                            new OsuSpriteText
                            {
                                Anchor   = Anchor.TopCentre,
                                Origin   = Anchor.TopCentre,
                                Text     = new RomanisableString(metadata.TitleUnicode, metadata.Title),
                                Font     = OsuFont.Torus.With(size: 20, weight: FontWeight.SemiBold),
                                MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2,
                                Truncate = true,
                            },
                            new OsuSpriteText
                            {
                                Anchor   = Anchor.TopCentre,
                                Origin   = Anchor.TopCentre,
                                Text     = new RomanisableString(metadata.ArtistUnicode, metadata.Artist),
                                Font     = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold),
                                MaxWidth = ScorePanel.EXPANDED_WIDTH - padding * 2,
                                Truncate = true,
                            },
                            new Container
                            {
                                Anchor = Anchor.TopCentre,
                                Origin = Anchor.TopCentre,
                                Margin = new MarginPadding {
                                    Top = 40
                                },
                                RelativeSizeAxes = Axes.X,
                                Height           = 230,
                                Child            = new AccuracyCircle(score, withFlair)
                                {
                                    Anchor           = Anchor.Centre,
                                    Origin           = Anchor.Centre,
                                    RelativeSizeAxes = Axes.Both,
                                    FillMode         = FillMode.Fit,
                                }
                            },
                            scoreCounter = new TotalScoreCounter
                            {
                                Margin = new MarginPadding {
                                    Top = 0, Bottom = 5
                                },
                                Current       = { Value = 0 },
                                Alpha         = 0,
                                AlwaysPresent = true
                            },
                            starAndModDisplay = new FillFlowContainer
                            {
                                Anchor       = Anchor.TopCentre,
                                Origin       = Anchor.TopCentre,
                                AutoSizeAxes = Axes.Both,
                                Spacing      = new Vector2(5, 0),
                            },
                            new FillFlowContainer
                            {
                                Anchor       = Anchor.TopCentre,
                                Origin       = Anchor.TopCentre,
                                Direction    = FillDirection.Vertical,
                                AutoSizeAxes = Axes.Both,
                                Children     = new Drawable[]
                                {
                                    new OsuSpriteText
                                    {
                                        Anchor = Anchor.TopCentre,
                                        Origin = Anchor.TopCentre,
                                        Text   = beatmap.DifficultyName,
                                        Font   = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold),
                                    },
                                    new OsuTextFlowContainer(s => s.Font = OsuFont.Torus.With(size: 12))
                                    {
                                        Anchor       = Anchor.TopCentre,
                                        Origin       = Anchor.TopCentre,
                                        AutoSizeAxes = Axes.Both,
                                        Direction    = FillDirection.Horizontal,
                                    }.With(t =>
                                    {
                                        if (!string.IsNullOrEmpty(creator))
                                        {
                                            t.AddText("mapped by ");
                                            t.AddText(creator, s => s.Font = s.Font.With(weight: FontWeight.SemiBold));
                                        }
                                    })
                                }
                            },
                        }
                    },
                    new FillFlowContainer
                    {
                        RelativeSizeAxes = Axes.X,
                        AutoSizeAxes     = Axes.Y,
                        Direction        = FillDirection.Vertical,
                        Spacing          = new Vector2(0, 5),
                        Children         = new Drawable[]
                        {
                            new GridContainer
                            {
                                RelativeSizeAxes = Axes.X,
                                AutoSizeAxes     = Axes.Y,
                                Content          = new[] { topStatistics.Cast <Drawable>().ToArray() },
                                RowDimensions    = new[]
                                {
                                    new Dimension(GridSizeMode.AutoSize),
                                }
                            },
                            new GridContainer
                            {
                                RelativeSizeAxes = Axes.X,
                                AutoSizeAxes     = Axes.Y,
                                Content          = new[] { bottomStatistics.Where(s => s.Result <= HitResult.Perfect).ToArray() },
                                RowDimensions    = new[]
                                {
                                    new Dimension(GridSizeMode.AutoSize),
                                }
                            },
                            new GridContainer
                            {
                                RelativeSizeAxes = Axes.X,
                                AutoSizeAxes     = Axes.Y,
                                Content          = new[] { bottomStatistics.Where(s => s.Result > HitResult.Perfect).ToArray() },
                                RowDimensions    = new[]
                                {
                                    new Dimension(GridSizeMode.AutoSize),
                                }
                            }
                        }
                    }
                }
            });

            if (score.Date != default)
            {
                AddInternal(new PlayedOnText(score.Date));
            }

            if (starDifficulty != null)
            {
                starAndModDisplay.Add(new StarRatingDisplay(starDifficulty.Value)
                {
                    Anchor = Anchor.CentreLeft,
                    Origin = Anchor.CentreLeft
                });
            }

            if (score.Mods.Any())
            {
                starAndModDisplay.Add(new ModDisplay
                {
                    Anchor        = Anchor.CentreLeft,
                    Origin        = Anchor.CentreLeft,
                    ExpansionMode = ExpansionMode.AlwaysExpanded,
                    Scale         = new Vector2(0.5f),
                    Current       = { Value = score.Mods }
                });
            }
        }
 public PerformanceBreakdownCalculator(IBeatmap playableBeatmap, BeatmapDifficultyCache difficultyCache, ScorePerformanceCache performanceCache)
 {
     this.playableBeatmap  = playableBeatmap;
     this.difficultyCache  = difficultyCache;
     this.performanceCache = performanceCache;
 }
Example #13
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));

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

            dependencies.Cache(realmFactory = new RealmContextFactory(Storage, "client"));

            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;

            runMigrations();

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

            // needs to be done here rather than inside SkinManager to ensure thread safety of CurrentSkinInfo.
            SkinManager.ItemRemoved += item => Schedule(() =>
            {
                // check the removed skin is not the current user choice. if it is, switch back to default.
                if (item.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(spectatorClient   = new OnlineSpectatorClient(endpoints));
            dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(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, Scheduler, Host, () => difficultyCache, LocalConfig));
            dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true));

            // the following realm components are not actively used yet, but initialised and kept up to date for initial testing.
            realmRulesetStore = new RealmRulesetStore(realmFactory, Storage);

            dependencies.Cache(realmRulesetStore);

            // this should likely be moved to ArchiveModelManager when another case appears 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.BeatmapInfo.ID)).ToList());
            }

            BeatmapManager.ItemRemoved += item => ScoreManager.Delete(getBeatmapScores(item), true);
            BeatmapManager.ItemUpdated += 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);

            migrateDataToRealm();

            dependencies.Cache(rulesetConfigCache = new RulesetConfigCache(realmFactory, 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);

            fileStore.Cleanup();

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

            AddInternal(rulesetConfigCache);

            GlobalActionContainer globalBindings;

            var mainContent = new Drawable[]
            {
                MenuCursorContainer = new MenuCursorContainer {
                    RelativeSizeAxes = Axes.Both
                },
                // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything.
                globalBindings = new GlobalActionContainer(this)
            };

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

            base.Content.Add(CreateScalingContainer().WithChildren(mainContent));

            KeyBindingStore = new RealmKeyBindingStore(realmFactory, 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);
        }
        private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache)
        {
            AutoSizeAxes = Axes.Both;

            var    starRatingParts = difficulty.Stars.ToString("0.00", CultureInfo.InvariantCulture).Split('.');
            string wholePart       = starRatingParts[0];
            string fractionPart    = starRatingParts[1];
            string separator       = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;

            ColourInfo backgroundColour = difficulty.DifficultyRating == DifficultyRating.ExpertPlus
                ? ColourInfo.GradientVertical(Color4Extensions.FromHex("#C1C1C1"), Color4Extensions.FromHex("#595959"))
                : (ColourInfo)colours.ForDifficultyRating(difficulty.DifficultyRating);

            InternalChildren = new Drawable[]
            {
                new CircularContainer
                {
                    RelativeSizeAxes = Axes.Both,
                    Masking          = true,
                    Children         = new Drawable[]
                    {
                        new Box
                        {
                            RelativeSizeAxes = Axes.Both,
                            Colour           = backgroundColour
                        },
                    }
                },
                new FillFlowContainer
                {
                    AutoSizeAxes = Axes.Both,
                    Padding      = new MarginPadding {
                        Horizontal = 8, Vertical = 4
                    },
                    Direction = FillDirection.Horizontal,
                    Spacing   = new Vector2(2, 0),
                    Children  = new Drawable[]
                    {
                        new SpriteIcon
                        {
                            Anchor = Anchor.CentreLeft,
                            Origin = Anchor.CentreLeft,
                            Size   = new Vector2(7),
                            Icon   = FontAwesome.Solid.Star,
                            Colour = Color4.Black
                        },
                        new OsuTextFlowContainer(s => s.Font = OsuFont.Numeric.With(weight: FontWeight.Black))
                        {
                            Anchor       = Anchor.CentreLeft,
                            Origin       = Anchor.CentreLeft,
                            AutoSizeAxes = Axes.Both,
                            Direction    = FillDirection.Horizontal,
                            TextAnchor   = Anchor.BottomLeft,
                        }.With(t =>
                        {
                            t.AddText($"{wholePart}", s =>
                            {
                                s.Colour             = Color4.Black;
                                s.Font               = s.Font.With(size: 14);
                                s.UseFullGlyphHeight = false;
                            });

                            t.AddText($"{separator}{fractionPart}", s =>
                            {
                                s.Colour             = Color4.Black;
                                s.Font               = s.Font.With(size: 7);
                                s.UseFullGlyphHeight = false;
                            });
                        })
                    }
                }
            };
        }
Example #15
0
        public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket)
        {
            var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating);

            Assert.AreEqual(expectedBracket, actualBracket);
        }
Example #16
0
 private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache)
 {
     Colour = colours.BlueLighter;
     valid.BindValueChanged(e =>
                            DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint));
 }