mirror of
https://github.com/ppy/osu.git
synced 2024-09-22 16:47:24 +08:00
Merge pull request #1923 from smoogipoo/fix-replays
A lot of fixes to replay playback
This commit is contained in:
commit
95a1556376
21
osu.Game.Tests/Visual/TestCaseAutoplay.cs
Normal file
21
osu.Game.Tests/Visual/TestCaseAutoplay.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
[Description("Player instantiated with an autoplay mod.")]
|
||||||
|
public class TestCaseAutoplay : TestCasePlayer
|
||||||
|
{
|
||||||
|
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
||||||
|
{
|
||||||
|
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
||||||
|
return base.CreatePlayer(beatmap, ruleset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,35 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("Player instantiated with a replay.")]
|
||||||
public class TestCaseReplay : TestCasePlayer
|
public class TestCaseReplay : TestCasePlayer
|
||||||
{
|
{
|
||||||
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
||||||
{
|
{
|
||||||
|
// We create a dummy RulesetContainer just to get the replay - we don't want to use mods here
|
||||||
|
// to simulate setting a replay rather than having the replay already set for us
|
||||||
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
||||||
return base.CreatePlayer(beatmap, ruleset);
|
var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(beatmap, false);
|
||||||
|
|
||||||
|
// We have the replay
|
||||||
|
var replay = dummyRulesetContainer.Replay;
|
||||||
|
|
||||||
|
// Reset the mods
|
||||||
|
beatmap.Mods.Value = beatmap.Mods.Value.Where(m => !(m is ModAutoplay));
|
||||||
|
|
||||||
|
return new ReplayPlayer(replay)
|
||||||
|
{
|
||||||
|
InitialBeatmap = beatmap
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,6 +137,7 @@
|
|||||||
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
|
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
|
||||||
<Compile Include="Visual\TestCasePopupDialog.cs" />
|
<Compile Include="Visual\TestCasePopupDialog.cs" />
|
||||||
<Compile Include="Visual\TestCaseRankGraph.cs" />
|
<Compile Include="Visual\TestCaseRankGraph.cs" />
|
||||||
|
<Compile Include="Visual\TestCaseAutoplay.cs" />
|
||||||
<Compile Include="Visual\TestCaseReplay.cs" />
|
<Compile Include="Visual\TestCaseReplay.cs" />
|
||||||
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
|
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
|
||||||
<Compile Include="Visual\TestCaseResults.cs" />
|
<Compile Include="Visual\TestCaseResults.cs" />
|
||||||
|
@ -156,6 +156,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public IQueryable<BeatmapInfo> Beatmaps => GetContext().BeatmapInfo
|
public IQueryable<BeatmapInfo> Beatmaps => GetContext().BeatmapInfo
|
||||||
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
||||||
|
.Include(b => b.BeatmapSet).ThenInclude(s => s.Files).ThenInclude(f => f.FileInfo)
|
||||||
.Include(b => b.Metadata)
|
.Include(b => b.Metadata)
|
||||||
.Include(b => b.Ruleset)
|
.Include(b => b.Ruleset)
|
||||||
.Include(b => b.BaseDifficulty);
|
.Include(b => b.BaseDifficulty);
|
||||||
|
@ -10,6 +10,7 @@ using osu.Game.Database;
|
|||||||
using osu.Game.IO.Legacy;
|
using osu.Game.IO.Legacy;
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osu.Game.Users;
|
||||||
using SharpCompress.Compressors.LZMA;
|
using SharpCompress.Compressors.LZMA;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Scoring
|
||||||
@ -54,7 +55,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
var beatmapHash = sr.ReadString();
|
var beatmapHash = sr.ReadString();
|
||||||
score.Beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == beatmapHash);
|
score.Beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == beatmapHash);
|
||||||
/* score.PlayerName = */
|
/* score.PlayerName = */
|
||||||
sr.ReadString();
|
score.User = new User { Username = sr.ReadString() };
|
||||||
/* var localScoreChecksum = */
|
/* var localScoreChecksum = */
|
||||||
sr.ReadString();
|
sr.ReadString();
|
||||||
/* score.Count300 = */
|
/* score.Count300 = */
|
||||||
@ -107,7 +108,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
|
using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
|
||||||
using (var reader = new StreamReader(lzma))
|
using (var reader = new StreamReader(lzma))
|
||||||
|
{
|
||||||
score.Replay = createLegacyReplay(reader);
|
score.Replay = createLegacyReplay(reader);
|
||||||
|
score.Replay.User = score.User;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,9 +133,22 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
{
|
{
|
||||||
var split = l.Split('|');
|
var split = l.Split('|');
|
||||||
|
|
||||||
if (split.Length < 4 || float.Parse(split[0]) < 0) continue;
|
if (split.Length < 4)
|
||||||
|
continue;
|
||||||
|
|
||||||
lastTime += float.Parse(split[0]);
|
if (split[0] == "-12345")
|
||||||
|
{
|
||||||
|
// Todo: The seed is provided in split[3], which we'll need to use at some point
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var diff = float.Parse(split[0]);
|
||||||
|
lastTime += diff;
|
||||||
|
|
||||||
|
// Todo: At some point we probably want to rewind and play back the negative-time frames
|
||||||
|
// but for now we'll achieve equal playback to stable by skipping negative frames
|
||||||
|
if (diff < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
frames.Add(new ReplayFrame(
|
frames.Add(new ReplayFrame(
|
||||||
lastTime,
|
lastTime,
|
||||||
|
@ -13,6 +13,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
@ -45,9 +46,9 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public PassThroughInputManager KeyBindingInputManager;
|
public PassThroughInputManager KeyBindingInputManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether we have a replay loaded currently.
|
/// Whether a replay is currently loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasReplayLoaded => ReplayInputManager?.ReplayInputHandler != null;
|
public readonly BindableBool HasReplayLoaded = new BindableBool();
|
||||||
|
|
||||||
public abstract IEnumerable<HitObject> Objects { get; }
|
public abstract IEnumerable<HitObject> Objects { get; }
|
||||||
|
|
||||||
@ -99,6 +100,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
Replay = replay;
|
Replay = replay;
|
||||||
ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
||||||
|
|
||||||
|
HasReplayLoaded.Value = ReplayInputManager.ReplayInputHandler != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public readonly ReplaySettingsOverlay ReplaySettingsOverlay;
|
public readonly ReplaySettingsOverlay ReplaySettingsOverlay;
|
||||||
|
|
||||||
private Bindable<bool> showHud;
|
private Bindable<bool> showHud;
|
||||||
private bool replayLoaded;
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
|
|
||||||
private static bool hasShownNotificationOnce;
|
private static bool hasShownNotificationOnce;
|
||||||
|
|
||||||
@ -91,22 +91,39 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void BindRulesetContainer(RulesetContainer rulesetContainer)
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
(rulesetContainer.KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(KeyCounter);
|
base.LoadComplete();
|
||||||
|
|
||||||
replayLoaded = rulesetContainer.HasReplayLoaded;
|
replayLoaded.ValueChanged += replayLoadedValueChanged;
|
||||||
|
replayLoaded.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
ReplaySettingsOverlay.ReplayLoaded = replayLoaded;
|
private void replayLoadedValueChanged(bool loaded)
|
||||||
|
{
|
||||||
|
ReplaySettingsOverlay.ReplayLoaded = loaded;
|
||||||
|
|
||||||
// in the case a replay isn't loaded, we want some elements to only appear briefly.
|
if (loaded)
|
||||||
if (!replayLoaded)
|
{
|
||||||
|
ReplaySettingsOverlay.Show();
|
||||||
|
ModDisplay.FadeIn(200);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ReplaySettingsOverlay.Hide();
|
ReplaySettingsOverlay.Hide();
|
||||||
ModDisplay.Delay(2000).FadeOut(200);
|
ModDisplay.Delay(2000).FadeOut(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void BindRulesetContainer(RulesetContainer rulesetContainer)
|
||||||
|
{
|
||||||
|
(rulesetContainer.KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(KeyCounter);
|
||||||
|
|
||||||
|
replayLoaded.BindTo(rulesetContainer.HasReplayLoaded);
|
||||||
|
|
||||||
|
Progress.BindRulestContainer(rulesetContainer);
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Repeat) return false;
|
if (args.Repeat) return false;
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public int RestartCount;
|
public int RestartCount;
|
||||||
|
|
||||||
public CursorContainer Cursor => RulesetContainer.Cursor;
|
public CursorContainer Cursor => RulesetContainer.Cursor;
|
||||||
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded;
|
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value;
|
||||||
|
|
||||||
private IAdjustableClock adjustableSourceClock;
|
private IAdjustableClock adjustableSourceClock;
|
||||||
private FramedOffsetClock offsetClock;
|
private FramedOffsetClock offsetClock;
|
||||||
@ -226,7 +226,6 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
hudOverlay.Progress.Objects = RulesetContainer.Objects;
|
hudOverlay.Progress.Objects = RulesetContainer.Objects;
|
||||||
hudOverlay.Progress.AudioClock = decoupledClock;
|
hudOverlay.Progress.AudioClock = decoupledClock;
|
||||||
hudOverlay.Progress.AllowSeeking = RulesetContainer.HasReplayLoaded;
|
|
||||||
hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos);
|
hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos);
|
||||||
|
|
||||||
hudOverlay.ModDisplay.Current.BindTo(working.Mods);
|
hudOverlay.ModDisplay.Current.BindTo(working.Mods);
|
||||||
|
@ -9,9 +9,12 @@ using System.Collections.Generic;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
public class SongProgress : OverlayContainer
|
public class SongProgress : OverlayContainer
|
||||||
@ -54,6 +57,8 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
@ -98,6 +103,14 @@ namespace osu.Game.Screens.Play
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
State = Visibility.Visible;
|
State = Visibility.Visible;
|
||||||
|
|
||||||
|
replayLoaded.ValueChanged += v => AllowSeeking = v;
|
||||||
|
replayLoaded.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BindRulestContainer(RulesetContainer rulesetContainer)
|
||||||
|
{
|
||||||
|
replayLoaded.BindTo(rulesetContainer.HasReplayLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool allowSeeking;
|
private bool allowSeeking;
|
||||||
|
Loading…
Reference in New Issue
Block a user