mirror of
https://github.com/ppy/osu.git
synced 2025-02-22 02:22:57 +08:00
Merge branch 'master' into fix-texture-loader-usages
This commit is contained in:
commit
f96d2f4ba4
@ -25,16 +25,22 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
private ScrollingHitObjectContainer hitObjectContainer;
|
private ScrollingHitObjectContainer hitObjectContainer;
|
||||||
|
|
||||||
[SetUpSteps]
|
[BackgroundDependencyLoader]
|
||||||
public void SetUp()
|
private void load()
|
||||||
=> AddStep("create SHOC", () => Child = hitObjectContainer = new ScrollingHitObjectContainer
|
{
|
||||||
|
Child = hitObjectContainer = new ScrollingHitObjectContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = 200,
|
Height = 200,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Clock = new FramedClock(new StopwatchClock())
|
Clock = new FramedClock(new StopwatchClock())
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUp()
|
||||||
|
=> AddStep("clear SHOC", () => hitObjectContainer.Clear(false));
|
||||||
|
|
||||||
protected void AddHitObject(DrawableHitObject hitObject)
|
protected void AddHitObject(DrawableHitObject hitObject)
|
||||||
=> AddStep("add to SHOC", () => hitObjectContainer.Add(hitObject));
|
=> AddStep("add to SHOC", () => hitObjectContainer.Add(hitObject));
|
||||||
|
@ -12,12 +12,13 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestApplyNewBarLine()
|
public void TestApplyNewBarLine()
|
||||||
{
|
{
|
||||||
DrawableBarLine barLine = new DrawableBarLine(PrepareObject(new BarLine
|
DrawableBarLine barLine = new DrawableBarLine();
|
||||||
|
|
||||||
|
AddStep("apply new bar line", () => barLine.Apply(PrepareObject(new BarLine
|
||||||
{
|
{
|
||||||
StartTime = 400,
|
StartTime = 400,
|
||||||
Major = true
|
Major = true
|
||||||
}));
|
}), null));
|
||||||
|
|
||||||
AddHitObject(barLine);
|
AddHitObject(barLine);
|
||||||
RemoveHitObject(barLine);
|
RemoveHitObject(barLine);
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneDrumRollApplication : HitObjectApplicationTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestApplyNewDrumRoll()
|
||||||
|
{
|
||||||
|
var drumRoll = new DrawableDrumRoll();
|
||||||
|
|
||||||
|
AddStep("apply new drum roll", () => drumRoll.Apply(PrepareObject(new DrumRoll
|
||||||
|
{
|
||||||
|
StartTime = 300,
|
||||||
|
Duration = 500,
|
||||||
|
IsStrong = false,
|
||||||
|
TickRate = 2
|
||||||
|
}), null));
|
||||||
|
|
||||||
|
AddHitObject(drumRoll);
|
||||||
|
RemoveHitObject(drumRoll);
|
||||||
|
|
||||||
|
AddStep("apply new drum roll", () => drumRoll.Apply(PrepareObject(new DrumRoll
|
||||||
|
{
|
||||||
|
StartTime = 150,
|
||||||
|
Duration = 400,
|
||||||
|
IsStrong = true,
|
||||||
|
TickRate = 16
|
||||||
|
}), null));
|
||||||
|
|
||||||
|
AddHitObject(drumRoll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs
Normal file
37
osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneHitApplication : HitObjectApplicationTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestApplyNewHit()
|
||||||
|
{
|
||||||
|
var hit = new DrawableHit();
|
||||||
|
|
||||||
|
AddStep("apply new hit", () => hit.Apply(PrepareObject(new Hit
|
||||||
|
{
|
||||||
|
Type = HitType.Rim,
|
||||||
|
IsStrong = false,
|
||||||
|
StartTime = 300
|
||||||
|
}), null));
|
||||||
|
|
||||||
|
AddHitObject(hit);
|
||||||
|
RemoveHitObject(hit);
|
||||||
|
|
||||||
|
AddStep("apply new hit", () => hit.Apply(PrepareObject(new Hit
|
||||||
|
{
|
||||||
|
Type = HitType.Centre,
|
||||||
|
IsStrong = true,
|
||||||
|
StartTime = 500
|
||||||
|
}), null));
|
||||||
|
|
||||||
|
AddHitObject(hit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -18,24 +19,33 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
public override void SetUpSteps()
|
public override void SetUpSteps()
|
||||||
{
|
{
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
AddAssert("has correct samples", () =>
|
|
||||||
|
var expectedSampleNames = new[]
|
||||||
{
|
{
|
||||||
var names = Player.DrawableRuleset.Playfield.AllHitObjects.OfType<DrawableHit>().Select(h => string.Join(',', h.GetSamples().Select(s => s.Name)));
|
string.Empty,
|
||||||
|
string.Empty,
|
||||||
|
string.Empty,
|
||||||
|
string.Empty,
|
||||||
|
HitSampleInfo.HIT_FINISH,
|
||||||
|
HitSampleInfo.HIT_WHISTLE,
|
||||||
|
HitSampleInfo.HIT_WHISTLE,
|
||||||
|
HitSampleInfo.HIT_WHISTLE,
|
||||||
|
};
|
||||||
|
var actualSampleNames = new List<string>();
|
||||||
|
|
||||||
var expected = new[]
|
// due to pooling we can't access all samples right away due to object re-use,
|
||||||
{
|
// so we need to collect as we go.
|
||||||
string.Empty,
|
AddStep("collect sample names", () => Player.DrawableRuleset.Playfield.NewResult += (dho, _) =>
|
||||||
string.Empty,
|
{
|
||||||
string.Empty,
|
if (!(dho is DrawableHit h))
|
||||||
string.Empty,
|
return;
|
||||||
HitSampleInfo.HIT_FINISH,
|
|
||||||
HitSampleInfo.HIT_WHISTLE,
|
|
||||||
HitSampleInfo.HIT_WHISTLE,
|
|
||||||
HitSampleInfo.HIT_WHISTLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
return names.SequenceEqual(expected);
|
actualSampleNames.Add(string.Join(',', h.GetSamples().Select(s => s.Name)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddUntilStep("all samples collected", () => actualSampleNames.Count == expectedSampleNames.Length);
|
||||||
|
|
||||||
|
AddAssert("samples are correct", () => actualSampleNames.SequenceEqual(expectedSampleNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TaikoBeatmapConversionTest().GetBeatmap("sample-to-type-conversions");
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TaikoBeatmapConversionTest().GetBeatmap("sample-to-type-conversions");
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -31,15 +32,26 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private int rollingHits;
|
private int rollingHits;
|
||||||
|
|
||||||
private Container tickContainer;
|
private readonly Container tickContainer;
|
||||||
|
|
||||||
private Color4 colourIdle;
|
private Color4 colourIdle;
|
||||||
private Color4 colourEngaged;
|
private Color4 colourEngaged;
|
||||||
|
|
||||||
public DrawableDrumRoll(DrumRoll drumRoll)
|
public DrawableDrumRoll()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableDrumRoll([CanBeNull] DrumRoll drumRoll)
|
||||||
: base(drumRoll)
|
: base(drumRoll)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
Content.Add(tickContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Depth = float.MinValue
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -47,12 +59,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
colourIdle = colours.YellowDark;
|
colourIdle = colours.YellowDark;
|
||||||
colourEngaged = colours.YellowDarker;
|
colourEngaged = colours.YellowDarker;
|
||||||
|
|
||||||
Content.Add(tickContainer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Depth = float.MinValue
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -68,6 +74,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
updateColour();
|
updateColour();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnFree()
|
||||||
|
{
|
||||||
|
base.OnFree();
|
||||||
|
rollingHits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||||
{
|
{
|
||||||
base.AddNestedHitObject(hitObject);
|
base.AddNestedHitObject(hitObject);
|
||||||
@ -83,7 +95,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
protected override void ClearNestedHitObjects()
|
protected override void ClearNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.ClearNestedHitObjects();
|
base.ClearNestedHitObjects();
|
||||||
tickContainer.Clear();
|
tickContainer.Clear(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
||||||
@ -114,7 +126,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
rollingHits = Math.Clamp(rollingHits, 0, rolling_hits_for_engaged_colour);
|
rollingHits = Math.Clamp(rollingHits, 0, rolling_hits_for_engaged_colour);
|
||||||
|
|
||||||
updateColour();
|
updateColour(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
@ -154,27 +166,34 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
Content.X = DrawHeight / 2;
|
Content.X = DrawHeight / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRoll.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this);
|
protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRoll.StrongNestedHit hitObject) => new StrongNestedHit(hitObject);
|
||||||
|
|
||||||
private void updateColour()
|
private void updateColour(double fadeDuration = 0)
|
||||||
{
|
{
|
||||||
Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1);
|
Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1);
|
||||||
(MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, 100);
|
(MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StrongNestedHit : DrawableStrongNestedHit
|
public class StrongNestedHit : DrawableStrongNestedHit
|
||||||
{
|
{
|
||||||
public StrongNestedHit(DrumRoll.StrongNestedHit nestedHit, DrawableDrumRoll drumRoll)
|
public new DrawableDrumRoll ParentHitObject => (DrawableDrumRoll)base.ParentHitObject;
|
||||||
: base(nestedHit, drumRoll)
|
|
||||||
|
public StrongNestedHit()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StrongNestedHit([CanBeNull] DrumRoll.StrongNestedHit nestedHit)
|
||||||
|
: base(nestedHit)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!MainObject.Judged)
|
if (!ParentHitObject.Judged)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ApplyResult(r => r.Type = MainObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
||||||
@ -16,7 +17,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public HitType JudgementType;
|
public HitType JudgementType;
|
||||||
|
|
||||||
public DrawableDrumRollTick(DrumRollTick tick)
|
public DrawableDrumRollTick()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableDrumRollTick([CanBeNull] DrumRollTick tick)
|
||||||
: base(tick)
|
: base(tick)
|
||||||
{
|
{
|
||||||
FillMode = FillMode.Fit;
|
FillMode = FillMode.Fit;
|
||||||
@ -61,21 +67,28 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
return UpdateResult(true);
|
return UpdateResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRollTick.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this);
|
protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRollTick.StrongNestedHit hitObject) => new StrongNestedHit(hitObject);
|
||||||
|
|
||||||
private class StrongNestedHit : DrawableStrongNestedHit
|
public class StrongNestedHit : DrawableStrongNestedHit
|
||||||
{
|
{
|
||||||
public StrongNestedHit(DrumRollTick.StrongNestedHit nestedHit, DrawableDrumRollTick tick)
|
public new DrawableDrumRollTick ParentHitObject => (DrawableDrumRollTick)base.ParentHitObject;
|
||||||
: base(nestedHit, tick)
|
|
||||||
|
public StrongNestedHit()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StrongNestedHit([CanBeNull] DrumRollTick.StrongNestedHit nestedHit)
|
||||||
|
: base(nestedHit)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!MainObject.Judged)
|
if (!ParentHitObject.Judged)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ApplyResult(r => r.Type = MainObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
|
@ -5,7 +5,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.Allocation;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -36,29 +36,51 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
private bool pressHandledThisFrame;
|
private bool pressHandledThisFrame;
|
||||||
|
|
||||||
private readonly Bindable<HitType> type;
|
private readonly Bindable<HitType> type = new Bindable<HitType>();
|
||||||
|
|
||||||
public DrawableHit(Hit hit)
|
public DrawableHit()
|
||||||
: base(hit)
|
: this(null)
|
||||||
{
|
{
|
||||||
type = HitObject.TypeBindable.GetBoundCopy();
|
|
||||||
FillMode = FillMode.Fit;
|
|
||||||
|
|
||||||
updateActionsFromType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
public DrawableHit([CanBeNull] Hit hit)
|
||||||
private void load()
|
: base(hit)
|
||||||
{
|
{
|
||||||
|
FillMode = FillMode.Fit;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
type.BindTo(HitObject.TypeBindable);
|
||||||
type.BindValueChanged(_ =>
|
type.BindValueChanged(_ =>
|
||||||
{
|
{
|
||||||
updateActionsFromType();
|
updateActionsFromType();
|
||||||
|
|
||||||
// will overwrite samples, should only be called on change.
|
// will overwrite samples, should only be called on subsequent changes
|
||||||
|
// after the initial application.
|
||||||
updateSamplesFromTypeChange();
|
updateSamplesFromTypeChange();
|
||||||
|
|
||||||
RecreatePieces();
|
RecreatePieces();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// action update also has to happen immediately on application.
|
||||||
|
updateActionsFromType();
|
||||||
|
|
||||||
|
base.OnApply();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFree()
|
||||||
|
{
|
||||||
|
base.OnFree();
|
||||||
|
|
||||||
|
type.UnbindFrom(HitObject.TypeBindable);
|
||||||
|
type.UnbindEvents();
|
||||||
|
|
||||||
|
UnproxyContent();
|
||||||
|
|
||||||
|
HitActions = null;
|
||||||
|
HitAction = null;
|
||||||
|
validActionPressed = pressHandledThisFrame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HitSampleInfo[] getRimSamples() => HitObject.Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray();
|
private HitSampleInfo[] getRimSamples() => HitObject.Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray();
|
||||||
@ -228,32 +250,37 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawableStrongNestedHit CreateStrongNestedHit(Hit.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this);
|
protected override DrawableStrongNestedHit CreateStrongNestedHit(Hit.StrongNestedHit hitObject) => new StrongNestedHit(hitObject);
|
||||||
|
|
||||||
private class StrongNestedHit : DrawableStrongNestedHit
|
public class StrongNestedHit : DrawableStrongNestedHit
|
||||||
{
|
{
|
||||||
|
public new DrawableHit ParentHitObject => (DrawableHit)base.ParentHitObject;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The lenience for the second key press.
|
/// The lenience for the second key press.
|
||||||
/// This does not adjust by map difficulty in ScoreV2 yet.
|
/// This does not adjust by map difficulty in ScoreV2 yet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const double second_hit_window = 30;
|
private const double second_hit_window = 30;
|
||||||
|
|
||||||
public new DrawableHit MainObject => (DrawableHit)base.MainObject;
|
public StrongNestedHit()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public StrongNestedHit(Hit.StrongNestedHit nestedHit, DrawableHit hit)
|
public StrongNestedHit([CanBeNull] Hit.StrongNestedHit nestedHit)
|
||||||
: base(nestedHit, hit)
|
: base(nestedHit)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!MainObject.Result.HasResult)
|
if (!ParentHitObject.Result.HasResult)
|
||||||
{
|
{
|
||||||
base.CheckForResult(userTriggered, timeOffset);
|
base.CheckForResult(userTriggered, timeOffset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MainObject.Result.IsHit)
|
if (!ParentHitObject.Result.IsHit)
|
||||||
{
|
{
|
||||||
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
return;
|
return;
|
||||||
@ -261,27 +288,27 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (timeOffset - MainObject.Result.TimeOffset > second_hit_window)
|
if (timeOffset - ParentHitObject.Result.TimeOffset > second_hit_window)
|
||||||
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.Abs(timeOffset - MainObject.Result.TimeOffset) <= second_hit_window)
|
if (Math.Abs(timeOffset - ParentHitObject.Result.TimeOffset) <= second_hit_window)
|
||||||
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(TaikoAction action)
|
||||||
{
|
{
|
||||||
// Don't process actions until the main hitobject is hit
|
// Don't process actions until the main hitobject is hit
|
||||||
if (!MainObject.IsHit)
|
if (!ParentHitObject.IsHit)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Don't process actions if the pressed button was released
|
// Don't process actions if the pressed button was released
|
||||||
if (MainObject.HitAction == null)
|
if (ParentHitObject.HitAction == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Don't handle invalid hit action presses
|
// Don't handle invalid hit action presses
|
||||||
if (!MainObject.HitActions.Contains(action))
|
if (!ParentHitObject.HitActions.Contains(action))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return UpdateResult(true);
|
return UpdateResult(true);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||||
@ -11,12 +11,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class DrawableStrongNestedHit : DrawableTaikoHitObject
|
public abstract class DrawableStrongNestedHit : DrawableTaikoHitObject
|
||||||
{
|
{
|
||||||
public readonly DrawableHitObject MainObject;
|
public new DrawableTaikoHitObject ParentHitObject => (DrawableTaikoHitObject)base.ParentHitObject;
|
||||||
|
|
||||||
protected DrawableStrongNestedHit(StrongNestedHitObject nestedHit, DrawableHitObject mainObject)
|
protected DrawableStrongNestedHit([CanBeNull] StrongNestedHitObject nestedHit)
|
||||||
: base(nestedHit)
|
: base(nestedHit)
|
||||||
{
|
{
|
||||||
MainObject = mainObject;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -35,7 +36,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
private readonly CircularContainer targetRing;
|
private readonly CircularContainer targetRing;
|
||||||
private readonly CircularContainer expandingRing;
|
private readonly CircularContainer expandingRing;
|
||||||
|
|
||||||
public DrawableSwell(Swell swell)
|
public DrawableSwell()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableSwell([CanBeNull] Swell swell)
|
||||||
: base(swell)
|
: base(swell)
|
||||||
{
|
{
|
||||||
FillMode = FillMode.Fit;
|
FillMode = FillMode.Fit;
|
||||||
@ -123,12 +129,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
});
|
});
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void OnFree()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.OnFree();
|
||||||
|
|
||||||
// We need to set this here because RelativeSizeAxes won't/can't set our size by default with a different RelativeChildSize
|
UnproxyContent();
|
||||||
Width *= Parent.RelativeChildSize.X;
|
|
||||||
|
lastWasCentre = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||||
@ -146,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
protected override void ClearNestedHitObjects()
|
protected override void ClearNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.ClearNestedHitObjects();
|
base.ClearNestedHitObjects();
|
||||||
ticks.Clear();
|
ticks.Clear(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -11,7 +12,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
public override bool DisplayResult => false;
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
public DrawableSwellTick(SwellTick hitObject)
|
public DrawableSwellTick()
|
||||||
|
: this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableSwellTick([CanBeNull] SwellTick hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
private readonly Container nonProxiedContent;
|
private readonly Container nonProxiedContent;
|
||||||
|
|
||||||
protected DrawableTaikoHitObject(TaikoHitObject hitObject)
|
protected DrawableTaikoHitObject([CanBeNull] TaikoHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
AddRangeInternal(new[]
|
AddRangeInternal(new[]
|
||||||
@ -113,25 +113,23 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
|
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
|
||||||
|
|
||||||
public new TObject HitObject;
|
public new TObject HitObject => (TObject)base.HitObject;
|
||||||
|
|
||||||
protected Vector2 BaseSize;
|
protected Vector2 BaseSize;
|
||||||
protected SkinnableDrawable MainPiece;
|
protected SkinnableDrawable MainPiece;
|
||||||
|
|
||||||
protected DrawableTaikoHitObject(TObject hitObject)
|
protected DrawableTaikoHitObject([CanBeNull] TObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
|
||||||
|
|
||||||
Anchor = Anchor.CentreLeft;
|
Anchor = Anchor.CentreLeft;
|
||||||
Origin = Anchor.Custom;
|
Origin = Anchor.Custom;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected override void OnApply()
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
|
base.OnApply();
|
||||||
RecreatePieces();
|
RecreatePieces();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -16,28 +16,38 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
where TObject : TaikoStrongableHitObject
|
where TObject : TaikoStrongableHitObject
|
||||||
where TStrongNestedObject : StrongNestedHitObject
|
where TStrongNestedObject : StrongNestedHitObject
|
||||||
{
|
{
|
||||||
private readonly Bindable<bool> isStrong;
|
private readonly Bindable<bool> isStrong = new BindableBool();
|
||||||
|
|
||||||
private readonly Container<DrawableStrongNestedHit> strongHitContainer;
|
private readonly Container<DrawableStrongNestedHit> strongHitContainer;
|
||||||
|
|
||||||
protected DrawableTaikoStrongableHitObject(TObject hitObject)
|
protected DrawableTaikoStrongableHitObject([CanBeNull] TObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
isStrong = HitObject.IsStrongBindable.GetBoundCopy();
|
|
||||||
|
|
||||||
AddInternal(strongHitContainer = new Container<DrawableStrongNestedHit>());
|
AddInternal(strongHitContainer = new Container<DrawableStrongNestedHit>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
protected override void OnApply()
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
|
isStrong.BindTo(HitObject.IsStrongBindable);
|
||||||
isStrong.BindValueChanged(_ =>
|
isStrong.BindValueChanged(_ =>
|
||||||
{
|
{
|
||||||
// will overwrite samples, should only be called on change.
|
// will overwrite samples, should only be called on subsequent changes
|
||||||
|
// after the initial application.
|
||||||
updateSamplesFromStrong();
|
updateSamplesFromStrong();
|
||||||
|
|
||||||
RecreatePieces();
|
RecreatePieces();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
base.OnApply();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFree()
|
||||||
|
{
|
||||||
|
base.OnFree();
|
||||||
|
|
||||||
|
isStrong.UnbindFrom(HitObject.IsStrongBindable);
|
||||||
|
// ensure the next application does not accidentally overwrite samples.
|
||||||
|
isStrong.UnbindEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HitSampleInfo[] getStrongSamples() => HitObject.Samples.Where(s => s.Name == HitSampleInfo.HIT_FINISH).ToArray();
|
private HitSampleInfo[] getStrongSamples() => HitObject.Samples.Where(s => s.Name == HitSampleInfo.HIT_FINISH).ToArray();
|
||||||
@ -86,7 +96,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
protected override void ClearNestedHitObjects()
|
protected override void ClearNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.ClearNestedHitObjects();
|
base.ClearNestedHitObjects();
|
||||||
strongHitContainer.Clear();
|
strongHitContainer.Clear(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
|
||||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.Taiko.Replays;
|
using osu.Game.Rulesets.Taiko.Replays;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
@ -64,22 +63,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo);
|
protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo);
|
||||||
|
|
||||||
public override DrawableHitObject<TaikoHitObject> CreateDrawableRepresentation(TaikoHitObject h)
|
public override DrawableHitObject<TaikoHitObject> CreateDrawableRepresentation(TaikoHitObject h) => null;
|
||||||
{
|
|
||||||
switch (h)
|
|
||||||
{
|
|
||||||
case Hit hit:
|
|
||||||
return new DrawableHit(hit);
|
|
||||||
|
|
||||||
case DrumRoll drumRoll:
|
|
||||||
return new DrawableDrumRoll(drumRoll);
|
|
||||||
|
|
||||||
case Swell swell:
|
|
||||||
return new DrawableSwell(swell);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
|
@ -147,6 +147,32 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
},
|
},
|
||||||
drumRollHitContainer.CreateProxy(),
|
drumRollHitContainer.CreateProxy(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RegisterPool<Hit, DrawableHit>(50);
|
||||||
|
RegisterPool<Hit.StrongNestedHit, DrawableHit.StrongNestedHit>(50);
|
||||||
|
|
||||||
|
RegisterPool<DrumRoll, DrawableDrumRoll>(5);
|
||||||
|
RegisterPool<DrumRoll.StrongNestedHit, DrawableDrumRoll.StrongNestedHit>(5);
|
||||||
|
|
||||||
|
RegisterPool<DrumRollTick, DrawableDrumRollTick>(100);
|
||||||
|
RegisterPool<DrumRollTick.StrongNestedHit, DrawableDrumRollTick.StrongNestedHit>(100);
|
||||||
|
|
||||||
|
RegisterPool<Swell, DrawableSwell>(5);
|
||||||
|
RegisterPool<SwellTick, DrawableSwellTick>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
NewResult += OnNewResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNewDrawableHitObject(DrawableHitObject drawableHitObject)
|
||||||
|
{
|
||||||
|
base.OnNewDrawableHitObject(drawableHitObject);
|
||||||
|
|
||||||
|
var taikoObject = (DrawableTaikoHitObject)drawableHitObject;
|
||||||
|
topLevelHitContainer.Add(taikoObject.CreateProxiedContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -207,9 +233,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
barLinePlayfield.Add(barLine);
|
barLinePlayfield.Add(barLine);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DrawableTaikoHitObject taikoObject:
|
case DrawableTaikoHitObject _:
|
||||||
h.OnNewResult += OnNewResult;
|
|
||||||
topLevelHitContainer.Add(taikoObject.CreateProxiedContent());
|
|
||||||
base.Add(h);
|
base.Add(h);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -226,8 +250,6 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
return barLinePlayfield.Remove(barLine);
|
return barLinePlayfield.Remove(barLine);
|
||||||
|
|
||||||
case DrawableTaikoHitObject _:
|
case DrawableTaikoHitObject _:
|
||||||
h.OnNewResult -= OnNewResult;
|
|
||||||
// todo: consider tidying of proxied content if required.
|
|
||||||
return base.Remove(h);
|
return base.Remove(h);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -248,7 +270,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
case TaikoStrongJudgement _:
|
case TaikoStrongJudgement _:
|
||||||
if (result.IsHit)
|
if (result.IsHit)
|
||||||
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit();
|
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).ParentHitObject)?.VisualiseSecondHit();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TaikoDrumRollTickJudgement _:
|
case TaikoDrumRollTickJudgement _:
|
||||||
|
@ -22,22 +22,28 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
new DrawableRoom(new Room
|
new DrawableRoom(new Room
|
||||||
{
|
{
|
||||||
Name = { Value = "Room 1" },
|
Name = { Value = "Open - ending in 1 day" },
|
||||||
Status = { Value = new RoomStatusOpen() },
|
Status = { Value = new RoomStatusOpen() },
|
||||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
|
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
|
||||||
}) { MatchingFilter = true },
|
}) { MatchingFilter = true },
|
||||||
new DrawableRoom(new Room
|
new DrawableRoom(new Room
|
||||||
{
|
{
|
||||||
Name = { Value = "Room 2" },
|
Name = { Value = "Playing - ending in 1 day" },
|
||||||
Status = { Value = new RoomStatusPlaying() },
|
Status = { Value = new RoomStatusPlaying() },
|
||||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
|
EndDate = { Value = DateTimeOffset.Now.AddDays(1) }
|
||||||
}) { MatchingFilter = true },
|
}) { MatchingFilter = true },
|
||||||
new DrawableRoom(new Room
|
new DrawableRoom(new Room
|
||||||
{
|
{
|
||||||
Name = { Value = "Room 3" },
|
Name = { Value = "Ended" },
|
||||||
Status = { Value = new RoomStatusEnded() },
|
Status = { Value = new RoomStatusEnded() },
|
||||||
EndDate = { Value = DateTimeOffset.Now }
|
EndDate = { Value = DateTimeOffset.Now }
|
||||||
}) { MatchingFilter = true },
|
}) { MatchingFilter = true },
|
||||||
|
new DrawableRoom(new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Open (realtime)" },
|
||||||
|
Status = { Value = new RoomStatusOpen() },
|
||||||
|
Category = { Value = RoomCategory.Realtime }
|
||||||
|
}) { MatchingFilter = true },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -0,0 +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 Newtonsoft.Json.Converters;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
|
namespace osu.Game.IO.Serialization.Converters
|
||||||
|
{
|
||||||
|
public class SnakeCaseStringEnumConverter : StringEnumConverter
|
||||||
|
{
|
||||||
|
public SnakeCaseStringEnumConverter()
|
||||||
|
{
|
||||||
|
NamingStrategy = new SnakeCaseNamingStrategy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -80,7 +80,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
|
|
||||||
public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
return new BeatmapSetInfo
|
var beatmapSet = new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = OnlineBeatmapSetID,
|
OnlineBeatmapSetID = OnlineBeatmapSetID,
|
||||||
Metadata = this,
|
Metadata = this,
|
||||||
@ -104,8 +104,17 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
Genre = genre,
|
Genre = genre,
|
||||||
Language = language
|
Language = language
|
||||||
},
|
},
|
||||||
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
beatmapSet.Beatmaps = beatmaps?.Select(b =>
|
||||||
|
{
|
||||||
|
var beatmap = b.ToBeatmap(rulesets);
|
||||||
|
beatmap.BeatmapSet = beatmapSet;
|
||||||
|
beatmap.Metadata = beatmapSet.Metadata;
|
||||||
|
return beatmap;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
return beatmapSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.IO.Serialization.Converters;
|
||||||
using osu.Game.Online.Multiplayer.GameTypes;
|
using osu.Game.Online.Multiplayer.GameTypes;
|
||||||
using osu.Game.Online.Multiplayer.RoomStatuses;
|
using osu.Game.Online.Multiplayer.RoomStatuses;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -35,12 +36,21 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
public readonly Bindable<int> ChannelId = new Bindable<int>();
|
public readonly Bindable<int> ChannelId = new Bindable<int>();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
[JsonProperty("category")]
|
[JsonIgnore]
|
||||||
public readonly Bindable<RoomCategory> Category = new Bindable<RoomCategory>();
|
public readonly Bindable<RoomCategory> Category = new Bindable<RoomCategory>();
|
||||||
|
|
||||||
|
// Todo: osu-framework bug (https://github.com/ppy/osu-framework/issues/4106)
|
||||||
|
[JsonProperty("category")]
|
||||||
|
[JsonConverter(typeof(SnakeCaseStringEnumConverter))]
|
||||||
|
private RoomCategory category
|
||||||
|
{
|
||||||
|
get => Category.Value;
|
||||||
|
set => Category.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public readonly Bindable<TimeSpan> Duration = new Bindable<TimeSpan>(TimeSpan.FromMinutes(30));
|
public readonly Bindable<TimeSpan?> Duration = new Bindable<TimeSpan?>();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
@ -67,27 +77,26 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
public readonly BindableList<User> RecentParticipants = new BindableList<User>();
|
public readonly BindableList<User> RecentParticipants = new BindableList<User>();
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
|
[JsonProperty("participant_count")]
|
||||||
public readonly Bindable<int> ParticipantCount = new Bindable<int>();
|
public readonly Bindable<int> ParticipantCount = new Bindable<int>();
|
||||||
|
|
||||||
// todo: TEMPORARY
|
|
||||||
[JsonProperty("participant_count")]
|
|
||||||
private int? participantCount
|
|
||||||
{
|
|
||||||
get => ParticipantCount.Value;
|
|
||||||
set => ParticipantCount.Value = value ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonProperty("duration")]
|
[JsonProperty("duration")]
|
||||||
private int duration
|
private int? duration
|
||||||
{
|
{
|
||||||
get => (int)Duration.Value.TotalMinutes;
|
get => (int?)Duration.Value?.TotalMinutes;
|
||||||
set => Duration.Value = TimeSpan.FromMinutes(value);
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
Duration.Value = null;
|
||||||
|
else
|
||||||
|
Duration.Value = TimeSpan.FromMinutes(value.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only supports retrieval for now
|
// Only supports retrieval for now
|
||||||
[Cached]
|
[Cached]
|
||||||
[JsonProperty("ends_at")]
|
[JsonProperty("ends_at")]
|
||||||
public readonly Bindable<DateTimeOffset> EndDate = new Bindable<DateTimeOffset>();
|
public readonly Bindable<DateTimeOffset?> EndDate = new Bindable<DateTimeOffset?>();
|
||||||
|
|
||||||
// Todo: Find a better way to do this (https://github.com/ppy/osu-framework/issues/1930)
|
// Todo: Find a better way to do this (https://github.com/ppy/osu-framework/issues/1930)
|
||||||
[JsonProperty("max_attempts", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
[JsonProperty("max_attempts", DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||||
@ -133,7 +142,7 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
ParticipantCount.Value = other.ParticipantCount.Value;
|
ParticipantCount.Value = other.ParticipantCount.Value;
|
||||||
EndDate.Value = other.EndDate.Value;
|
EndDate.Value = other.EndDate.Value;
|
||||||
|
|
||||||
if (DateTimeOffset.Now >= EndDate.Value)
|
if (EndDate.Value != null && DateTimeOffset.Now >= EndDate.Value)
|
||||||
Status.Value = new RoomStatusEnded();
|
Status.Value = new RoomStatusEnded();
|
||||||
|
|
||||||
if (!Playlist.SequenceEqual(other.Playlist))
|
if (!Playlist.SequenceEqual(other.Playlist))
|
||||||
|
@ -303,7 +303,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
samplesBindable.CollectionChanged -= onSamplesChanged;
|
samplesBindable.CollectionChanged -= onSamplesChanged;
|
||||||
|
|
||||||
// Release the samples for other hitobjects to use.
|
// Release the samples for other hitobjects to use.
|
||||||
Samples.Samples = null;
|
if (Samples != null)
|
||||||
|
Samples.Samples = null;
|
||||||
|
|
||||||
if (nestedHitObjects.IsValueCreated)
|
if (nestedHitObjects.IsValueCreated)
|
||||||
{
|
{
|
||||||
|
@ -112,7 +112,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
{
|
{
|
||||||
currentJoinRoomRequest?.Cancel();
|
currentJoinRoomRequest?.Cancel();
|
||||||
|
|
||||||
if (JoinedRoom == null)
|
if (JoinedRoom.Value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
api.Queue(new PartRoomRequest(joinedRoom.Value));
|
api.Queue(new PartRoomRequest(joinedRoom.Value));
|
||||||
|
@ -48,16 +48,23 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
|
|
||||||
private class EndDatePart : DrawableDate
|
private class EndDatePart : DrawableDate
|
||||||
{
|
{
|
||||||
public readonly IBindable<DateTimeOffset> EndDate = new Bindable<DateTimeOffset>();
|
public readonly IBindable<DateTimeOffset?> EndDate = new Bindable<DateTimeOffset?>();
|
||||||
|
|
||||||
public EndDatePart()
|
public EndDatePart()
|
||||||
: base(DateTimeOffset.UtcNow)
|
: base(DateTimeOffset.UtcNow)
|
||||||
{
|
{
|
||||||
EndDate.BindValueChanged(date => Date = date.NewValue);
|
EndDate.BindValueChanged(date =>
|
||||||
|
{
|
||||||
|
// If null, set a very large future date to prevent unnecessary schedules.
|
||||||
|
Date = date.NewValue ?? DateTimeOffset.Now.AddYears(1);
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string Format()
|
protected override string Format()
|
||||||
{
|
{
|
||||||
|
if (EndDate.Value == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
var diffToNow = Date.Subtract(DateTimeOffset.Now);
|
var diffToNow = Date.Subtract(DateTimeOffset.Now);
|
||||||
|
|
||||||
if (diffToNow.TotalSeconds < -5)
|
if (diffToNow.TotalSeconds < -5)
|
||||||
|
@ -325,7 +325,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
|||||||
Availability.BindValueChanged(availability => AvailabilityPicker.Current.Value = availability.NewValue, true);
|
Availability.BindValueChanged(availability => AvailabilityPicker.Current.Value = availability.NewValue, true);
|
||||||
Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true);
|
Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true);
|
||||||
MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true);
|
MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true);
|
||||||
Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue, true);
|
Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue ?? TimeSpan.FromMinutes(30), true);
|
||||||
|
|
||||||
playlist.Items.BindTo(Playlist);
|
playlist.Items.BindTo(Playlist);
|
||||||
Playlist.BindCollectionChanged(onPlaylistChanged, true);
|
Playlist.BindCollectionChanged(onPlaylistChanged, true);
|
||||||
|
@ -40,12 +40,12 @@ namespace osu.Game.Screens.Multi
|
|||||||
protected Bindable<int?> MaxParticipants { get; private set; }
|
protected Bindable<int?> MaxParticipants { get; private set; }
|
||||||
|
|
||||||
[Resolved(typeof(Room))]
|
[Resolved(typeof(Room))]
|
||||||
protected Bindable<DateTimeOffset> EndDate { get; private set; }
|
protected Bindable<DateTimeOffset?> EndDate { get; private set; }
|
||||||
|
|
||||||
[Resolved(typeof(Room))]
|
[Resolved(typeof(Room))]
|
||||||
protected Bindable<RoomAvailability> Availability { get; private set; }
|
protected Bindable<RoomAvailability> Availability { get; private set; }
|
||||||
|
|
||||||
[Resolved(typeof(Room))]
|
[Resolved(typeof(Room))]
|
||||||
protected Bindable<TimeSpan> Duration { get; private set; }
|
protected Bindable<TimeSpan?> Duration { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
|
|||||||
|
|
||||||
public override void PartRoom()
|
public override void PartRoom()
|
||||||
{
|
{
|
||||||
if (JoinedRoom == null)
|
if (JoinedRoom.Value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var joinedRoom = JoinedRoom.Value;
|
var joinedRoom = JoinedRoom.Value;
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Screens.Multi.Timeshift
|
|||||||
public class TimeshiftReadyButton : ReadyButton
|
public class TimeshiftReadyButton : ReadyButton
|
||||||
{
|
{
|
||||||
[Resolved(typeof(Room), nameof(Room.EndDate))]
|
[Resolved(typeof(Room), nameof(Room.EndDate))]
|
||||||
private Bindable<DateTimeOffset> endDate { get; set; }
|
private Bindable<DateTimeOffset?> endDate { get; set; }
|
||||||
|
|
||||||
public TimeshiftReadyButton()
|
public TimeshiftReadyButton()
|
||||||
{
|
{
|
||||||
@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Timeshift
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
Enabled.Value = DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(GameBeatmap.Value.Track.Length) < endDate.Value;
|
Enabled.Value = endDate.Value != null && DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(GameBeatmap.Value.Track.Length) < endDate.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ using osu.Game.Screens.Multi.RealtimeMultiplayer;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual.RealtimeMultiplayer
|
namespace osu.Game.Tests.Visual.RealtimeMultiplayer
|
||||||
{
|
{
|
||||||
public class RealtimeMultiplayerTestScene : MultiplayerTestScene
|
public abstract class RealtimeMultiplayerTestScene : MultiplayerTestScene
|
||||||
{
|
{
|
||||||
[Cached(typeof(StatefulMultiplayerClient))]
|
[Cached(typeof(StatefulMultiplayerClient))]
|
||||||
public TestRealtimeMultiplayerClient Client { get; }
|
public TestRealtimeMultiplayerClient Client { get; }
|
||||||
@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
|
|||||||
|
|
||||||
private readonly bool joinRoom;
|
private readonly bool joinRoom;
|
||||||
|
|
||||||
public RealtimeMultiplayerTestScene(bool joinRoom = true)
|
protected RealtimeMultiplayerTestScene(bool joinRoom = true)
|
||||||
{
|
{
|
||||||
this.joinRoom = joinRoom;
|
this.joinRoom = joinRoom;
|
||||||
base.Content.Add(content = new TestRealtimeRoomContainer { RelativeSizeAxes = Axes.Both });
|
base.Content.Add(content = new TestRealtimeRoomContainer { RelativeSizeAxes = Axes.Both });
|
||||||
|
Loading…
Reference in New Issue
Block a user