mirror of
https://github.com/ppy/osu.git
synced 2024-12-05 10:33:22 +08:00
Merge pull request #8428 from peppy/replay-recording
Add local replay support for all rulesets
This commit is contained in:
commit
1587d4b26f
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
new KeyBinding(InputKey.Shift, CatchAction.Dash),
|
||||
};
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new CatchModNightcore();
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
}
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
Position = currentFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
||||
Dashing = currentFrame.ButtonState == ReplayButtonState.Left1;
|
||||
@ -56,5 +56,14 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
Actions.Add(CatchAction.MoveLeft);
|
||||
}
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
ReplayButtonState state = ReplayButtonState.None;
|
||||
|
||||
if (Actions.Contains(CatchAction.Dash)) state |= ReplayButtonState.Left1;
|
||||
|
||||
return new LegacyReplayFrame(Time, Position * CatchPlayfield.BASE_WIDTH, null, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
Normal file
26
osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatchReplayRecorder : ReplayRecorder<CatchAction>
|
||||
{
|
||||
private readonly CatchPlayfield playfield;
|
||||
|
||||
public CatchReplayRecorder(Replay target, CatchPlayfield playfield)
|
||||
: base(target)
|
||||
{
|
||||
this.playfield = playfield;
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<CatchAction> actions, ReplayFrame previousFrame)
|
||||
=> new CatchReplayFrame(Time.Current, playfield.CatcherArea.MovableCatcher.X, actions.Contains(CatchAction.Dash), previousFrame as CatchReplayFrame);
|
||||
}
|
||||
}
|
@ -32,6 +32,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new CatchReplayRecorder(replay, (CatchPlayfield)Playfield);
|
||||
|
||||
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
|
||||
|
||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer();
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
public override ISkin CreateLegacySkinProvider(ISkinSource source) => new ManiaLegacySkinTransformer(source);
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new ManiaModNightcore();
|
||||
@ -118,6 +118,59 @@ namespace osu.Game.Rulesets.Mania
|
||||
yield return new ManiaModRandom();
|
||||
}
|
||||
|
||||
public override LegacyMods ConvertToLegacyMods(Mod[] mods)
|
||||
{
|
||||
var value = base.ConvertToLegacyMods(mods);
|
||||
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case ManiaModKey1 _:
|
||||
value |= LegacyMods.Key1;
|
||||
break;
|
||||
|
||||
case ManiaModKey2 _:
|
||||
value |= LegacyMods.Key2;
|
||||
break;
|
||||
|
||||
case ManiaModKey3 _:
|
||||
value |= LegacyMods.Key3;
|
||||
break;
|
||||
|
||||
case ManiaModKey4 _:
|
||||
value |= LegacyMods.Key4;
|
||||
break;
|
||||
|
||||
case ManiaModKey5 _:
|
||||
value |= LegacyMods.Key5;
|
||||
break;
|
||||
|
||||
case ManiaModKey6 _:
|
||||
value |= LegacyMods.Key6;
|
||||
break;
|
||||
|
||||
case ManiaModKey7 _:
|
||||
value |= LegacyMods.Key7;
|
||||
break;
|
||||
|
||||
case ManiaModKey8 _:
|
||||
value |= LegacyMods.Key8;
|
||||
break;
|
||||
|
||||
case ManiaModKey9 _:
|
||||
value |= LegacyMods.Key9;
|
||||
break;
|
||||
|
||||
case ManiaModFadeIn _:
|
||||
value |= LegacyMods.FadeIn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||
{
|
||||
switch (type)
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
// We don't need to fully convert, just create the converter
|
||||
var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset());
|
||||
@ -56,5 +56,42 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
activeColumns >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
int keys = 0;
|
||||
|
||||
var converter = new ManiaBeatmapConverter(beatmap, new ManiaRuleset());
|
||||
|
||||
var stage = new StageDefinition { Columns = converter.TargetColumns };
|
||||
|
||||
var specialColumns = new List<int>();
|
||||
|
||||
for (int i = 0; i < converter.TargetColumns; i++)
|
||||
{
|
||||
if (stage.IsSpecialColumn(i))
|
||||
specialColumns.Add(i);
|
||||
}
|
||||
|
||||
foreach (var action in Actions)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ManiaAction.Special1:
|
||||
keys |= 1 << specialColumns[0];
|
||||
break;
|
||||
|
||||
case ManiaAction.Special2:
|
||||
keys |= 1 << specialColumns[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
keys |= 1 << (action - ManiaAction.Key1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new LegacyReplayFrame(Time, keys, null, ReplayButtonState.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,5 +85,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new ManiaReplayRecorder(replay);
|
||||
}
|
||||
}
|
||||
|
23
osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs
Normal file
23
osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public class ManiaReplayRecorder : ReplayRecorder<ManiaAction>
|
||||
{
|
||||
public ManiaReplayRecorder(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<ManiaAction> actions, ReplayFrame previousFrame)
|
||||
=> new ManiaReplayFrame(Time.Current, actions.ToArray());
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
|
||||
};
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new OsuModNightcore();
|
||||
|
@ -26,11 +26,23 @@ namespace osu.Game.Rulesets.Osu.Replays
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
Position = currentFrame.Position;
|
||||
if (currentFrame.MouseLeft) Actions.Add(OsuAction.LeftButton);
|
||||
if (currentFrame.MouseRight) Actions.Add(OsuAction.RightButton);
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
ReplayButtonState state = ReplayButtonState.None;
|
||||
|
||||
if (Actions.Contains(OsuAction.LeftButton))
|
||||
state |= ReplayButtonState.Left1;
|
||||
if (Actions.Contains(OsuAction.RightButton))
|
||||
state |= ReplayButtonState.Right1;
|
||||
|
||||
return new LegacyReplayFrame(Time, Position.X, Position.Y, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new OsuReplayRecorder(replay);
|
||||
|
||||
public override double GameplayStartTime
|
||||
{
|
||||
get
|
||||
|
23
osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs
Normal file
23
osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
public class OsuReplayRecorder : ReplayRecorder<OsuAction>
|
||||
{
|
||||
public OsuReplayRecorder(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<OsuAction> actions, ReplayFrame previousFrame)
|
||||
=> new OsuReplayFrame(Time.Current, mousePosition, actions.ToArray());
|
||||
}
|
||||
}
|
@ -23,12 +23,24 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null)
|
||||
{
|
||||
if (currentFrame.MouseRight1) Actions.Add(TaikoAction.LeftRim);
|
||||
if (currentFrame.MouseRight2) Actions.Add(TaikoAction.RightRim);
|
||||
if (currentFrame.MouseLeft1) Actions.Add(TaikoAction.LeftCentre);
|
||||
if (currentFrame.MouseLeft2) Actions.Add(TaikoAction.RightCentre);
|
||||
}
|
||||
|
||||
public LegacyReplayFrame ToLegacy(IBeatmap beatmap)
|
||||
{
|
||||
ReplayButtonState state = ReplayButtonState.None;
|
||||
|
||||
if (Actions.Contains(TaikoAction.LeftRim)) state |= ReplayButtonState.Right1;
|
||||
if (Actions.Contains(TaikoAction.RightRim)) state |= ReplayButtonState.Right2;
|
||||
if (Actions.Contains(TaikoAction.LeftCentre)) state |= ReplayButtonState.Left1;
|
||||
if (Actions.Contains(TaikoAction.RightCentre)) state |= ReplayButtonState.Left2;
|
||||
|
||||
return new LegacyReplayFrame(Time, null, null, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Taiko
|
||||
new KeyBinding(InputKey.K, TaikoAction.RightRim),
|
||||
};
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
public override IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
yield return new TaikoModNightcore();
|
||||
|
@ -65,5 +65,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
}
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay);
|
||||
|
||||
protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new TaikoReplayRecorder(replay);
|
||||
}
|
||||
}
|
||||
|
23
osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs
Normal file
23
osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Taiko.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public class TaikoReplayRecorder : ReplayRecorder<TaikoAction>
|
||||
{
|
||||
public TaikoReplayRecorder(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<TaikoAction> actions, ReplayFrame previousFrame) =>
|
||||
new TaikoReplayFrame(Time.Current, actions.ToArray());
|
||||
}
|
||||
}
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -49,7 +48,10 @@ namespace osu.Game.Tests.Gameplay
|
||||
{
|
||||
recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
|
||||
{
|
||||
Recorder = recorder = new TestReplayRecorder(replay),
|
||||
Recorder = recorder = new TestReplayRecorder(replay)
|
||||
{
|
||||
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos),
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -273,8 +275,8 @@ namespace osu.Game.Tests.Gameplay
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(InputState state, List<TestAction> pressedActions, ReplayFrame previousFrame) =>
|
||||
new TestReplayFrame(Time.Current, ToLocalSpace(state.Mouse.Position), pressedActions.ToArray());
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<TestAction> actions, ReplayFrame previousFrame)
|
||||
=> new TestReplayFrame(Time.Current, mousePosition, actions.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
221
osu.Game.Tests/Gameplay/TestSceneReplayRecording.cs
Normal file
221
osu.Game.Tests/Gameplay/TestSceneReplayRecording.cs
Normal file
@ -0,0 +1,221 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.StateChanges;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osu.Game.Tests.Visual.UserInterface;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Gameplay
|
||||
{
|
||||
public class TestSceneReplayRecording : OsuTestScene
|
||||
{
|
||||
private readonly TestRulesetInputManager playbackManager;
|
||||
|
||||
private readonly TestRulesetInputManager recordingManager;
|
||||
|
||||
public TestSceneReplayRecording()
|
||||
{
|
||||
Replay replay = new Replay();
|
||||
|
||||
Add(new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
|
||||
{
|
||||
Recorder = new TestReplayRecorder(replay)
|
||||
{
|
||||
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos)
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Brown,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Recording",
|
||||
Scale = new Vector2(3),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new TestConsumer()
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
playbackManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
|
||||
{
|
||||
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
|
||||
{
|
||||
GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.DarkBlue,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Playback",
|
||||
Scale = new Vector2(3),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
new TestConsumer()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
playbackManager.ReplayInputHandler.SetFrameFromTime(Time.Current - 500);
|
||||
}
|
||||
}
|
||||
|
||||
public class TestFramedReplayInputHandler : FramedReplayInputHandler<TestReplayFrame>
|
||||
{
|
||||
public TestFramedReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
public override List<IInput> GetPendingInputs()
|
||||
{
|
||||
return new List<IInput>
|
||||
{
|
||||
new MousePositionAbsoluteInput
|
||||
{
|
||||
Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero)
|
||||
},
|
||||
new ReplayState<TestAction>
|
||||
{
|
||||
PressedActions = CurrentFrame?.Actions ?? new List<TestAction>()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class TestConsumer : CompositeDrawable, IKeyBindingHandler<TestAction>
|
||||
{
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
private readonly Box box;
|
||||
|
||||
public TestConsumer()
|
||||
{
|
||||
Size = new Vector2(30);
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
box = new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||
{
|
||||
Position = e.MousePosition;
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
public bool OnPressed(TestAction action)
|
||||
{
|
||||
box.Colour = Color4.White;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnReleased(TestAction action)
|
||||
{
|
||||
box.Colour = Color4.Black;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestRulesetInputManager : RulesetInputManager<TestAction>
|
||||
{
|
||||
public TestRulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
: base(ruleset, variant, unique)
|
||||
{
|
||||
}
|
||||
|
||||
protected override KeyBindingContainer<TestAction> CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique)
|
||||
=> new TestKeyBindingContainer();
|
||||
|
||||
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
|
||||
{
|
||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
||||
{
|
||||
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class TestReplayFrame : ReplayFrame
|
||||
{
|
||||
public Vector2 Position;
|
||||
|
||||
public List<TestAction> Actions = new List<TestAction>();
|
||||
|
||||
public TestReplayFrame(double time, Vector2 position, params TestAction[] actions)
|
||||
: base(time)
|
||||
{
|
||||
Position = position;
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
}
|
||||
|
||||
public enum TestAction
|
||||
{
|
||||
Down,
|
||||
}
|
||||
|
||||
internal class TestReplayRecorder : ReplayRecorder<TestAction>
|
||||
{
|
||||
public TestReplayRecorder(Replay target)
|
||||
: base(target)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<TestAction> actions, ReplayFrame previousFrame) =>
|
||||
new TestReplayFrame(Time.Current, mousePosition, actions.ToArray());
|
||||
}
|
||||
}
|
@ -236,8 +236,6 @@ namespace osu.Game.Tests.Scores.IO
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => new[] { "test_file.osr" };
|
||||
|
||||
public override Stream GetUnderlyingStream() => new MemoryStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,5 @@ namespace osu.Game.IO.Archives
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Stream GetUnderlyingStream();
|
||||
}
|
||||
}
|
||||
|
30
osu.Game/IO/Archives/LegacyByteArrayReader.cs
Normal file
30
osu.Game/IO/Archives/LegacyByteArrayReader.cs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace osu.Game.IO.Archives
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows reading a single file from the provided stream.
|
||||
/// </summary>
|
||||
public class LegacyByteArrayReader : ArchiveReader
|
||||
{
|
||||
private readonly byte[] content;
|
||||
|
||||
public LegacyByteArrayReader(byte[] content, string filename)
|
||||
: base(filename)
|
||||
{
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public override Stream GetStream(string name) => new MemoryStream(content);
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => new[] { Name };
|
||||
}
|
||||
}
|
@ -28,7 +28,5 @@ namespace osu.Game.IO.Archives
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => Directory.GetFiles(path, "*", SearchOption.AllDirectories).Select(f => f.Replace(path, string.Empty).Trim(Path.DirectorySeparatorChar)).ToArray();
|
||||
|
||||
public override Stream GetUnderlyingStream() => null;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,5 @@ namespace osu.Game.IO.Archives
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => new[] { Name };
|
||||
|
||||
public override Stream GetUnderlyingStream() => null;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,5 @@ namespace osu.Game.IO.Archives
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => archive.Entries.Select(e => e.Key).ExcludeSystemFileNames();
|
||||
|
||||
public override Stream GetUnderlyingStream() => archiveStream;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,12 @@ namespace osu.Game.Rulesets.Replays.Types
|
||||
/// <param name="currentFrame">The <see cref="LegacyReplayFrame"/> to extract values from.</param>
|
||||
/// <param name="beatmap">The beatmap.</param>
|
||||
/// <param name="lastFrame">The last post-conversion <see cref="ReplayFrame"/>, used to fill in missing delta information. May be null.</param>
|
||||
void ConvertFrom(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null);
|
||||
void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null);
|
||||
|
||||
/// <summary>
|
||||
/// Populates this <see cref="ReplayFrame"/> using values from a <see cref="LegacyReplayFrame"/>.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap.</param>
|
||||
LegacyReplayFrame ToLegacy(IBeatmap beatmap);
|
||||
}
|
||||
}
|
||||
|
@ -42,9 +42,63 @@ namespace osu.Game.Rulesets
|
||||
/// <summary>
|
||||
/// Converts mods from legacy enum values. Do not override if you're not a legacy ruleset.
|
||||
/// </summary>
|
||||
/// <param name="mods">The legacy enum which will be converted</param>
|
||||
/// <returns>An enumerable of constructed <see cref="Mod"/>s</returns>
|
||||
public virtual IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods) => Array.Empty<Mod>();
|
||||
/// <param name="mods">The legacy enum which will be converted.</param>
|
||||
/// <returns>An enumerable of constructed <see cref="Mod"/>s.</returns>
|
||||
public virtual IEnumerable<Mod> ConvertFromLegacyMods(LegacyMods mods) => Array.Empty<Mod>();
|
||||
|
||||
/// <summary>
|
||||
/// Converts mods to legacy enum values. Do not override if you're not a legacy ruleset.
|
||||
/// </summary>
|
||||
/// <param name="mods">The mods which will be converted.</param>
|
||||
/// <returns>A single bitwise enumerable value representing (to the best of our ability) the mods.</returns>
|
||||
public virtual LegacyMods ConvertToLegacyMods(Mod[] mods)
|
||||
{
|
||||
var value = LegacyMods.None;
|
||||
|
||||
foreach (var mod in mods)
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case ModNoFail _:
|
||||
value |= LegacyMods.NoFail;
|
||||
break;
|
||||
|
||||
case ModEasy _:
|
||||
value |= LegacyMods.Easy;
|
||||
break;
|
||||
|
||||
case ModHidden _:
|
||||
value |= LegacyMods.Hidden;
|
||||
break;
|
||||
|
||||
case ModHardRock _:
|
||||
value |= LegacyMods.HardRock;
|
||||
break;
|
||||
|
||||
case ModSuddenDeath _:
|
||||
value |= LegacyMods.SuddenDeath;
|
||||
break;
|
||||
|
||||
case ModDoubleTime _:
|
||||
value |= LegacyMods.DoubleTime;
|
||||
break;
|
||||
|
||||
case ModRelax _:
|
||||
value |= LegacyMods.Relax;
|
||||
break;
|
||||
|
||||
case ModHalfTime _:
|
||||
value |= LegacyMods.HalfTime;
|
||||
break;
|
||||
|
||||
case ModFlashlight _:
|
||||
value |= LegacyMods.Flashlight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public ModAutoplay GetAutoplayMod() => GetAllMods().OfType<ModAutoplay>().First();
|
||||
|
||||
|
@ -262,6 +262,21 @@ namespace osu.Game.Rulesets.UI
|
||||
Playfield.Add(drawableObject);
|
||||
}
|
||||
|
||||
public override void SetRecordTarget(Replay recordingReplay)
|
||||
{
|
||||
if (!(KeyBindingInputManager is IHasRecordingHandler recordingInputManager))
|
||||
throw new InvalidOperationException($"A {nameof(KeyBindingInputManager)} which supports recording is not available");
|
||||
|
||||
var recorder = CreateReplayRecorder(recordingReplay);
|
||||
|
||||
if (recorder == null)
|
||||
return;
|
||||
|
||||
recorder.ScreenSpaceToGamefield = Playfield.ScreenSpaceToGamefield;
|
||||
|
||||
recordingInputManager.Recorder = recorder;
|
||||
}
|
||||
|
||||
public override void SetReplayScore(Score replayScore)
|
||||
{
|
||||
if (!(KeyBindingInputManager is IHasReplayHandler replayInputManager))
|
||||
@ -472,6 +487,12 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <param name="replayScore">The replay, null for local input.</param>
|
||||
public abstract void SetReplayScore(Score replayScore);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a replay to be used to record gameplay.
|
||||
/// </summary>
|
||||
/// <param name="recordingReplay">The target to be recorded to.</param>
|
||||
public abstract void SetRecordTarget(Replay recordingReplay);
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the interactive user requests resuming from a paused state.
|
||||
/// Allows potentially delaying the resume process until an interaction is performed.
|
||||
|
@ -30,6 +30,11 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public Func<Vector2, Vector2> GamefieldToScreenSpace => HitObjectContainer.ToScreenSpace;
|
||||
|
||||
/// <summary>
|
||||
/// A function that converts screen space coordinates to gamefield.
|
||||
/// </summary>
|
||||
public Func<Vector2, Vector2> ScreenSpaceToGamefield => HitObjectContainer.ToLocalSpace;
|
||||
|
||||
/// <summary>
|
||||
/// All the <see cref="DrawableHitObject"/>s contained in this <see cref="Playfield"/> and all <see cref="NestedPlayfields"/>.
|
||||
/// </summary>
|
||||
|
@ -1,15 +1,16 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
@ -66,16 +67,19 @@ namespace osu.Game.Rulesets.UI
|
||||
if (!important && last != null && Time.Current - last.Time < (1000d / RecordFrameRate))
|
||||
return;
|
||||
|
||||
var frame = HandleFrame(inputManager.CurrentState, pressedActions, last);
|
||||
var position = ScreenSpaceToGamefield?.Invoke(inputManager.CurrentState.Mouse.Position) ?? inputManager.CurrentState.Mouse.Position;
|
||||
|
||||
var frame = HandleFrame(position, pressedActions, last);
|
||||
|
||||
if (frame != null)
|
||||
target.Frames.Add(frame);
|
||||
}
|
||||
|
||||
protected abstract ReplayFrame HandleFrame(InputState state, List<T> testActions, ReplayFrame previousFrame);
|
||||
protected abstract ReplayFrame HandleFrame(Vector2 mousePosition, List<T> actions, ReplayFrame previousFrame);
|
||||
}
|
||||
|
||||
public abstract class ReplayRecorder : Component
|
||||
{
|
||||
public Func<Vector2, Vector2> ScreenSpaceToGamefield;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ using MouseState = osu.Framework.Input.States.MouseState;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
public abstract class RulesetInputManager<T> : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler
|
||||
public abstract class RulesetInputManager<T> : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler
|
||||
where T : struct
|
||||
{
|
||||
private ReplayRecorder recorder;
|
||||
@ -184,6 +184,11 @@ namespace osu.Game.Rulesets.UI
|
||||
ReplayInputHandler ReplayInputHandler { get; set; }
|
||||
}
|
||||
|
||||
public interface IHasRecordingHandler
|
||||
{
|
||||
public ReplayRecorder Recorder { set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supports attaching a <see cref="KeyCounterDisplay"/>.
|
||||
/// Keys will be populated automatically and a receptor will be injected inside.
|
||||
|
@ -7,15 +7,15 @@ using osu.Game.Rulesets;
|
||||
namespace osu.Game.Scoring.Legacy
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="LegacyScoreParser"/> which retrieves the applicable <see cref="Beatmap"/> and <see cref="Ruleset"/>
|
||||
/// A <see cref="LegacyScoreDecoder"/> which retrieves the applicable <see cref="Beatmap"/> and <see cref="Ruleset"/>
|
||||
/// for the score from the database.
|
||||
/// </summary>
|
||||
public class DatabasedLegacyScoreParser : LegacyScoreParser
|
||||
public class DatabasedLegacyScoreDecoder : LegacyScoreDecoder
|
||||
{
|
||||
private readonly RulesetStore rulesets;
|
||||
private readonly BeatmapManager beatmaps;
|
||||
|
||||
public DatabasedLegacyScoreParser(RulesetStore rulesets, BeatmapManager beatmaps)
|
||||
public DatabasedLegacyScoreDecoder(RulesetStore rulesets, BeatmapManager beatmaps)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
this.beatmaps = beatmaps;
|
@ -19,7 +19,7 @@ using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace osu.Game.Scoring.Legacy
|
||||
{
|
||||
public abstract class LegacyScoreParser
|
||||
public abstract class LegacyScoreDecoder
|
||||
{
|
||||
private IBeatmap currentBeatmap;
|
||||
private Ruleset currentRuleset;
|
||||
@ -66,7 +66,7 @@ namespace osu.Game.Scoring.Legacy
|
||||
/* score.Perfect = */
|
||||
sr.ReadBoolean();
|
||||
|
||||
scoreInfo.Mods = currentRuleset.ConvertLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();
|
||||
scoreInfo.Mods = currentRuleset.ConvertFromLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();
|
||||
|
||||
/* score.HpGraphString = */
|
||||
sr.ReadString();
|
||||
@ -264,7 +264,7 @@ namespace osu.Game.Scoring.Legacy
|
||||
if (convertible == null)
|
||||
throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}");
|
||||
|
||||
convertible.ConvertFrom(currentFrame, currentBeatmap, lastFrame);
|
||||
convertible.FromLegacy(currentFrame, currentBeatmap, lastFrame);
|
||||
|
||||
var frame = (ReplayFrame)convertible;
|
||||
frame.Time = currentFrame.Time;
|
114
osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs
Normal file
114
osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.IO.Legacy;
|
||||
using osu.Game.Replays.Legacy;
|
||||
using osu.Game.Rulesets.Replays.Types;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace osu.Game.Scoring.Legacy
|
||||
{
|
||||
public class LegacyScoreEncoder
|
||||
{
|
||||
public const int LATEST_VERSION = 128;
|
||||
|
||||
private readonly Score score;
|
||||
private readonly IBeatmap beatmap;
|
||||
|
||||
public LegacyScoreEncoder(Score score, IBeatmap beatmap)
|
||||
{
|
||||
this.score = score;
|
||||
this.beatmap = beatmap;
|
||||
|
||||
if (score.ScoreInfo.Beatmap.RulesetID < 0 || score.ScoreInfo.Beatmap.RulesetID > 3)
|
||||
throw new ArgumentException("Only scores in the osu, taiko, catch, or mania rulesets can be encoded to the legacy score format.", nameof(score));
|
||||
}
|
||||
|
||||
public void Encode(Stream stream)
|
||||
{
|
||||
using (SerializationWriter sw = new SerializationWriter(stream))
|
||||
{
|
||||
sw.Write((byte)(score.ScoreInfo.Ruleset.ID ?? 0));
|
||||
sw.Write(LATEST_VERSION);
|
||||
sw.Write(score.ScoreInfo.Beatmap.MD5Hash);
|
||||
sw.Write(score.ScoreInfo.UserString);
|
||||
sw.Write($"lazer-{score.ScoreInfo.UserString}-{score.ScoreInfo.Date}".ComputeMD5Hash());
|
||||
sw.Write((ushort)(score.ScoreInfo.GetCount300() ?? 0));
|
||||
sw.Write((ushort)(score.ScoreInfo.GetCount100() ?? 0));
|
||||
sw.Write((ushort)(score.ScoreInfo.GetCount50() ?? 0));
|
||||
sw.Write((ushort)(score.ScoreInfo.GetCountGeki() ?? 0));
|
||||
sw.Write((ushort)(score.ScoreInfo.GetCountKatu() ?? 0));
|
||||
sw.Write((ushort)(score.ScoreInfo.GetCountMiss() ?? 0));
|
||||
sw.Write((int)(score.ScoreInfo.TotalScore));
|
||||
sw.Write((ushort)score.ScoreInfo.MaxCombo);
|
||||
sw.Write(score.ScoreInfo.Combo == score.ScoreInfo.MaxCombo);
|
||||
sw.Write((int)score.ScoreInfo.Ruleset.CreateInstance().ConvertToLegacyMods(score.ScoreInfo.Mods));
|
||||
|
||||
sw.Write(getHpGraphFormatted());
|
||||
sw.Write(score.ScoreInfo.Date.DateTime);
|
||||
sw.WriteByteArray(createReplayData());
|
||||
sw.Write((long)0);
|
||||
writeModSpecificData(score.ScoreInfo, sw);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeModSpecificData(ScoreInfo score, SerializationWriter sw)
|
||||
{
|
||||
}
|
||||
|
||||
private byte[] createReplayData()
|
||||
{
|
||||
var content = new ASCIIEncoding().GetBytes(replayStringContent);
|
||||
|
||||
using (var outStream = new MemoryStream())
|
||||
{
|
||||
using (var lzma = new LzmaStream(new LzmaEncoderProperties(false, 1 << 21, 255), false, outStream))
|
||||
{
|
||||
outStream.Write(lzma.Properties);
|
||||
|
||||
long fileSize = content.Length;
|
||||
for (int i = 0; i < 8; i++)
|
||||
outStream.WriteByte((byte)(fileSize >> (8 * i)));
|
||||
|
||||
lzma.Write(content);
|
||||
}
|
||||
|
||||
return outStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private string replayStringContent
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder replayData = new StringBuilder();
|
||||
|
||||
if (score.Replay != null)
|
||||
{
|
||||
LegacyReplayFrame lastF = new LegacyReplayFrame(0, 0, 0, ReplayButtonState.None);
|
||||
|
||||
foreach (var f in score.Replay.Frames.OfType<IConvertibleReplayFrame>().Select(f => f.ToLegacy(beatmap)))
|
||||
{
|
||||
replayData.Append(FormattableString.Invariant($"{f.Time - lastF.Time}|{f.MouseX ?? 0}|{f.MouseY ?? 0}|{(int)f.ButtonState},"));
|
||||
lastF = f;
|
||||
}
|
||||
}
|
||||
|
||||
replayData.AppendFormat(@"{0}|{1}|{2}|{3},", -12345, 0, 0, 0);
|
||||
return replayData.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private string getHpGraphFormatted()
|
||||
{
|
||||
// todo: implement, maybe?
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ namespace osu.Game.Scoring
|
||||
var replayFilename = score.Files.First(f => f.Filename.EndsWith(".osr", StringComparison.InvariantCultureIgnoreCase)).FileInfo.StoragePath;
|
||||
|
||||
using (var stream = store.GetStream(replayFilename))
|
||||
Replay = new DatabasedLegacyScoreParser(rulesets, beatmaps).Parse(stream).Replay;
|
||||
Replay = new DatabasedLegacyScoreDecoder(rulesets, beatmaps).Parse(stream).Replay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ namespace osu.Game.Scoring
|
||||
{
|
||||
try
|
||||
{
|
||||
return new DatabasedLegacyScoreParser(rulesets, beatmaps()).Parse(stream).ScoreInfo;
|
||||
return new DatabasedLegacyScoreDecoder(rulesets, beatmaps()).Parse(stream).ScoreInfo;
|
||||
}
|
||||
catch (LegacyScoreParser.BeatmapNotFoundException e)
|
||||
catch (LegacyScoreDecoder.BeatmapNotFoundException e)
|
||||
{
|
||||
Logger.Log(e.Message, LoggingTarget.Information, LogLevel.Error);
|
||||
return null;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
@ -17,13 +18,16 @@ using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users;
|
||||
@ -117,6 +121,23 @@ namespace osu.Game.Screens.Play
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
PrepareReplay();
|
||||
}
|
||||
|
||||
private Replay recordingReplay;
|
||||
|
||||
/// <summary>
|
||||
/// Run any recording / playback setup for replays.
|
||||
/// </summary>
|
||||
protected virtual void PrepareReplay()
|
||||
{
|
||||
DrawableRuleset.SetRecordTarget(recordingReplay = new Replay());
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuConfigManager config)
|
||||
{
|
||||
@ -622,19 +643,33 @@ namespace osu.Game.Screens.Play
|
||||
completionProgressDelegate?.Cancel();
|
||||
completionProgressDelegate = Schedule(delegate
|
||||
{
|
||||
var score = CreateScore();
|
||||
|
||||
if (DrawableRuleset.ReplayScore == null)
|
||||
{
|
||||
scoreManager.Import(score).ContinueWith(_ => Schedule(() =>
|
||||
{
|
||||
// screen may be in the exiting transition phase.
|
||||
if (this.IsCurrentScreen())
|
||||
this.Push(CreateResults(score));
|
||||
}));
|
||||
}
|
||||
if (DrawableRuleset.ReplayScore != null)
|
||||
this.Push(CreateResults(DrawableRuleset.ReplayScore.ScoreInfo));
|
||||
else
|
||||
this.Push(CreateResults(score));
|
||||
{
|
||||
var score = new Score { ScoreInfo = CreateScore() };
|
||||
|
||||
LegacyByteArrayReader replayReader = null;
|
||||
|
||||
if (recordingReplay?.Frames.Count > 0)
|
||||
{
|
||||
score.Replay = recordingReplay;
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
new LegacyScoreEncoder(score, gameplayBeatmap).Encode(stream);
|
||||
replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr");
|
||||
}
|
||||
}
|
||||
|
||||
scoreManager.Import(score.ScoreInfo, replayReader)
|
||||
.ContinueWith(imported => Schedule(() =>
|
||||
{
|
||||
// screen may be in the exiting transition phase.
|
||||
if (this.IsCurrentScreen())
|
||||
this.Push(CreateResults(imported.Result));
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,8 @@ namespace osu.Game.Screens.Play
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
protected override void PrepareReplay()
|
||||
{
|
||||
base.LoadComplete();
|
||||
DrawableRuleset?.SetReplayScore(score);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
protected void Test(LegacyMods legacyMods, Type[] expectedMods)
|
||||
{
|
||||
var ruleset = CreateRuleset();
|
||||
var mods = ruleset.ConvertLegacyMods(legacyMods).ToList();
|
||||
var mods = ruleset.ConvertFromLegacyMods(legacyMods).ToList();
|
||||
Assert.AreEqual(expectedMods.Length, mods.Count);
|
||||
|
||||
foreach (var modType in expectedMods)
|
||||
|
Loading…
Reference in New Issue
Block a user