mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 10:52:53 +08:00
Merge branch 'master' into mania-step-interval
This commit is contained in:
commit
0e0e64895a
36
COMPILING.md
36
COMPILING.md
@ -1,36 +0,0 @@
|
||||
# Linux
|
||||
### 1. Requirements:
|
||||
Mono >= 5.4.0 (>= 5.8.0 recommended)
|
||||
Please check [here](http://www.mono-project.com/download/) for stable or [here](http://www.mono-project.com/download/alpha/) for an alpha release.
|
||||
NuGet >= 4.4.0
|
||||
msbuild
|
||||
git
|
||||
|
||||
### 2. Cloning project
|
||||
Clone the entire repository with submodules using
|
||||
```
|
||||
git clone https://github.com/ppy/osu --recursive
|
||||
```
|
||||
Then restore NuGet packages from the repository
|
||||
```
|
||||
nuget restore
|
||||
```
|
||||
### 3. Compiling
|
||||
Simply run `msbuild` where `osu.sln` is located, this will create all binaries in `osu/osu.Desktop/bin/Debug`.
|
||||
### 4. Optimizing
|
||||
If you want additional performance you can change build type to Release with
|
||||
```
|
||||
msbuild -p:Configuration=Release
|
||||
```
|
||||
Additionally, mono provides an AOT utility which attempts to precompile binaries. You can utilize that by running
|
||||
```
|
||||
mono --aot ./osu\!.exe
|
||||
```
|
||||
### 5. Troubleshooting
|
||||
You may run into trouble with NuGet versioning, as the one in packaging system is almost always out of date. Simply run
|
||||
```
|
||||
nuget
|
||||
sudo nuget update -self
|
||||
```
|
||||
**Warning** NuGet creates few config files when it's run for the first time.
|
||||
Do not run NuGet as root on the first run or you might run into very peculiar issues.
|
@ -26,10 +26,10 @@
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
|
@ -82,56 +82,25 @@ namespace osu.Game.Rulesets.Catch
|
||||
{
|
||||
new CatchModEasy(),
|
||||
new CatchModNoFail(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new CatchModHalfTime(),
|
||||
new CatchModDaycore(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new CatchModHalfTime(), new CatchModDaycore())
|
||||
};
|
||||
|
||||
case ModType.DifficultyIncrease:
|
||||
return new Mod[]
|
||||
{
|
||||
new CatchModHardRock(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new CatchModSuddenDeath(),
|
||||
new CatchModPerfect(),
|
||||
},
|
||||
},
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new CatchModDoubleTime(),
|
||||
new CatchModNightcore(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new CatchModSuddenDeath(), new CatchModPerfect()),
|
||||
new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()),
|
||||
new CatchModHidden(),
|
||||
new CatchModFlashlight(),
|
||||
};
|
||||
|
||||
case ModType.Special:
|
||||
return new Mod[]
|
||||
{
|
||||
new CatchModRelax(),
|
||||
null,
|
||||
null,
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new CatchModAutoplay(),
|
||||
new ModCinema(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new CatchModAutoplay(), new ModCinema()),
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Configuration
|
||||
{
|
||||
public class ManiaConfigManager : RulesetConfigManager<ManiaSetting>
|
||||
{
|
||||
public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant)
|
||||
public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null)
|
||||
: base(settings, ruleset, variant)
|
||||
{
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
@ -141,5 +142,22 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
|
||||
{
|
||||
new ManiaModDoubleTime(),
|
||||
new ManiaModHalfTime(),
|
||||
new ManiaModEasy(),
|
||||
new ManiaModHardRock(),
|
||||
new ManiaModKey1(),
|
||||
new ManiaModKey2(),
|
||||
new ManiaModKey3(),
|
||||
new ManiaModKey4(),
|
||||
new ManiaModKey5(),
|
||||
new ManiaModKey6(),
|
||||
new ManiaModKey7(),
|
||||
new ManiaModKey8(),
|
||||
new ManiaModKey9(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,11 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Replays.Types;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Difficulty;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
@ -105,78 +108,34 @@ namespace osu.Game.Rulesets.Mania
|
||||
{
|
||||
new ManiaModEasy(),
|
||||
new ManiaModNoFail(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new ManiaModHalfTime(),
|
||||
new ManiaModDaycore(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new ManiaModHalfTime(), new ManiaModDaycore()),
|
||||
};
|
||||
|
||||
case ModType.DifficultyIncrease:
|
||||
return new Mod[]
|
||||
{
|
||||
new ManiaModHardRock(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new ManiaModSuddenDeath(),
|
||||
new ManiaModPerfect(),
|
||||
},
|
||||
},
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new ManiaModDoubleTime(),
|
||||
new ManiaModNightcore(),
|
||||
},
|
||||
},
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new ManiaModFadeIn(),
|
||||
new ManiaModHidden(),
|
||||
}
|
||||
},
|
||||
new MultiMod(new ManiaModSuddenDeath(), new ManiaModPerfect()),
|
||||
new MultiMod(new ManiaModDoubleTime(), new ManiaModNightcore()),
|
||||
new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()),
|
||||
new ManiaModFlashlight(),
|
||||
};
|
||||
|
||||
case ModType.Special:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new ManiaModKey4(),
|
||||
new ManiaModKey5(),
|
||||
new ManiaModKey6(),
|
||||
new ManiaModKey7(),
|
||||
new ManiaModKey8(),
|
||||
new ManiaModKey9(),
|
||||
new ManiaModKey1(),
|
||||
new ManiaModKey2(),
|
||||
new ManiaModKey3(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new ManiaModKey4(),
|
||||
new ManiaModKey5(),
|
||||
new ManiaModKey6(),
|
||||
new ManiaModKey7(),
|
||||
new ManiaModKey8(),
|
||||
new ManiaModKey9(),
|
||||
new ManiaModKey1(),
|
||||
new ManiaModKey2(),
|
||||
new ManiaModKey3()),
|
||||
new ManiaModRandom(),
|
||||
new ManiaModDualStages(),
|
||||
new ManiaModMirror(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new ManiaModAutoplay(),
|
||||
new ModCinema(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new ManiaModAutoplay(), new ModCinema()),
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
}
|
||||
@ -194,6 +153,8 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame();
|
||||
|
||||
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo);
|
||||
|
||||
public ManiaRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
// 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.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -24,5 +26,18 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
mbc.TargetColumns = KeyCount;
|
||||
}
|
||||
|
||||
public override Type[] IncompatibleMods => new[]
|
||||
{
|
||||
typeof(ManiaModKey1),
|
||||
typeof(ManiaModKey2),
|
||||
typeof(ManiaModKey3),
|
||||
typeof(ManiaModKey4),
|
||||
typeof(ManiaModKey5),
|
||||
typeof(ManiaModKey6),
|
||||
typeof(ManiaModKey7),
|
||||
typeof(ManiaModKey8),
|
||||
typeof(ManiaModKey9),
|
||||
}.Except(new[] { GetType() }).ToArray();
|
||||
}
|
||||
}
|
||||
|
@ -277,8 +277,13 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
if (action != Action)
|
||||
return false;
|
||||
|
||||
var hitObject = HitObjects.Objects.LastOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.FirstOrDefault();
|
||||
hitObject?.PlaySamples();
|
||||
var nextObject =
|
||||
HitObjects.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ??
|
||||
// fallback to non-alive objects to find next off-screen object
|
||||
HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ??
|
||||
HitObjects.Objects.LastOrDefault();
|
||||
|
||||
nextObject?.PlaySamples();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -10,12 +10,9 @@ using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Input.Handlers;
|
||||
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;
|
||||
@ -103,7 +100,5 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
||||
|
||||
protected override IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => new ManiaConfigManager(settings, Ruleset.RulesetInfo, Variant);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Skills;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
@ -71,5 +72,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
return starRating;
|
||||
}
|
||||
|
||||
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHalfTime(),
|
||||
new OsuModEasy(),
|
||||
new OsuModHardRock(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -93,57 +93,26 @@ namespace osu.Game.Rulesets.Osu
|
||||
{
|
||||
new OsuModEasy(),
|
||||
new OsuModNoFail(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModHalfTime(),
|
||||
new OsuModDaycore(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new OsuModHalfTime(), new OsuModDaycore()),
|
||||
};
|
||||
|
||||
case ModType.DifficultyIncrease:
|
||||
return new Mod[]
|
||||
{
|
||||
new OsuModHardRock(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModSuddenDeath(),
|
||||
new OsuModPerfect(),
|
||||
},
|
||||
},
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModNightcore(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()),
|
||||
new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
};
|
||||
|
||||
case ModType.Special:
|
||||
return new Mod[]
|
||||
{
|
||||
new OsuModRelax(),
|
||||
new OsuModAutopilot(),
|
||||
new OsuModSpunOut(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModAutoplay(),
|
||||
new ModCinema(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new OsuModAutoplay(), new ModCinema()),
|
||||
new OsuModTarget(),
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
}
|
||||
@ -161,7 +130,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
|
||||
public override string ShortName => "osu";
|
||||
|
||||
public override SettingsSubsection CreateSettings() => new OsuSettings();
|
||||
public override RulesetSettingsSubsection CreateSettings() => new OsuSettings(this);
|
||||
|
||||
public override int? LegacyID => 0;
|
||||
|
||||
|
@ -64,9 +64,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
public override void PostProcess()
|
||||
{
|
||||
connectionLayer.HitObjects = HitObjects.Objects
|
||||
.Select(d => d.HitObject)
|
||||
.OrderBy(h => h.StartTime).OfType<OsuHitObject>();
|
||||
connectionLayer.HitObjects = HitObjects.Objects.Select(d => d.HitObject).OfType<OsuHitObject>();
|
||||
}
|
||||
|
||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||
|
@ -8,10 +8,15 @@ using osu.Game.Overlays.Settings;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
public class OsuSettings : SettingsSubsection
|
||||
public class OsuSettings : RulesetSettingsSubsection
|
||||
{
|
||||
protected override string Header => "osu!";
|
||||
|
||||
public OsuSettings(Ruleset ruleset)
|
||||
: base(ruleset)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||
@ -62,6 +63,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||
return starRating;
|
||||
}
|
||||
|
||||
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
|
||||
{
|
||||
new TaikoModDoubleTime(),
|
||||
new TaikoModHalfTime(),
|
||||
new TaikoModEasy(),
|
||||
new TaikoModHardRock(),
|
||||
};
|
||||
|
||||
private bool calculateStrainValues()
|
||||
{
|
||||
// Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
|
||||
|
@ -84,56 +84,25 @@ namespace osu.Game.Rulesets.Taiko
|
||||
{
|
||||
new TaikoModEasy(),
|
||||
new TaikoModNoFail(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new TaikoModHalfTime(),
|
||||
new TaikoModDaycore(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new TaikoModHalfTime(), new TaikoModDaycore()),
|
||||
};
|
||||
|
||||
case ModType.DifficultyIncrease:
|
||||
return new Mod[]
|
||||
{
|
||||
new TaikoModHardRock(),
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new TaikoModSuddenDeath(),
|
||||
new TaikoModPerfect(),
|
||||
},
|
||||
},
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new TaikoModDoubleTime(),
|
||||
new TaikoModNightcore(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new TaikoModSuddenDeath(), new TaikoModPerfect()),
|
||||
new MultiMod(new TaikoModDoubleTime(), new TaikoModNightcore()),
|
||||
new TaikoModHidden(),
|
||||
new TaikoModFlashlight(),
|
||||
};
|
||||
|
||||
case ModType.Special:
|
||||
return new Mod[]
|
||||
{
|
||||
new TaikoModRelax(),
|
||||
null,
|
||||
null,
|
||||
new MultiMod
|
||||
{
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new TaikoModAutoplay(),
|
||||
new ModCinema(),
|
||||
},
|
||||
},
|
||||
new MultiMod(new TaikoModAutoplay(), new ModCinema()),
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual(string.Empty, metadata.Source);
|
||||
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
|
||||
Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID);
|
||||
Assert.AreEqual(241526, metadata.OnlineBeatmapSetID);
|
||||
Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineBeatmapSetID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
{
|
||||
var beatmap = decodeAsJson(normal);
|
||||
var meta = beatmap.BeatmapInfo.Metadata;
|
||||
Assert.AreEqual(241526, meta.OnlineBeatmapSetID);
|
||||
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
|
||||
Assert.AreEqual("Soleily", meta.Artist);
|
||||
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||
|
@ -48,11 +48,14 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
var reader = new ZipArchiveReader(osz);
|
||||
|
||||
BeatmapMetadata meta;
|
||||
using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
|
||||
meta = Decoder.GetDecoder<Beatmap>(stream).Decode(stream).Metadata;
|
||||
Beatmap beatmap;
|
||||
|
||||
Assert.AreEqual(241526, meta.OnlineBeatmapSetID);
|
||||
using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
|
||||
beatmap = Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
|
||||
|
||||
var meta = beatmap.Metadata;
|
||||
|
||||
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
|
||||
Assert.AreEqual("Soleily", meta.Artist);
|
||||
Assert.AreEqual("Soleily", meta.ArtistUnicode);
|
||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||
|
@ -0,0 +1,152 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class DifficultyAdjustmentModCombinationsTest
|
||||
{
|
||||
[Test]
|
||||
public void TestNoMods()
|
||||
{
|
||||
var combinations = new TestDifficultyCalculator().CreateDifficultyAdjustmentModCombinations();
|
||||
|
||||
Assert.AreEqual(1, combinations.Length);
|
||||
Assert.IsTrue(combinations[0] is NoModMod);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSingleMod()
|
||||
{
|
||||
var combinations = new TestDifficultyCalculator(new ModA()).CreateDifficultyAdjustmentModCombinations();
|
||||
|
||||
Assert.AreEqual(2, combinations.Length);
|
||||
Assert.IsTrue(combinations[0] is NoModMod);
|
||||
Assert.IsTrue(combinations[1] is ModA);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoubleMod()
|
||||
{
|
||||
var combinations = new TestDifficultyCalculator(new ModA(), new ModB()).CreateDifficultyAdjustmentModCombinations();
|
||||
|
||||
Assert.AreEqual(4, combinations.Length);
|
||||
Assert.IsTrue(combinations[0] is NoModMod);
|
||||
Assert.IsTrue(combinations[1] is ModA);
|
||||
Assert.IsTrue(combinations[2] is MultiMod);
|
||||
Assert.IsTrue(combinations[3] is ModB);
|
||||
|
||||
Assert.IsTrue(((MultiMod)combinations[2]).Mods[0] is ModA);
|
||||
Assert.IsTrue(((MultiMod)combinations[2]).Mods[1] is ModB);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIncompatibleMods()
|
||||
{
|
||||
var combinations = new TestDifficultyCalculator(new ModA(), new ModIncompatibleWithA()).CreateDifficultyAdjustmentModCombinations();
|
||||
|
||||
Assert.AreEqual(3, combinations.Length);
|
||||
Assert.IsTrue(combinations[0] is NoModMod);
|
||||
Assert.IsTrue(combinations[1] is ModA);
|
||||
Assert.IsTrue(combinations[2] is ModIncompatibleWithA);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoubleIncompatibleMods()
|
||||
{
|
||||
var combinations = new TestDifficultyCalculator(new ModA(), new ModB(), new ModIncompatibleWithA(), new ModIncompatibleWithAAndB()).CreateDifficultyAdjustmentModCombinations();
|
||||
|
||||
Assert.AreEqual(8, combinations.Length);
|
||||
Assert.IsTrue(combinations[0] is NoModMod);
|
||||
Assert.IsTrue(combinations[1] is ModA);
|
||||
Assert.IsTrue(combinations[2] is MultiMod);
|
||||
Assert.IsTrue(combinations[3] is ModB);
|
||||
Assert.IsTrue(combinations[4] is MultiMod);
|
||||
Assert.IsTrue(combinations[5] is ModIncompatibleWithA);
|
||||
Assert.IsTrue(combinations[6] is MultiMod);
|
||||
Assert.IsTrue(combinations[7] is ModIncompatibleWithAAndB);
|
||||
|
||||
Assert.IsTrue(((MultiMod)combinations[2]).Mods[0] is ModA);
|
||||
Assert.IsTrue(((MultiMod)combinations[2]).Mods[1] is ModB);
|
||||
Assert.IsTrue(((MultiMod)combinations[4]).Mods[0] is ModB);
|
||||
Assert.IsTrue(((MultiMod)combinations[4]).Mods[1] is ModIncompatibleWithA);
|
||||
Assert.IsTrue(((MultiMod)combinations[6]).Mods[0] is ModIncompatibleWithA);
|
||||
Assert.IsTrue(((MultiMod)combinations[6]).Mods[1] is ModIncompatibleWithAAndB);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIncompatibleThroughBaseType()
|
||||
{
|
||||
var combinations = new TestDifficultyCalculator(new ModAofA(), new ModIncompatibleWithAofA()).CreateDifficultyAdjustmentModCombinations();
|
||||
|
||||
Assert.AreEqual(3, combinations.Length);
|
||||
Assert.IsTrue(combinations[0] is NoModMod);
|
||||
Assert.IsTrue(combinations[1] is ModAofA);
|
||||
Assert.IsTrue(combinations[2] is ModIncompatibleWithAofA);
|
||||
}
|
||||
|
||||
private class ModA : Mod
|
||||
{
|
||||
public override string Name => nameof(ModA);
|
||||
public override string ShortenedName => nameof(ModA);
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithA), typeof(ModIncompatibleWithAAndB) };
|
||||
}
|
||||
|
||||
private class ModB : Mod
|
||||
{
|
||||
public override string Name => nameof(ModB);
|
||||
public override string ShortenedName => nameof(ModB);
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithAAndB) };
|
||||
}
|
||||
|
||||
private class ModIncompatibleWithA : Mod
|
||||
{
|
||||
public override string Name => $"Incompatible With {nameof(ModA)}";
|
||||
public override string ShortenedName => $"Incompatible With {nameof(ModA)}";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModA) };
|
||||
}
|
||||
|
||||
private class ModAofA : ModA
|
||||
{
|
||||
}
|
||||
|
||||
private class ModIncompatibleWithAofA : ModIncompatibleWithA
|
||||
{
|
||||
// Incompatible through base type
|
||||
}
|
||||
|
||||
private class ModIncompatibleWithAAndB : Mod
|
||||
{
|
||||
public override string Name => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
|
||||
public override string ShortenedName => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModA), typeof(ModB) };
|
||||
}
|
||||
|
||||
private class TestDifficultyCalculator : DifficultyCalculator
|
||||
{
|
||||
public TestDifficultyCalculator(params Mod[] mods)
|
||||
: base(null)
|
||||
{
|
||||
DifficultyAdjustmentMods = mods;
|
||||
}
|
||||
|
||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => throw new NotImplementedException();
|
||||
|
||||
protected override Mod[] DifficultyAdjustmentMods { get; }
|
||||
}
|
||||
}
|
||||
}
|
@ -449,7 +449,6 @@ namespace osu.Game.Tests.Visual
|
||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
OnlineBeatmapSetID = id,
|
||||
// Create random metadata, then we can check if sorting works based on these
|
||||
Artist = $"peppy{id.ToString().PadLeft(6, '0')}",
|
||||
Title = $"test set #{id}!",
|
||||
@ -503,7 +502,6 @@ namespace osu.Game.Tests.Visual
|
||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
OnlineBeatmapSetID = id,
|
||||
// Create random metadata, then we can check if sorting works based on these
|
||||
Artist = $"peppy{id.ToString().PadLeft(6, '0')}",
|
||||
Title = $"test set #{id}!",
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
@ -15,6 +14,7 @@ using osu.Game.Users;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
@ -22,9 +22,9 @@ namespace osu.Game.Tests.Visual
|
||||
[System.ComponentModel.Description("in BeatmapOverlay")]
|
||||
public class TestCaseBeatmapScoresContainer : OsuTestCase
|
||||
{
|
||||
private readonly IEnumerable<OnlineScore> scores;
|
||||
private readonly IEnumerable<OnlineScore> anotherScores;
|
||||
private readonly OnlineScore topScore;
|
||||
private readonly IEnumerable<APIScore> scores;
|
||||
private readonly IEnumerable<APIScore> anotherScores;
|
||||
private readonly APIScore topScore;
|
||||
private readonly Box background;
|
||||
|
||||
public TestCaseBeatmapScoresContainer()
|
||||
@ -52,12 +52,12 @@ namespace osu.Game.Tests.Visual
|
||||
AddStep("remove scores", () => scoresContainer.Scores = null);
|
||||
AddStep("resize to big", () => container.ResizeWidthTo(1, 300));
|
||||
AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300));
|
||||
AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapSetID = 1, OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo });
|
||||
AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo });
|
||||
|
||||
|
||||
scores = new[]
|
||||
{
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 1234567890,
|
||||
Accuracy = 1,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 1234789,
|
||||
Accuracy = 0.9997,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 12345678,
|
||||
Accuracy = 0.9854,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -143,7 +143,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 1234567,
|
||||
Accuracy = 0.8765,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -169,7 +169,7 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
anotherScores = new[]
|
||||
{
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 1234789,
|
||||
Accuracy = 0.9997,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 1234567890,
|
||||
Accuracy = 1,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -230,7 +230,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 123456,
|
||||
Accuracy = 0.6543,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -251,7 +251,7 @@ namespace osu.Game.Tests.Visual
|
||||
TotalScore = 12345678,
|
||||
Accuracy = 0.9854,
|
||||
},
|
||||
new OnlineScore
|
||||
new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -279,7 +279,7 @@ namespace osu.Game.Tests.Visual
|
||||
s.Statistics.Add(HitResult.Meh, RNG.Next(2000));
|
||||
}
|
||||
|
||||
topScore = new OnlineScore
|
||||
topScore = new APIScore
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Tests.Visual
|
||||
[TestFixture]
|
||||
public class TestCaseEditorComposeTimeline : OsuTestCase
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ScrollableTimeline), typeof(ScrollingTimelineContainer), typeof(BeatmapWaveformGraph), typeof(TimelineButton) };
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) };
|
||||
|
||||
public TestCaseEditorComposeTimeline()
|
||||
{
|
||||
@ -27,11 +27,12 @@ namespace osu.Game.Tests.Visual
|
||||
Origin = Anchor.TopCentre,
|
||||
State = Visibility.Visible
|
||||
},
|
||||
new ScrollableTimeline
|
||||
new TimelineArea
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(1000, 100)
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Size = new Vector2(0.8f, 100)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -122,7 +122,6 @@ namespace osu.Game.Tests.Visual
|
||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
// Create random metadata, then we can check if sorting works based on these
|
||||
Artist = "MONACA " + RNG.Next(0, 9),
|
||||
Title = "Black Song " + RNG.Next(0, 9),
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Overlays.Profile.Sections.Recent;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
@ -49,15 +50,15 @@ namespace osu.Game.Tests.Visual
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<RecentActivity> createDummyActivities()
|
||||
private IEnumerable<APIRecentActivity> createDummyActivities()
|
||||
{
|
||||
var dummyBeatmap = new RecentActivity.RecentActivityBeatmap
|
||||
var dummyBeatmap = new APIRecentActivity.RecentActivityBeatmap
|
||||
{
|
||||
Title = @"Dummy beatmap",
|
||||
Url = "/b/1337",
|
||||
};
|
||||
|
||||
var dummyUser = new RecentActivity.RecentActivityUser
|
||||
var dummyUser = new APIRecentActivity.RecentActivityUser
|
||||
{
|
||||
Username = "DummyReborn",
|
||||
Url = "/u/666",
|
||||
@ -66,61 +67,61 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
return new[]
|
||||
{
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.Achievement,
|
||||
Achievement = new RecentActivity.RecentActivityAchievement
|
||||
Achievement = new APIRecentActivity.RecentActivityAchievement
|
||||
{
|
||||
Name = @"Feelin' It",
|
||||
Slug = @"all-secret-feelinit",
|
||||
},
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapPlaycount,
|
||||
Count = 1337,
|
||||
Beatmap = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetApprove,
|
||||
Approval = BeatmapApproval.Qualified,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetDelete,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetRevive,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetRevive,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetUpdate,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.BeatmapsetUpload,
|
||||
Beatmapset = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.Rank,
|
||||
@ -128,29 +129,29 @@ namespace osu.Game.Tests.Visual
|
||||
Mode = "osu!",
|
||||
Beatmap = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.RankLost,
|
||||
Mode = "osu!",
|
||||
Beatmap = dummyBeatmap,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.UsernameChange,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.UserSupportAgain,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.UserSupportFirst,
|
||||
},
|
||||
new RecentActivity
|
||||
new APIRecentActivity
|
||||
{
|
||||
User = dummyUser,
|
||||
Type = RecentActivityType.UserSupportGift,
|
||||
|
@ -6,11 +6,11 @@ using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Screens.Edit.Screens.Compose.Timeline;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
@ -40,14 +40,13 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
for (int i = 1; i <= 16; i *= 2)
|
||||
{
|
||||
var newDisplay = new BeatmapWaveformGraph
|
||||
var newDisplay = new WaveformGraph
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Resolution = 1f / i,
|
||||
Beatmap = Beatmap
|
||||
};
|
||||
|
||||
Beatmap.ValueChanged += b => newDisplay.Beatmap = b;
|
||||
Beatmap.ValueChanged += b => newDisplay.Waveform = b.Waveform;
|
||||
|
||||
flow.Add(new Container
|
||||
{
|
||||
|
142
osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs
Normal file
142
osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs
Normal file
@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Screens.Edit.Screens.Compose.Timeline;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
public class TestCaseZoomableScrollContainer : ManualInputManagerTestCase
|
||||
{
|
||||
private readonly ZoomableScrollContainer scrollContainer;
|
||||
private readonly Drawable innerBox;
|
||||
|
||||
public TestCaseZoomableScrollContainer()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 250,
|
||||
Width = 0.75f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(30)
|
||||
},
|
||||
scrollContainer = new ZoomableScrollContainer { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
},
|
||||
new MenuCursor()
|
||||
};
|
||||
|
||||
scrollContainer.Add(innerBox = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientHorizontal(new Color4(0.8f, 0.6f, 0.4f, 1f), new Color4(0.4f, 0.6f, 0.8f, 1f))
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestZoom0()
|
||||
{
|
||||
reset();
|
||||
AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft));
|
||||
AddAssert("Box width = 1x", () => Precision.AlmostEquals(boxQuad.Size, scrollQuad.Size));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestZoom10()
|
||||
{
|
||||
reset();
|
||||
AddStep("Set zoom = 10", () => scrollContainer.Zoom = 10);
|
||||
AddAssert("Box at 1/2", () => Precision.AlmostEquals(boxQuad.Centre, scrollQuad.Centre));
|
||||
AddAssert("Box width = 10x", () => Precision.AlmostEquals(boxQuad.Size.X, 10 * scrollQuad.Size.X));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMouseZoomInOnceOutOnce()
|
||||
{
|
||||
reset();
|
||||
|
||||
// Scroll in at 0.25
|
||||
AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y)));
|
||||
AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl));
|
||||
AddStep("Scroll by 3", () => InputManager.ScrollBy(new Vector2(3, 0)));
|
||||
AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl));
|
||||
AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft));
|
||||
AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X));
|
||||
|
||||
// Scroll out at 0.25
|
||||
AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl));
|
||||
AddStep("Scroll by -3", () => InputManager.ScrollBy(new Vector2(-3, 0)));
|
||||
AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl));
|
||||
AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft));
|
||||
AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMouseZoomInTwiceOutTwice()
|
||||
{
|
||||
reset();
|
||||
|
||||
// Scroll in at 0.25
|
||||
AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y)));
|
||||
AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl));
|
||||
AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(1, 0)));
|
||||
AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl));
|
||||
|
||||
// Scroll in at 0.6
|
||||
AddStep("Move mouse to 0.75x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.75f * scrollQuad.Size.X, scrollQuad.Centre.Y)));
|
||||
AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl));
|
||||
AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(1, 0)));
|
||||
AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl));
|
||||
AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft));
|
||||
|
||||
// Very hard to determine actual position, so approximate
|
||||
AddAssert("Box at correct position (1)", () => Precision.DefinitelyBigger(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X));
|
||||
AddAssert("Box at correct position (2)", () => Precision.DefinitelyBigger(scrollQuad.TopLeft.X + 0.6f * scrollQuad.Size.X, boxQuad.TopLeft.X + 0.3f * boxQuad.Size.X));
|
||||
AddAssert("Box at correct position (3)", () => Precision.DefinitelyBigger(boxQuad.TopLeft.X + 0.6f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.6f * scrollQuad.Size.X));
|
||||
|
||||
// Scroll out at 0.6
|
||||
AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl));
|
||||
AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(-1, 0)));
|
||||
AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl));
|
||||
|
||||
// Scroll out at 0.25
|
||||
AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y)));
|
||||
AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl));
|
||||
AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(-1, 0)));
|
||||
AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl));
|
||||
AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft));
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
AddStep("Reset", () =>
|
||||
{
|
||||
scrollContainer.Zoom = 0;
|
||||
scrollContainer.ScrollTo(0, false);
|
||||
});
|
||||
}
|
||||
|
||||
private Quad scrollQuad => scrollContainer.ScreenSpaceDrawQuad;
|
||||
private Quad boxQuad => innerBox.ScreenSpaceDrawQuad;
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@ namespace osu.Game.Beatmaps
|
||||
public int BeatmapVersion;
|
||||
|
||||
private int? onlineBeatmapID;
|
||||
private int? onlineBeatmapSetID;
|
||||
|
||||
[JsonProperty("id")]
|
||||
public int? OnlineBeatmapID
|
||||
@ -32,19 +31,10 @@ namespace osu.Game.Beatmaps
|
||||
set { onlineBeatmapID = value > 0 ? value : null; }
|
||||
}
|
||||
|
||||
[JsonProperty("beatmapset_id")]
|
||||
[NotMapped]
|
||||
public int? OnlineBeatmapSetID
|
||||
{
|
||||
get { return onlineBeatmapSetID; }
|
||||
set { onlineBeatmapSetID = value > 0 ? value : null; }
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public int BeatmapSetInfoID { get; set; }
|
||||
|
||||
[Required]
|
||||
[JsonIgnore]
|
||||
public BeatmapSetInfo BeatmapSet { get; set; }
|
||||
|
||||
public BeatmapMetadata Metadata { get; set; }
|
||||
@ -141,8 +131,8 @@ namespace osu.Game.Beatmaps
|
||||
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
|
||||
|
||||
public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
||||
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
|
||||
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a shallow-clone of this <see cref="BeatmapInfo"/>.
|
||||
|
@ -81,12 +81,31 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
protected override void Populate(BeatmapSetInfo model, ArchiveReader archive)
|
||||
{
|
||||
model.Beatmaps = createBeatmapDifficulties(model, archive);
|
||||
model.Beatmaps = createBeatmapDifficulties(archive);
|
||||
|
||||
// remove metadata from difficulties where it matches the set
|
||||
foreach (BeatmapInfo b in model.Beatmaps)
|
||||
{
|
||||
// remove metadata from difficulties where it matches the set
|
||||
if (model.Metadata.Equals(b.Metadata))
|
||||
b.Metadata = null;
|
||||
|
||||
// by setting the model here, we can update the noline set id below.
|
||||
b.BeatmapSet = model;
|
||||
|
||||
fetchAndPopulateOnlineIDs(b);
|
||||
}
|
||||
|
||||
// check if a set already exists with the same online id, delete if it does.
|
||||
if (model.OnlineBeatmapSetID != null)
|
||||
{
|
||||
var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID);
|
||||
if (existingOnlineId != null)
|
||||
{
|
||||
Delete(existingOnlineId);
|
||||
beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID);
|
||||
Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model)
|
||||
@ -99,18 +118,6 @@ namespace osu.Game.Beatmaps
|
||||
return existingHashMatch;
|
||||
}
|
||||
|
||||
// check if a set already exists with the same online id
|
||||
if (model.OnlineBeatmapSetID != null)
|
||||
{
|
||||
var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID);
|
||||
if (existingOnlineId != null)
|
||||
{
|
||||
Delete(existingOnlineId);
|
||||
beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID);
|
||||
Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -306,29 +313,29 @@ namespace osu.Game.Beatmaps
|
||||
return hashable.ComputeSHA2Hash();
|
||||
}
|
||||
|
||||
protected override BeatmapSetInfo CreateModel(ArchiveReader reader)
|
||||
protected override BeatmapSetInfo CreateModel(ArchiveReader reader)
|
||||
{
|
||||
// let's make sure there are actually .osu files to import.
|
||||
string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu"));
|
||||
if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in this beatmap archive.");
|
||||
|
||||
BeatmapMetadata metadata;
|
||||
Beatmap beatmap;
|
||||
using (var stream = new StreamReader(reader.GetStream(mapName)))
|
||||
metadata = Decoder.GetDecoder<Beatmap>(stream).Decode(stream).Metadata;
|
||||
beatmap = Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
|
||||
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
|
||||
OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID,
|
||||
Beatmaps = new List<BeatmapInfo>(),
|
||||
Hash = computeBeatmapSetHash(reader),
|
||||
Metadata = metadata
|
||||
Metadata = beatmap.Metadata
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create all required <see cref="BeatmapInfo"/>s for the provided archive.
|
||||
/// </summary>
|
||||
private List<BeatmapInfo> createBeatmapDifficulties(BeatmapSetInfo model, ArchiveReader reader)
|
||||
private List<BeatmapInfo> createBeatmapDifficulties(ArchiveReader reader)
|
||||
{
|
||||
var beatmapInfos = new List<BeatmapInfo>();
|
||||
|
||||
@ -348,10 +355,6 @@ namespace osu.Game.Beatmaps
|
||||
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
||||
beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash();
|
||||
|
||||
// ensure we have the same online set ID as the set itself.
|
||||
beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID;
|
||||
beatmap.BeatmapInfo.Metadata.OnlineBeatmapSetID = model.OnlineBeatmapSetID;
|
||||
|
||||
// check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence.
|
||||
if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null)
|
||||
beatmap.BeatmapInfo.OnlineBeatmapID = null;
|
||||
@ -376,6 +379,40 @@ namespace osu.Game.Beatmaps
|
||||
return beatmapInfos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap to populate.</param>
|
||||
/// <param name="force">Whether to re-query if the provided beatmap already has populated values.</param>
|
||||
/// <returns>True if population was successful.</returns>
|
||||
private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, bool force = false)
|
||||
{
|
||||
if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null)
|
||||
return true;
|
||||
|
||||
Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database);
|
||||
|
||||
try
|
||||
{
|
||||
var req = new GetBeatmapRequest(beatmap);
|
||||
|
||||
req.Perform(api);
|
||||
|
||||
var res = req.Result;
|
||||
|
||||
Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database);
|
||||
|
||||
beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID;
|
||||
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log($"Failed ({e})", LoggingTarget.Database);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation.
|
||||
/// </summary>
|
||||
|
@ -17,16 +17,6 @@ namespace osu.Game.Beatmaps
|
||||
[JsonIgnore]
|
||||
public int ID { get; set; }
|
||||
|
||||
private int? onlineBeatmapSetID;
|
||||
|
||||
[NotMapped]
|
||||
[JsonProperty(@"id")]
|
||||
public int? OnlineBeatmapSetID
|
||||
{
|
||||
get { return onlineBeatmapSetID; }
|
||||
set { onlineBeatmapSetID = value > 0 ? value : null; }
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string TitleUnicode { get; set; }
|
||||
public string Artist { get; set; }
|
||||
@ -82,8 +72,7 @@ namespace osu.Game.Beatmaps
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return onlineBeatmapSetID == other.onlineBeatmapSetID
|
||||
&& Title == other.Title
|
||||
return Title == other.Title
|
||||
&& TitleUnicode == other.TitleUnicode
|
||||
&& Artist == other.Artist
|
||||
&& ArtistUnicode == other.ArtistUnicode
|
||||
|
@ -22,18 +22,18 @@ namespace osu.Game.Beatmaps
|
||||
[NotMapped]
|
||||
public BeatmapSetOnlineInfo OnlineInfo { get; set; }
|
||||
|
||||
public double MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty);
|
||||
public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0;
|
||||
|
||||
[NotMapped]
|
||||
public bool DeletePending { get; set; }
|
||||
|
||||
public string Hash { get; set; }
|
||||
|
||||
public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename;
|
||||
public string StoryboardFile => Files?.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename;
|
||||
|
||||
public List<BeatmapSetFileInfo> Files { get; set; }
|
||||
|
||||
public override string ToString() => Metadata.ToString();
|
||||
public override string ToString() => Metadata?.ToString() ?? base.ToString();
|
||||
|
||||
public bool Protected { get; set; }
|
||||
}
|
||||
|
84
osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs
Normal file
84
osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs
Normal file
@ -0,0 +1,84 @@
|
||||
// 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.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
/// A component to allow downloading of a beatmap set. Automatically handles state syncing between other instances.
|
||||
/// </summary>
|
||||
public class BeatmapSetDownloader : Component
|
||||
{
|
||||
private readonly BeatmapSetInfo set;
|
||||
private readonly bool noVideo;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the associated beatmap set has been downloading (by this instance or any other instance).
|
||||
/// </summary>
|
||||
public readonly BindableBool Downloaded = new BindableBool();
|
||||
|
||||
public BeatmapSetDownloader(BeatmapSetInfo set, bool noVideo = false)
|
||||
{
|
||||
this.set = set;
|
||||
this.noVideo = noVideo;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapManager beatmaps)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
|
||||
beatmaps.ItemAdded += setAdded;
|
||||
beatmaps.ItemRemoved += setRemoved;
|
||||
|
||||
// initial value
|
||||
if (set.OnlineBeatmapSetID != null)
|
||||
Downloaded.Value = beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (beatmaps != null)
|
||||
{
|
||||
beatmaps.ItemAdded -= setAdded;
|
||||
beatmaps.ItemRemoved -= setRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begin downloading the associated beatmap set.
|
||||
/// </summary>
|
||||
/// <returns>True if downloading began. False if an existing download is active or completed.</returns>
|
||||
public bool Download()
|
||||
{
|
||||
if (Downloaded.Value)
|
||||
return false;
|
||||
|
||||
if (beatmaps.GetExistingDownload(set) != null)
|
||||
return false;
|
||||
|
||||
beatmaps.Download(set, noVideo);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo s)
|
||||
{
|
||||
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
Downloaded.Value = true;
|
||||
}
|
||||
|
||||
private void setRemoved(BeatmapSetInfo s)
|
||||
{
|
||||
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
Downloaded.Value = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -34,7 +34,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private readonly int offset;
|
||||
|
||||
public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version)
|
||||
public LegacyBeatmapDecoder(int version = LATEST_VERSION)
|
||||
: base(version)
|
||||
{
|
||||
// BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off)
|
||||
offset = FormatVersion < 5 ? 24 : 0;
|
||||
@ -135,6 +136,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser();
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case @"LetterboxInBreaks":
|
||||
beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1;
|
||||
@ -207,8 +209,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value);
|
||||
break;
|
||||
case @"BeatmapSetID":
|
||||
beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value);
|
||||
metadata.OnlineBeatmapSetID = int.Parse(pair.Value);
|
||||
beatmap.BeatmapInfo.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = int.Parse(pair.Value) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ namespace osu.Game.Configuration
|
||||
{
|
||||
private readonly SettingsStore settings;
|
||||
|
||||
private readonly int variant;
|
||||
private readonly int? variant;
|
||||
|
||||
private readonly List<DatabasedSetting> databasedSettings;
|
||||
|
||||
private readonly RulesetInfo ruleset;
|
||||
|
||||
protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int variant = 0)
|
||||
protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int? variant = null)
|
||||
{
|
||||
this.settings = settings;
|
||||
this.ruleset = ruleset;
|
||||
|
@ -5,6 +5,7 @@ using osu.Framework.Configuration;
|
||||
using osu.Framework.Configuration.Tracking;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
@ -80,6 +81,8 @@ namespace osu.Game.Configuration
|
||||
|
||||
Set(OsuSetting.FloatingComments, false);
|
||||
|
||||
Set(OsuSetting.ScoreDisplayMode, ScoringMode.Standardised);
|
||||
|
||||
Set(OsuSetting.SpeedChangeVisualisation, SpeedChangeVisualisationMethod.Sequential);
|
||||
|
||||
Set(OsuSetting.IncreaseFirstObjectVisibility, true);
|
||||
@ -147,6 +150,7 @@ namespace osu.Game.Configuration
|
||||
SongSelectRightMouseScroll,
|
||||
BeatmapSkins,
|
||||
BeatmapHitsounds,
|
||||
IncreaseFirstObjectVisibility
|
||||
IncreaseFirstObjectVisibility,
|
||||
ScoreDisplayMode
|
||||
}
|
||||
}
|
||||
|
@ -14,16 +14,19 @@ namespace osu.Game.Online.API
|
||||
{
|
||||
protected override WebRequest CreateWebRequest() => new JsonWebRequest<T>(Uri);
|
||||
|
||||
public T Result => ((JsonWebRequest<T>)WebRequest).ResponseObject;
|
||||
|
||||
protected APIRequest()
|
||||
{
|
||||
base.Success += onSuccess;
|
||||
}
|
||||
|
||||
private void onSuccess()
|
||||
{
|
||||
Success?.Invoke(((JsonWebRequest<T>)WebRequest).ResponseObject);
|
||||
}
|
||||
private void onSuccess() => Success?.Invoke(Result);
|
||||
|
||||
/// <summary>
|
||||
/// Invoked on successful completion of an API request.
|
||||
/// This will be scheduled to the API's internal scheduler (run on update thread automatically).
|
||||
/// </summary>
|
||||
public new event APISuccessHandler<T> Success;
|
||||
}
|
||||
|
||||
@ -52,7 +55,16 @@ namespace osu.Game.Online.API
|
||||
protected APIAccess API;
|
||||
protected WebRequest WebRequest;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked on successful completion of an API request.
|
||||
/// This will be scheduled to the API's internal scheduler (run on update thread automatically).
|
||||
/// </summary>
|
||||
public event APISuccessHandler Success;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked on failure to complete an API request.
|
||||
/// This will be scheduled to the API's internal scheduler (run on update thread automatically).
|
||||
/// </summary>
|
||||
public event APIFailureHandler Failure;
|
||||
|
||||
private bool cancelled;
|
||||
|
@ -1,149 +0,0 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class APIResponseBeatmapSet : BeatmapMetadata // todo: this is a bit wrong...
|
||||
{
|
||||
[JsonProperty(@"covers")]
|
||||
private BeatmapSetOnlineCovers covers { get; set; }
|
||||
|
||||
[JsonProperty(@"preview_url")]
|
||||
private string preview { get; set; }
|
||||
|
||||
[JsonProperty(@"play_count")]
|
||||
private int playCount { get; set; }
|
||||
|
||||
[JsonProperty(@"favourite_count")]
|
||||
private int favouriteCount { get; set; }
|
||||
|
||||
[JsonProperty(@"bpm")]
|
||||
private double bpm { get; set; }
|
||||
|
||||
[JsonProperty(@"video")]
|
||||
private bool hasVideo { get; set; }
|
||||
|
||||
[JsonProperty(@"storyboard")]
|
||||
private bool hasStoryboard { get; set; }
|
||||
|
||||
[JsonProperty(@"status")]
|
||||
private BeatmapSetOnlineStatus status { get; set; }
|
||||
|
||||
[JsonProperty(@"submitted_date")]
|
||||
private DateTimeOffset submitted { get; set; }
|
||||
|
||||
[JsonProperty(@"ranked_date")]
|
||||
private DateTimeOffset ranked { get; set; }
|
||||
|
||||
[JsonProperty(@"last_updated")]
|
||||
private DateTimeOffset lastUpdated { get; set; }
|
||||
|
||||
[JsonProperty(@"user_id")]
|
||||
private long creatorId {
|
||||
set { Author.Id = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"beatmaps")]
|
||||
private IEnumerable<APIResponseBeatmap> beatmaps { get; set; }
|
||||
|
||||
public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = OnlineBeatmapSetID,
|
||||
Metadata = this,
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Covers = covers,
|
||||
Preview = preview,
|
||||
PlayCount = playCount,
|
||||
FavouriteCount = favouriteCount,
|
||||
BPM = bpm,
|
||||
Status = status,
|
||||
HasVideo = hasVideo,
|
||||
HasStoryboard = hasStoryboard,
|
||||
Submitted = submitted,
|
||||
Ranked = ranked,
|
||||
LastUpdated = lastUpdated,
|
||||
},
|
||||
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
|
||||
};
|
||||
}
|
||||
|
||||
private class APIResponseBeatmap : BeatmapMetadata
|
||||
{
|
||||
[JsonProperty(@"id")]
|
||||
private int onlineBeatmapID { get; set; }
|
||||
|
||||
[JsonProperty(@"playcount")]
|
||||
private int playCount { get; set; }
|
||||
|
||||
[JsonProperty(@"passcount")]
|
||||
private int passCount { get; set; }
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
private int ruleset { get; set; }
|
||||
|
||||
[JsonProperty(@"difficulty_rating")]
|
||||
private double starDifficulty { get; set; }
|
||||
|
||||
[JsonProperty(@"drain")]
|
||||
private float drainRate { get; set; }
|
||||
|
||||
[JsonProperty(@"cs")]
|
||||
private float circleSize { get; set; }
|
||||
|
||||
[JsonProperty(@"ar")]
|
||||
private float approachRate { get; set; }
|
||||
|
||||
[JsonProperty(@"accuracy")]
|
||||
private float overallDifficulty { get; set; }
|
||||
|
||||
[JsonProperty(@"total_length")]
|
||||
private double length { get; set; }
|
||||
|
||||
[JsonProperty(@"count_circles")]
|
||||
private int circleCount { get; set; }
|
||||
|
||||
[JsonProperty(@"count_sliders")]
|
||||
private int sliderCount { get; set; }
|
||||
|
||||
[JsonProperty(@"version")]
|
||||
private string version { get; set; }
|
||||
|
||||
public BeatmapInfo ToBeatmap(RulesetStore rulesets)
|
||||
{
|
||||
return new BeatmapInfo
|
||||
{
|
||||
Metadata = this,
|
||||
Ruleset = rulesets.GetRuleset(ruleset),
|
||||
StarDifficulty = starDifficulty,
|
||||
OnlineBeatmapID = onlineBeatmapID,
|
||||
Version = version,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
DrainRate = drainRate,
|
||||
CircleSize = circleSize,
|
||||
ApproachRate = approachRate,
|
||||
OverallDifficulty = overallDifficulty,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
PlayCount = playCount,
|
||||
PassCount = passCount,
|
||||
Length = length,
|
||||
CircleCount = circleCount,
|
||||
SliderCount = sliderCount,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +1,20 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetBeatmapDetailsRequest : APIRequest<GetBeatmapDetailsResponse>
|
||||
public class GetBeatmapDetailsRequest : APIRequest<APIBeatmapMetrics>
|
||||
{
|
||||
private readonly BeatmapInfo beatmap;
|
||||
|
||||
private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}";
|
||||
|
||||
public GetBeatmapDetailsRequest(BeatmapInfo beatmap)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmaps/{lookupString}";
|
||||
}
|
||||
|
||||
public class GetBeatmapDetailsResponse : BeatmapMetrics
|
||||
{
|
||||
//the online API returns some metrics as a nested object.
|
||||
[JsonProperty(@"failtimes")]
|
||||
private BeatmapMetrics failTimes
|
||||
{
|
||||
set
|
||||
{
|
||||
Fails = value.Fails;
|
||||
Retries = value.Retries;
|
||||
}
|
||||
}
|
||||
|
||||
//and other metrics in the beatmap set.
|
||||
[JsonProperty(@"beatmapset")]
|
||||
private BeatmapMetrics beatmapSet
|
||||
{
|
||||
set
|
||||
{
|
||||
Ratings = value.Ratings;
|
||||
}
|
||||
}
|
||||
protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}";
|
||||
}
|
||||
}
|
||||
|
22
osu.Game/Online/API/Requests/GetBeatmapRequest.cs
Normal file
22
osu.Game/Online/API/Requests/GetBeatmapRequest.cs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetBeatmapRequest : APIRequest<APIBeatmap>
|
||||
{
|
||||
private readonly BeatmapInfo beatmap;
|
||||
|
||||
private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.MD5Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}";
|
||||
|
||||
public GetBeatmapRequest(BeatmapInfo beatmap)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmaps/{lookupString}";
|
||||
}
|
||||
}
|
@ -1,9 +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.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetBeatmapSetRequest : APIRequest<APIResponseBeatmapSet>
|
||||
public class GetBeatmapSetRequest : APIRequest<APIBeatmapSet>
|
||||
{
|
||||
private readonly int id;
|
||||
private readonly BeatmapSetLookupType type;
|
||||
|
@ -2,20 +2,15 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetScoresRequest : APIRequest<GetScoresResponse>
|
||||
public class GetScoresRequest : APIRequest<APIScores>
|
||||
{
|
||||
private readonly BeatmapInfo beatmap;
|
||||
private readonly LeaderboardScope scope;
|
||||
@ -36,9 +31,9 @@ namespace osu.Game.Online.API.Requests
|
||||
Success += onSuccess;
|
||||
}
|
||||
|
||||
private void onSuccess(GetScoresResponse r)
|
||||
private void onSuccess(APIScores r)
|
||||
{
|
||||
foreach (OnlineScore score in r.Scores)
|
||||
foreach (APIScore score in r.Scores)
|
||||
score.ApplyBeatmap(beatmap);
|
||||
}
|
||||
|
||||
@ -55,112 +50,4 @@ namespace osu.Game.Online.API.Requests
|
||||
|
||||
protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores";
|
||||
}
|
||||
|
||||
public class GetScoresResponse
|
||||
{
|
||||
[JsonProperty(@"scores")]
|
||||
public IEnumerable<OnlineScore> Scores;
|
||||
}
|
||||
|
||||
public class OnlineScore : Score
|
||||
{
|
||||
[JsonProperty(@"score")]
|
||||
private double totalScore
|
||||
{
|
||||
set { TotalScore = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"max_combo")]
|
||||
private int maxCombo
|
||||
{
|
||||
set { MaxCombo = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
private User user
|
||||
{
|
||||
set { User = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"replay_data")]
|
||||
private Replay replay
|
||||
{
|
||||
set { Replay = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
public int OnlineRulesetID { get; set; }
|
||||
|
||||
[JsonProperty(@"score_id")]
|
||||
private long onlineScoreID
|
||||
{
|
||||
set { OnlineScoreID = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
private DateTimeOffset date
|
||||
{
|
||||
set { Date = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"beatmap")]
|
||||
private BeatmapInfo beatmap
|
||||
{
|
||||
set { Beatmap = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"beatmapset")]
|
||||
private BeatmapMetadata metadata
|
||||
{
|
||||
set { Beatmap.Metadata = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"statistics")]
|
||||
private Dictionary<string, object> jsonStats
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var kvp in value)
|
||||
{
|
||||
HitResult newKey;
|
||||
switch (kvp.Key)
|
||||
{
|
||||
case @"count_300":
|
||||
newKey = HitResult.Great;
|
||||
break;
|
||||
case @"count_100":
|
||||
newKey = HitResult.Good;
|
||||
break;
|
||||
case @"count_50":
|
||||
newKey = HitResult.Meh;
|
||||
break;
|
||||
case @"count_miss":
|
||||
newKey = HitResult.Miss;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
Statistics.Add(newKey, kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
private string[] modStrings { get; set; }
|
||||
|
||||
public void ApplyBeatmap(BeatmapInfo beatmap)
|
||||
{
|
||||
Beatmap = beatmap;
|
||||
ApplyRuleset(beatmap.Ruleset);
|
||||
}
|
||||
|
||||
public void ApplyRuleset(RulesetInfo ruleset)
|
||||
{
|
||||
Ruleset = ruleset;
|
||||
|
||||
// Evaluate the mod string
|
||||
Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,11 @@
|
||||
|
||||
using Humanizer;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserBeatmapsRequest : APIRequest<List<APIResponseBeatmapSet>>
|
||||
public class GetUserBeatmapsRequest : APIRequest<List<APIBeatmapSet>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly int offset;
|
||||
|
@ -1,14 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserMostPlayedBeatmapsRequest : APIRequest<List<MostPlayedBeatmap>>
|
||||
public class GetUserMostPlayedBeatmapsRequest : APIRequest<List<APIUserMostPlayedBeatmap>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly int offset;
|
||||
@ -21,28 +19,4 @@ namespace osu.Game.Online.API.Requests
|
||||
|
||||
protected override string Target => $@"users/{userId}/beatmapsets/most_played?offset={offset}";
|
||||
}
|
||||
|
||||
public class MostPlayedBeatmap
|
||||
{
|
||||
[JsonProperty("beatmap_id")]
|
||||
public int BeatmapID;
|
||||
|
||||
[JsonProperty("count")]
|
||||
public int PlayCount;
|
||||
|
||||
[JsonProperty]
|
||||
private BeatmapInfo beatmap;
|
||||
|
||||
[JsonProperty]
|
||||
private APIResponseBeatmapSet beatmapSet;
|
||||
|
||||
public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets)
|
||||
{
|
||||
BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets);
|
||||
beatmap.BeatmapSet = setInfo;
|
||||
beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID;
|
||||
beatmap.Metadata = setInfo.Metadata;
|
||||
return beatmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using Humanizer;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserRecentActivitiesRequest : APIRequest<List<RecentActivity>>
|
||||
public class GetUserRecentActivitiesRequest : APIRequest<List<APIRecentActivity>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly int offset;
|
||||
@ -23,86 +20,6 @@ namespace osu.Game.Online.API.Requests
|
||||
protected override string Target => $"users/{userId}/recent_activity?offset={offset}";
|
||||
}
|
||||
|
||||
public class RecentActivity
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int ID;
|
||||
|
||||
[JsonProperty("createdAt")]
|
||||
public DateTimeOffset CreatedAt;
|
||||
|
||||
[JsonProperty]
|
||||
private string type
|
||||
{
|
||||
set => Type = (RecentActivityType)Enum.Parse(typeof(RecentActivityType), value.Pascalize());
|
||||
}
|
||||
|
||||
public RecentActivityType Type;
|
||||
|
||||
[JsonProperty]
|
||||
private string scoreRank
|
||||
{
|
||||
set => ScoreRank = (ScoreRank)Enum.Parse(typeof(ScoreRank), value);
|
||||
}
|
||||
|
||||
public ScoreRank ScoreRank;
|
||||
|
||||
[JsonProperty("rank")]
|
||||
public int Rank;
|
||||
|
||||
[JsonProperty("approval")]
|
||||
public BeatmapApproval Approval;
|
||||
|
||||
[JsonProperty("count")]
|
||||
public int Count;
|
||||
|
||||
[JsonProperty("mode")]
|
||||
public string Mode;
|
||||
|
||||
[JsonProperty("beatmap")]
|
||||
public RecentActivityBeatmap Beatmap;
|
||||
|
||||
[JsonProperty("beatmapset")]
|
||||
public RecentActivityBeatmap Beatmapset;
|
||||
|
||||
[JsonProperty("user")]
|
||||
public RecentActivityUser User;
|
||||
|
||||
[JsonProperty("achievement")]
|
||||
public RecentActivityAchievement Achievement;
|
||||
|
||||
public class RecentActivityBeatmap
|
||||
{
|
||||
[JsonProperty("title")]
|
||||
public string Title;
|
||||
|
||||
[JsonProperty("url")]
|
||||
public string Url;
|
||||
}
|
||||
|
||||
public class RecentActivityUser
|
||||
{
|
||||
[JsonProperty("username")]
|
||||
public string Username;
|
||||
|
||||
[JsonProperty("url")]
|
||||
public string Url;
|
||||
|
||||
[JsonProperty("previousUsername")]
|
||||
public string PreviousUsername;
|
||||
}
|
||||
|
||||
public class RecentActivityAchievement
|
||||
{
|
||||
[JsonProperty("slug")]
|
||||
public string Slug;
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum RecentActivityType
|
||||
{
|
||||
Achievement,
|
||||
|
@ -2,10 +2,11 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserScoresRequest : APIRequest<List<OnlineScore>>
|
||||
public class GetUserScoresRequest : APIRequest<List<APIScore>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly ScoreType type;
|
||||
|
@ -2,19 +2,12 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUsersRequest : APIRequest<List<RankingEntry>>
|
||||
public class GetUsersRequest : APIRequest<List<APIUser>>
|
||||
{
|
||||
protected override string Target => @"rankings/osu/performance";
|
||||
}
|
||||
|
||||
public class RankingEntry
|
||||
{
|
||||
[JsonProperty]
|
||||
public User User;
|
||||
}
|
||||
}
|
||||
|
85
osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
Normal file
85
osu.Game/Online/API/Requests/Responses/APIBeatmap.cs
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIBeatmap : BeatmapMetadata
|
||||
{
|
||||
[JsonProperty(@"id")]
|
||||
public int OnlineBeatmapID { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmapset_id")]
|
||||
public int OnlineBeatmapSetID { get; set; }
|
||||
|
||||
[JsonProperty(@"playcount")]
|
||||
private int playCount { get; set; }
|
||||
|
||||
[JsonProperty(@"passcount")]
|
||||
private int passCount { get; set; }
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
private int ruleset { get; set; }
|
||||
|
||||
[JsonProperty(@"difficulty_rating")]
|
||||
private double starDifficulty { get; set; }
|
||||
|
||||
[JsonProperty(@"drain")]
|
||||
private float drainRate { get; set; }
|
||||
|
||||
[JsonProperty(@"cs")]
|
||||
private float circleSize { get; set; }
|
||||
|
||||
[JsonProperty(@"ar")]
|
||||
private float approachRate { get; set; }
|
||||
|
||||
[JsonProperty(@"accuracy")]
|
||||
private float overallDifficulty { get; set; }
|
||||
|
||||
[JsonProperty(@"total_length")]
|
||||
private double length { get; set; }
|
||||
|
||||
[JsonProperty(@"count_circles")]
|
||||
private int circleCount { get; set; }
|
||||
|
||||
[JsonProperty(@"count_sliders")]
|
||||
private int sliderCount { get; set; }
|
||||
|
||||
[JsonProperty(@"version")]
|
||||
private string version { get; set; }
|
||||
|
||||
public BeatmapInfo ToBeatmap(RulesetStore rulesets)
|
||||
{
|
||||
return new BeatmapInfo
|
||||
{
|
||||
Metadata = this,
|
||||
Ruleset = rulesets.GetRuleset(ruleset),
|
||||
StarDifficulty = starDifficulty,
|
||||
OnlineBeatmapID = OnlineBeatmapID,
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = OnlineBeatmapSetID,
|
||||
},
|
||||
Version = version,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
DrainRate = drainRate,
|
||||
CircleSize = circleSize,
|
||||
ApproachRate = approachRate,
|
||||
OverallDifficulty = overallDifficulty,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
PlayCount = playCount,
|
||||
PassCount = passCount,
|
||||
Length = length,
|
||||
CircleCount = circleCount,
|
||||
SliderCount = sliderCount,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
29
osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs
Normal file
29
osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIBeatmapMetrics : BeatmapMetrics
|
||||
{
|
||||
//the online API returns some metrics as a nested object.
|
||||
[JsonProperty(@"failtimes")]
|
||||
private BeatmapMetrics failTimes
|
||||
{
|
||||
set
|
||||
{
|
||||
Fails = value.Fails;
|
||||
Retries = value.Retries;
|
||||
}
|
||||
}
|
||||
|
||||
//and other metrics in the beatmap set.
|
||||
[JsonProperty(@"beatmapset")]
|
||||
private BeatmapMetrics beatmapSet
|
||||
{
|
||||
set => Ratings = value.Ratings;
|
||||
}
|
||||
}
|
||||
}
|
90
osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
Normal file
90
osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
Normal file
@ -0,0 +1,90 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIBeatmapSet : BeatmapMetadata // todo: this is a bit wrong...
|
||||
{
|
||||
[JsonProperty(@"covers")]
|
||||
private BeatmapSetOnlineCovers covers { get; set; }
|
||||
|
||||
private int? onlineBeatmapSetID;
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
public int? OnlineBeatmapSetID
|
||||
{
|
||||
get { return onlineBeatmapSetID; }
|
||||
set { onlineBeatmapSetID = value > 0 ? value : null; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"preview_url")]
|
||||
private string preview { get; set; }
|
||||
|
||||
[JsonProperty(@"play_count")]
|
||||
private int playCount { get; set; }
|
||||
|
||||
[JsonProperty(@"favourite_count")]
|
||||
private int favouriteCount { get; set; }
|
||||
|
||||
[JsonProperty(@"bpm")]
|
||||
private double bpm { get; set; }
|
||||
|
||||
[JsonProperty(@"video")]
|
||||
private bool hasVideo { get; set; }
|
||||
|
||||
[JsonProperty(@"storyboard")]
|
||||
private bool hasStoryboard { get; set; }
|
||||
|
||||
[JsonProperty(@"status")]
|
||||
private BeatmapSetOnlineStatus status { get; set; }
|
||||
|
||||
[JsonProperty(@"submitted_date")]
|
||||
private DateTimeOffset submitted { get; set; }
|
||||
|
||||
[JsonProperty(@"ranked_date")]
|
||||
private DateTimeOffset ranked { get; set; }
|
||||
|
||||
[JsonProperty(@"last_updated")]
|
||||
private DateTimeOffset lastUpdated { get; set; }
|
||||
|
||||
[JsonProperty(@"user_id")]
|
||||
private long creatorId
|
||||
{
|
||||
set { Author.Id = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"beatmaps")]
|
||||
private IEnumerable<APIBeatmap> beatmaps { get; set; }
|
||||
|
||||
public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = OnlineBeatmapSetID,
|
||||
Metadata = this,
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
Covers = covers,
|
||||
Preview = preview,
|
||||
PlayCount = playCount,
|
||||
FavouriteCount = favouriteCount,
|
||||
BPM = bpm,
|
||||
Status = status,
|
||||
HasVideo = hasVideo,
|
||||
HasStoryboard = hasStoryboard,
|
||||
Submitted = submitted,
|
||||
Ranked = ranked,
|
||||
LastUpdated = lastUpdated,
|
||||
},
|
||||
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
89
osu.Game/Online/API/Requests/Responses/APIRecentActivity.cs
Normal file
89
osu.Game/Online/API/Requests/Responses/APIRecentActivity.cs
Normal file
@ -0,0 +1,89 @@
|
||||
// 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 Humanizer;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIRecentActivity
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int ID;
|
||||
|
||||
[JsonProperty("createdAt")]
|
||||
public DateTimeOffset CreatedAt;
|
||||
|
||||
[JsonProperty]
|
||||
private string type
|
||||
{
|
||||
set => Type = (RecentActivityType)Enum.Parse(typeof(RecentActivityType), value.Pascalize());
|
||||
}
|
||||
|
||||
public RecentActivityType Type;
|
||||
|
||||
[JsonProperty]
|
||||
private string scoreRank
|
||||
{
|
||||
set => ScoreRank = (ScoreRank)Enum.Parse(typeof(ScoreRank), value);
|
||||
}
|
||||
|
||||
public ScoreRank ScoreRank;
|
||||
|
||||
[JsonProperty("rank")]
|
||||
public int Rank;
|
||||
|
||||
[JsonProperty("approval")]
|
||||
public BeatmapApproval Approval;
|
||||
|
||||
[JsonProperty("count")]
|
||||
public int Count;
|
||||
|
||||
[JsonProperty("mode")]
|
||||
public string Mode;
|
||||
|
||||
[JsonProperty("beatmap")]
|
||||
public RecentActivityBeatmap Beatmap;
|
||||
|
||||
[JsonProperty("beatmapset")]
|
||||
public RecentActivityBeatmap Beatmapset;
|
||||
|
||||
[JsonProperty("user")]
|
||||
public RecentActivityUser User;
|
||||
|
||||
[JsonProperty("achievement")]
|
||||
public RecentActivityAchievement Achievement;
|
||||
|
||||
public class RecentActivityBeatmap
|
||||
{
|
||||
[JsonProperty("title")]
|
||||
public string Title;
|
||||
|
||||
[JsonProperty("url")]
|
||||
public string Url;
|
||||
}
|
||||
|
||||
public class RecentActivityUser
|
||||
{
|
||||
[JsonProperty("username")]
|
||||
public string Username;
|
||||
|
||||
[JsonProperty("url")]
|
||||
public string Url;
|
||||
|
||||
[JsonProperty("previousUsername")]
|
||||
public string PreviousUsername;
|
||||
}
|
||||
|
||||
public class RecentActivityAchievement
|
||||
{
|
||||
[JsonProperty("slug")]
|
||||
public string Slug;
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name;
|
||||
}
|
||||
}
|
||||
}
|
117
osu.Game/Online/API/Requests/Responses/APIScore.cs
Normal file
117
osu.Game/Online/API/Requests/Responses/APIScore.cs
Normal file
@ -0,0 +1,117 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIScore : Score
|
||||
{
|
||||
[JsonProperty(@"score")]
|
||||
private double totalScore
|
||||
{
|
||||
set => TotalScore = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"max_combo")]
|
||||
private int maxCombo
|
||||
{
|
||||
set => MaxCombo = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
private User user
|
||||
{
|
||||
set => User = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"replay_data")]
|
||||
private Replay replay
|
||||
{
|
||||
set => Replay = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
public int OnlineRulesetID { get; set; }
|
||||
|
||||
[JsonProperty(@"score_id")]
|
||||
private long onlineScoreID
|
||||
{
|
||||
set => OnlineScoreID = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
private DateTimeOffset date
|
||||
{
|
||||
set => Date = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"beatmap")]
|
||||
private BeatmapInfo beatmap
|
||||
{
|
||||
set => Beatmap = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"beatmapset")]
|
||||
private BeatmapMetadata metadata
|
||||
{
|
||||
set => Beatmap.Metadata = value;
|
||||
}
|
||||
|
||||
[JsonProperty(@"statistics")]
|
||||
private Dictionary<string, object> jsonStats
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var kvp in value)
|
||||
{
|
||||
HitResult newKey;
|
||||
switch (kvp.Key)
|
||||
{
|
||||
case @"count_300":
|
||||
newKey = HitResult.Great;
|
||||
break;
|
||||
case @"count_100":
|
||||
newKey = HitResult.Good;
|
||||
break;
|
||||
case @"count_50":
|
||||
newKey = HitResult.Meh;
|
||||
break;
|
||||
case @"count_miss":
|
||||
newKey = HitResult.Miss;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
Statistics.Add(newKey, kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
private string[] modStrings { get; set; }
|
||||
|
||||
public void ApplyBeatmap(BeatmapInfo beatmap)
|
||||
{
|
||||
Beatmap = beatmap;
|
||||
ApplyRuleset(beatmap.Ruleset);
|
||||
}
|
||||
|
||||
public void ApplyRuleset(RulesetInfo ruleset)
|
||||
{
|
||||
Ruleset = ruleset;
|
||||
|
||||
// Evaluate the mod string
|
||||
Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
14
osu.Game/Online/API/Requests/Responses/APIScores.cs
Normal file
14
osu.Game/Online/API/Requests/Responses/APIScores.cs
Normal file
@ -0,0 +1,14 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIScores
|
||||
{
|
||||
[JsonProperty(@"scores")]
|
||||
public IEnumerable<APIScore> Scores;
|
||||
}
|
||||
}
|
14
osu.Game/Online/API/Requests/Responses/APIUser.cs
Normal file
14
osu.Game/Online/API/Requests/Responses/APIUser.cs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIUser
|
||||
{
|
||||
[JsonProperty]
|
||||
public User User;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIUserMostPlayedBeatmap
|
||||
{
|
||||
[JsonProperty("beatmap_id")]
|
||||
public int BeatmapID;
|
||||
|
||||
[JsonProperty("count")]
|
||||
public int PlayCount;
|
||||
|
||||
[JsonProperty]
|
||||
private BeatmapInfo beatmap;
|
||||
|
||||
[JsonProperty]
|
||||
private APIBeatmapSet beatmapSet;
|
||||
|
||||
public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets)
|
||||
{
|
||||
BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets);
|
||||
beatmap.BeatmapSet = setInfo;
|
||||
beatmap.Metadata = setInfo.Metadata;
|
||||
return beatmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,13 +3,14 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class SearchBeatmapSetsRequest : APIRequest<IEnumerable<APIResponseBeatmapSet>>
|
||||
public class SearchBeatmapSetsRequest : APIRequest<IEnumerable<APIBeatmapSet>>
|
||||
{
|
||||
private readonly string query;
|
||||
private readonly RulesetInfo ruleset;
|
||||
|
@ -56,6 +56,8 @@ namespace osu.Game
|
||||
|
||||
protected SettingsStore SettingsStore;
|
||||
|
||||
protected RulesetConfigCache RulesetConfigCache;
|
||||
|
||||
protected MenuCursorContainer MenuCursorContainer;
|
||||
|
||||
private Container content;
|
||||
@ -123,6 +125,7 @@ namespace osu.Game
|
||||
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory, Host, BeatmapManager, RulesetStore));
|
||||
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore));
|
||||
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory));
|
||||
dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore));
|
||||
dependencies.Cache(new OsuColour());
|
||||
|
||||
fileImporters.Add(BeatmapManager);
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using OpenTK;
|
||||
@ -11,10 +13,11 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
public class DownloadButton : HeaderButton
|
||||
{
|
||||
public DownloadButton(string title, string subtitle)
|
||||
public DownloadButton(BeatmapSetInfo set, bool noVideo = false)
|
||||
{
|
||||
Width = 120;
|
||||
|
||||
BeatmapSetDownloader downloader;
|
||||
Add(new Container
|
||||
{
|
||||
Depth = -1,
|
||||
@ -22,6 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
Padding = new MarginPadding { Horizontal = 10 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
downloader = new BeatmapSetDownloader(set, noVideo),
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
@ -32,13 +36,13 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = title,
|
||||
Text = "Download",
|
||||
TextSize = 13,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = subtitle,
|
||||
Text = set.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty,
|
||||
TextSize = 11,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
@ -54,6 +58,25 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Action = () =>
|
||||
{
|
||||
if (!downloader.Download())
|
||||
{
|
||||
Content.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(0, 50, Easing.InSine);
|
||||
}
|
||||
};
|
||||
|
||||
downloader.Downloaded.ValueChanged += d =>
|
||||
{
|
||||
if (d)
|
||||
this.FadeOut(200);
|
||||
else
|
||||
this.FadeIn(200);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,6 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private readonly BeatmapSetOnlineStatusPill onlineStatusPill;
|
||||
public Details Details;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
public readonly BeatmapPicker Picker;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
@ -68,8 +66,24 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
downloadButtonsContainer.FadeIn(transition_duration);
|
||||
favouriteButton.FadeIn(transition_duration);
|
||||
|
||||
noVideoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 0 : 1, transition_duration);
|
||||
videoButtons.FadeTo(BeatmapSet.OnlineInfo.HasVideo ? 1 : 0, transition_duration);
|
||||
if (BeatmapSet.OnlineInfo.HasVideo)
|
||||
{
|
||||
videoButtons.Children = new[]
|
||||
{
|
||||
new DownloadButton(BeatmapSet),
|
||||
new DownloadButton(BeatmapSet, true),
|
||||
};
|
||||
|
||||
videoButtons.FadeIn(transition_duration);
|
||||
noVideoButtons.FadeOut(transition_duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
noVideoButtons.Child = new DownloadButton(BeatmapSet);
|
||||
|
||||
noVideoButtons.FadeIn(transition_duration);
|
||||
videoButtons.FadeOut(transition_duration);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -192,27 +206,12 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0f,
|
||||
Child = new DownloadButton("Download", @"")
|
||||
{
|
||||
Action = () => download(false),
|
||||
},
|
||||
},
|
||||
videoButtons = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(buttons_spacing),
|
||||
Alpha = 0f,
|
||||
Children = new[]
|
||||
{
|
||||
new DownloadButton("Download", "with Video")
|
||||
{
|
||||
Action = () => download(false),
|
||||
},
|
||||
new DownloadButton("Download", "without Video")
|
||||
{
|
||||
Action = () => download(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -248,41 +247,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, BeatmapManager beatmaps)
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
tabsBg.Colour = colours.Gray3;
|
||||
this.beatmaps = beatmaps;
|
||||
|
||||
beatmaps.ItemAdded += handleBeatmapAdd;
|
||||
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
if (beatmaps != null) beatmaps.ItemAdded -= handleBeatmapAdd;
|
||||
}
|
||||
|
||||
private void handleBeatmapAdd(BeatmapSetInfo beatmap) => Schedule(() =>
|
||||
{
|
||||
if (beatmap.OnlineBeatmapSetID == BeatmapSet?.OnlineBeatmapSetID)
|
||||
downloadButtonsContainer.FadeOut(transition_duration);
|
||||
});
|
||||
|
||||
private void download(bool noVideo)
|
||||
{
|
||||
if (beatmaps.GetExistingDownload(BeatmapSet) != null)
|
||||
{
|
||||
downloadButtonsContainer.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(0, 50, Easing.InSine).Then();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
beatmaps.Download(BeatmapSet, noVideo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
private readonly Box background;
|
||||
|
||||
public DrawableScore(int index, OnlineScore score)
|
||||
public DrawableScore(int index, APIScore score)
|
||||
{
|
||||
ScoreModsContainer modsContainer;
|
||||
|
||||
|
@ -11,7 +11,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -42,8 +42,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
private readonly InfoColumn statistics;
|
||||
private readonly ScoreModsContainer modsContainer;
|
||||
|
||||
private OnlineScore score;
|
||||
public OnlineScore Score
|
||||
private APIScore score;
|
||||
public APIScore Score
|
||||
{
|
||||
get { return score; }
|
||||
set
|
||||
|
@ -11,6 +11,7 @@ using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
{
|
||||
@ -28,10 +29,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
set => loadingAnimation.FadeTo(value ? 1 : 0, fade_duration);
|
||||
}
|
||||
|
||||
private IEnumerable<OnlineScore> scores;
|
||||
private IEnumerable<APIScore> scores;
|
||||
private BeatmapInfo beatmap;
|
||||
|
||||
public IEnumerable<OnlineScore> Scores
|
||||
public IEnumerable<APIScore> Scores
|
||||
{
|
||||
get { return scores; }
|
||||
set
|
||||
|
@ -166,14 +166,13 @@ namespace osu.Game.Overlays.Direct
|
||||
},
|
||||
},
|
||||
},
|
||||
new DownloadButton
|
||||
new DownloadButton(SetInfo)
|
||||
{
|
||||
Size = new Vector2(30),
|
||||
Margin = new MarginPadding(horizontal_padding),
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Colour = colours.Gray5,
|
||||
Action = StartDownload
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -12,28 +12,31 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public class DirectListPanel : DirectPanel
|
||||
{
|
||||
private const float transition_duration = 120;
|
||||
private const float horizontal_padding = 10;
|
||||
private const float vertical_padding = 5;
|
||||
private const float height = 70;
|
||||
|
||||
private PlayButton playButton;
|
||||
private Box progressBar;
|
||||
private Container downloadContainer;
|
||||
|
||||
protected override PlayButton PlayButton => playButton;
|
||||
protected override Box PreviewBar => progressBar;
|
||||
|
||||
public DirectListPanel(BeatmapSetInfo beatmap) : base(beatmap)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
private PlayButton playButton;
|
||||
private Box progressBar;
|
||||
|
||||
protected override PlayButton PlayButton => playButton;
|
||||
protected override Box PreviewBar => progressBar;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(LocalisationEngine localisation, OsuColour colours)
|
||||
{
|
||||
@ -59,7 +62,7 @@ namespace osu.Game.Overlays.Direct
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
LayoutEasing = Easing.OutQuint,
|
||||
LayoutDuration = 120,
|
||||
LayoutDuration = transition_duration,
|
||||
Spacing = new Vector2(10, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -104,53 +107,69 @@ namespace osu.Game.Overlays.Direct
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Margin = new MarginPadding { Right = height - vertical_padding * 2 + vertical_padding },
|
||||
Direction = FillDirection.Horizontal,
|
||||
LayoutEasing = Easing.OutQuint,
|
||||
LayoutDuration = transition_duration,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Statistic(FontAwesome.fa_play_circle, SetInfo.OnlineInfo?.PlayCount ?? 0)
|
||||
downloadContainer = new Container
|
||||
{
|
||||
Margin = new MarginPadding { Right = 1 },
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
Child = new DownloadButton(SetInfo)
|
||||
{
|
||||
Size = new Vector2(height - vertical_padding * 2),
|
||||
Margin = new MarginPadding { Left = vertical_padding },
|
||||
},
|
||||
},
|
||||
new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new[]
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
new Statistic(FontAwesome.fa_play_circle, SetInfo.OnlineInfo?.PlayCount ?? 0)
|
||||
{
|
||||
Text = "mapped by ",
|
||||
TextSize = 14,
|
||||
Margin = new MarginPadding { Right = 1 },
|
||||
},
|
||||
new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "mapped by ",
|
||||
TextSize = 14,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = SetInfo.Metadata.Author.Username,
|
||||
TextSize = 14,
|
||||
Font = @"Exo2.0-SemiBoldItalic",
|
||||
},
|
||||
},
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = SetInfo.Metadata.Author.Username,
|
||||
Text = $"from {SetInfo.Metadata.Source}",
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
Font = @"Exo2.0-SemiBoldItalic",
|
||||
Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
|
||||
},
|
||||
},
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"from {SetInfo.Metadata.Source}",
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 14,
|
||||
Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
|
||||
},
|
||||
},
|
||||
},
|
||||
new DownloadButton
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Size = new Vector2(height - vertical_padding * 2),
|
||||
Action = StartDownload
|
||||
},
|
||||
},
|
||||
},
|
||||
progressBar = new Box
|
||||
@ -165,5 +184,17 @@ namespace osu.Game.Overlays.Direct
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
downloadContainer.FadeIn(transition_duration, Easing.InOutQuint);
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
downloadContainer.FadeOut(transition_duration, Easing.InOutQuint);
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,22 +147,6 @@ namespace osu.Game.Overlays.Direct
|
||||
|
||||
protected void ShowInformation() => beatmapSetOverlay?.ShowBeatmapSet(SetInfo);
|
||||
|
||||
protected void StartDownload()
|
||||
{
|
||||
if (beatmaps.GetExistingDownload(SetInfo) != null)
|
||||
{
|
||||
// we already have an active download running.
|
||||
content.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(0, 50, Easing.InSine).Then();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
beatmaps.Download(SetInfo);
|
||||
}
|
||||
|
||||
private void attachDownload(DownloadBeatmapSetRequest request)
|
||||
{
|
||||
if (request.BeatmapSet.OnlineBeatmapSetID != SetInfo.OnlineBeatmapSetID)
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using OpenTK;
|
||||
@ -13,10 +15,12 @@ namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public DownloadButton()
|
||||
public DownloadButton(BeatmapSetInfo set, bool noVideo = false)
|
||||
{
|
||||
BeatmapSetDownloader downloader;
|
||||
Children = new Drawable[]
|
||||
{
|
||||
downloader = new BeatmapSetDownloader(set, noVideo),
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@ -25,6 +29,25 @@ namespace osu.Game.Overlays.Direct
|
||||
Icon = FontAwesome.fa_osu_chevron_down_o,
|
||||
},
|
||||
};
|
||||
|
||||
Action = () =>
|
||||
{
|
||||
if (!downloader.Download())
|
||||
{
|
||||
Content.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(0, 50, Easing.InSine);
|
||||
}
|
||||
};
|
||||
|
||||
downloader.Downloaded.ValueChanged += d =>
|
||||
{
|
||||
if (d)
|
||||
this.FadeOut(200);
|
||||
else
|
||||
this.FadeIn(200);
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
|
@ -28,7 +28,6 @@ namespace osu.Game.Overlays
|
||||
|
||||
private APIAccess api;
|
||||
private RulesetStore rulesets;
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
private readonly FillFlowContainer resultCountsContainer;
|
||||
private readonly OsuSpriteText resultCountsText;
|
||||
@ -177,24 +176,14 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps)
|
||||
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets)
|
||||
{
|
||||
this.api = api;
|
||||
this.rulesets = rulesets;
|
||||
this.beatmaps = beatmaps;
|
||||
|
||||
resultCountsContainer.Colour = colours.Yellow;
|
||||
|
||||
beatmaps.ItemAdded += setAdded;
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo set) => Schedule(() =>
|
||||
{
|
||||
// if a new map was imported, we should remove it from search results (download completed etc.)
|
||||
panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire();
|
||||
BeatmapSets = BeatmapSets?.Where(b => b.OnlineBeatmapSetID != set.OnlineBeatmapSetID);
|
||||
});
|
||||
|
||||
private void updateResultCounts()
|
||||
{
|
||||
resultCountsContainer.FadeTo(ResultAmounts == null ? 0f : 1f, 200, Easing.OutQuint);
|
||||
@ -297,9 +286,7 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
var onlineIds = response.Select(r => r.OnlineBeatmapSetID).ToList();
|
||||
var presentOnlineIds = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID) && !s.DeletePending).Select(r => r.OnlineBeatmapSetID).ToList();
|
||||
var sets = response.Select(r => r.ToBeatmapSet(rulesets)).Where(b => !presentOnlineIds.Contains(b.OnlineBeatmapSetID)).ToList();
|
||||
var sets = response.Select(r => r.ToBeatmapSet(rulesets)).ToList();
|
||||
|
||||
// may not need scheduling; loads async internally.
|
||||
Schedule(() =>
|
||||
@ -323,14 +310,6 @@ namespace osu.Game.Overlays
|
||||
|
||||
private int distinctCount(List<string> list) => list.Distinct().ToArray().Length;
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (beatmaps != null)
|
||||
beatmaps.ItemAdded -= setAdded;
|
||||
}
|
||||
|
||||
public class ResultCounts
|
||||
{
|
||||
public readonly int Artists;
|
||||
|
@ -107,13 +107,20 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
visibleBadge = 0;
|
||||
|
||||
badgeFlowContainer.Clear();
|
||||
foreach (var badge in badges)
|
||||
for (var index = 0; index < badges.Length; index++)
|
||||
{
|
||||
LoadComponentAsync(new DrawableBadge(badge)
|
||||
int displayIndex = index;
|
||||
LoadComponentAsync(new DrawableBadge(badges[index])
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
}, badgeFlowContainer.Add);
|
||||
}, asyncBadge =>
|
||||
{
|
||||
badgeFlowContainer.Add(asyncBadge);
|
||||
|
||||
// load in stable order regardless of async load order.
|
||||
badgeFlowContainer.SetLayoutPosition(asyncBadge, displayIndex);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
Action = () =>
|
||||
{
|
||||
if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value);
|
||||
if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value);
|
||||
};
|
||||
|
||||
Child = new FillFlowContainer
|
||||
|
@ -8,6 +8,7 @@ using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Users;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
@ -49,7 +50,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
|
||||
MissingText.Hide();
|
||||
|
||||
foreach (OnlineScore score in scores)
|
||||
foreach (APIScore score in scores)
|
||||
{
|
||||
DrawableProfileScore drawableScore;
|
||||
|
||||
|
@ -8,6 +8,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
|
||||
@ -17,11 +18,11 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
|
||||
{
|
||||
private APIAccess api;
|
||||
|
||||
private readonly RecentActivity activity;
|
||||
private readonly APIRecentActivity activity;
|
||||
|
||||
private LinkFlowContainer content;
|
||||
|
||||
public DrawableRecentActivity(RecentActivity activity)
|
||||
public DrawableRecentActivity(APIRecentActivity activity)
|
||||
{
|
||||
this.activity = activity;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Users;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Recent
|
||||
{
|
||||
@ -36,7 +37,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
|
||||
|
||||
MissingText.Hide();
|
||||
|
||||
foreach (RecentActivity activity in activities)
|
||||
foreach (APIRecentActivity activity in activities)
|
||||
{
|
||||
ItemsContainer.Add(new DrawableRecentActivity(activity));
|
||||
}
|
||||
|
35
osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs
Normal file
35
osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs
Normal file
@ -0,0 +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 osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="SettingsSubsection"/> which provides subclasses with the <see cref="IRulesetConfigManager"/>
|
||||
/// from the <see cref="Ruleset"/>'s <see cref="Ruleset.CreateConfig()"/>.
|
||||
/// </summary>
|
||||
public abstract class RulesetSettingsSubsection : SettingsSubsection
|
||||
{
|
||||
private readonly Ruleset ruleset;
|
||||
|
||||
protected RulesetSettingsSubsection(Ruleset ruleset)
|
||||
{
|
||||
this.ruleset = ruleset;
|
||||
}
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
|
||||
var config = dependencies.Get<RulesetConfigCache>().GetConfigFor(ruleset);
|
||||
if (config != null)
|
||||
dependencies.Cache(config);
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
{
|
||||
@ -38,6 +39,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
LabelText = "Always show key overlay",
|
||||
Bindable = config.GetBindable<bool>(OsuSetting.KeyOverlay)
|
||||
},
|
||||
new SettingsEnumDropdown<ScoringMode>
|
||||
{
|
||||
LabelText = "Score display mode",
|
||||
Bindable = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -167,9 +167,25 @@ namespace osu.Game.Overlays.Volume
|
||||
private set => Bindable.Value = value;
|
||||
}
|
||||
|
||||
public void Increase() => Volume += 0.05f;
|
||||
private const float adjust_step = 0.05f;
|
||||
|
||||
public void Decrease() => Volume -= 0.05f;
|
||||
public void Increase() => adjust(1);
|
||||
public void Decrease() => adjust(-1);
|
||||
|
||||
private void adjust(int direction)
|
||||
{
|
||||
float amount = adjust_step * direction;
|
||||
|
||||
var mouse = GetContainingInputManager().CurrentState.Mouse;
|
||||
if (mouse.HasPreciseScroll)
|
||||
{
|
||||
float scrollDelta = mouse.ScrollDelta.Y;
|
||||
if (scrollDelta != 0)
|
||||
amount *= Math.Abs(scrollDelta / 10);
|
||||
}
|
||||
|
||||
Volume += amount;
|
||||
}
|
||||
|
||||
public bool OnPressed(GlobalAction action)
|
||||
{
|
||||
|
@ -8,7 +8,8 @@ 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)
|
||||
protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null)
|
||||
: base(settings, ruleset, variant)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Framework.Extensions.IEnumerableExtensions;
|
||||
@ -36,6 +37,44 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates all <see cref="Mod"/> combinations which adjust the <see cref="Beatmap"/> difficulty.
|
||||
/// </summary>
|
||||
public Mod[] CreateDifficultyAdjustmentModCombinations()
|
||||
{
|
||||
return createDifficultyAdjustmentModCombinations(Enumerable.Empty<Mod>(), DifficultyAdjustmentMods).ToArray();
|
||||
|
||||
IEnumerable<Mod> createDifficultyAdjustmentModCombinations(IEnumerable<Mod> currentSet, Mod[] adjustmentSet, int currentSetCount = 0, int adjustmentSetStart = 0)
|
||||
{
|
||||
// Initial-case: Empty current set
|
||||
if (currentSetCount == 0)
|
||||
yield return new NoModMod();
|
||||
|
||||
if (currentSetCount == 1)
|
||||
yield return currentSet.Single();
|
||||
|
||||
if (currentSetCount > 1)
|
||||
yield return new MultiMod(currentSet.ToArray());
|
||||
|
||||
// Apply mods in the adjustment set recursively. Using the entire adjustment set would result in duplicate multi-mod mod
|
||||
// combinations in further recursions, so a moving subset is used to eliminate this effect
|
||||
for (int i = adjustmentSetStart; i < adjustmentSet.Length; i++)
|
||||
{
|
||||
var adjustmentMod = adjustmentSet[i];
|
||||
if (currentSet.Any(c => c.IncompatibleMods.Any(m => m.IsInstanceOfType(adjustmentMod))))
|
||||
continue;
|
||||
|
||||
foreach (var combo in createDifficultyAdjustmentModCombinations(currentSet.Append(adjustmentMod), adjustmentSet, currentSetCount + 1, i + 1))
|
||||
yield return combo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves all <see cref="Mod"/>s which adjust the <see cref="Beatmap"/> difficulty.
|
||||
/// </summary>
|
||||
protected virtual Mod[] DifficultyAdjustmentMods => Array.Empty<Mod>();
|
||||
|
||||
public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null);
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public virtual void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
||||
{
|
||||
// todo: fix ordering of objects so we don't have to do this (#2740).
|
||||
foreach (var d in drawables.Reverse().Skip(IncreaseFirstObjectVisibility ? 1 : 0))
|
||||
foreach (var d in drawables.Skip(IncreaseFirstObjectVisibility ? 1 : 0))
|
||||
d.ApplyCustomUpdateState += ApplyHiddenState;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
DifficultyReduction,
|
||||
DifficultyIncrease,
|
||||
Special,
|
||||
Special
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
// 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.Linq;
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public class MultiMod : Mod
|
||||
@ -10,6 +13,13 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override string Description => string.Empty;
|
||||
public override double ScoreMultiplier => 0;
|
||||
|
||||
public Mod[] Mods;
|
||||
public Mod[] Mods { get; }
|
||||
|
||||
public MultiMod(params Mod[] mods)
|
||||
{
|
||||
Mods = mods;
|
||||
}
|
||||
|
||||
public override Type[] IncompatibleMods => Mods.SelectMany(m => m.IncompatibleMods).ToArray();
|
||||
}
|
||||
}
|
||||
|
15
osu.Game/Rulesets/Mods/NoModMod.cs
Normal file
15
osu.Game/Rulesets/Mods/NoModMod.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
|
||||
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a type of mod that doesn't do anything.
|
||||
/// </summary>
|
||||
public sealed class NoModMod : Mod
|
||||
{
|
||||
public override string Name => "No Mod";
|
||||
public override string ShortenedName => "NM";
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
@ -15,6 +15,8 @@ using osu.Game.Rulesets.Replays.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
@ -69,7 +71,13 @@ namespace osu.Game.Rulesets
|
||||
|
||||
public abstract string Description { get; }
|
||||
|
||||
public virtual SettingsSubsection CreateSettings() => null;
|
||||
public virtual RulesetSettingsSubsection CreateSettings() => null;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="IRulesetConfigManager"/> for this <see cref="Ruleset"/>.
|
||||
/// </summary>
|
||||
/// <param name="settings">The <see cref="SettingsStore"/> to store the settings.</param>
|
||||
public virtual IRulesetConfigManager CreateConfig(SettingsStore settings) => null;
|
||||
|
||||
/// <summary>
|
||||
/// Do not override this unless you are a legacy mode.
|
||||
|
43
osu.Game/Rulesets/RulesetConfigCache.cs
Normal file
43
osu.Game/Rulesets/RulesetConfigCache.cs
Normal file
@ -0,0 +1,43 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache that provides a single <see cref="IRulesetConfigManager"/> per-ruleset.
|
||||
/// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings.
|
||||
/// </summary>
|
||||
public class RulesetConfigCache : Component
|
||||
{
|
||||
private readonly Dictionary<int, IRulesetConfigManager> configCache = new Dictionary<int, IRulesetConfigManager>();
|
||||
private readonly SettingsStore settingsStore;
|
||||
|
||||
public RulesetConfigCache(SettingsStore settingsStore)
|
||||
{
|
||||
this.settingsStore = settingsStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="IRulesetConfigManager"/> for a <see cref="Ruleset"/>.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The <see cref="Ruleset"/> to retrieve the <see cref="IRulesetConfigManager"/> for.</param>
|
||||
/// <returns>The <see cref="IRulesetConfigManager"/> defined by <paramref name="ruleset"/>, null if <paramref name="ruleset"/> doesn't define one.</returns>
|
||||
/// <exception cref="InvalidOperationException">If <paramref name="ruleset"/> doesn't have a valid <see cref="RulesetInfo.ID"/>.</exception>
|
||||
public IRulesetConfigManager GetConfigFor(Ruleset ruleset)
|
||||
{
|
||||
if (ruleset.RulesetInfo.ID == null)
|
||||
throw new InvalidOperationException("The provided ruleset doesn't have a valid id.");
|
||||
|
||||
if (configCache.TryGetValue(ruleset.RulesetInfo.ID.Value, out var existing))
|
||||
return existing;
|
||||
|
||||
return configCache[ruleset.RulesetInfo.ID.Value] = ruleset.CreateConfig(settingsStore);
|
||||
}
|
||||
}
|
||||
}
|
@ -65,6 +65,11 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// </summary>
|
||||
public readonly BindableInt HighestCombo = new BindableInt();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ScoringMode"/> used to calculate scores.
|
||||
/// </summary>
|
||||
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether all <see cref="Judgement"/>s have been processed.
|
||||
/// </summary>
|
||||
@ -169,8 +174,6 @@ namespace osu.Game.Rulesets.Scoring
|
||||
private const double combo_portion = 0.7;
|
||||
private const double max_score = 1000000;
|
||||
|
||||
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>();
|
||||
|
||||
protected sealed override bool HasCompleted => JudgedHits == MaxHits;
|
||||
|
||||
protected int MaxHits { get; private set; }
|
||||
@ -199,16 +202,18 @@ namespace osu.Game.Rulesets.Scoring
|
||||
|
||||
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
||||
{
|
||||
Mode.Value = ScoringMode.Exponential;
|
||||
Mode.Value = ScoringMode.Classic;
|
||||
Mode.Disabled = true;
|
||||
}
|
||||
|
||||
Mode.ValueChanged += _ => updateScore();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates an autoplay of <see cref="HitObject"/>s that will be judged by this <see cref="ScoreProcessor{TObject}"/>
|
||||
/// by adding <see cref="Judgement"/>s for each <see cref="HitObject"/> in the <see cref="Beatmap{TObject}"/>.
|
||||
/// <para>
|
||||
/// This is required for <see cref="ScoringMode.Standardised"/> to work, otherwise <see cref="ScoringMode.Exponential"/> will be used.
|
||||
/// This is required for <see cref="ScoringMode.Standardised"/> to work, otherwise <see cref="ScoringMode.Classic"/> will be used.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> containing the <see cref="HitObject"/>s that will be judged by this <see cref="ScoreProcessor{TObject}"/>.</param>
|
||||
@ -295,8 +300,9 @@ namespace osu.Game.Rulesets.Scoring
|
||||
case ScoringMode.Standardised:
|
||||
TotalScore.Value = max_score * (base_portion * baseScore / maxBaseScore + combo_portion * HighestCombo / maxHighestCombo) + bonusScore;
|
||||
break;
|
||||
case ScoringMode.Exponential:
|
||||
TotalScore.Value = (baseScore + bonusScore) * Math.Log(HighestCombo + 1, 2);
|
||||
case ScoringMode.Classic:
|
||||
// should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1)
|
||||
TotalScore.Value = bonusScore + baseScore * (1 + Math.Max(0, HighestCombo - 1) / 25);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -322,6 +328,6 @@ namespace osu.Game.Rulesets.Scoring
|
||||
public enum ScoringMode
|
||||
{
|
||||
Standardised,
|
||||
Exponential
|
||||
Classic
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
public class HitObjectContainer : CompositeDrawable
|
||||
{
|
||||
public virtual IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>();
|
||||
public virtual IEnumerable<DrawableHitObject> AliveObjects => AliveInternalChildren.Cast<DrawableHitObject>();
|
||||
public IEnumerable<DrawableHitObject> Objects => InternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
|
||||
public IEnumerable<DrawableHitObject> AliveObjects => AliveInternalChildren.Cast<DrawableHitObject>().OrderBy(h => h.HitObject.StartTime);
|
||||
|
||||
public virtual void Add(DrawableHitObject hitObject) => AddInternal(hitObject);
|
||||
public virtual bool Remove(DrawableHitObject hitObject) => RemoveInternal(hitObject);
|
||||
|
@ -73,11 +73,6 @@ namespace osu.Game.Rulesets.UI
|
||||
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>
|
||||
@ -90,18 +85,20 @@ namespace osu.Game.Rulesets.UI
|
||||
Cursor = CreateCursor();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OnScreenDisplay onScreenDisplay, SettingsStore settings)
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||
{
|
||||
this.onScreenDisplay = onScreenDisplay;
|
||||
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
|
||||
rulesetConfig = CreateConfig(Ruleset, settings);
|
||||
onScreenDisplay = dependencies.Get<OnScreenDisplay>();
|
||||
|
||||
rulesetConfig = dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);
|
||||
if (rulesetConfig != null)
|
||||
{
|
||||
dependencies.Cache(rulesetConfig);
|
||||
onScreenDisplay?.BeginTracking(this, rulesetConfig);
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public abstract ScoreProcessor CreateScoreProcessor();
|
||||
@ -136,8 +133,6 @@ 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>
|
||||
|
@ -121,6 +121,8 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
private bool validState;
|
||||
|
||||
protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState;
|
||||
|
||||
private bool isAttached => replayInputHandler != null && !UseParentState;
|
||||
|
||||
private const int max_catch_up_updates_per_frame = 50;
|
||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Right = 5 },
|
||||
Child = new ScrollableTimeline { RelativeSizeAxes = Axes.Both }
|
||||
Child = new TimelineArea { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
|
@ -1,31 +0,0 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
|
||||
{
|
||||
public class BeatmapWaveformGraph : CompositeDrawable
|
||||
{
|
||||
public WorkingBeatmap Beatmap { set => graph.Waveform = value.Waveform; }
|
||||
|
||||
private readonly WaveformGraph graph;
|
||||
|
||||
public BeatmapWaveformGraph()
|
||||
{
|
||||
InternalChild = graph = new WaveformGraph { RelativeSizeAxes = Axes.Both };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="WaveformGraph.Resolution"/>.
|
||||
/// </summary>
|
||||
public float Resolution
|
||||
{
|
||||
get { return graph.Resolution; }
|
||||
set { graph.Resolution = value; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
|
||||
{
|
||||
public class ScrollableTimeline : CompositeDrawable
|
||||
{
|
||||
private readonly ScrollingTimelineContainer timelineContainer;
|
||||
|
||||
public ScrollableTimeline()
|
||||
{
|
||||
Masking = true;
|
||||
CornerRadius = 5;
|
||||
|
||||
OsuCheckbox hitObjectsCheckbox;
|
||||
OsuCheckbox hitSoundsCheckbox;
|
||||
OsuCheckbox waveformCheckbox;
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("111")
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("222")
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 160,
|
||||
Padding = new MarginPadding { Horizontal = 15 },
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 4),
|
||||
Children = new[]
|
||||
{
|
||||
hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" },
|
||||
hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" },
|
||||
waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("333")
|
||||
},
|
||||
new Container<TimelineButton>
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Masking = true,
|
||||
Children = new[]
|
||||
{
|
||||
new TimelineButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Height = 0.5f,
|
||||
Icon = FontAwesome.fa_search_plus,
|
||||
Action = () => timelineContainer.Zoom++
|
||||
},
|
||||
new TimelineButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Height = 0.5f,
|
||||
Icon = FontAwesome.fa_search_minus,
|
||||
Action = () => timelineContainer.Zoom--
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
timelineContainer = new ScrollingTimelineContainer { RelativeSizeAxes = Axes.Y }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
hitObjectsCheckbox.Current.Value = true;
|
||||
hitSoundsCheckbox.Current.Value = true;
|
||||
waveformCheckbox.Current.Value = true;
|
||||
|
||||
timelineContainer.WaveformVisible.BindTo(waveformCheckbox.Current);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
timelineContainer.Size = new Vector2(DrawSize.X - timelineContainer.DrawPosition.X, 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
// 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.Framework.Allocation;
|
||||
using OpenTK;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
|
||||
{
|
||||
public class ScrollingTimelineContainer : ScrollContainer
|
||||
{
|
||||
public readonly Bindable<bool> HitObjectsVisible = new Bindable<bool>();
|
||||
public readonly Bindable<bool> HitSoundsVisible = new Bindable<bool>();
|
||||
public readonly Bindable<bool> WaveformVisible = new Bindable<bool>();
|
||||
|
||||
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
private readonly BeatmapWaveformGraph waveform;
|
||||
|
||||
public ScrollingTimelineContainer()
|
||||
: base(Direction.Horizontal)
|
||||
{
|
||||
Masking = true;
|
||||
|
||||
Add(waveform = new BeatmapWaveformGraph
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("222"),
|
||||
Depth = float.MaxValue
|
||||
});
|
||||
|
||||
Content.AutoSizeAxes = Axes.None;
|
||||
Content.RelativeSizeAxes = Axes.Both;
|
||||
|
||||
WaveformVisible.ValueChanged += waveformVisibilityChanged;
|
||||
|
||||
Zoom = 10;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IBindableBeatmap beatmap)
|
||||
{
|
||||
this.beatmap.BindTo(beatmap);
|
||||
this.beatmap.BindValueChanged(beatmapChanged, true);
|
||||
}
|
||||
|
||||
private void beatmapChanged(WorkingBeatmap beatmap) => waveform.Beatmap = beatmap;
|
||||
|
||||
private float minZoom = 1;
|
||||
/// <summary>
|
||||
/// The minimum zoom level allowed.
|
||||
/// </summary>
|
||||
public float MinZoom
|
||||
{
|
||||
get { return minZoom; }
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
if (minZoom == value)
|
||||
return;
|
||||
minZoom = value;
|
||||
|
||||
// Update the zoom level
|
||||
Zoom = Zoom;
|
||||
}
|
||||
}
|
||||
|
||||
private float maxZoom = 30;
|
||||
/// <summary>
|
||||
/// The maximum zoom level allowed.
|
||||
/// </summary>
|
||||
public float MaxZoom
|
||||
{
|
||||
get { return maxZoom; }
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
if (maxZoom == value)
|
||||
return;
|
||||
maxZoom = value;
|
||||
|
||||
// Update the zoom level
|
||||
Zoom = Zoom;
|
||||
}
|
||||
}
|
||||
|
||||
private float zoom = 1;
|
||||
/// <summary>
|
||||
/// The current zoom level.
|
||||
/// </summary>
|
||||
public float Zoom
|
||||
{
|
||||
get { return zoom; }
|
||||
set
|
||||
{
|
||||
value = MathHelper.Clamp(value, MinZoom, MaxZoom);
|
||||
if (zoom == value)
|
||||
return;
|
||||
zoom = value;
|
||||
|
||||
// Make the zoom target default to the center of the graph if it hasn't been set
|
||||
if (relativeContentZoomTarget == null)
|
||||
relativeContentZoomTarget = ToSpaceOfOtherDrawable(DrawSize / 2, Content).X / Content.DrawSize.X;
|
||||
if (localZoomTarget == null)
|
||||
localZoomTarget = DrawSize.X / 2;
|
||||
|
||||
Content.ResizeWidthTo(Zoom);
|
||||
|
||||
// Update the scroll position to focus on the zoom target
|
||||
float scrollPos = Content.DrawSize.X * relativeContentZoomTarget.Value - localZoomTarget.Value;
|
||||
ScrollTo(scrollPos, false);
|
||||
|
||||
relativeContentZoomTarget = null;
|
||||
localZoomTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zoom target as a relative position in the <see cref="ScrollingTimelineContainer.Content"/> space.
|
||||
/// </summary>
|
||||
private float? relativeContentZoomTarget;
|
||||
|
||||
/// <summary>
|
||||
/// Zoom target as a position in our local space.
|
||||
/// </summary>
|
||||
private float? localZoomTarget;
|
||||
|
||||
protected override bool OnScroll(InputState state)
|
||||
{
|
||||
if (!state.Keyboard.ControlPressed)
|
||||
return base.OnScroll(state);
|
||||
|
||||
relativeContentZoomTarget = Content.ToLocalSpace(state.Mouse.NativeState.Position).X / Content.DrawSize.X;
|
||||
localZoomTarget = ToLocalSpace(state.Mouse.NativeState.Position).X;
|
||||
|
||||
Zoom += state.Mouse.ScrollDelta.Y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void waveformVisibilityChanged(bool visible) => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint);
|
||||
}
|
||||
}
|
57
osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs
Normal file
57
osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs
Normal file
@ -0,0 +1,57 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
|
||||
{
|
||||
public class Timeline : ZoomableScrollContainer
|
||||
{
|
||||
public readonly Bindable<bool> WaveformVisible = new Bindable<bool>();
|
||||
public readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
public Timeline()
|
||||
{
|
||||
ZoomDuration = 200;
|
||||
ZoomEasing = Easing.OutQuint;
|
||||
Zoom = 10;
|
||||
}
|
||||
|
||||
private WaveformGraph waveform;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IBindableBeatmap beatmap)
|
||||
{
|
||||
Child = waveform = new WaveformGraph
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("222"),
|
||||
Depth = float.MaxValue
|
||||
};
|
||||
|
||||
WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint);
|
||||
|
||||
Beatmap.BindTo(beatmap);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
Beatmap.BindValueChanged(b => waveform.Waveform = b.Waveform);
|
||||
waveform.Waveform = Beatmap.Value.Waveform;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
// We want time = 0 to be at the centre of the container when scrolled to the start
|
||||
Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 };
|
||||
}
|
||||
}
|
||||
}
|
128
osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs
Normal file
128
osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs
Normal file
@ -0,0 +1,128 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
|
||||
{
|
||||
public class TimelineArea : CompositeDrawable
|
||||
{
|
||||
private readonly Timeline timeline;
|
||||
|
||||
public TimelineArea()
|
||||
{
|
||||
Masking = true;
|
||||
CornerRadius = 5;
|
||||
|
||||
OsuCheckbox hitObjectsCheckbox;
|
||||
OsuCheckbox hitSoundsCheckbox;
|
||||
OsuCheckbox waveformCheckbox;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("111")
|
||||
},
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("222")
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 160,
|
||||
Padding = new MarginPadding { Horizontal = 15 },
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 4),
|
||||
Children = new[]
|
||||
{
|
||||
hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" },
|
||||
hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" },
|
||||
waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex("333")
|
||||
},
|
||||
new Container<TimelineButton>
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Masking = true,
|
||||
Children = new[]
|
||||
{
|
||||
new TimelineButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Height = 0.5f,
|
||||
Icon = FontAwesome.fa_search_plus,
|
||||
Action = () => timeline.Zoom++
|
||||
},
|
||||
new TimelineButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Height = 0.5f,
|
||||
Icon = FontAwesome.fa_search_minus,
|
||||
Action = () => timeline.Zoom--
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
timeline = new Timeline { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
},
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.Distributed),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
hitObjectsCheckbox.Current.Value = true;
|
||||
hitSoundsCheckbox.Current.Value = true;
|
||||
waveformCheckbox.Current.Value = true;
|
||||
|
||||
timeline.WaveformVisible.BindTo(waveformCheckbox.Current);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
// 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.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Screens.Compose.Timeline
|
||||
{
|
||||
public class ZoomableScrollContainer : ScrollContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// The time to zoom into/out of a point.
|
||||
/// All user scroll input will be overwritten during the zoom transform.
|
||||
/// </summary>
|
||||
public double ZoomDuration;
|
||||
|
||||
/// <summary>
|
||||
/// The easing with which to transform the zoom.
|
||||
/// </summary>
|
||||
public Easing ZoomEasing;
|
||||
|
||||
private readonly Container zoomedContent;
|
||||
protected override Container<Drawable> Content => zoomedContent;
|
||||
|
||||
private float currentZoom = 1;
|
||||
|
||||
public ZoomableScrollContainer()
|
||||
: base(Direction.Horizontal)
|
||||
{
|
||||
base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y });
|
||||
}
|
||||
|
||||
private int minZoom = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum zoom level allowed.
|
||||
/// </summary>
|
||||
public int MinZoom
|
||||
{
|
||||
get => minZoom;
|
||||
set
|
||||
{
|
||||
if (value < 1)
|
||||
throw new ArgumentException($"{nameof(MinZoom)} must be >= 1.", nameof(value));
|
||||
minZoom = value;
|
||||
|
||||
if (Zoom < value)
|
||||
Zoom = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int maxZoom = 60;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum zoom level allowed.
|
||||
/// </summary>
|
||||
public int MaxZoom
|
||||
{
|
||||
get => maxZoom;
|
||||
set
|
||||
{
|
||||
if (value < 1)
|
||||
throw new ArgumentException($"{nameof(MaxZoom)} must be >= 1.", nameof(value));
|
||||
maxZoom = value;
|
||||
|
||||
if (Zoom > value)
|
||||
Zoom = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content zoom level of this <see cref="ZoomableScrollContainer"/>.
|
||||
/// </summary>
|
||||
public float Zoom
|
||||
{
|
||||
get => zoomTarget;
|
||||
set
|
||||
{
|
||||
value = MathHelper.Clamp(value, MinZoom, MaxZoom);
|
||||
|
||||
if (IsLoaded)
|
||||
setZoomTarget(value, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X);
|
||||
else
|
||||
currentZoom = zoomTarget = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
zoomedContent.Width = DrawWidth * currentZoom;
|
||||
}
|
||||
|
||||
protected override bool OnScroll(InputState state)
|
||||
{
|
||||
if (!state.Keyboard.ControlPressed)
|
||||
return base.OnScroll(state);
|
||||
|
||||
setZoomTarget(zoomTarget + state.Mouse.ScrollDelta.X, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X);
|
||||
return true;
|
||||
}
|
||||
|
||||
private float zoomTarget = 1;
|
||||
private void setZoomTarget(float newZoom, float focusPoint)
|
||||
{
|
||||
zoomTarget = MathHelper.Clamp(newZoom, MinZoom, MaxZoom);
|
||||
transformZoomTo(zoomTarget, focusPoint, ZoomDuration, ZoomEasing);
|
||||
}
|
||||
|
||||
private void transformZoomTo(float newZoom, float focusPoint, double duration = 0, Easing easing = Easing.None)
|
||||
=> this.TransformTo(this.PopulateTransform(new TransformZoom(focusPoint, zoomedContent.DrawWidth, Current), newZoom, duration, easing));
|
||||
|
||||
private class TransformZoom : Transform<float, ZoomableScrollContainer>
|
||||
{
|
||||
/// <summary>
|
||||
/// The focus point in absolute coordinates local to the content.
|
||||
/// </summary>
|
||||
private readonly float focusPoint;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the content.
|
||||
/// </summary>
|
||||
private readonly float contentSize;
|
||||
|
||||
/// <summary>
|
||||
/// The scroll offset at the start of the transform.
|
||||
/// </summary>
|
||||
private readonly float scrollOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Transforms <see cref="TimeTimelinem"/> to a new value.
|
||||
/// </summary>
|
||||
/// <param name="focusPoint">The focus point in absolute coordinates local to the content.</param>
|
||||
/// <param name="contentSize">The size of the content.</param>
|
||||
/// <param name="scrollOffset">The scroll offset at the start of the transform.</param>
|
||||
public TransformZoom(float focusPoint, float contentSize, float scrollOffset)
|
||||
{
|
||||
this.focusPoint = focusPoint;
|
||||
this.contentSize = contentSize;
|
||||
this.scrollOffset = scrollOffset;
|
||||
}
|
||||
|
||||
public override string TargetMember => nameof(currentZoom);
|
||||
|
||||
private float valueAt(double time)
|
||||
{
|
||||
if (time < StartTime) return StartValue;
|
||||
if (time >= EndTime) return EndValue;
|
||||
|
||||
return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
|
||||
}
|
||||
|
||||
protected override void Apply(ZoomableScrollContainer d, double time)
|
||||
{
|
||||
float newZoom = valueAt(time);
|
||||
|
||||
float focusOffset = focusPoint - scrollOffset;
|
||||
float expectedWidth = d.DrawWidth * newZoom;
|
||||
float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset;
|
||||
|
||||
d.currentZoom = newZoom;
|
||||
d.ScrollTo(targetOffset, false);
|
||||
}
|
||||
|
||||
protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.currentZoom;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,8 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
private const int duration = 100;
|
||||
|
||||
private Bindable<bool> showKeyCounter;
|
||||
public readonly Bindable<bool> Visible = new Bindable<bool>(true);
|
||||
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
|
||||
|
||||
public KeyCounterCollection()
|
||||
{
|
||||
@ -46,9 +47,10 @@ namespace osu.Game.Screens.Play
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
showKeyCounter = config.GetBindable<bool>(OsuSetting.KeyOverlay);
|
||||
showKeyCounter.ValueChanged += keyCounterVisibility => this.FadeTo(keyCounterVisibility ? 1 : 0, duration);
|
||||
showKeyCounter.TriggerChange();
|
||||
config.BindWith(OsuSetting.KeyOverlay, configVisibility);
|
||||
|
||||
Visible.BindValueChanged(_ => updateVisibility());
|
||||
configVisibility.BindValueChanged(_ => updateVisibility(), true);
|
||||
}
|
||||
|
||||
//further: change default values here and in KeyCounter if needed, instead of passing them in every constructor
|
||||
@ -111,6 +113,8 @@ namespace osu.Game.Screens.Play
|
||||
}
|
||||
}
|
||||
|
||||
private void updateVisibility() => this.FadeTo(Visible.Value || configVisibility.Value ? 1 : 0, duration);
|
||||
|
||||
public override bool HandleKeyboardInput => receptor == null;
|
||||
public override bool HandleMouseInput => receptor == null;
|
||||
|
||||
|
@ -158,6 +158,7 @@ namespace osu.Game.Screens.Play
|
||||
userAudioOffset.TriggerChange();
|
||||
|
||||
ScoreProcessor = RulesetContainer.CreateScoreProcessor();
|
||||
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -228,6 +229,7 @@ namespace osu.Game.Screens.Play
|
||||
};
|
||||
|
||||
hudOverlay.HoldToQuit.Action = Exit;
|
||||
hudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded);
|
||||
|
||||
if (ShowStoryboard)
|
||||
initializeStoryboard(false);
|
||||
|
@ -15,12 +15,12 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Humanizer" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.607.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.611.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.18.1" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.4.0" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -11,9 +11,9 @@
|
||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
|
||||
<PackageReference Include="DeepEqual" Version="1.6.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
</ItemGroup>
|
||||
@ -25,4 +25,4 @@
|
||||
<PropertyGroup>
|
||||
<GenerateProgramFile>false</GenerateProgramFile>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user