mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 08:52:55 +08:00
Merge branch 'master' into repeat-points
This commit is contained in:
commit
06b615c474
@ -1 +1 @@
|
||||
Subproject commit a7dd1fba8473f636ee8f6e49075331d9076383ee
|
||||
Subproject commit 90bf49a2df3dbad5994d922df63e4891c622dbc3
|
@ -1 +1 @@
|
||||
Subproject commit 7724abdf1d7c9705ba2e3989a9c604e17ccdc871
|
||||
Subproject commit 266965f0d795b94a126e2da302bd2c10eadd642a
|
@ -32,6 +32,10 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.8.1" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
</packages>
|
34
osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs
Normal file
34
osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Configuration.Tracking;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Configuration
|
||||
{
|
||||
public class ManiaConfigManager : RulesetConfigManager<ManiaSetting>
|
||||
{
|
||||
public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant)
|
||||
: base(settings, ruleset, variant)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
base.InitialiseDefaults();
|
||||
|
||||
Set(ManiaSetting.ScrollTime, 1500.0, 50.0, 10000.0, 50.0);
|
||||
}
|
||||
|
||||
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||
{
|
||||
new TrackedSetting<double>(ManiaSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms"))
|
||||
};
|
||||
}
|
||||
|
||||
public enum ManiaSetting
|
||||
{
|
||||
ScrollTime
|
||||
}
|
||||
}
|
@ -11,13 +11,14 @@ using osu.Framework.Graphics.Colour;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class Column : ScrollingPlayfield, IHasAccentColour
|
||||
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||
{
|
||||
private const float key_icon_size = 10;
|
||||
private const float key_icon_corner_radius = 3;
|
||||
@ -259,5 +260,26 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
public bool OnPressed(ManiaAction action) => Pressed?.Invoke(action) ?? false;
|
||||
public bool OnReleased(ManiaAction action) => Released?.Invoke(action) ?? false;
|
||||
}
|
||||
|
||||
public bool OnPressed(ManiaAction action)
|
||||
{
|
||||
// Play the sounds of the next hitobject
|
||||
if (HitObjects.AliveObjects.Any())
|
||||
{
|
||||
// If there are alive hitobjects, we can abuse the fact that AliveObjects are sorted by time (see: Add())
|
||||
HitObjects.AliveObjects.First().PlaySamples();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not, we do a slow search - we might want to do a BinarySearch here if this becomes problematic
|
||||
// We fallback to LastOrDefault() if we're beyond the last note in the map
|
||||
var hitObject = HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.LastOrDefault();
|
||||
hitObject?.PlaySamples();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnReleased(ManiaAction action) => false;
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
@ -78,6 +80,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
return null;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ManiaConfigManager maniaConfig)
|
||||
{
|
||||
maniaConfig.BindWith(ManiaSetting.ScrollTime, VisibleTimeRange);
|
||||
}
|
||||
|
||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
{
|
||||
getStageByColumn(((ManiaHitObject)judgedObject.HitObject).Column).OnJudgement(judgedObject, judgement);
|
||||
|
@ -10,8 +10,11 @@ using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
@ -77,11 +80,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
||||
|
||||
public override PassThroughInputManager CreateInputManager()
|
||||
{
|
||||
var variantType = Mods.OfType<IPlayfieldTypeMod>().FirstOrDefault()?.PlayfieldType ?? PlayfieldType.Single;
|
||||
return new ManiaInputManager(Ruleset.RulesetInfo, (int)variantType + Beatmap.TotalColumns);
|
||||
}
|
||||
public override int Variant => (int)(Mods.OfType<IPlayfieldTypeMod>().FirstOrDefault()?.PlayfieldType ?? PlayfieldType.Single) + Beatmap.TotalColumns;
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
||||
|
||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap);
|
||||
|
||||
@ -103,5 +104,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f);
|
||||
|
||||
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay, this);
|
||||
|
||||
protected override IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => new ManiaConfigManager(settings, Ruleset.RulesetInfo, Variant);
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,10 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
@ -58,6 +62,7 @@
|
||||
<Compile Include="Beatmaps\Patterns\Legacy\PatternType.cs" />
|
||||
<Compile Include="Beatmaps\ManiaBeatmapConverter.cs" />
|
||||
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
||||
<Compile Include="Configuration\ManiaConfigManager.cs" />
|
||||
<Compile Include="MathUtils\FastRandom.cs" />
|
||||
<Compile Include="Judgements\HitWindows.cs" />
|
||||
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.8.1" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
</packages>
|
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
continue;
|
||||
|
||||
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
|
||||
float stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||
|
||||
if (objectN.StartTime - endTime > stackThreshold)
|
||||
//We are no longer within stacking range of the next object.
|
||||
@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
OsuHitObject objectI = beatmap.HitObjects[i];
|
||||
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
||||
|
||||
float stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||
|
||||
/* If this object is a hitcircle, then we enter this "special" case.
|
||||
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string Description => @"Play with no approach circles and fading notes for a slight score advantage.";
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
|
||||
private const float fade_in_duration_multiplier = 0.4f;
|
||||
private const double fade_in_duration_multiplier = 0.4;
|
||||
private const double fade_out_duration_multiplier = 0.3;
|
||||
|
||||
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
||||
|
@ -22,8 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
/// </summary>
|
||||
private bool isRepeatAtEnd => repeatPoint.RepeatIndex % 2 == 0;
|
||||
|
||||
public double FadeInTime;
|
||||
public double FadeOutTime;
|
||||
private double animDuration;
|
||||
|
||||
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
|
||||
: base(repeatPoint)
|
||||
@ -54,11 +53,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
{
|
||||
var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime);
|
||||
animDuration = Math.Min(150, repeatPoint.SpanDuration / 2);
|
||||
|
||||
this.FadeIn(animIn).ScaleTo(1.2f, animIn)
|
||||
this.FadeIn(animDuration).ScaleTo(1.2f, animDuration / 2)
|
||||
.Then()
|
||||
.ScaleTo(1, 150, Easing.Out);
|
||||
.ScaleTo(1, animDuration / 2, Easing.Out);
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
@ -66,14 +65,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Idle:
|
||||
this.Delay(FadeOutTime - repeatPoint.StartTime).FadeOut();
|
||||
this.Delay(HitObject.TimePreempt).FadeOut();
|
||||
break;
|
||||
case ArmedState.Miss:
|
||||
this.FadeOut(160);
|
||||
this.FadeOut(animDuration);
|
||||
break;
|
||||
case ArmedState.Hit:
|
||||
this.FadeOut(120, Easing.OutQuint)
|
||||
.ScaleTo(Scale * 1.5f, 120, Easing.OutQuint);
|
||||
this.FadeOut(animDuration, Easing.OutQuint)
|
||||
.ScaleTo(Scale * 1.5f, animDuration, Easing.OutQuint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -75,12 +75,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
AddNested(InitialCircle);
|
||||
|
||||
var spanDuration = s.Curve.Distance / s.Velocity;
|
||||
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
|
||||
{
|
||||
var spanStartTime = s.StartTime + tick.SpanIndex * spanDuration;
|
||||
var spanStartTime = s.StartTime + tick.SpanIndex * s.SpanDuration;
|
||||
var fadeInTime = spanStartTime + (tick.StartTime - spanStartTime) / 2 - (tick.SpanIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2);
|
||||
var fadeOutTime = spanStartTime + spanDuration;
|
||||
var fadeOutTime = spanStartTime + s.SpanDuration;
|
||||
|
||||
var drawableTick = new DrawableSliderTick(tick)
|
||||
{
|
||||
@ -95,15 +94,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
|
||||
{
|
||||
var repeatStartTime = s.StartTime + (repeatPoint.RepeatIndex + 1) * spanDuration;
|
||||
var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2);
|
||||
var fadeOutTime = repeatStartTime + spanDuration;
|
||||
|
||||
var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this)
|
||||
{
|
||||
FadeInTime = fadeInTime,
|
||||
FadeOutTime = fadeOutTime,
|
||||
Position = repeatPoint.Position,
|
||||
Position = repeatPoint.Position
|
||||
};
|
||||
|
||||
repeatPoints.Add(drawableRepeatPoint);
|
||||
|
@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public double HitWindow100 = 80;
|
||||
public double HitWindow300 = 30;
|
||||
|
||||
public float TimePreempt = 600;
|
||||
public float TimeFadein = 400;
|
||||
public double TimePreempt = 600;
|
||||
public double TimeFadein = 400;
|
||||
|
||||
public Vector2 Position { get; set; }
|
||||
public float X => Position.X;
|
||||
|
@ -1,10 +1,25 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
public class RepeatPoint : OsuHitObject
|
||||
{
|
||||
public int RepeatIndex { get; set; }
|
||||
public double SpanDuration { get; set; }
|
||||
|
||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
// We want to show the first RepeatPoint as the TimePreempt dictates but on short (and possibly fast) sliders
|
||||
// we may need to cut down this time on following RepeatPoints to only show up to two RepeatPoints at any given time.
|
||||
if (RepeatIndex > 0)
|
||||
TimePreempt = Math.Min(SpanDuration * 2, TimePreempt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,11 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public List<List<SampleInfo>> RepeatSamples { get; set; } = new List<List<SampleInfo>>();
|
||||
public int RepeatCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The length of one span of this <see cref="Slider"/>.
|
||||
/// </summary>
|
||||
public double SpanDuration => Duration / this.SpanCount();
|
||||
|
||||
private int stackHeight;
|
||||
|
||||
public override int StackHeight
|
||||
@ -102,13 +107,12 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
var length = Curve.Distance;
|
||||
var tickDistance = Math.Min(TickDistance, length);
|
||||
var spanDuration = length / Velocity;
|
||||
|
||||
var minDistanceFromEnd = Velocity * 0.01;
|
||||
|
||||
for (var span = 0; span < this.SpanCount(); span++)
|
||||
{
|
||||
var spanStartTime = StartTime + span * spanDuration;
|
||||
var spanStartTime = StartTime + span * SpanDuration;
|
||||
var reversed = span % 2 == 1;
|
||||
|
||||
for (var d = tickDistance; d <= length; d += tickDistance)
|
||||
@ -133,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
AddNested(new SliderTick
|
||||
{
|
||||
SpanIndex = span,
|
||||
StartTime = spanStartTime + timeProgress * spanDuration,
|
||||
StartTime = spanStartTime + timeProgress * SpanDuration,
|
||||
Position = Curve.PositionAt(distanceProgress),
|
||||
StackHeight = StackHeight,
|
||||
Scale = Scale,
|
||||
@ -146,16 +150,13 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
private void createRepeatPoints()
|
||||
{
|
||||
var repeatDuration = Distance / Velocity;
|
||||
|
||||
for (int repeatIndex = 0, repeat = 1; repeatIndex < RepeatCount; repeatIndex++, repeat++)
|
||||
{
|
||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
||||
|
||||
AddNested(new RepeatPoint
|
||||
{
|
||||
RepeatIndex = repeatIndex,
|
||||
StartTime = repeatStartTime,
|
||||
SpanDuration = SpanDuration,
|
||||
StartTime = StartTime + repeat * SpanDuration,
|
||||
Position = Curve.PositionAt(repeat % 2),
|
||||
StackHeight = StackHeight,
|
||||
Scale = Scale,
|
||||
|
@ -63,6 +63,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
AddStep("Fast Short Slider", () => testShortHighSpeed());
|
||||
AddStep("Fast Short Slider 1 Repeat", () => testShortHighSpeed(1));
|
||||
AddStep("Fast Short Slider 2 Repeats", () => testShortHighSpeed(2));
|
||||
AddStep("Fast Short Slider 6 Repeats", () => testShortHighSpeed(6));
|
||||
|
||||
AddStep("Perfect Curve", () => testPerfect());
|
||||
AddStep("Perfect Curve 1 Repeat", () => testPerfect(1));
|
||||
|
@ -33,6 +33,10 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.8.1" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
</packages>
|
@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
{
|
||||
bool hitButton = true;
|
||||
|
||||
Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None));
|
||||
Frames.Add(new ReplayFrame(Beatmap.HitObjects[0].StartTime - 1000, null, null, ReplayButtonState.None));
|
||||
Frames.Add(new TaikoReplayFrame(-100000, ReplayButtonState.None));
|
||||
Frames.Add(new TaikoReplayFrame(Beatmap.HitObjects[0].StartTime - 1000, ReplayButtonState.None));
|
||||
|
||||
for (int i = 0; i < Beatmap.HitObjects.Count; i++)
|
||||
{
|
||||
@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
break;
|
||||
}
|
||||
|
||||
Frames.Add(new ReplayFrame(j, null, null, button));
|
||||
Frames.Add(new TaikoReplayFrame(j, button));
|
||||
d = (d + 1) % 4;
|
||||
if (++count == req)
|
||||
break;
|
||||
@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
{
|
||||
foreach (var tick in drumRoll.NestedHitObjects.OfType<DrumRollTick>())
|
||||
{
|
||||
Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Right1 : ReplayButtonState.Right2));
|
||||
Frames.Add(new TaikoReplayFrame(tick.StartTime, hitButton ? ReplayButtonState.Right1 : ReplayButtonState.Right2));
|
||||
hitButton = !hitButton;
|
||||
}
|
||||
}
|
||||
@ -107,18 +107,18 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
button = hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2;
|
||||
}
|
||||
|
||||
Frames.Add(new ReplayFrame(h.StartTime, null, null, button));
|
||||
Frames.Add(new TaikoReplayFrame(h.StartTime, button));
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException("Unknown hit object type.");
|
||||
|
||||
Frames.Add(new ReplayFrame(endTime + KEY_UP_DELAY, null, null, ReplayButtonState.None));
|
||||
Frames.Add(new TaikoReplayFrame(endTime + KEY_UP_DELAY, ReplayButtonState.None));
|
||||
|
||||
if (i < Beatmap.HitObjects.Count - 1)
|
||||
{
|
||||
double waitTime = Beatmap.HitObjects[i + 1].StartTime - 1000;
|
||||
if (waitTime > endTime)
|
||||
Frames.Add(new ReplayFrame(waitTime, null, null, ReplayButtonState.None));
|
||||
Frames.Add(new TaikoReplayFrame(waitTime, ReplayButtonState.None));
|
||||
}
|
||||
|
||||
hitButton = !hitButton;
|
||||
|
17
osu.Game.Rulesets.Taiko/Replays/TaikoReplayFrame.cs
Normal file
17
osu.Game.Rulesets.Taiko/Replays/TaikoReplayFrame.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Replays
|
||||
{
|
||||
public class TaikoReplayFrame : ReplayFrame
|
||||
{
|
||||
public override bool IsImportant => MouseLeft || MouseRight;
|
||||
|
||||
public TaikoReplayFrame(double time, ReplayButtonState buttons)
|
||||
: base(time, null, null, buttons)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -32,6 +32,10 @@
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
@ -91,6 +95,7 @@
|
||||
<Compile Include="Replays\TaikoAutoGenerator.cs" />
|
||||
<Compile Include="Objects\TaikoHitObject.cs" />
|
||||
<Compile Include="Objects\TaikoHitObjectDifficulty.cs" />
|
||||
<Compile Include="Replays\TaikoReplayFrame.cs" />
|
||||
<Compile Include="TaikoDifficultyCalculator.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Scoring\TaikoScoreProcessor.cs" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.8.1" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
</packages>
|
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition);
|
||||
Assert.IsTrue(sprite.IsDrawable);
|
||||
Assert.AreEqual(Anchor.Centre, sprite.Origin);
|
||||
Assert.AreEqual(Path.Combine("SB", "lyric", "ja-21.png"), sprite.Path);
|
||||
Assert.AreEqual("SB/lyric/ja-21.png", sprite.Path);
|
||||
|
||||
var animation = background.Elements.ElementAt(12) as StoryboardAnimation;
|
||||
Assert.NotNull(animation);
|
||||
@ -82,7 +82,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.IsTrue(animation.IsDrawable);
|
||||
Assert.AreEqual(AnimationLoopType.LoopForever, animation.LoopType);
|
||||
Assert.AreEqual(Anchor.Centre, animation.Origin);
|
||||
Assert.AreEqual(Path.Combine("SB", "red jitter", "red_0000.jpg"), animation.Path);
|
||||
Assert.AreEqual("SB/red jitter/red_0000.jpg", animation.Path);
|
||||
Assert.AreEqual(78993, animation.StartTime);
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,10 @@
|
||||
<Reference Include="DeepEqual, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(SolutionDir)\packages\DeepEqual.1.6.0.0\lib\net40\DeepEqual.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
@ -1,11 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<packages>
|
||||
<package id="DeepEqual" version="1.6.0.0" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.8.1" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
<package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<packages>
|
||||
<package id="DeepEqual" version="1.6.0.0" targetFramework="net461" />
|
||||
<package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.8.1" targetFramework="net461" />
|
||||
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
|
||||
<package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
|
||||
</packages>
|
@ -301,6 +301,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
private string cleanFilename(string path) => FileSafety.PathSanitise(path.Trim('\"'));
|
||||
private string cleanFilename(string path) => FileSafety.PathStandardise(FileSafety.PathSanitise(path.Trim('\"')));
|
||||
}
|
||||
}
|
||||
|
71
osu.Game/Configuration/DatabasedConfigManager.cs
Normal file
71
osu.Game/Configuration/DatabasedConfigManager.cs
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public abstract class DatabasedConfigManager<T> : ConfigManager<T>
|
||||
where T : struct
|
||||
{
|
||||
private readonly SettingsStore settings;
|
||||
|
||||
private readonly int variant;
|
||||
|
||||
private readonly List<DatabasedSetting> databasedSettings;
|
||||
|
||||
private readonly RulesetInfo ruleset;
|
||||
|
||||
protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int variant = 0)
|
||||
{
|
||||
this.settings = settings;
|
||||
this.ruleset = ruleset;
|
||||
this.variant = variant;
|
||||
|
||||
databasedSettings = settings.Query(ruleset?.ID, variant);
|
||||
|
||||
InitialiseDefaults();
|
||||
}
|
||||
|
||||
protected override void PerformLoad()
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool PerformSave()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void AddBindable<TBindable>(T lookup, Bindable<TBindable> bindable)
|
||||
{
|
||||
base.AddBindable(lookup, bindable);
|
||||
|
||||
var setting = databasedSettings.FirstOrDefault(s => (int)s.Key == (int)(object)lookup);
|
||||
if (setting != null)
|
||||
{
|
||||
bindable.Parse(setting.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.Update(setting = new DatabasedSetting
|
||||
{
|
||||
Key = lookup,
|
||||
Value = bindable.Value,
|
||||
RulesetID = ruleset?.ID,
|
||||
Variant = variant,
|
||||
});
|
||||
|
||||
databasedSettings.Add(setting);
|
||||
}
|
||||
|
||||
bindable.ValueChanged += v =>
|
||||
{
|
||||
setting.Value = v;
|
||||
settings.Update(setting);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
51
osu.Game/Configuration/DatabasedSetting.cs
Normal file
51
osu.Game/Configuration/DatabasedSetting.cs
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
[Table("Settings")]
|
||||
public class DatabasedSetting : IHasPrimaryKey
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int ID { get; set; }
|
||||
|
||||
public int? RulesetID { get; set; }
|
||||
|
||||
public int? Variant { get; set; }
|
||||
|
||||
[Column("Key")]
|
||||
public int IntKey
|
||||
{
|
||||
get => (int)Key;
|
||||
private set => Key = value;
|
||||
}
|
||||
|
||||
[Column("Value")]
|
||||
public string StringValue
|
||||
{
|
||||
get => Value.ToString();
|
||||
set => Value = value;
|
||||
}
|
||||
|
||||
public object Key;
|
||||
public object Value;
|
||||
|
||||
public DatabasedSetting(object key, object value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for derived classes that may require serialisation.
|
||||
/// </summary>
|
||||
public DatabasedSetting()
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Key}=>{Value}";
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public class OsuConfigManager : ConfigManager<OsuSetting>
|
||||
public class OsuConfigManager : IniConfigManager<OsuSetting>
|
||||
{
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
|
44
osu.Game/Configuration/SettingsStore.cs
Normal file
44
osu.Game/Configuration/SettingsStore.cs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public class SettingsStore : DatabaseBackedStore
|
||||
{
|
||||
public event Action SettingChanged;
|
||||
|
||||
public SettingsStore(Func<OsuDbContext> createContext)
|
||||
: base(createContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve <see cref="DatabasedSetting"/>s for a specified ruleset/variant content.
|
||||
/// </summary>
|
||||
/// <param name="rulesetId">The ruleset's internal ID.</param>
|
||||
/// <param name="variant">An optional variant.</param>
|
||||
/// <returns></returns>
|
||||
public List<DatabasedSetting> Query(int? rulesetId = null, int? variant = null) =>
|
||||
GetContext().DatabasedSetting.Where(b => b.RulesetID == rulesetId && b.Variant == variant).ToList();
|
||||
|
||||
public void Update(DatabasedSetting setting)
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
var newValue = setting.Value;
|
||||
|
||||
Refresh(ref setting);
|
||||
|
||||
setting.Value = newValue;
|
||||
|
||||
context.SaveChanges();
|
||||
|
||||
SettingChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
@ -34,8 +34,14 @@ namespace osu.Game.Database
|
||||
if (context.Entry(obj).State != EntityState.Detached) return;
|
||||
|
||||
var id = obj.ID;
|
||||
obj = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
|
||||
context.Entry(obj).Reload();
|
||||
var foundObject = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
|
||||
if (foundObject != null)
|
||||
{
|
||||
obj = foundObject;
|
||||
context.Entry(obj).Reload();
|
||||
}
|
||||
else
|
||||
context.Add(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -8,9 +8,10 @@ using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Rulesets;
|
||||
using DatabasedKeyBinding = osu.Game.Input.Bindings.DatabasedKeyBinding;
|
||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||
|
||||
namespace osu.Game.Database
|
||||
@ -22,6 +23,7 @@ namespace osu.Game.Database
|
||||
public DbSet<BeatmapMetadata> BeatmapMetadata { get; set; }
|
||||
public DbSet<BeatmapSetInfo> BeatmapSetInfo { get; set; }
|
||||
public DbSet<DatabasedKeyBinding> DatabasedKeyBinding { get; set; }
|
||||
public DbSet<DatabasedSetting> DatabasedSetting { get; set; }
|
||||
public DbSet<FileInfo> FileInfo { get; set; }
|
||||
public DbSet<RulesetInfo> RulesetInfo { get; set; }
|
||||
|
||||
@ -86,9 +88,11 @@ namespace osu.Game.Database
|
||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.DeletePending);
|
||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.Variant);
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => new { b.RulesetID, b.Variant });
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.IntAction);
|
||||
|
||||
modelBuilder.Entity<DatabasedSetting>().HasIndex(b => new { b.RulesetID, b.Variant });
|
||||
|
||||
modelBuilder.Entity<FileInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||
modelBuilder.Entity<FileInfo>().HasIndex(b => b.ReferenceCount);
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class IconButton : OsuClickableContainer
|
||||
{
|
||||
private const float button_size = 30;
|
||||
public const float BUTTON_SIZE = 30;
|
||||
|
||||
private Color4? flashColour;
|
||||
/// <summary>
|
||||
@ -106,7 +106,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Size = new Vector2(button_size),
|
||||
Size = new Vector2(BUTTON_SIZE),
|
||||
CornerRadius = 5,
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Threading;
|
||||
using OpenTK;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface.Volume
|
||||
@ -14,6 +15,7 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
||||
public class VolumeControl : OverlayContainer
|
||||
{
|
||||
private readonly VolumeMeter volumeMeterMaster;
|
||||
private readonly IconButton muteIcon;
|
||||
|
||||
protected override bool BlockPassThroughMouse => false;
|
||||
|
||||
@ -34,6 +36,17 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
||||
Spacing = new Vector2(15, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Size = new Vector2(IconButton.BUTTON_SIZE),
|
||||
Child = muteIcon = new IconButton
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = FontAwesome.fa_volume_up,
|
||||
Action = () => Adjust(GlobalAction.ToggleMute),
|
||||
}
|
||||
},
|
||||
volumeMeterMaster = new VolumeMeter("Master"),
|
||||
volumeMeterEffect = new VolumeMeter("Effects"),
|
||||
volumeMeterMusic = new VolumeMeter("Music")
|
||||
@ -46,18 +59,10 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
volumeMeterMaster.Bindable.ValueChanged += volumeChanged;
|
||||
volumeMeterEffect.Bindable.ValueChanged += volumeChanged;
|
||||
volumeMeterMusic.Bindable.ValueChanged += volumeChanged;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
volumeMeterMaster.Bindable.ValueChanged -= volumeChanged;
|
||||
volumeMeterEffect.Bindable.ValueChanged -= volumeChanged;
|
||||
volumeMeterMusic.Bindable.ValueChanged -= volumeChanged;
|
||||
volumeMeterMaster.Bindable.ValueChanged += _ => settingChanged();
|
||||
volumeMeterEffect.Bindable.ValueChanged += _ => settingChanged();
|
||||
volumeMeterMusic.Bindable.ValueChanged += _ => settingChanged();
|
||||
muted.ValueChanged += _ => settingChanged();
|
||||
}
|
||||
|
||||
public bool Adjust(GlobalAction action)
|
||||
@ -76,23 +81,45 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
||||
else
|
||||
volumeMeterMaster.Increase();
|
||||
return true;
|
||||
case GlobalAction.ToggleMute:
|
||||
Show();
|
||||
muted.Toggle();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void volumeChanged(double newVolume)
|
||||
private void settingChanged()
|
||||
{
|
||||
Show();
|
||||
schedulePopOut();
|
||||
}
|
||||
|
||||
private readonly BindableDouble muteAdjustment = new BindableDouble();
|
||||
|
||||
private readonly BindableBool muted = new BindableBool();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
volumeMeterMaster.Bindable.BindTo(audio.Volume);
|
||||
volumeMeterEffect.Bindable.BindTo(audio.VolumeSample);
|
||||
volumeMeterMusic.Bindable.BindTo(audio.VolumeTrack);
|
||||
|
||||
muted.ValueChanged += mute =>
|
||||
{
|
||||
if (mute)
|
||||
{
|
||||
audio.AddAdjustment(AdjustableProperty.Volume, muteAdjustment);
|
||||
muteIcon.Icon = FontAwesome.fa_volume_off;
|
||||
}
|
||||
else
|
||||
{
|
||||
audio.RemoveAdjustment(AdjustableProperty.Volume, muteAdjustment);
|
||||
muteIcon.Icon = FontAwesome.fa_volume_up;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ScheduledDelegate popOutDelegate;
|
||||
|
@ -70,11 +70,8 @@ namespace osu.Game.Graphics.UserInterface.Volume
|
||||
|
||||
public double Volume
|
||||
{
|
||||
get { return Bindable.Value; }
|
||||
private set
|
||||
{
|
||||
Bindable.Value = value;
|
||||
}
|
||||
get => Bindable.Value;
|
||||
private set => Bindable.Value = value;
|
||||
}
|
||||
|
||||
public void Increase()
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Input.Bindings
|
||||
/// A KeyBindingInputManager with a database backing for custom overrides.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the custom action.</typeparam>
|
||||
public class DatabasedKeyBindingInputManager<T> : KeyBindingContainer<T>
|
||||
public class DatabasedKeyBindingContainer<T> : KeyBindingContainer<T>
|
||||
where T : struct
|
||||
{
|
||||
private readonly RulesetInfo ruleset;
|
||||
@ -31,7 +31,7 @@ namespace osu.Game.Input.Bindings
|
||||
/// <param name="ruleset">A reference to identify the current <see cref="Ruleset"/>. Used to lookup mappings. Null for global mappings.</param>
|
||||
/// <param name="variant">An optional variant for the specified <see cref="Ruleset"/>. Used when a ruleset has more than one possible keyboard layouts.</param>
|
||||
/// <param name="simultaneousMode">Specify how to deal with multiple matches of <see cref="KeyCombination"/>s and <see cref="T"/>s.</param>
|
||||
public DatabasedKeyBindingInputManager(RulesetInfo ruleset = null, int? variant = null, SimultaneousBindingMode simultaneousMode = SimultaneousBindingMode.None)
|
||||
public DatabasedKeyBindingContainer(RulesetInfo ruleset = null, int? variant = null, SimultaneousBindingMode simultaneousMode = SimultaneousBindingMode.None)
|
||||
: base(simultaneousMode)
|
||||
{
|
||||
this.ruleset = ruleset;
|
@ -10,11 +10,11 @@ using osu.Framework.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Input.Bindings
|
||||
{
|
||||
public class GlobalKeyBindingInputManager : DatabasedKeyBindingInputManager<GlobalAction>, IHandleGlobalInput
|
||||
public class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalInput
|
||||
{
|
||||
private readonly Drawable handler;
|
||||
|
||||
public GlobalKeyBindingInputManager(OsuGameBase game)
|
||||
public GlobalActionContainer(OsuGameBase game)
|
||||
{
|
||||
if (game is IKeyBindingHandler<GlobalAction>)
|
||||
handler = game;
|
||||
@ -29,10 +29,11 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
||||
new KeyBinding(new[] { InputKey.Up }, GlobalAction.IncreaseVolume),
|
||||
new KeyBinding(new[] { InputKey.MouseWheelUp }, GlobalAction.IncreaseVolume),
|
||||
new KeyBinding(new[] { InputKey.Down }, GlobalAction.DecreaseVolume),
|
||||
new KeyBinding(new[] { InputKey.MouseWheelDown }, GlobalAction.DecreaseVolume),
|
||||
new KeyBinding(InputKey.Up, GlobalAction.IncreaseVolume),
|
||||
new KeyBinding(InputKey.MouseWheelUp, GlobalAction.IncreaseVolume),
|
||||
new KeyBinding(InputKey.Down, GlobalAction.DecreaseVolume),
|
||||
new KeyBinding(InputKey.MouseWheelDown, GlobalAction.DecreaseVolume),
|
||||
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
||||
};
|
||||
|
||||
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
||||
@ -63,6 +64,8 @@ namespace osu.Game.Input.Bindings
|
||||
IncreaseVolume,
|
||||
[Description("Decrease Volume")]
|
||||
DecreaseVolume,
|
||||
[Description("Toggle mute")]
|
||||
ToggleMute,
|
||||
|
||||
// In-Game Keybindings
|
||||
[Description("Skip Cutscene")]
|
329
osu.Game/Migrations/20180125143340_Settings.Designer.cs
generated
Normal file
329
osu.Game/Migrations/20180125143340_Settings.Designer.cs
generated
Normal file
@ -0,0 +1,329 @@
|
||||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using osu.Game.Database;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Migrations
|
||||
{
|
||||
[DbContext(typeof(OsuDbContext))]
|
||||
[Migration("20180125143340_Settings")]
|
||||
partial class Settings
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<float>("ApproachRate");
|
||||
|
||||
b.Property<float>("CircleSize");
|
||||
|
||||
b.Property<float>("DrainRate");
|
||||
|
||||
b.Property<float>("OverallDifficulty");
|
||||
|
||||
b.Property<float>("SliderMultiplier");
|
||||
|
||||
b.Property<float>("SliderTickRate");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.ToTable("BeatmapDifficulty");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AudioLeadIn");
|
||||
|
||||
b.Property<int>("BaseDifficultyID");
|
||||
|
||||
b.Property<int>("BeatDivisor");
|
||||
|
||||
b.Property<int>("BeatmapSetInfoID");
|
||||
|
||||
b.Property<bool>("Countdown");
|
||||
|
||||
b.Property<double>("DistanceSpacing");
|
||||
|
||||
b.Property<int>("GridSize");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<bool>("Hidden");
|
||||
|
||||
b.Property<bool>("LetterboxInBreaks");
|
||||
|
||||
b.Property<string>("MD5Hash");
|
||||
|
||||
b.Property<int?>("MetadataID");
|
||||
|
||||
b.Property<int?>("OnlineBeatmapID");
|
||||
|
||||
b.Property<string>("Path");
|
||||
|
||||
b.Property<int>("RulesetID");
|
||||
|
||||
b.Property<bool>("SpecialStyle");
|
||||
|
||||
b.Property<float>("StackLeniency");
|
||||
|
||||
b.Property<double>("StarDifficulty");
|
||||
|
||||
b.Property<string>("StoredBookmarks");
|
||||
|
||||
b.Property<double>("TimelineZoom");
|
||||
|
||||
b.Property<string>("Version");
|
||||
|
||||
b.Property<bool>("WidescreenStoryboard");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("BaseDifficultyID");
|
||||
|
||||
b.HasIndex("BeatmapSetInfoID");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MD5Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
b.HasIndex("OnlineBeatmapID")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("RulesetID");
|
||||
|
||||
b.ToTable("BeatmapInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Artist");
|
||||
|
||||
b.Property<string>("ArtistUnicode");
|
||||
|
||||
b.Property<string>("AudioFile");
|
||||
|
||||
b.Property<string>("AuthorString")
|
||||
.HasColumnName("Author");
|
||||
|
||||
b.Property<string>("BackgroundFile");
|
||||
|
||||
b.Property<int>("PreviewTime");
|
||||
|
||||
b.Property<string>("Source");
|
||||
|
||||
b.Property<string>("Tags");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TitleUnicode");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.ToTable("BeatmapMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("BeatmapSetInfoID");
|
||||
|
||||
b.Property<int>("FileInfoID");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("BeatmapSetInfoID");
|
||||
|
||||
b.HasIndex("FileInfoID");
|
||||
|
||||
b.ToTable("BeatmapSetFileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("DeletePending");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int?>("MetadataID");
|
||||
|
||||
b.Property<int?>("OnlineBeatmapSetID");
|
||||
|
||||
b.Property<bool>("Protected");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("DeletePending");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
b.HasIndex("OnlineBeatmapSetID")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("BeatmapSetInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("IntKey")
|
||||
.HasColumnName("Key");
|
||||
|
||||
b.Property<int?>("RulesetID");
|
||||
|
||||
b.Property<string>("StringValue")
|
||||
.HasColumnName("Value");
|
||||
|
||||
b.Property<int?>("Variant");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("RulesetID", "Variant");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("IntAction")
|
||||
.HasColumnName("Action");
|
||||
|
||||
b.Property<string>("KeysString")
|
||||
.HasColumnName("Keys");
|
||||
|
||||
b.Property<int?>("RulesetID");
|
||||
|
||||
b.Property<int?>("Variant");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("IntAction");
|
||||
|
||||
b.HasIndex("RulesetID", "Variant");
|
||||
|
||||
b.ToTable("KeyBinding");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int>("ReferenceCount");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ReferenceCount");
|
||||
|
||||
b.ToTable("FileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
|
||||
{
|
||||
b.Property<int?>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("InstantiationInfo");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("ShortName");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Available");
|
||||
|
||||
b.HasIndex("ShortName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("RulesetInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
|
||||
.WithMany()
|
||||
.HasForeignKey("BaseDifficultyID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
|
||||
.WithMany("Beatmaps")
|
||||
.HasForeignKey("BeatmapSetInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||
.WithMany("Beatmaps")
|
||||
.HasForeignKey("MetadataID");
|
||||
|
||||
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||
.WithMany()
|
||||
.HasForeignKey("RulesetID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
|
||||
.WithMany("Files")
|
||||
.HasForeignKey("BeatmapSetInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||
.WithMany()
|
||||
.HasForeignKey("FileInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||
.WithMany("BeatmapSets")
|
||||
.HasForeignKey("MetadataID");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
57
osu.Game/Migrations/20180125143340_Settings.cs
Normal file
57
osu.Game/Migrations/20180125143340_Settings.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Migrations
|
||||
{
|
||||
public partial class Settings : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_KeyBinding_Variant",
|
||||
table: "KeyBinding");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Settings",
|
||||
columns: table => new
|
||||
{
|
||||
ID = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Key = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
RulesetID = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
Value = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Variant = table.Column<int>(type: "INTEGER", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Settings", x => x.ID);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_KeyBinding_RulesetID_Variant",
|
||||
table: "KeyBinding",
|
||||
columns: new[] { "RulesetID", "Variant" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Settings_RulesetID_Variant",
|
||||
table: "Settings",
|
||||
columns: new[] { "RulesetID", "Variant" });
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Settings");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_KeyBinding_RulesetID_Variant",
|
||||
table: "KeyBinding");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_KeyBinding_Variant",
|
||||
table: "KeyBinding",
|
||||
column: "Variant");
|
||||
}
|
||||
}
|
||||
}
|
25
osu.Game/Migrations/20180131154205_AddMuteBinding.cs
Normal file
25
osu.Game/Migrations/20180131154205_AddMuteBinding.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Migrations
|
||||
{
|
||||
[DbContext(typeof(OsuDbContext))]
|
||||
[Migration("20180131154205_AddMuteBinding")]
|
||||
public partial class AddMuteBinding : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql($"UPDATE KeyBinding SET Action = Action + 1 WHERE RulesetID IS NULL AND Variant IS NULL AND Action >= {(int)GlobalAction.ToggleMute}");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql($"DELETE FROM KeyBinding WHERE RulesetID IS NULL AND Variant IS NULL AND Action = {(int)GlobalAction.ToggleMute}");
|
||||
migrationBuilder.Sql($"UPDATE KeyBinding SET Action = Action - 1 WHERE RulesetID IS NULL AND Variant IS NULL AND Action > {(int)GlobalAction.ToggleMute}");
|
||||
}
|
||||
}
|
||||
}
|
@ -193,6 +193,28 @@ namespace osu.Game.Migrations
|
||||
b.ToTable("BeatmapSetInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("IntKey")
|
||||
.HasColumnName("Key");
|
||||
|
||||
b.Property<int?>("RulesetID");
|
||||
|
||||
b.Property<string>("StringValue")
|
||||
.HasColumnName("Value");
|
||||
|
||||
b.Property<int?>("Variant");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("RulesetID", "Variant");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
@ -212,7 +234,7 @@ namespace osu.Game.Migrations
|
||||
|
||||
b.HasIndex("IntAction");
|
||||
|
||||
b.HasIndex("Variant");
|
||||
b.HasIndex("RulesetID", "Variant");
|
||||
|
||||
b.ToTable("KeyBinding");
|
||||
});
|
||||
|
@ -126,6 +126,7 @@ namespace osu.Game.Online.API
|
||||
userReq.Success += u =>
|
||||
{
|
||||
LocalUser.Value = u;
|
||||
Username = LocalUser.Value.Username;
|
||||
failureCount = 0;
|
||||
|
||||
//we're connected!
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Configuration;
|
||||
@ -27,6 +28,7 @@ using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game
|
||||
@ -71,6 +73,7 @@ namespace osu.Game
|
||||
private OsuScreen screenStack;
|
||||
|
||||
private VolumeControl volume;
|
||||
private OnScreenDisplay onscreenDisplay;
|
||||
|
||||
private Bindable<int> configRuleset;
|
||||
public Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
@ -79,6 +82,9 @@ namespace osu.Game
|
||||
|
||||
private SettingsOverlay settings;
|
||||
|
||||
// todo: move this to SongSelect once Screen has the ability to unsuspend.
|
||||
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(new List<Mod>());
|
||||
|
||||
public OsuGame(string[] args = null)
|
||||
{
|
||||
this.args = args;
|
||||
@ -110,7 +116,7 @@ namespace osu.Game
|
||||
Task.Run(() => BeatmapManager.Import(paths.ToArray()));
|
||||
}
|
||||
|
||||
dependencies.CacheAs<OsuGame>(this);
|
||||
dependencies.CacheAs(this);
|
||||
|
||||
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
|
||||
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
|
||||
@ -195,7 +201,7 @@ namespace osu.Game
|
||||
}, overlayContent.Add);
|
||||
|
||||
loadComponentSingleFile(volume = new VolumeControl(), Add);
|
||||
loadComponentSingleFile(new OnScreenDisplay(), Add);
|
||||
loadComponentSingleFile(onscreenDisplay = new OnScreenDisplay(), Add);
|
||||
|
||||
//overlay elements
|
||||
loadComponentSingleFile(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
|
||||
@ -232,6 +238,7 @@ namespace osu.Game
|
||||
forwardLoggedErrorsToNotifications();
|
||||
|
||||
dependencies.Cache(settings);
|
||||
dependencies.Cache(onscreenDisplay);
|
||||
dependencies.Cache(social);
|
||||
dependencies.Cache(direct);
|
||||
dependencies.Cache(chat);
|
||||
|
@ -44,6 +44,8 @@ namespace osu.Game
|
||||
|
||||
protected KeyBindingStore KeyBindingStore;
|
||||
|
||||
protected SettingsStore SettingsStore;
|
||||
|
||||
protected CursorOverrideContainer CursorOverrideContainer;
|
||||
|
||||
protected override string MainResourceFile => @"osu.Game.Resources.dll";
|
||||
@ -93,7 +95,7 @@ namespace osu.Game
|
||||
|
||||
dependencies.Cache(new LargeTextureStore(new RawTextureLoaderStore(new NamespacedResourceStore<byte[]>(Resources, @"Textures"))));
|
||||
|
||||
dependencies.CacheAs<OsuGameBase>(this);
|
||||
dependencies.CacheAs(this);
|
||||
dependencies.Cache(LocalConfig);
|
||||
|
||||
runMigrations();
|
||||
@ -109,6 +111,7 @@ namespace osu.Game
|
||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory.GetContext, RulesetStore, API, Host));
|
||||
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory.GetContext, Host, BeatmapManager, RulesetStore));
|
||||
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory.GetContext, RulesetStore));
|
||||
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory.GetContext));
|
||||
dependencies.Cache(new OsuColour());
|
||||
|
||||
//this completely overrides the framework default. will need to change once we make a proper FontStore.
|
||||
@ -209,10 +212,10 @@ namespace osu.Game
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
GlobalKeyBindingInputManager globalBinding;
|
||||
GlobalActionContainer globalBinding;
|
||||
|
||||
CursorOverrideContainer = new CursorOverrideContainer { RelativeSizeAxes = Axes.Both };
|
||||
CursorOverrideContainer.Child = globalBinding = new GlobalKeyBindingInputManager(this)
|
||||
CursorOverrideContainer.Child = globalBinding = new GlobalActionContainer(this)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = content = new OsuTooltipContainer(CursorOverrideContainer.Cursor) { RelativeSizeAxes = Axes.Both }
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays.KeyBinding
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_hot;
|
||||
public override string Header => "Global";
|
||||
|
||||
public GlobalKeyBindingsSection(GlobalKeyBindingInputManager manager)
|
||||
public GlobalKeyBindingsSection(GlobalActionContainer manager)
|
||||
{
|
||||
Add(new DefaultBindingsSubsection(manager));
|
||||
Add(new InGameKeyBindingsSubsection(manager));
|
||||
@ -23,7 +23,7 @@ namespace osu.Game.Overlays.KeyBinding
|
||||
{
|
||||
protected override string Header => string.Empty;
|
||||
|
||||
public DefaultBindingsSubsection(GlobalKeyBindingInputManager manager)
|
||||
public DefaultBindingsSubsection(GlobalActionContainer manager)
|
||||
: base(null)
|
||||
{
|
||||
Defaults = manager.GlobalKeyBindings;
|
||||
@ -34,7 +34,7 @@ namespace osu.Game.Overlays.KeyBinding
|
||||
{
|
||||
protected override string Header => "In Game";
|
||||
|
||||
public InGameKeyBindingsSubsection(GlobalKeyBindingInputManager manager) : base(null)
|
||||
public InGameKeyBindingsSubsection(GlobalActionContainer manager) : base(null)
|
||||
{
|
||||
Defaults = manager.InGameKeyBindings;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Overlays
|
||||
protected override Drawable CreateHeader() => new SettingsHeader("key configuration", "Customise your keys!");
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(RulesetStore rulesets, GlobalKeyBindingInputManager global)
|
||||
private void load(RulesetStore rulesets, GlobalActionContainer global)
|
||||
{
|
||||
AddSection(new GlobalKeyBindingsSection(global));
|
||||
|
||||
|
@ -188,17 +188,19 @@ namespace osu.Game.Overlays.Mods
|
||||
start = Mods.Length - 1;
|
||||
|
||||
for (int i = start; i < Mods.Length && i >= 0; i += direction)
|
||||
{
|
||||
if (Mods[i].HasImplementation)
|
||||
{
|
||||
changeSelectedIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (SelectAt(i)) return;
|
||||
|
||||
Deselect();
|
||||
}
|
||||
|
||||
public bool SelectAt(int index)
|
||||
{
|
||||
if (!Mods[index].HasImplementation) return false;
|
||||
|
||||
changeSelectedIndex(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Deselect() => changeSelectedIndex(-1);
|
||||
|
||||
private void displayMod(Mod mod)
|
||||
|
@ -113,6 +113,23 @@ namespace osu.Game.Overlays.Mods
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select one or more mods in this section.
|
||||
/// </summary>
|
||||
/// <param name="mods">The types of <see cref="Mod"/>s which should be deselected.</param>
|
||||
public void SelectTypes(IEnumerable<Mod> mods)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
for (int i = 0; i < button.Mods.Length; i++)
|
||||
{
|
||||
foreach (var mod in mods)
|
||||
if (mod.GetType().IsInstanceOfType(button.Mods[i]))
|
||||
button.SelectAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ModSection()
|
||||
{
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
@ -51,6 +51,8 @@ namespace osu.Game.Overlays.Mods
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(OsuColour colours, OsuGame osu, RulesetStore rulesets)
|
||||
{
|
||||
SelectedMods.ValueChanged += selectedModsChanged;
|
||||
|
||||
LowMultiplierColour = colours.Red;
|
||||
HighMultiplierColour = colours.Green;
|
||||
|
||||
@ -63,6 +65,37 @@ namespace osu.Game.Overlays.Mods
|
||||
Ruleset.TriggerChange();
|
||||
}
|
||||
|
||||
private void selectedModsChanged(IEnumerable<Mod> obj)
|
||||
{
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
section.SelectTypes(obj);
|
||||
|
||||
updateMods();
|
||||
}
|
||||
|
||||
private void updateMods()
|
||||
{
|
||||
double multiplier = 1.0;
|
||||
bool ranked = true;
|
||||
|
||||
foreach (Mod mod in SelectedMods.Value)
|
||||
{
|
||||
multiplier *= mod.ScoreMultiplier;
|
||||
ranked &= mod.Ranked;
|
||||
}
|
||||
|
||||
MultiplierLabel.Text = $"{multiplier:N2}x";
|
||||
if (!ranked)
|
||||
MultiplierLabel.Text += " (Unranked)";
|
||||
|
||||
if (multiplier > 1.0)
|
||||
MultiplierLabel.FadeColour(HighMultiplierColour, 200);
|
||||
else if (multiplier < 1.0)
|
||||
MultiplierLabel.FadeColour(LowMultiplierColour, 200);
|
||||
else
|
||||
MultiplierLabel.FadeColour(Color4.White, 200);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
@ -97,6 +130,7 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
foreach (ModSection section in ModSectionsContainer.Children)
|
||||
section.DeselectAll();
|
||||
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
@ -119,30 +153,7 @@ namespace osu.Game.Overlays.Mods
|
||||
refreshSelectedMods();
|
||||
}
|
||||
|
||||
private void refreshSelectedMods()
|
||||
{
|
||||
SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
|
||||
|
||||
double multiplier = 1.0;
|
||||
bool ranked = true;
|
||||
|
||||
foreach (Mod mod in SelectedMods.Value)
|
||||
{
|
||||
multiplier *= mod.ScoreMultiplier;
|
||||
ranked &= mod.Ranked;
|
||||
}
|
||||
|
||||
MultiplierLabel.Text = $"{multiplier:N2}x";
|
||||
if (!ranked)
|
||||
MultiplierLabel.Text += " (Unranked)";
|
||||
|
||||
if (multiplier > 1.0)
|
||||
MultiplierLabel.FadeColour(HighMultiplierColour, 200);
|
||||
else if (multiplier < 1.0)
|
||||
MultiplierLabel.FadeColour(LowMultiplierColour, 200);
|
||||
else
|
||||
MultiplierLabel.FadeColour(Color4.White, 200);
|
||||
}
|
||||
private void refreshSelectedMods() => SelectedMods.Value = ModSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray();
|
||||
|
||||
public ModSelectOverlay()
|
||||
{
|
||||
|
@ -5,8 +5,6 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
@ -20,10 +18,12 @@ using osu.Framework.Localisation;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays.Music;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Music;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
@ -65,6 +65,12 @@ namespace osu.Game.Overlays
|
||||
AlwaysPresent = true;
|
||||
}
|
||||
|
||||
protected override bool OnDragStart(InputState state)
|
||||
{
|
||||
base.OnDragStart(state);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (base.OnDrag(state)) return true;
|
||||
|
@ -5,7 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Configuration.Tracking;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -118,43 +118,62 @@ namespace osu.Game.Overlays
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(FrameworkConfigManager frameworkConfig)
|
||||
{
|
||||
trackSetting(frameworkConfig.GetBindable<FrameSync>(FrameworkSetting.FrameSync), v => display(v, "Frame Limiter", v.GetDescription(), "Ctrl+F7"));
|
||||
trackSetting(frameworkConfig.GetBindable<string>(FrameworkSetting.AudioDevice), v => display(v, "Audio Device", string.IsNullOrEmpty(v) ? "Default" : v, v));
|
||||
trackSetting(frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay), v => display(v, "Debug Logs", v ? "visible" : "hidden", "Ctrl+F10"));
|
||||
|
||||
void displayResolution() => display(null, "Screen Resolution", frameworkConfig.Get<int>(FrameworkSetting.Width) + "x" + frameworkConfig.Get<int>(FrameworkSetting.Height));
|
||||
|
||||
trackSetting(frameworkConfig.GetBindable<int>(FrameworkSetting.Width), v => displayResolution());
|
||||
trackSetting(frameworkConfig.GetBindable<int>(FrameworkSetting.Height), v => displayResolution());
|
||||
|
||||
trackSetting(frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity), v => display(v, "Cursor Sensitivity", v.ToString(@"0.##x"), "Ctrl+Alt+R to reset"));
|
||||
trackSetting(frameworkConfig.GetBindable<string>(FrameworkSetting.ActiveInputHandlers),
|
||||
delegate (string v)
|
||||
{
|
||||
bool raw = v.Contains("Raw");
|
||||
display(raw, "Raw Input", raw ? "enabled" : "disabled", "Ctrl+Alt+R to reset");
|
||||
});
|
||||
|
||||
trackSetting(frameworkConfig.GetBindable<WindowMode>(FrameworkSetting.WindowMode), v => display(v, "Screen Mode", v.ToString(), "Alt+Enter"));
|
||||
BeginTracking(this, frameworkConfig);
|
||||
}
|
||||
|
||||
private readonly List<IBindable> references = new List<IBindable>();
|
||||
private readonly Dictionary<(object, IConfigManager), TrackedSettings> trackedConfigManagers = new Dictionary<(object, IConfigManager), TrackedSettings>();
|
||||
|
||||
private void trackSetting<T>(Bindable<T> bindable, Action<T> action)
|
||||
/// <summary>
|
||||
/// Registers a <see cref="ConfigManager{T}"/> to have its settings tracked by this <see cref="OnScreenDisplay"/>.
|
||||
/// </summary>
|
||||
/// <param name="source">The object that is registering the <see cref="ConfigManager{T}"/> to be tracked.</param>
|
||||
/// <param name="configManager">The <see cref="ConfigManager{T}"/> to be tracked.</param>
|
||||
/// <exception cref="ArgumentNullException">If <paramref name="configManager"/> is null.</exception>
|
||||
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception>
|
||||
public void BeginTracking(object source, ITrackableConfigManager configManager)
|
||||
{
|
||||
// we need to keep references as we bind
|
||||
references.Add(bindable);
|
||||
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||
|
||||
bindable.ValueChanged += action;
|
||||
if (trackedConfigManagers.ContainsKey((source, configManager)))
|
||||
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
|
||||
|
||||
var trackedSettings = configManager.CreateTrackedSettings();
|
||||
if (trackedSettings == null)
|
||||
return;
|
||||
|
||||
configManager.LoadInto(trackedSettings);
|
||||
trackedSettings.SettingChanged += display;
|
||||
|
||||
trackedConfigManagers.Add((source, configManager), trackedSettings);
|
||||
}
|
||||
|
||||
private void display(object rawValue, string settingName, string settingValue, string shortcut = @"")
|
||||
/// <summary>
|
||||
/// Unregisters a <see cref="ConfigManager{T}"/> from having its settings tracked by this <see cref="OnScreenDisplay"/>.
|
||||
/// </summary>
|
||||
/// <param name="source">The object that registered the <see cref="ConfigManager{T}"/> to be tracked.</param>
|
||||
/// <param name="configManager">The <see cref="ConfigManager{T}"/> that is being tracked.</param>
|
||||
/// <exception cref="ArgumentNullException">If <paramref name="configManager"/> is null.</exception>
|
||||
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <see cref="source"/>.</exception>
|
||||
public void StopTracking(object source, ITrackableConfigManager configManager)
|
||||
{
|
||||
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||
|
||||
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
|
||||
throw new InvalidOperationException($"{nameof(configManager)} is not registered.");
|
||||
|
||||
existing.Unload();
|
||||
existing.SettingChanged -= display;
|
||||
|
||||
trackedConfigManagers.Remove((source, configManager));
|
||||
}
|
||||
|
||||
private void display(SettingDescription description)
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
textLine1.Text = settingName.ToUpper();
|
||||
textLine2.Text = settingValue;
|
||||
textLine3.Text = shortcut.ToUpper();
|
||||
textLine1.Text = description.Name.ToUpper();
|
||||
textLine2.Text = description.Value;
|
||||
textLine3.Text = description.Shortcut.ToUpper();
|
||||
|
||||
box.Animate(
|
||||
b => b.FadeIn(500, Easing.OutQuint),
|
||||
@ -167,16 +186,16 @@ namespace osu.Game.Overlays
|
||||
int optionCount = 0;
|
||||
int selectedOption = -1;
|
||||
|
||||
if (rawValue is bool)
|
||||
if (description.RawValue is bool)
|
||||
{
|
||||
optionCount = 1;
|
||||
if ((bool)rawValue) selectedOption = 0;
|
||||
if ((bool)description.RawValue) selectedOption = 0;
|
||||
}
|
||||
else if (rawValue is Enum)
|
||||
else if (description.RawValue is Enum)
|
||||
{
|
||||
var values = Enum.GetValues(rawValue.GetType());
|
||||
var values = Enum.GetValues(description.RawValue.GetType());
|
||||
optionCount = values.Length;
|
||||
selectedOption = Convert.ToInt32(rawValue);
|
||||
selectedOption = Convert.ToInt32(description.RawValue);
|
||||
}
|
||||
|
||||
textLine2.Origin = optionCount > 0 ? Anchor.BottomCentre : Anchor.Centre;
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(SettingsOverlay settings)
|
||||
private void load(MainSettings settings)
|
||||
{
|
||||
StateContainer = settings;
|
||||
}
|
||||
|
11
osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs
Normal file
11
osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Configuration.Tracking;
|
||||
|
||||
namespace osu.Game.Rulesets.Configuration
|
||||
{
|
||||
public interface IRulesetConfigManager : ITrackableConfigManager
|
||||
{
|
||||
}
|
||||
}
|
15
osu.Game/Rulesets/Configuration/RulesetConfigManager.cs
Normal file
15
osu.Game/Rulesets/Configuration/RulesetConfigManager.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Configuration
|
||||
{
|
||||
public abstract class RulesetConfigManager<T> : DatabasedConfigManager<T>, IRulesetConfigManager
|
||||
where T : struct
|
||||
{
|
||||
protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant) : base(settings, ruleset, variant)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -136,7 +136,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// </summary>
|
||||
public event Action<DrawableHitObject, ArmedState> ApplyCustomUpdateState;
|
||||
|
||||
protected void PlaySamples() => Samples.ForEach(s => s?.Play());
|
||||
/// <summary>
|
||||
/// Plays all the hitsounds for this <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
public void PlaySamples() => Samples.ForEach(s => s?.Play());
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
|
@ -16,6 +16,9 @@ using System.Linq;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using OpenTK;
|
||||
@ -35,6 +38,11 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public bool AspectAdjust = true;
|
||||
|
||||
/// <summary>
|
||||
/// The selected variant.
|
||||
/// </summary>
|
||||
public virtual int Variant => 0;
|
||||
|
||||
/// <summary>
|
||||
/// The input manager for this RulesetContainer.
|
||||
/// </summary>
|
||||
@ -65,6 +73,14 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
protected readonly Ruleset Ruleset;
|
||||
|
||||
private IRulesetConfigManager rulesetConfig;
|
||||
private OnScreenDisplay onScreenDisplay;
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
|
||||
/// <summary>
|
||||
/// A visual representation of a <see cref="Rulesets.Ruleset"/>.
|
||||
/// </summary>
|
||||
@ -77,6 +93,20 @@ namespace osu.Game.Rulesets.UI
|
||||
Cursor = CreateCursor();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OnScreenDisplay onScreenDisplay, SettingsStore settings)
|
||||
{
|
||||
this.onScreenDisplay = onScreenDisplay;
|
||||
|
||||
rulesetConfig = CreateConfig(Ruleset, settings);
|
||||
|
||||
if (rulesetConfig != null)
|
||||
{
|
||||
dependencies.Cache(rulesetConfig);
|
||||
onScreenDisplay?.BeginTracking(this, rulesetConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract ScoreProcessor CreateScoreProcessor();
|
||||
|
||||
/// <summary>
|
||||
@ -110,11 +140,24 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
protected virtual CursorContainer CreateCursor() => null;
|
||||
|
||||
protected virtual IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Playfield.
|
||||
/// </summary>
|
||||
/// <returns>The Playfield.</returns>
|
||||
protected abstract Playfield CreatePlayfield();
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (rulesetConfig != null)
|
||||
{
|
||||
onScreenDisplay?.StopTracking(this, rulesetConfig);
|
||||
rulesetConfig = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.UI
|
||||
public abstract class RulesetInputManager<T> : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler
|
||||
where T : struct
|
||||
{
|
||||
public class RulesetKeyBindingContainer : DatabasedKeyBindingInputManager<T>
|
||||
public class RulesetKeyBindingContainer : DatabasedKeyBindingContainer<T>
|
||||
{
|
||||
public RulesetKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
: base(ruleset, variant, unique)
|
||||
@ -136,9 +136,20 @@ namespace osu.Game.Rulesets.UI
|
||||
int loops = 0;
|
||||
|
||||
while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame)
|
||||
{
|
||||
if (!base.UpdateSubTree())
|
||||
return false;
|
||||
|
||||
if (isAttached)
|
||||
{
|
||||
// When handling replay input, we need to consider the possibility of fast-forwarding, which may cause the clock to be updated
|
||||
// to a point very far into the future, then playing a frame at that time. In such a case, lifetime MUST be updated before
|
||||
// input is handled. This is why base.Update is not called from the derived Update when handling replay input, and is instead
|
||||
// called manually at the correct time here.
|
||||
base.Update();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -173,8 +184,11 @@ namespace osu.Game.Rulesets.UI
|
||||
// to ensure that the its time is valid for our children before input is processed
|
||||
Clock.ProcessFrame();
|
||||
|
||||
// Process input
|
||||
base.Update();
|
||||
if (!isAttached)
|
||||
{
|
||||
// For non-replay input handling, this provides equivalent input ordering as if Update was not overridden
|
||||
base.Update();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -41,6 +41,12 @@ namespace osu.Game.Screens.Play.BreaksOverlay
|
||||
private readonly InfoContainer info;
|
||||
private readonly ArrowsOverlay arrowsOverlay;
|
||||
|
||||
public BreakOverlay(bool letterboxing, ScoreProcessor scoreProcessor)
|
||||
: this(letterboxing)
|
||||
{
|
||||
bindProcessor(scoreProcessor);
|
||||
}
|
||||
|
||||
public BreakOverlay(bool letterboxing)
|
||||
{
|
||||
this.letterboxing = letterboxing;
|
||||
@ -148,7 +154,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay
|
||||
arrowsOverlay.Hide();
|
||||
}
|
||||
|
||||
public void BindProcessor(ScoreProcessor processor)
|
||||
private void bindProcessor(ScoreProcessor processor)
|
||||
{
|
||||
info.AccuracyDisplay.Current.BindTo(processor.Accuracy);
|
||||
info.GradeDisplay.Current.BindTo(processor.Rank);
|
||||
|
@ -6,6 +6,8 @@ using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -39,7 +41,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private static bool hasShownNotificationOnce;
|
||||
|
||||
public HUDOverlay()
|
||||
public HUDOverlay(ScoreProcessor scoreProcessor, RulesetContainer rulesetContainer, DecoupleableInterpolatingFramedClock decoupledClock, WorkingBeatmap working, IAdjustableClock adjustableSourceClock)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
@ -59,6 +61,18 @@ namespace osu.Game.Screens.Play
|
||||
ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
|
||||
}
|
||||
});
|
||||
|
||||
BindProcessor(scoreProcessor);
|
||||
BindRulesetContainer(rulesetContainer);
|
||||
|
||||
Progress.Objects = rulesetContainer.Objects;
|
||||
Progress.AudioClock = decoupledClock;
|
||||
Progress.AllowSeeking = rulesetContainer.HasReplayLoaded;
|
||||
Progress.OnSeek = pos => decoupledClock.Seek(pos);
|
||||
|
||||
ModDisplay.Current.BindTo(working.Mods);
|
||||
|
||||
ReplaySettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
@ -115,7 +129,7 @@ namespace osu.Game.Screens.Play
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void BindRulesetContainer(RulesetContainer rulesetContainer)
|
||||
protected virtual void BindRulesetContainer(RulesetContainer rulesetContainer)
|
||||
{
|
||||
(rulesetContainer.KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(KeyCounter);
|
||||
|
||||
@ -201,7 +215,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay();
|
||||
|
||||
public virtual void BindProcessor(ScoreProcessor processor)
|
||||
protected virtual void BindProcessor(ScoreProcessor processor)
|
||||
{
|
||||
ScoreCounter?.Current.BindTo(processor.TotalScore);
|
||||
AccuracyCounter?.Current.BindTo(processor.Accuracy);
|
||||
|
@ -1,35 +1,35 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Play.BreaksOverlay;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
@ -79,7 +79,6 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
#endregion
|
||||
|
||||
private BreakOverlay breakOverlay;
|
||||
private Container storyboardContainer;
|
||||
private DrawableStoryboard storyboard;
|
||||
|
||||
@ -155,6 +154,8 @@ namespace osu.Game.Screens.Play
|
||||
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
||||
userAudioOffset.TriggerChange();
|
||||
|
||||
scoreProcessor = RulesetContainer.CreateScoreProcessor();
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
storyboardContainer = new Container
|
||||
@ -170,13 +171,12 @@ namespace osu.Game.Screens.Play
|
||||
OnRetry = Restart,
|
||||
OnQuit = Exit,
|
||||
CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded,
|
||||
OnPause = () => {
|
||||
OnPause = () =>
|
||||
{
|
||||
pauseContainer.Retries = RestartCount;
|
||||
hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused;
|
||||
},
|
||||
OnResume = () => {
|
||||
hudOverlay.KeyCounter.IsCounting = true;
|
||||
},
|
||||
OnResume = () => hudOverlay.KeyCounter.IsCounting = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
@ -186,12 +186,12 @@ namespace osu.Game.Screens.Play
|
||||
Child = RulesetContainer,
|
||||
},
|
||||
new SkipButton(firstObjectTime) { AudioClock = decoupledClock },
|
||||
hudOverlay = new HUDOverlay
|
||||
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, decoupledClock, working, adjustableSourceClock)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
},
|
||||
breakOverlay = new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks)
|
||||
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -207,7 +207,10 @@ namespace osu.Game.Screens.Play
|
||||
},
|
||||
new HotkeyRetryOverlay
|
||||
{
|
||||
Action = () => {
|
||||
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();
|
||||
@ -216,24 +219,9 @@ namespace osu.Game.Screens.Play
|
||||
}
|
||||
};
|
||||
|
||||
scoreProcessor = RulesetContainer.CreateScoreProcessor();
|
||||
|
||||
if (showStoryboard)
|
||||
initializeStoryboard(false);
|
||||
|
||||
hudOverlay.BindProcessor(scoreProcessor);
|
||||
hudOverlay.BindRulesetContainer(RulesetContainer);
|
||||
|
||||
hudOverlay.Progress.Objects = RulesetContainer.Objects;
|
||||
hudOverlay.Progress.AudioClock = decoupledClock;
|
||||
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;
|
||||
@ -288,6 +276,8 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
onCompletionEvent = Schedule(delegate
|
||||
{
|
||||
if (!IsCurrentScreen) return;
|
||||
|
||||
var score = new Score
|
||||
{
|
||||
Beatmap = Beatmap.Value.BeatmapInfo,
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
@ -47,10 +48,13 @@ namespace osu.Game.Screens.Select
|
||||
private SampleChannel sampleConfirm;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, DialogOverlay dialogOverlay)
|
||||
private void load(OsuColour colours, AudioManager audio, BeatmapManager beatmaps, DialogOverlay dialogOverlay, OsuGame game)
|
||||
{
|
||||
sampleConfirm = audio.Sample.Get(@"SongSelect/confirm-selection");
|
||||
|
||||
if (game != null)
|
||||
modSelect.SelectedMods.BindTo(game.SelectedMods);
|
||||
|
||||
Footer.AddButton(@"mods", colours.Yellow, modSelect, Key.F1, float.MaxValue);
|
||||
|
||||
BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1);
|
||||
@ -121,6 +125,9 @@ namespace osu.Game.Screens.Select
|
||||
if (Beatmap.Value.Track != null)
|
||||
Beatmap.Value.Track.Looping = false;
|
||||
|
||||
Beatmap.Value.Mods.UnbindBindings();
|
||||
Beatmap.Value.Mods.Value = new Mod[] { };
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ namespace osu.Game.Screens.Select
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours)
|
||||
{
|
||||
dependencies.CacheAs<SongSelect>(this);
|
||||
dependencies.CacheAs(this);
|
||||
|
||||
if (Footer != null)
|
||||
{
|
||||
|
@ -6,7 +6,7 @@ using osu.Framework.Platform;
|
||||
|
||||
namespace osu.Game.Screens.Tournament.Components
|
||||
{
|
||||
public class DrawingsConfigManager : ConfigManager<DrawingsConfig>
|
||||
public class DrawingsConfigManager : IniConfigManager<DrawingsConfig>
|
||||
{
|
||||
protected override string Filename => @"drawings.ini";
|
||||
|
||||
|
@ -91,6 +91,10 @@
|
||||
<Reference Include="Humanizer, Version=2.2.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="JetBrains.Annotations, Version=11.1.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\JetBrains.Annotations.11.1.0\lib\net20\JetBrains.Annotations.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Data.Sqlite, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Microsoft.Data.Sqlite.Core.2.0.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll</HintPath>
|
||||
</Reference>
|
||||
@ -265,10 +269,18 @@
|
||||
<Compile Include="Beatmaps\Formats\JsonBeatmapDecoder.cs" />
|
||||
<Compile Include="Beatmaps\Formats\LegacyDecoder.cs" />
|
||||
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" />
|
||||
<Compile Include="Configuration\DatabasedSetting.cs" />
|
||||
<Compile Include="Configuration\SettingsStore.cs" />
|
||||
<Compile Include="Configuration\DatabasedConfigManager.cs" />
|
||||
<Compile Include="Configuration\SpeedChangeVisualisationMethod.cs" />
|
||||
<Compile Include="Database\DatabaseContextFactory.cs" />
|
||||
<Compile Include="Database\IHasPrimaryKey.cs" />
|
||||
<Compile Include="Graphics\Textures\LargeTextureStore.cs" />
|
||||
<Compile Include="Migrations\20180125143340_Settings.cs" />
|
||||
<Compile Include="Migrations\20180125143340_Settings.Designer.cs">
|
||||
<DependentUpon>20180125143340_Settings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\20180131154205_AddMuteBinding.cs" />
|
||||
<Compile Include="Overlays\Profile\SupporterIcon.cs" />
|
||||
<Compile Include="Online\API\Requests\GetFriendsRequest.cs" />
|
||||
<Compile Include="Overlays\Settings\DangerousSettingsButton.cs" />
|
||||
@ -314,6 +326,8 @@
|
||||
<Compile Include="Overlays\Profile\Sections\Ranks\ScoreModsContainer.cs" />
|
||||
<Compile Include="Overlays\Settings\Sections\Gameplay\ScrollingSettings.cs" />
|
||||
<Compile Include="Overlays\Settings\Sections\Maintenance\DeleteAllBeatmapsDialog.cs" />
|
||||
<Compile Include="Rulesets\Configuration\IRulesetConfigManager.cs" />
|
||||
<Compile Include="Rulesets\Configuration\RulesetConfigManager.cs" />
|
||||
<Compile Include="Rulesets\Mods\IApplicableFailOverride.cs" />
|
||||
<Compile Include="Rulesets\Mods\IApplicableMod.cs" />
|
||||
<Compile Include="Rulesets\Mods\IApplicableToBeatmapConverter.cs" />
|
||||
@ -433,8 +447,8 @@
|
||||
<Compile Include="Graphics\UserInterface\Volume\VolumeControlReceptor.cs" />
|
||||
<Compile Include="Graphics\UserInterface\Volume\VolumeMeter.cs" />
|
||||
<Compile Include="Input\Bindings\DatabasedKeyBinding.cs" />
|
||||
<Compile Include="Input\Bindings\DatabasedKeyBindingInputManager.cs" />
|
||||
<Compile Include="Input\Bindings\GlobalKeyBindingInputManager.cs" />
|
||||
<Compile Include="Input\Bindings\DatabasedKeyBindingContainer.cs" />
|
||||
<Compile Include="Input\Bindings\GlobalActionContainer.cs" />
|
||||
<Compile Include="Input\Handlers\ReplayInputHandler.cs" />
|
||||
<Compile Include="Input\KeyBindingStore.cs" />
|
||||
<Compile Include="IO\FileInfo.cs" />
|
||||
|
@ -47,6 +47,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
||||
<package id="Humanizer.Core.zh-CN" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Humanizer.Core.zh-Hans" version="2.2.0" targetFramework="net461" />
|
||||
<package id="Humanizer.Core.zh-Hant" version="2.2.0" targetFramework="net461" />
|
||||
<package id="JetBrains.Annotations" version="11.1.0" targetFramework="net461" />
|
||||
<package id="Microsoft.CSharp" version="4.4.0" targetFramework="net461" />
|
||||
<package id="Microsoft.Data.Sqlite.Core" version="2.0.0" targetFramework="net461" />
|
||||
<package id="Microsoft.EntityFrameworkCore" version="2.0.0" targetFramework="net461" />
|
||||
|
Loading…
Reference in New Issue
Block a user