public PippidonScoreProcessor(RulesetContainer <PippidonObject> ruleset) : base(ruleset) { }
public override void ApplyToRulesetContainer(RulesetContainer <CatchHitObject> rulesetContainer) { playfield = (CatchPlayfield)rulesetContainer.Playfield; base.ApplyToRulesetContainer(rulesetContainer); }
public OsuScoreProcessor(RulesetContainer <OsuHitObject> rulesetContainer) : base(rulesetContainer) { }
public void BindRulestContainer(RulesetContainer rulesetContainer) { replayLoaded.BindTo(rulesetContainer.HasReplayLoaded); }
public TaikoScoreProcessor(RulesetContainer <TaikoHitObject> rulesetContainer) : base(rulesetContainer) { }
public KaraokeScoreProcessor(RulesetContainer <Lyric> rulesetContainer) : base(rulesetContainer) { }
public void ApplyToRulesetContainer(RulesetContainer <OsuHitObject> rulesetContainer) { rulesetContainer.Overlays.Add(blinds = new DrawableOsuBlinds(rulesetContainer.Playfield.HitObjectContainer, rulesetContainer.Beatmap)); }
private void load(OsuGameBase osuGame) { try { rulesetContainer = CreateRulesetContainer(ruleset, osuGame.Beatmap.Value); // TODO: should probably be done at a RulesetContainer level to share logic with Player. rulesetContainer.Clock = new InterpolatingFramedClock((IAdjustableClock)osuGame.Beatmap.Value.Track ?? new StopwatchClock()); } catch (Exception e) { Logger.Error(e, "Could not load beatmap sucessfully!"); return; } HitObjectOverlayLayer hitObjectOverlayLayer = CreateHitObjectOverlayLayer(); SelectionLayer selectionLayer = new SelectionLayer(rulesetContainer.Playfield); var layerBelowRuleset = new BorderLayer { RelativeSizeAxes = Axes.Both, Child = CreateLayerContainer() }; var layerAboveRuleset = CreateLayerContainer(); layerAboveRuleset.Children = new Drawable[] { selectionLayer, // Below object overlays for input hitObjectOverlayLayer, selectionLayer.CreateProxy() // Proxy above object overlays for selections }; layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); RadioButtonCollection toolboxCollection; InternalChild = new GridContainer { RelativeSizeAxes = Axes.Both, Content = new[] { new Drawable[] { new FillFlowContainer { Name = "Sidebar", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 10 }, Children = new Drawable[] { new ToolboxGroup { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } } } }, new Container { Name = "Content", RelativeSizeAxes = Axes.Both, Children = new Drawable[] { layerBelowRuleset, rulesetContainer, layerAboveRuleset } } }, }, ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, 200), } }; selectionLayer.ObjectSelected += hitObjectOverlayLayer.AddOverlay; selectionLayer.ObjectDeselected += hitObjectOverlayLayer.RemoveOverlay; toolboxCollection.Items = new[] { new RadioButton("Select", () => setCompositionTool(null)) } .Concat( CompositionTools.Select(t => new RadioButton(t.Name, () => setCompositionTool(t))) ) .ToList(); toolboxCollection.Items[0].Select(); }
private void load(AudioManager audio, APIAccess api, OsuConfigManager config) { this.api = api; WorkingBeatmap working = loadBeatmap(); if (working == null) { return; } sampleRestart = audio.Sample.Get(@"Gameplay/restart"); mouseWheelDisabled = config.GetBindable <bool>(OsuSetting.MouseDisableWheel); ScoreProcessor = RulesetContainer.CreateScoreProcessor(); if (!ScoreProcessor.Mode.Disabled) { config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); } InternalChild = gameplayClockContainer = new GameplayClockContainer(working, AllowLeadIn, RulesetContainer.GameplayStartTime); gameplayClockContainer.Children = new Drawable[] { PausableGameplayContainer = new PausableGameplayContainer { Retries = RestartCount, OnRetry = restart, OnQuit = performUserRequestedExit, Start = gameplayClockContainer.Start, Stop = gameplayClockContainer.Stop, IsPaused = { BindTarget = gameplayClockContainer.IsPaused }, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded.Value, Children = new[] { StoryboardContainer = CreateStoryboardContainer(), new ScalingContainer(ScalingMode.Gameplay) { Child = new LocalSkinOverrideContainer(working.Skin) { RelativeSizeAxes = Axes.Both, Child = RulesetContainer } }, new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { Anchor = Anchor.Centre, Origin = Anchor.Centre, Breaks = working.Beatmap.Breaks }, // display the cursor above some HUD elements. RulesetContainer.Cursor?.CreateProxy() ?? new Container(), HUDOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working) { HoldToQuit = { Action = performUserRequestedExit }, PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = gameplayClockContainer.UserPlaybackRate } } }, KeyCounter = { Visible = { BindTarget = RulesetContainer.HasReplayLoaded } }, RequestSeek = gameplayClockContainer.Seek, Anchor = Anchor.Centre, Origin = Anchor.Centre }, new SkipOverlay(RulesetContainer.GameplayStartTime) { RequestSeek = gameplayClockContainer.Seek }, } }, failOverlay = new FailOverlay { OnRetry = restart, OnQuit = performUserRequestedExit, }, new HotkeyRetryOverlay { Action = () => { if (!this.IsCurrentScreen()) { return; } fadeOut(true); restart(); }, } }; // bind clock into components that require it RulesetContainer.IsPaused.BindTo(gameplayClockContainer.IsPaused); if (ShowStoryboard.Value) { initializeStoryboard(false); } // 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(OsuGameBase osuGame, IFrameBasedClock framedClock) { beatmap.BindTo(osuGame.Beatmap); try { rulesetContainer = CreateRulesetContainer(ruleset, beatmap.Value); rulesetContainer.Clock = framedClock; } catch (Exception e) { Logger.Error(e, "Could not load beatmap sucessfully!"); return; } var layerBelowRuleset = new BorderLayer { RelativeSizeAxes = Axes.Both, Child = CreateLayerContainer() }; var layerAboveRuleset = CreateLayerContainer(); layerAboveRuleset.Child = new HitObjectMaskLayer(rulesetContainer.Playfield, this); layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); RadioButtonCollection toolboxCollection; InternalChild = new GridContainer { RelativeSizeAxes = Axes.Both, Content = new[] { new Drawable[] { new FillFlowContainer { Name = "Sidebar", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 10 }, Children = new Drawable[] { new ToolboxGroup { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } } } }, new Container { Name = "Content", RelativeSizeAxes = Axes.Both, Children = new Drawable[] { layerBelowRuleset, rulesetContainer, layerAboveRuleset } } }, }, ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, 200), } }; toolboxCollection.Items = CompositionTools.Select(t => new RadioButton(t.Name, () => setCompositionTool(t))) .Prepend(new RadioButton("Select", () => setCompositionTool(null))) .ToList(); toolboxCollection.Items[0].Select(); }
public InvadersScoreProcessor(RulesetContainer <InvadersHitObject> rulesetContainer) : base(rulesetContainer) { }
protected override void LoadComplete() { base.LoadComplete(); RulesetContainer?.SetReplayScore(score); }
public RpScoreProcessor(RulesetContainer <BaseRpObject> hitRenderer) : base(hitRenderer) { }
protected override void LoadComplete() { base.LoadComplete(); RulesetContainer.SetReplay(score.Replay); }
public CatchScoreProcessor(RulesetContainer <CatchBaseHit, CatchJudgement> rulesetContainer) : base(rulesetContainer) { }
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(); Schedule(() => { adjustableSourceClock.Reset(); foreach (var mod in working.Mods.Value.OfType <IApplicableToClock>()) { mod.ApplyToClock(adjustableSourceClock); } decoupledClock.ChangeSource(adjustableSourceClock); }); 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 = () => 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); // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; scoreProcessor.Failed += onFail; }
public void ApplyToRulesetContainer(RulesetContainer <T> rulesetContainer) { rulesetContainer.SetReplay(CreateReplayScore(rulesetContainer.Beatmap)?.Replay); }
public ManiaScoreProcessor(RulesetContainer <ManiaHitObject> rulesetContainer) : base(rulesetContainer) { }
public void ApplyToRulesetContainer(RulesetContainer <ManiaHitObject> rulesetContainer) { var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns; rulesetContainer.Objects.OfType <ManiaHitObject>().ForEach(h => h.Column = availableColumns - 1 - h.Column); }
public CatchScoreProcessor(RulesetContainer <CatchHitObject> rulesetContainer) : base(rulesetContainer) { }
public override void ApplyToRulesetContainer(RulesetContainer <TaikoHitObject> rulesetContainer) { playfield = (TaikoPlayfield)rulesetContainer.Playfield; base.ApplyToRulesetContainer(rulesetContainer); }
public virtual void ApplyToRulesetContainer(RulesetContainer <T> rulesetContainer) => rulesetContainer.SetReplayScore(CreateReplayScore(rulesetContainer.Beatmap));
public CytusScoreProcessor(RulesetContainer <CytusHitObject> rulesetContainer) : base(rulesetContainer) { }
private void load(AudioManager audio, APIAccess api, OsuConfigManager config) { this.api = api; WorkingBeatmap working = Beatmap.Value; if (working is DummyWorkingBeatmap) { return; } sampleRestart = audio.Sample.Get(@"Gameplay/restart"); mouseWheelDisabled = config.GetBindable <bool>(OsuSetting.MouseDisableWheel); userAudioOffset = config.GetBindable <double>(OsuSetting.AudioOffset); IBeatmap 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); } 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.Value); } if (!RulesetContainer.Objects.Any()) { Logger.Error(new InvalidOperationException("Beatmap contains no hit objects!"), "Beatmap contains no hit objects!"); return; } } catch (Exception e) { Logger.Error(e, "Could not load beatmap sucessfully!"); //couldn't load, hard abort! return; } sourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock(); adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; adjustableClock.Seek(AllowLeadIn ? Math.Min(RulesetContainer.GameplayStartTime, beatmap.HitObjects.First().StartTime - beatmap.BeatmapInfo.AudioLeadIn) : RulesetContainer.GameplayStartTime); adjustableClock.ProcessFrame(); // Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited. // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. var platformOffsetClock = new FramedOffsetClock(adjustableClock) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 22 : 0 }; // the final usable gameplay clock with user-set offsets applied. var offsetClock = new FramedOffsetClock(platformOffsetClock); userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.TriggerChange(); ScoreProcessor = RulesetContainer.CreateScoreProcessor(); if (!ScoreProcessor.Mode.Disabled) { config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode); } Children = new Drawable[] { pauseContainer = new PauseContainer(offsetClock, adjustableClock) { Retries = RestartCount, OnRetry = Restart, OnQuit = Exit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, Children = new[] { storyboardContainer = new Container { RelativeSizeAxes = Axes.Both, Alpha = 0, }, new LocalSkinOverrideContainer(working.Skin) { RelativeSizeAxes = Axes.Both, Child = RulesetContainer }, new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { Anchor = Anchor.Centre, Origin = Anchor.Centre, ProcessCustomClock = false, Breaks = beatmap.Breaks }, RulesetContainer.Cursor?.CreateProxy() ?? new Container(), hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) { Clock = Clock, // hud overlay doesn't want to use the audio clock directly ProcessCustomClock = false, Anchor = Anchor.Centre, Origin = Anchor.Centre }, new SkipOverlay(RulesetContainer.GameplayStartTime) { Clock = Clock, // skip button doesn't want to use the audio clock directly ProcessCustomClock = false, AdjustableClock = adjustableClock, FramedClock = offsetClock, }, } }, failOverlay = new FailOverlay { OnRetry = Restart, OnQuit = Exit, }, new HotkeyRetryOverlay { Action = () => { if (!IsCurrentScreen) { return; } pauseContainer.Hide(); Restart(); }, } }; hudOverlay.HoldToQuit.Action = Exit; hudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); RulesetContainer.IsPaused.BindTo(pauseContainer.IsPaused); if (ShowStoryboard) { initializeStoryboard(false); } // Bind ScoreProcessor to ourselves ScoreProcessor.AllJudged += onCompletion; ScoreProcessor.Failed += onFail; foreach (var mod in Beatmap.Value.Mods.Value.OfType <IApplicableToScoreProcessor>()) { mod.ApplyToScoreProcessor(ScoreProcessor); } }
public void ApplyToRulesetContainer(RulesetContainer <OsuHitObject> rulesetContainer) { // grab the input manager for future use. osuInputManager = (OsuInputManager)rulesetContainer.KeyBindingInputManager; osuInputManager.AllowUserPresses = false; }
private void load(AudioManager audio, APIAccess api, OsuConfigManager config) { this.api = api; WorkingBeatmap working = Beatmap.Value; if (working is DummyWorkingBeatmap) { return; } sampleRestart = audio.Sample.Get(@"Gameplay/restart"); mouseWheelDisabled = config.GetBindable <bool>(OsuSetting.MouseDisableWheel); userAudioOffset = config.GetBindable <double>(OsuSetting.AudioOffset); IBeatmap 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); } 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); } if (!RulesetContainer.Objects.Any()) { Logger.Error(new InvalidOperationException("Beatmap contains no hit objects!"), "Beatmap contains no hit objects!"); return; } } catch (Exception e) { Logger.Error(e, "Could not load beatmap sucessfully!"); //couldn't load, hard abort! return; } sourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock(); adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var firstObjectTime = RulesetContainer.Objects.First().StartTime; adjustableClock.Seek(AllowLeadIn ? Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn)) : firstObjectTime); adjustableClock.ProcessFrame(); // the final usable gameplay clock with user-set offsets applied. var offsetClock = new FramedOffsetClock(adjustableClock); userAudioOffset.ValueChanged += v => offsetClock.Offset = v; userAudioOffset.TriggerChange(); ScoreProcessor = RulesetContainer.CreateScoreProcessor(); Children = new Drawable[] { pauseContainer = new PauseContainer(offsetClock, adjustableClock) { OnRetry = Restart, OnQuit = Exit, CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded, OnPause = () => { pauseContainer.Retries = RestartCount; hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, OnResume = () => hudOverlay.KeyCounter.IsCounting = true, Children = new[] { storyboardContainer = new Container { RelativeSizeAxes = Axes.Both, Alpha = 0, }, new LocalSkinOverrideContainer(working.Skin) { RelativeSizeAxes = Axes.Both, Child = RulesetContainer }, new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { Anchor = Anchor.Centre, Origin = Anchor.Centre, ProcessCustomClock = false, Breaks = beatmap.Breaks }, RulesetContainer.Cursor?.CreateProxy() ?? new Container(), hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) { Clock = Clock, // hud overlay doesn't want to use the audio clock directly ProcessCustomClock = false, Anchor = Anchor.Centre, Origin = Anchor.Centre }, new SkipOverlay(firstObjectTime) { Clock = Clock, // skip button doesn't want to use the audio clock directly ProcessCustomClock = false, AdjustableClock = adjustableClock, FramedClock = offsetClock, }, } }, failOverlay = new FailOverlay { OnRetry = Restart, OnQuit = Exit, }, new HotkeyRetryOverlay { Action = () => { if (!IsCurrentScreen) { return; } //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(); }, } }; hudOverlay.HoldToQuit.Action = Exit; if (ShowStoryboard) { initializeStoryboard(false); } // 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([NotNull] OsuGameBase osuGame, [NotNull] IAdjustableClock adjustableClock, [NotNull] IFrameBasedClock framedClock, [CanBeNull] BindableBeatDivisor beatDivisor) { this.adjustableClock = adjustableClock; if (beatDivisor != null) { this.beatDivisor.BindTo(beatDivisor); } beatmap.BindTo(osuGame.Beatmap); try { rulesetContainer = CreateRulesetContainer(ruleset, beatmap.Value); rulesetContainer.Clock = framedClock; } catch (Exception e) { Logger.Error(e, "Could not load beatmap sucessfully!"); return; } HitObjectMaskLayer hitObjectMaskLayer = new HitObjectMaskLayer(this); SelectionLayer selectionLayer = new SelectionLayer(rulesetContainer.Playfield); var layerBelowRuleset = new BorderLayer { RelativeSizeAxes = Axes.Both, Child = CreateLayerContainer() }; var layerAboveRuleset = CreateLayerContainer(); layerAboveRuleset.Children = new Drawable[] { selectionLayer, // Below object overlays for input hitObjectMaskLayer, selectionLayer.CreateProxy() // Proxy above object overlays for selections }; layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); RadioButtonCollection toolboxCollection; InternalChild = new GridContainer { RelativeSizeAxes = Axes.Both, Content = new[] { new Drawable[] { new FillFlowContainer { Name = "Sidebar", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 10 }, Children = new Drawable[] { new ToolboxGroup { Child = toolboxCollection = new RadioButtonCollection { RelativeSizeAxes = Axes.X } } } }, new Container { Name = "Content", RelativeSizeAxes = Axes.Both, Children = new Drawable[] { layerBelowRuleset, rulesetContainer, layerAboveRuleset } } }, }, ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, 200), } }; selectionLayer.ObjectSelected += hitObjectMaskLayer.AddOverlay; selectionLayer.ObjectDeselected += hitObjectMaskLayer.RemoveOverlay; selectionLayer.SelectionCleared += hitObjectMaskLayer.RemoveSelectionOverlay; selectionLayer.SelectionFinished += hitObjectMaskLayer.AddSelectionOverlay; toolboxCollection.Items = new[] { new RadioButton("Select", () => setCompositionTool(null)) } .Concat( CompositionTools.Select(t => new RadioButton(t.Name, () => setCompositionTool(t))) ) .ToList(); toolboxCollection.Items[0].Select(); }