private void load(AudioManager audio, OsuConfigManager config, APIAccess api) { this.api = api; dimLevel = config.GetBindable <double>(OsuSetting.DimLevel); showStoryboard = config.GetBindable <bool>(OsuSetting.ShowStoryboard); mouseWheelDisabled = config.GetBindable <bool>(OsuSetting.MouseDisableWheel); sampleRestart = audio.Sample.Get(@"Gameplay/restart"); WorkingBeatmap working = Beatmap.Value; Beatmap beatmap; try { beatmap = working.Beatmap; if (beatmap == null) { throw new InvalidOperationException("Beatmap was not loaded"); } ruleset = Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset; var rulesetInstance = ruleset.CreateInstance(); try { RulesetContainer = rulesetInstance.CreateRulesetContainerWith(working, ruleset.ID == beatmap.BeatmapInfo.Ruleset.ID); } catch (BeatmapInvalidForRulesetException) { // we may fail to create a RulesetContainer if the beatmap cannot be loaded with the user's preferred ruleset // let's try again forcing the beatmap's ruleset. ruleset = beatmap.BeatmapInfo.Ruleset; rulesetInstance = ruleset.CreateInstance(); RulesetContainer = rulesetInstance.CreateRulesetContainerWith(Beatmap, true); } if (!RulesetContainer.Objects.Any()) { throw new InvalidOperationException("Beatmap contains no hit objects!"); } } catch (Exception e) { Logger.Log($"Could not load this beatmap sucessfully ({e})!", LoggingTarget.Runtime, LogLevel.Error); //couldn't load, hard abort! Exit(); return; } adjustableSourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock(); decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var firstObjectTime = RulesetContainer.Objects.First().StartTime; decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn))); decoupledClock.ProcessFrame(); offsetClock = new FramedOffsetClock(decoupledClock); userAudioOffset = config.GetBindable <double>(OsuSetting.AudioOffset); userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.TriggerChange(); Children = new Drawable[] { storyboardContainer = new Container { RelativeSizeAxes = Axes.Both, Clock = offsetClock, Alpha = 0, }, pauseContainer = new PauseContainer { AudioClock = decoupledClock, FramedClock = offsetClock, OnRetry = Restart, OnQuit = Exit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, Retries = RestartCount, OnPause = () => { hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, OnResume = () => { hudOverlay.KeyCounter.IsCounting = true; }, Children = new Drawable[] { new SkipButton(firstObjectTime) { AudioClock = decoupledClock }, new Container { RelativeSizeAxes = Axes.Both, Clock = offsetClock, Child = RulesetContainer, }, hudOverlay = new HUDOverlay { Anchor = Anchor.Centre, Origin = Anchor.Centre }, breakOverlay = new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks) { Anchor = Anchor.Centre, Origin = Anchor.Centre, Clock = decoupledClock, Breaks = beatmap.Breaks }, } }, failOverlay = new FailOverlay { OnRetry = Restart, OnQuit = Exit, }, new HotkeyRetryOverlay { Action = () => { //we want to hide the hitrenderer immediately (looks better). //we may be able to remove this once the mouse cursor trail is improved. RulesetContainer?.Hide(); Restart(); }, } }; scoreProcessor = RulesetContainer.CreateScoreProcessor(); if (showStoryboard) { initializeStoryboard(false); } hudOverlay.BindProcessor(scoreProcessor); hudOverlay.BindRulesetContainer(RulesetContainer); hudOverlay.Progress.Objects = RulesetContainer.Objects; hudOverlay.Progress.AudioClock = decoupledClock; hudOverlay.Progress.AllowSeeking = RulesetContainer.HasReplayLoaded; hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos); hudOverlay.ModDisplay.Current.BindTo(working.Mods); breakOverlay.BindProcessor(scoreProcessor); hudOverlay.ReplaySettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock; // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; scoreProcessor.Failed += onFail; foreach (var mod in Beatmap.Value.Mods.Value.OfType <IApplicableToScoreProcessor>()) { mod.ApplyToScoreProcessor(scoreProcessor); } }
private void load(AudioManager audio, OsuConfigManager config, OsuGame osu) { dimLevel = config.GetBindable <double>(OsuSetting.DimLevel); mouseWheelDisabled = config.GetBindable <bool>(OsuSetting.MouseDisableWheel); sampleRestart = audio.Sample.Get(@"Gameplay/restart"); Ruleset rulesetInstance; try { if (Beatmap.Value.Beatmap == null) { throw new InvalidOperationException("Beatmap was not loaded"); } ruleset = osu?.Ruleset.Value ?? Beatmap.Value.BeatmapInfo.Ruleset; rulesetInstance = ruleset.CreateInstance(); try { HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, ruleset.ID == Beatmap.Value.BeatmapInfo.Ruleset.ID); } catch (BeatmapInvalidForRulesetException) { // we may fail to create a HitRenderer if the beatmap cannot be loaded with the user's preferred ruleset // let's try again forcing the beatmap's ruleset. ruleset = Beatmap.Value.BeatmapInfo.Ruleset; rulesetInstance = ruleset.CreateInstance(); HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, true); } if (!HitRenderer.Objects.Any()) { throw new InvalidOperationException("Beatmap contains no hit objects!"); } } catch (Exception e) { Logger.Log($"Could not load this beatmap sucessfully ({e})!", LoggingTarget.Runtime, LogLevel.Error); //couldn't load, hard abort! Exit(); return; } Track track = Beatmap.Value.Track; if (track != null) { adjustableSourceClock = track; } adjustableSourceClock = (IAdjustableClock)track ?? new StopwatchClock(); decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var firstObjectTime = HitRenderer.Objects.First().StartTime; decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, Beatmap.Value.BeatmapInfo.AudioLeadIn))); decoupledClock.ProcessFrame(); offsetClock = new FramedOffsetClock(decoupledClock); userAudioOffset = config.GetBindable <double>(OsuSetting.AudioOffset); userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.TriggerChange(); Schedule(() => { adjustableSourceClock.Reset(); foreach (var mod in Beatmap.Value.Mods.Value.OfType <IApplicableToClock>()) { mod.ApplyToClock(adjustableSourceClock); } decoupledClock.ChangeSource(adjustableSourceClock); }); Children = new Drawable[] { pauseContainer = new PauseContainer { AudioClock = decoupledClock, FramedClock = offsetClock, OnRetry = Restart, OnQuit = Exit, CheckCanPause = () => ValidForResume && !HasFailed && !HitRenderer.HasReplayLoaded, Retries = RestartCount, OnPause = () => { hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, OnResume = () => { hudOverlay.KeyCounter.IsCounting = true; }, Children = new Drawable[] { new SkipButton(firstObjectTime) { AudioClock = decoupledClock }, new Container { RelativeSizeAxes = Axes.Both, Clock = offsetClock, Children = new Drawable[] { HitRenderer, } }, hudOverlay = new HUDOverlay { Anchor = Anchor.Centre, Origin = Anchor.Centre }, } }, failOverlay = new FailOverlay { OnRetry = Restart, OnQuit = Exit, }, new HotkeyRetryOverlay { Action = () => { //we want to hide the hitrenderer immediately (looks better). //we may be able to remove this once the mouse cursor trail is improved. HitRenderer?.Hide(); Restart(); }, } }; scoreProcessor = HitRenderer.CreateScoreProcessor(); hudOverlay.KeyCounter.AddRange(rulesetInstance.CreateGameplayKeys()); hudOverlay.BindProcessor(scoreProcessor); hudOverlay.BindHitRenderer(HitRenderer); hudOverlay.Progress.Objects = HitRenderer.Objects; hudOverlay.Progress.AudioClock = decoupledClock; hudOverlay.Progress.AllowSeeking = HitRenderer.HasReplayLoaded; hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos); hudOverlay.ModDisplay.Current.BindTo(Beatmap.Value.Mods); //bind HitRenderer to ScoreProcessor and ourselves (for a pass situation) HitRenderer.OnAllJudged += onCompletion; //bind ScoreProcessor to ourselves (for a fail situation) scoreProcessor.Failed += onFail; }