1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-12 13:17:26 +08:00

Merge branch 'tournament-tools' of https://github.com/peppy/osu into tournament-tools

This commit is contained in:
Dean Herbert 2018-12-05 13:08:55 +09:00
commit 51cb7dc774
228 changed files with 4297 additions and 920 deletions

View File

@ -5,20 +5,17 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModAutoplay : ModAutoplay<CatchHitObject>
{
protected override Score CreateReplayScore(Beatmap<CatchHitObject> beatmap)
protected override Score CreateReplayScore(Beatmap<CatchHitObject> beatmap) => new Score
{
return new Score
{
User = new User { Username = "osu!salad!" },
Replay = new CatchAutoGenerator(beatmap).Generate(),
};
}
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
Replay = new CatchAutoGenerator(beatmap).Generate(),
};
}
}

View File

@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
private void load()
{
// todo: this should come from the skin.
AccentColour = colourForRrepesentation(HitObject.VisualRepresentation);
AccentColour = colourForRepresentation(HitObject.VisualRepresentation);
InternalChildren = new[]
{
@ -275,7 +275,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
}
private Color4 colourForRrepesentation(FruitVisualRepresentation representation)
private Color4 colourForRepresentation(FruitVisualRepresentation representation)
{
switch (representation)
{

View File

@ -5,10 +5,10 @@ using System;
using System.Linq;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Replays;
using osu.Game.Users;
namespace osu.Game.Rulesets.Catch.Replays
{
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Replays
public CatchAutoGenerator(Beatmap<CatchHitObject> beatmap)
: base(beatmap)
{
Replay = new Replay { User = new User { Username = @"Autoplay" } };
Replay = new Replay();
}
protected Replay Replay;

View File

@ -4,6 +4,7 @@
using System.Collections.Generic;
using osu.Framework.Input.StateChanges;
using osu.Framework.MathUtils;
using osu.Game.Replays;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Catch.Replays

View File

@ -2,9 +2,9 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Legacy;
using osu.Game.Rulesets.Replays.Types;
namespace osu.Game.Rulesets.Catch.Replays

View File

@ -5,12 +5,12 @@ using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Input.Handlers;
using osu.Game.Replays;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;

View File

@ -0,0 +1,52 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Rulesets.Mania.Edit;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Tests.Visual;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests
{
[Cached(Type = typeof(IManiaHitObjectComposer))]
public abstract class ManiaPlacementBlueprintTestCase : PlacementBlueprintTestCase, IManiaHitObjectComposer
{
private readonly Column column;
protected ManiaPlacementBlueprintTestCase()
{
Add(column = new Column(0)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AccentColour = Color4.OrangeRed,
Clock = new FramedClock(new StopwatchClock()), // No scroll
});
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs(((ScrollingTestContainer)HitObjectContainer).ScrollingInfo);
return dependencies;
}
protected override Container CreateHitObjectContainer() => new ScrollingTestContainer(ScrollingDirection.Down) { RelativeSizeAxes = Axes.Both };
protected override void AddHitObject(DrawableHitObject hitObject) => column.Add((DrawableManiaHitObject)hitObject);
public Column ColumnAt(Vector2 screenSpacePosition) => column;
public int TotalColumns => 1;
}
}

View File

@ -0,0 +1,38 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Rulesets.Mania.Edit;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Tests.Visual;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Tests
{
[Cached(Type = typeof(IManiaHitObjectComposer))]
public abstract class ManiaSelectionBlueprintTestCase : SelectionBlueprintTestCase, IManiaHitObjectComposer
{
[Cached(Type = typeof(IAdjustableClock))]
private readonly IAdjustableClock clock = new StopwatchClock();
private readonly Column column;
protected ManiaSelectionBlueprintTestCase()
{
Add(column = new Column(0)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AccentColour = Color4.OrangeRed,
Clock = new FramedClock(new StopwatchClock()), // No scroll
});
}
public Column ColumnAt(Vector2 screenSpacePosition) => column;
public int TotalColumns => 1;
}
}

View File

@ -49,8 +49,8 @@ namespace osu.Game.Rulesets.Mania.Tests
Spacing = new Vector2(20, 0),
Children = new[]
{
createColumn(ScrollingDirection.Up, ManiaAction.Key1),
createColumn(ScrollingDirection.Down, ManiaAction.Key2)
createColumn(ScrollingDirection.Up, ManiaAction.Key1, 0),
createColumn(ScrollingDirection.Down, ManiaAction.Key2, 1)
}
};
}
@ -85,9 +85,9 @@ namespace osu.Game.Rulesets.Mania.Tests
}
}
private Drawable createColumn(ScrollingDirection direction, ManiaAction action)
private Drawable createColumn(ScrollingDirection direction, ManiaAction action, int index)
{
var column = new Column
var column = new Column(index)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,

View File

@ -0,0 +1,18 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Tests
{
public class TestCaseHoldNotePlacementBlueprint : ManiaPlacementBlueprintTestCase
{
protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHoldNote((HoldNote)hitObject);
protected override PlacementBlueprint CreateBlueprint() => new HoldNotePlacementBlueprint();
}
}

View File

@ -15,7 +15,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests
{
public class TestCaseHoldNoteSelectionBlueprint : SelectionBlueprintTestCase
public class TestCaseHoldNoteSelectionBlueprint : ManiaSelectionBlueprintTestCase
{
private readonly DrawableHoldNote drawableObject;

View File

@ -0,0 +1,18 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Tests
{
public class TestCaseNotePlacementBlueprint : ManiaPlacementBlueprintTestCase
{
protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableNote((Note)hitObject);
protected override PlacementBlueprint CreateBlueprint() => new NotePlacementBlueprint();
}
}

View File

@ -15,7 +15,7 @@ using osuTK;
namespace osu.Game.Rulesets.Mania.Tests
{
public class TestCaseNoteSelectionBlueprint : SelectionBlueprintTestCase
public class TestCaseNoteSelectionBlueprint : ManiaSelectionBlueprintTestCase
{
private readonly DrawableNote drawableObject;

View File

@ -8,6 +8,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Mania.Difficulty
{
@ -27,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
private int countMeh;
private int countMiss;
public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
: base(ruleset, beatmap, score)
{
}

View File

@ -0,0 +1,21 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
{
public class EditBodyPiece : BodyPiece
{
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.Yellow;
Background.Alpha = 0.5f;
Foreground.Alpha = 0;
}
}
}

View File

@ -0,0 +1,74 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
using osu.Game.Rulesets.Mania.Objects;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
public class HoldNotePlacementBlueprint : ManiaPlacementBlueprint<HoldNote>
{
private readonly EditBodyPiece bodyPiece;
private readonly EditNotePiece headPiece;
private readonly EditNotePiece tailPiece;
public HoldNotePlacementBlueprint()
: base(new HoldNote())
{
RelativeSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
bodyPiece = new EditBodyPiece { Origin = Anchor.TopCentre },
headPiece = new EditNotePiece { Origin = Anchor.Centre },
tailPiece = new EditNotePiece { Origin = Anchor.Centre }
};
}
protected override void Update()
{
base.Update();
if (Column != null)
{
headPiece.Y = PositionAt(HitObject.StartTime);
tailPiece.Y = PositionAt(HitObject.EndTime);
}
var topPosition = new Vector2(headPiece.DrawPosition.X, Math.Min(headPiece.DrawPosition.Y, tailPiece.DrawPosition.Y));
var bottomPosition = new Vector2(headPiece.DrawPosition.X, Math.Max(headPiece.DrawPosition.Y, tailPiece.DrawPosition.Y));
bodyPiece.Position = topPosition;
bodyPiece.Width = headPiece.Width;
bodyPiece.Height = (bottomPosition - topPosition).Y;
}
private double originalStartTime;
protected override bool OnMouseMove(MouseMoveEvent e)
{
base.OnMouseMove(e);
if (PlacementBegun)
{
var endTime = TimeAt(e.ScreenSpaceMousePosition);
HitObject.StartTime = endTime < originalStartTime ? endTime : originalStartTime;
HitObject.Duration = Math.Abs(endTime - originalStartTime);
}
else
{
headPiece.Width = tailPiece.Width = SnappedWidth;
headPiece.X = tailPiece.X = SnappedMousePosition.X;
originalStartTime = HitObject.StartTime = TimeAt(e.ScreenSpaceMousePosition);
}
return true;
}
}
}

View File

@ -49,7 +49,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
base.Update();
Size = HitObject.DrawSize + new Vector2(0, HitObject.Tail.DrawHeight);
Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
// This is a side-effect of not matching the hitobject's anchors/origins, which is kinda hard to do
// When scrolling upwards our origin is already at the top of the head note (which is the intended location),

View File

@ -0,0 +1,118 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
public abstract class ManiaPlacementBlueprint<T> : PlacementBlueprint,
IRequireHighFrequencyMousePosition // the playfield could be moving behind us
where T : ManiaHitObject
{
protected new T HitObject => (T)base.HitObject;
protected Column Column;
/// <summary>
/// The current mouse position, snapped to the closest column.
/// </summary>
protected Vector2 SnappedMousePosition { get; private set; }
/// <summary>
/// The width of the closest column to the current mouse position.
/// </summary>
protected float SnappedWidth { get; private set; }
[Resolved]
private IManiaHitObjectComposer composer { get; set; }
[Resolved]
private IScrollingInfo scrollingInfo { get; set; }
protected ManiaPlacementBlueprint(T hitObject)
: base(hitObject)
{
RelativeSizeAxes = Axes.None;
}
protected override bool OnMouseDown(MouseDownEvent e)
{
if (Column == null)
return base.OnMouseDown(e);
HitObject.StartTime = TimeAt(e.ScreenSpaceMousePosition);
HitObject.Column = Column.Index;
BeginPlacement();
return true;
}
protected override bool OnMouseUp(MouseUpEvent e)
{
EndPlacement();
return base.OnMouseUp(e);
}
protected override bool OnMouseMove(MouseMoveEvent e)
{
if (!PlacementBegun)
Column = ColumnAt(e.ScreenSpaceMousePosition);
if (Column == null) return false;
SnappedWidth = Column.DrawWidth;
// Snap to the column
var parentPos = Parent.ToLocalSpace(Column.ToScreenSpace(new Vector2(Column.DrawWidth / 2, 0)));
SnappedMousePosition = new Vector2(parentPos.X, e.MousePosition.Y);
return true;
}
protected double TimeAt(Vector2 screenSpacePosition)
{
if (Column == null)
return 0;
var hitObjectContainer = Column.HitObjectContainer;
// If we're scrolling downwards, a position of 0 is actually further away from the hit target
// so we need to flip the vertical coordinate in the hitobject container's space
var hitObjectPos = Column.HitObjectContainer.ToLocalSpace(applyPositionOffset(screenSpacePosition, false)).Y;
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
hitObjectPos = hitObjectContainer.DrawHeight - hitObjectPos;
return scrollingInfo.Algorithm.TimeAt(hitObjectPos,
EditorClock.CurrentTime,
scrollingInfo.TimeRange.Value,
hitObjectContainer.DrawHeight);
}
protected float PositionAt(double time)
{
var pos = scrollingInfo.Algorithm.PositionAt(time,
EditorClock.CurrentTime,
scrollingInfo.TimeRange.Value,
Column.HitObjectContainer.DrawHeight);
return applyPositionOffset(Column.HitObjectContainer.ToSpaceOfOtherDrawable(new Vector2(0, pos), Parent), true).Y;
}
protected Column ColumnAt(Vector2 screenSpacePosition)
=> composer.ColumnAt(applyPositionOffset(screenSpacePosition, false));
private Vector2 applyPositionOffset(Vector2 position, bool reverse)
{
position.Y += (scrollingInfo.Direction.Value == ScrollingDirection.Up && !reverse ? -1 : 1) * NotePiece.NOTE_HEIGHT / 2;
return position;
}
}
}

View File

@ -1,23 +1,80 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
using osu.Framework.Timing;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
public class ManiaSelectionBlueprint : SelectionBlueprint
{
public Vector2 ScreenSpaceDragPosition { get; private set; }
public Vector2 DragPosition { get; private set; }
protected new DrawableManiaHitObject HitObject => (DrawableManiaHitObject)base.HitObject;
protected IClock EditorClock { get; private set; }
[Resolved]
private IScrollingInfo scrollingInfo { get; set; }
[Resolved]
private IManiaHitObjectComposer composer { get; set; }
public ManiaSelectionBlueprint(DrawableHitObject hitObject)
: base(hitObject)
{
RelativeSizeAxes = Axes.None;
}
public override void AdjustPosition(DragEvent dragEvent)
[BackgroundDependencyLoader]
private void load(IAdjustableClock clock)
{
EditorClock = clock;
}
protected override void Update()
{
base.Update();
Position = Parent.ToLocalSpace(HitObject.ToScreenSpace(Vector2.Zero));
}
protected override bool OnMouseDown(MouseDownEvent e)
{
ScreenSpaceDragPosition = e.ScreenSpaceMousePosition;
DragPosition = HitObject.ToLocalSpace(e.ScreenSpaceMousePosition);
return base.OnMouseDown(e);
}
protected override bool OnDrag(DragEvent e)
{
var result = base.OnDrag(e);
ScreenSpaceDragPosition = e.ScreenSpaceMousePosition;
DragPosition = HitObject.ToLocalSpace(e.ScreenSpaceMousePosition);
return result;
}
public override void Show()
{
HitObject.AlwaysAlive = true;
base.Show();
}
public override void Hide()
{
HitObject.AlwaysAlive = false;
base.Hide();
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
using osu.Game.Rulesets.Mania.Objects;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
public class NotePlacementBlueprint : ManiaPlacementBlueprint<Note>
{
public NotePlacementBlueprint()
: base(new Note())
{
Origin = Anchor.Centre;
AutoSizeAxes = Axes.Y;
InternalChild = new EditNotePiece { RelativeSizeAxes = Axes.X };
}
protected override void Update()
{
base.Update();
Width = SnappedWidth;
Position = SnappedMousePosition;
}
}
}

View File

@ -20,7 +20,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
base.Update();
Size = HitObject.DrawSize;
Position = Parent.ToLocalSpace(HitObject.ScreenSpaceDrawQuad.TopLeft);
}
}
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
namespace osu.Game.Rulesets.Mania.Edit
{
public class HoldNoteCompositionTool : HitObjectCompositionTool
{
public HoldNoteCompositionTool()
: base("Hold")
{
}
public override PlacementBlueprint CreatePlacementBlueprint() => new HoldNotePlacementBlueprint();
}
}

View File

@ -0,0 +1,15 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mania.UI;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit
{
public interface IManiaHitObjectComposer
{
Column ColumnAt(Vector2 screenSpacePosition);
int TotalColumns { get; }
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
@ -11,33 +10,54 @@ using osu.Game.Rulesets.Objects.Drawables;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Compose.Components;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit
{
public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>
[Cached(Type = typeof(IManiaHitObjectComposer))]
public class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>, IManiaHitObjectComposer
{
protected new ManiaEditRulesetContainer RulesetContainer { get; private set; }
public ManiaHitObjectComposer(Ruleset ruleset)
: base(ruleset)
{
}
/// <summary>
/// Retrieves the column that intersects a screen-space position.
/// </summary>
/// <param name="screenSpacePosition">The screen-space position.</param>
/// <returns>The column which intersects with <paramref name="screenSpacePosition"/>.</returns>
public Column ColumnAt(Vector2 screenSpacePosition) => RulesetContainer.GetColumnByPosition(screenSpacePosition);
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
public int TotalColumns => ((ManiaPlayfield)RulesetContainer.Playfield).TotalColumns;
protected override RulesetContainer<ManiaHitObject> CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
{
var rulesetContainer = new ManiaEditRulesetContainer(ruleset, beatmap);
RulesetContainer = new ManiaEditRulesetContainer(ruleset, beatmap);
// This is the earliest we can cache the scrolling info to ourselves, before masks are added to the hierarchy and inject it
dependencies.CacheAs(rulesetContainer.ScrollingInfo);
dependencies.CacheAs(RulesetContainer.ScrollingInfo);
return rulesetContainer;
return RulesetContainer;
}
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => Array.Empty<HitObjectCompositionTool>();
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]
{
new NoteCompositionTool(),
new HoldNoteCompositionTool()
};
public override SelectionHandler CreateSelectionHandler() => new ManiaSelectionHandler();
public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
{

View File

@ -0,0 +1,125 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Input.Events;
using osu.Framework.Timing;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Screens.Edit.Compose.Components;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit
{
public class ManiaSelectionHandler : SelectionHandler
{
[Resolved]
private IScrollingInfo scrollingInfo { get; set; }
[Resolved]
private IManiaHitObjectComposer composer { get; set; }
private IClock editorClock;
[BackgroundDependencyLoader]
private void load(IAdjustableClock clock)
{
editorClock = clock;
}
public override void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent)
{
adjustOrigins((ManiaSelectionBlueprint)blueprint);
performDragMovement(dragEvent);
performColumnMovement(dragEvent);
base.HandleDrag(blueprint, dragEvent);
}
/// <summary>
/// Ensures that the position of hitobjects remains centred to the mouse position.
/// E.g. The hitobject position will change if the editor scrolls while a hitobject is dragged.
/// </summary>
/// <param name="reference">The <see cref="ManiaSelectionBlueprint"/> that received the drag event.</param>
private void adjustOrigins(ManiaSelectionBlueprint reference)
{
var referenceParent = (HitObjectContainer)reference.HitObject.Parent;
float offsetFromReferenceOrigin = reference.DragPosition.Y - reference.HitObject.OriginPosition.Y;
float targetPosition = referenceParent.ToLocalSpace(reference.ScreenSpaceDragPosition).Y - offsetFromReferenceOrigin;
// Flip the vertical coordinate space when scrolling downwards
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
targetPosition = targetPosition - referenceParent.DrawHeight;
float movementDelta = targetPosition - reference.HitObject.Position.Y;
foreach (var b in SelectedBlueprints.OfType<ManiaSelectionBlueprint>())
b.HitObject.Y += movementDelta;
}
private void performDragMovement(DragEvent dragEvent)
{
foreach (var b in SelectedBlueprints)
{
var hitObject = b.HitObject;
var objectParent = (HitObjectContainer)hitObject.Parent;
// Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame
// without the position having been updated by the parenting ScrollingHitObjectContainer
hitObject.Y += dragEvent.Delta.Y;
float targetPosition;
// If we're scrolling downwards, a position of 0 is actually further away from the hit target
// so we need to flip the vertical coordinate in the hitobject container's space
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
targetPosition = -hitObject.Position.Y;
else
targetPosition = hitObject.Position.Y;
objectParent.Remove(hitObject);
hitObject.HitObject.StartTime = scrollingInfo.Algorithm.TimeAt(targetPosition,
editorClock.CurrentTime,
scrollingInfo.TimeRange.Value,
objectParent.DrawHeight);
objectParent.Add(hitObject);
}
}
private void performColumnMovement(DragEvent dragEvent)
{
var lastColumn = composer.ColumnAt(dragEvent.ScreenSpaceLastMousePosition);
var currentColumn = composer.ColumnAt(dragEvent.ScreenSpaceMousePosition);
if (lastColumn == null || currentColumn == null)
return;
int columnDelta = currentColumn.Index - lastColumn.Index;
if (columnDelta == 0)
return;
int minColumn = int.MaxValue;
int maxColumn = int.MinValue;
foreach (var obj in SelectedHitObjects.OfType<ManiaHitObject>())
{
if (obj.Column < minColumn)
minColumn = obj.Column;
if (obj.Column > maxColumn)
maxColumn = obj.Column;
}
columnDelta = MathHelper.Clamp(columnDelta, -minColumn, composer.TotalColumns - 1 - maxColumn);
foreach (var obj in SelectedHitObjects.OfType<ManiaHitObject>())
obj.Column += columnDelta;
}
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects;
namespace osu.Game.Rulesets.Mania.Edit
{
public class NoteCompositionTool : HitObjectCompositionTool
{
public NoteCompositionTool()
: base(nameof(Note))
{
}
public override PlacementBlueprint CreatePlacementBlueprint() => new NotePlacementBlueprint();
}
}

View File

@ -24,7 +24,7 @@ using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Mania.Edit;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Mania
{
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Mania
{
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this);

View File

@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public abstract class ManiaKeyMod : Mod, IApplicableToBeatmapConverter
{
public override string ShortenedName => Name;
public override string Acronym => Name;
public abstract int KeyCount { get; }
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier

View File

@ -6,20 +6,17 @@ using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModAutoplay : ModAutoplay<ManiaHitObject>
{
protected override Score CreateReplayScore(Beatmap<ManiaHitObject> beatmap)
protected override Score CreateReplayScore(Beatmap<ManiaHitObject> beatmap) => new Score
{
return new Score
{
User = new User { Username = "osu!topus!" },
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
};
}
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
};
}
}

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToBeatmap<ManiaHitObject>
{
public override string Name => "Dual Stages";
public override string ShortenedName => "DS";
public override string Acronym => "DS";
public override string Description => @"Double the stages, double the fun!";
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;

View File

@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModFadeIn : Mod
{
public override string Name => "Fade In";
public override string ShortenedName => "FI";
public override string Acronym => "FI";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => @"Keys appear out of nowhere!";

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 1;
public override string Name => "One Key";
public override string ShortenedName => "1K";
public override string Acronym => "1K";
public override string Description => @"Play with one key.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 2;
public override string Name => "Two Keys";
public override string ShortenedName => "2K";
public override string Acronym => "2K";
public override string Description => @"Play with two keys.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 3;
public override string Name => "Three Keys";
public override string ShortenedName => "3K";
public override string Acronym => "3K";
public override string Description => @"Play with three keys.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 4;
public override string Name => "Four Keys";
public override string ShortenedName => "4K";
public override string Acronym => "4K";
public override string Description => @"Play with four keys.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 5;
public override string Name => "Five Keys";
public override string ShortenedName => "5K";
public override string Acronym => "5K";
public override string Description => @"Play with five keys.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 6;
public override string Name => "Six Keys";
public override string ShortenedName => "6K";
public override string Acronym => "6K";
public override string Description => @"Play with six keys.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 7;
public override string Name => "Seven Keys";
public override string ShortenedName => "7K";
public override string Acronym => "7K";
public override string Description => @"Play with seven keys.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 8;
public override string Name => "Eight Keys";
public override string ShortenedName => "8K";
public override string Acronym => "8K";
public override string Description => @"Play with eight keys.";
}
}

View File

@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override int KeyCount => 9;
public override string Name => "Nine Keys";
public override string ShortenedName => "9K";
public override string Acronym => "9K";
public override string Description => @"Play with nine keys.";
}
}

View File

@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModMirror : Mod, IApplicableToRulesetContainer<ManiaHitObject>
{
public override string Name => "Mirror";
public override string ShortenedName => "MR";
public override string Acronym => "MR";
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1;
public override bool Ranked => true;

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModRandom : Mod, IApplicableToRulesetContainer<ManiaHitObject>
{
public override string Name => "Random";
public override string ShortenedName => "RD";
public override string Acronym => "RD";
public override ModType Type => ModType.Conversion;
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
public override string Description => @"Shuffle around the keys!";

View File

@ -12,6 +12,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public abstract class DrawableManiaHitObject : DrawableHitObject<ManiaHitObject>
{
/// <summary>
/// Whether this <see cref="DrawableManiaHitObject"/> should always remain alive.
/// </summary>
internal bool AlwaysAlive;
/// <summary>
/// The <see cref="ManiaAction"/> which causes this <see cref="DrawableManiaHitObject{TObject}"/> to be hit.
/// </summary>
@ -34,6 +39,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Direction.BindValueChanged(OnDirectionChanged, true);
}
protected override bool ShouldBeAlive => AlwaysAlive || base.ShouldBeAlive;
protected virtual void OnDirectionChanged(ScrollingDirection direction)
{
Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;

View File

@ -15,12 +15,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// <summary>
/// Represents length-wise portion of a hold note.
/// </summary>
internal class BodyPiece : Container, IHasAccentColour
public class BodyPiece : Container, IHasAccentColour
{
private readonly Container subtractionLayer;
private readonly Drawable background;
private readonly BufferedContainer foreground;
protected readonly Drawable Background;
protected readonly BufferedContainer Foreground;
private readonly BufferedContainer subtractionContainer;
public BodyPiece()
@ -29,8 +29,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Children = new[]
{
background = new Box { RelativeSizeAxes = Axes.Both },
foreground = new BufferedContainer
Background = new Box { RelativeSizeAxes = Axes.Both },
Foreground = new BufferedContainer
{
Blending = BlendingMode.Additive,
RelativeSizeAxes = Axes.Both,
@ -123,7 +123,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Radius = DrawWidth
};
foreground.ForceRedraw();
Foreground.ForceRedraw();
subtractionContainer.ForceRedraw();
subtractionCache.Validate();
@ -137,18 +137,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
if (!IsLoaded)
return;
foreground.Colour = AccentColour.Opacity(0.5f);
background.Colour = AccentColour.Opacity(0.7f);
Foreground.Colour = AccentColour.Opacity(0.5f);
Background.Colour = AccentColour.Opacity(0.7f);
const float animation_length = 50;
foreground.ClearTransforms(false, nameof(foreground.Colour));
Foreground.ClearTransforms(false, nameof(Foreground.Colour));
if (hitting)
{
// wait for the next sync point
double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2);
using (foreground.BeginDelayedSequence(synchronisedOffset))
foreground.FadeColour(AccentColour.Lighten(0.2f), animation_length).Then().FadeColour(foreground.Colour, animation_length).Loop();
using (Foreground.BeginDelayedSequence(synchronisedOffset))
Foreground.FadeColour(AccentColour.Lighten(0.2f), animation_length).Then().FadeColour(Foreground.Colour, animation_length).Loop();
}
subtractionCache.Invalidate();

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Game.Rulesets.Mania.Objects.Types;
using osu.Game.Rulesets.Objects;
@ -8,7 +9,13 @@ namespace osu.Game.Rulesets.Mania.Objects
{
public abstract class ManiaHitObject : HitObject, IHasColumn
{
public virtual int Column { get; set; }
public readonly Bindable<int> ColumnBindable = new Bindable<int>();
public virtual int Column
{
get => ColumnBindable;
set => ColumnBindable.Value = value;
}
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
}

View File

@ -3,11 +3,11 @@
using System.Collections.Generic;
using System.Linq;
using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Users;
namespace osu.Game.Rulesets.Mania.Replays
{
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Replays
public ManiaAutoGenerator(ManiaBeatmap beatmap)
: base(beatmap)
{
Replay = new Replay { User = new User { Username = @"Autoplay" } };
Replay = new Replay();
columnActions = new ManiaAction[Beatmap.TotalColumns];

View File

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Input.StateChanges;
using osu.Game.Replays;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Mania.Replays

View File

@ -3,9 +3,9 @@
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Legacy;
using osu.Game.Rulesets.Replays.Types;
namespace osu.Game.Rulesets.Mania.Replays

View File

@ -13,6 +13,7 @@ using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.UI.Components;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
namespace osu.Game.Rulesets.Mania.UI
{
@ -21,6 +22,11 @@ namespace osu.Game.Rulesets.Mania.UI
private const float column_width = 45;
private const float special_column_width = 70;
/// <summary>
/// The index of this column as part of the whole playfield.
/// </summary>
public readonly int Index;
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
private readonly ColumnBackground background;
@ -30,8 +36,10 @@ namespace osu.Game.Rulesets.Mania.UI
internal readonly Container TopLevelContainer;
private readonly Container explosionContainer;
public Column()
public Column(int index)
{
Index = index;
RelativeSizeAxes = Axes.Y;
Width = column_width;
@ -137,6 +145,15 @@ namespace osu.Game.Rulesets.Mania.UI
HitObjectContainer.Add(hitObject);
}
public override bool Remove(DrawableHitObject h)
{
if (!base.Remove(h))
return false;
h.OnNewResult -= OnNewResult;
return true;
}
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
{
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements)
@ -165,5 +182,9 @@ namespace osu.Game.Rulesets.Mania.UI
}
public bool OnReleased(ManiaAction action) => false;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
=> DrawRectangle.Inflate(new Vector2(ManiaStage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos));
}
}

View File

@ -5,6 +5,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@ -17,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.UI
{
private readonly List<ManiaStage> stages = new List<ManiaStage>();
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => stages.Any(s => s.ReceivePositionalInputAt(screenSpacePos));
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
{
if (stageDefinitions == null)
@ -52,8 +55,42 @@ namespace osu.Game.Rulesets.Mania.UI
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
public override bool Remove(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Remove(h);
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
/// <summary>
/// Retrieves a column from a screen-space position.
/// </summary>
/// <param name="screenSpacePosition">The screen-space position.</param>
/// <returns>The column which the <paramref name="screenSpacePosition"/> lies in.</returns>
public Column GetColumnByPosition(Vector2 screenSpacePosition)
{
Column found = null;
foreach (var stage in stages)
{
foreach (var column in stage.Columns)
{
if (column.ReceivePositionalInputAt(screenSpacePosition))
{
found = column;
break;
}
}
if (found != null)
break;
}
return found;
}
/// <summary>
/// Retrieves the total amount of columns across all stages in this playfield.
/// </summary>
public int TotalColumns => stages.Sum(s => s.Columns.Count);
private ManiaStage getStageByColumn(int column)
{
int sum = 0;

View File

@ -12,6 +12,7 @@ using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Input.Handlers;
using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Mods;
@ -21,10 +22,10 @@ using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
namespace osu.Game.Rulesets.Mania.UI
{
@ -80,6 +81,13 @@ namespace osu.Game.Rulesets.Mania.UI
Config.BindWith(ManiaSetting.ScrollTime, TimeRange);
}
/// <summary>
/// Retrieves the column that intersects a screen-space position.
/// </summary>
/// <param name="screenSpacePosition">The screen-space position.</param>
/// <returns>The column which intersects with <paramref name="screenSpacePosition"/>.</returns>
public Column GetColumnByPosition(Vector2 screenSpacePosition) => Playfield.GetColumnByPosition(screenSpacePosition);
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
{
Anchor = Anchor.Centre,

View File

@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.UI
/// </summary>
public class ManiaStage : ScrollingPlayfield
{
public const float COLUMN_SPACING = 1;
public const float HIT_TARGET_POSITION = 50;
public IReadOnlyList<Column> Columns => columnFlow.Children;
@ -40,6 +42,8 @@ namespace osu.Game.Rulesets.Mania.UI
private List<Color4> normalColumnColours = new List<Color4>();
private Color4 specialColumnColour;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos));
private readonly int firstColumnIndex;
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
@ -84,8 +88,8 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Left = 1, Right = 1 },
Spacing = new Vector2(1, 0)
Padding = new MarginPadding { Left = COLUMN_SPACING, Right = COLUMN_SPACING },
Spacing = new Vector2(COLUMN_SPACING, 0)
},
}
},
@ -123,7 +127,7 @@ namespace osu.Game.Rulesets.Mania.UI
for (int i = 0; i < definition.Columns; i++)
{
var isSpecial = definition.IsSpecialColumn(i);
var column = new Column
var column = new Column(firstColumnIndex + i)
{
IsSpecial = isSpecial,
Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
@ -152,11 +156,31 @@ namespace osu.Game.Rulesets.Mania.UI
public override void Add(DrawableHitObject h)
{
var maniaObject = (ManiaHitObject)h.HitObject;
int columnIndex = maniaObject.Column - firstColumnIndex;
Columns.ElementAt(columnIndex).Add(h);
int columnIndex = -1;
maniaObject.ColumnBindable.BindValueChanged(_ =>
{
if (columnIndex != -1)
Columns.ElementAt(columnIndex).Remove(h);
columnIndex = maniaObject.Column - firstColumnIndex;
Columns.ElementAt(columnIndex).Add(h);
}, true);
h.OnNewResult += OnNewResult;
}
public override bool Remove(DrawableHitObject h)
{
var maniaObject = (ManiaHitObject)h.HitObject;
int columnIndex = maniaObject.Column - firstColumnIndex;
Columns.ElementAt(columnIndex).Remove(h);
h.OnNewResult -= OnNewResult;
return true;
}
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)

View File

@ -10,6 +10,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Osu.Difficulty
{
@ -29,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private int countMeh;
private int countMiss;
public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
: base(ruleset, beatmap, score)
{
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@ -16,7 +15,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
: base(hitObject)
{
}
public override void AdjustPosition(DragEvent dragEvent) => OsuObject.Position += dragEvent.Delta;
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@ -10,13 +9,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
{
public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint
{
private readonly Slider slider;
public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position)
: base(hitObject)
{
this.slider = slider;
InternalChild = new SliderCirclePiece(slider, position);
Select();
@ -24,7 +19,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
// Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input.
public override bool HandlePositionalInput => false;
public override void AdjustPosition(DragEvent dragEvent) => slider.Position += dragEvent.Delta;
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@ -20,10 +19,5 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos);
public override void AdjustPosition(DragEvent dragEvent)
{
// Spinners don't support position adjustments
}
}
}

View File

@ -15,6 +15,7 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Compose.Components;
namespace osu.Game.Rulesets.Osu.Edit
{
@ -35,6 +36,8 @@ namespace osu.Game.Rulesets.Osu.Edit
new SpinnerCompositionTool()
};
public override SelectionHandler CreateSelectionHandler() => new OsuSelectionHandler();
protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both };
public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)

View File

@ -0,0 +1,30 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Compose.Components;
namespace osu.Game.Rulesets.Osu.Edit
{
public class OsuSelectionHandler : SelectionHandler
{
public override void HandleDrag(SelectionBlueprint blueprint, DragEvent dragEvent)
{
foreach (var h in SelectedHitObjects.OfType<OsuHitObject>())
{
if (h is Spinner)
{
// Spinners don't support position adjustments
continue;
}
h.Position += dragEvent.Delta;
}
base.HandleDrag(blueprint, dragEvent);
}
}
}

View File

@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModAutopilot : Mod
{
public override string Name => "Autopilot";
public override string ShortenedName => "AP";
public override string Acronym => "AP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
public override ModType Type => ModType.Automation;
public override string Description => @"Automatic cursor movement - just follow the rhythm.";

View File

@ -7,7 +7,8 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Rulesets.Osu.Mods
{
@ -15,12 +16,10 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
protected override Score CreateReplayScore(Beatmap<OsuHitObject> beatmap)
protected override Score CreateReplayScore(Beatmap<OsuHitObject> beatmap) => new Score
{
return new Score
{
Replay = new OsuAutoGenerator(beatmap).Generate()
};
}
ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } },
Replay = new OsuAutoGenerator(beatmap).Generate()
};
}
}

View File

@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModSpunOut : Mod
{
public override string Name => "Spun Out";
public override string ShortenedName => "SO";
public override string Acronym => "SO";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
public override ModType Type => ModType.DifficultyReduction;
public override string Description => @"Spinners will be automatically completed.";

View File

@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModTarget : Mod
{
public override string Name => "Target";
public override string ShortenedName => "TP";
public override string Acronym => "TP";
public override ModType Type => ModType.Conversion;
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
public override string Description => @"Practice keeping up with the beat of the song.";

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Mods
internal class OsuModTransform : Mod, IApplicableToDrawableHitObjects
{
public override string Name => "Transform";
public override string ShortenedName => "TR";
public override string Acronym => "TR";
public override FontAwesome Icon => FontAwesome.fa_arrows;
public override ModType Type => ModType.Fun;
public override string Description => "Everything rotates. EVERYTHING.";

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods
internal class OsuModWiggle : Mod, IApplicableToDrawableHitObjects
{
public override string Name => "Wiggle";
public override string ShortenedName => "WG";
public override string Acronym => "WG";
public override FontAwesome Icon => FontAwesome.fa_certificate;
public override ModType Type => ModType.Fun;
public override string Description => "They just won't stay still...";

View File

@ -16,8 +16,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableOsuHitObject : DrawableHitObject<OsuHitObject>
{
public override bool IsPresent => base.IsPresent || State.Value == ArmedState.Idle && Clock?.CurrentTime >= HitObject.StartTime - HitObject.TimePreempt;
private readonly ShakeContainer shakeContainer;
protected DrawableOsuHitObject(OsuHitObject hitObject)

View File

@ -217,6 +217,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
switch (state)
{
case ArmedState.Idle:
Expire(true);
break;
case ArmedState.Hit:
sequence.ScaleTo(Scale * 1.2f, 320, Easing.Out);
break;

View File

@ -11,7 +11,6 @@ using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Overlays.Settings;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Osu.Edit;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Replays;
@ -20,6 +19,7 @@ using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Difficulty;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Osu
{
@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Osu
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new OsuPerformanceCalculator(this, beatmap, score);
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);

View File

@ -8,8 +8,8 @@ using osu.Game.Rulesets.Osu.Objects;
using System;
using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Replays;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Replays

View File

@ -6,9 +6,9 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using System;
using System.Collections.Generic;
using osu.Game.Replays;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Replays;
using osu.Game.Users;
namespace osu.Game.Rulesets.Osu.Replays
{
@ -37,13 +37,7 @@ namespace osu.Game.Rulesets.Osu.Replays
protected OsuAutoGeneratorBase(Beatmap<OsuHitObject> beatmap)
: base(beatmap)
{
Replay = new Replay
{
User = new User
{
Username = @"Autoplay",
}
};
Replay = new Replay();
// We are using ApplyModsToRate and not ApplyModsToTime to counteract the speed up / slow down from HalfTime / DoubleTime so that we remain at a constant framerate of 60 fps.
FrameDelay = ApplyModsToRate(1000.0 / 60.0);

View File

@ -3,8 +3,8 @@
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Legacy;
using osu.Game.Rulesets.Replays.Types;
using osuTK;

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Input.StateChanges;
using osu.Framework.MathUtils;
using osu.Game.Replays;
using osu.Game.Rulesets.Replays;
using osuTK;

View File

@ -9,6 +9,7 @@ using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Osu.Scoring
{
@ -39,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
comboResultCounts.Clear();
}
public override void PopulateScore(Score score)
public override void PopulateScore(ScoreInfo score)
{
base.PopulateScore(score);

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Input.Handlers;
using osu.Game.Replays;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@ -14,7 +15,6 @@ using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Osu.UI.Cursor;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Osu.UI
{

View File

@ -9,6 +9,7 @@ using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Taiko.Difficulty
{
@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
private int countMeh;
private int countMiss;
public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
: base(ruleset, beatmap, score)
{
}

View File

@ -3,22 +3,19 @@
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Replays;
using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModAutoplay : ModAutoplay<TaikoHitObject>
{
protected override Score CreateReplayScore(Beatmap<TaikoHitObject> beatmap)
protected override Score CreateReplayScore(Beatmap<TaikoHitObject> beatmap) => new Score
{
return new Score
{
User = new User { Username = "mekkadosu!" },
Replay = new TaikoAutoGenerator(beatmap).Generate(),
};
}
ScoreInfo = new ScoreInfo { User = new User { Username = "mekkadosu!" } },
Replay = new TaikoAutoGenerator(beatmap).Generate(),
};
}
}

View File

@ -5,10 +5,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Replays;
using osu.Game.Users;
namespace osu.Game.Rulesets.Taiko.Replays
{
@ -19,13 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Replays
public TaikoAutoGenerator(Beatmap<TaikoHitObject> beatmap)
: base(beatmap)
{
Replay = new Replay
{
User = new User
{
Username = @"Autoplay",
}
};
Replay = new Replay();
}
protected Replay Replay;

View File

@ -5,6 +5,7 @@ using osu.Game.Rulesets.Replays;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Input.StateChanges;
using osu.Game.Replays;
namespace osu.Game.Rulesets.Taiko.Replays
{

View File

@ -3,8 +3,8 @@
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Legacy;
using osu.Game.Rulesets.Replays.Types;
namespace osu.Game.Rulesets.Taiko.Replays

View File

@ -14,9 +14,9 @@ using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.Taiko.Replays;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Beatmaps;
using osu.Game.Rulesets.Taiko.Difficulty;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Taiko
{
@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Taiko
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score);
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new TaikoPerformanceCalculator(this, beatmap, score);
public override int? LegacyID => 1;

View File

@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
@ -16,6 +15,7 @@ using System.Linq;
using osu.Framework.Input;
using osu.Game.Configuration;
using osu.Game.Input.Handlers;
using osu.Game.Replays;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Taiko.UI

View File

@ -102,7 +102,7 @@ namespace osu.Game.Tests.Beatmaps.IO
int fireCount = 0;
// ReSharper disable once AccessToModifiedClosure
manager.ItemAdded += _ => fireCount++;
manager.ItemAdded += (_, __, ___) => fireCount++;
manager.ItemRemoved += _ => fireCount++;
var imported = loadOszIntoOsu(osu);

View File

@ -18,7 +18,7 @@ namespace osu.Game.Tests.NonVisual
var combinations = new TestDifficultyCalculator().CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(1, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[0] is ModNoMod);
}
[Test]
@ -27,7 +27,7 @@ namespace osu.Game.Tests.NonVisual
var combinations = new TestDifficultyCalculator(new ModA()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(2, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[0] is ModNoMod);
Assert.IsTrue(combinations[1] is ModA);
}
@ -37,7 +37,7 @@ namespace osu.Game.Tests.NonVisual
var combinations = new TestDifficultyCalculator(new ModA(), new ModB()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(4, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[0] is ModNoMod);
Assert.IsTrue(combinations[1] is ModA);
Assert.IsTrue(combinations[2] is MultiMod);
Assert.IsTrue(combinations[3] is ModB);
@ -52,7 +52,7 @@ namespace osu.Game.Tests.NonVisual
var combinations = new TestDifficultyCalculator(new ModA(), new ModIncompatibleWithA()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(3, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[0] is ModNoMod);
Assert.IsTrue(combinations[1] is ModA);
Assert.IsTrue(combinations[2] is ModIncompatibleWithA);
}
@ -63,7 +63,7 @@ namespace osu.Game.Tests.NonVisual
var combinations = new TestDifficultyCalculator(new ModA(), new ModB(), new ModIncompatibleWithA(), new ModIncompatibleWithAAndB()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(8, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[0] is ModNoMod);
Assert.IsTrue(combinations[1] is ModA);
Assert.IsTrue(combinations[2] is MultiMod);
Assert.IsTrue(combinations[3] is ModB);
@ -86,7 +86,7 @@ namespace osu.Game.Tests.NonVisual
var combinations = new TestDifficultyCalculator(new ModAofA(), new ModIncompatibleWithAofA()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(3, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[0] is ModNoMod);
Assert.IsTrue(combinations[1] is ModAofA);
Assert.IsTrue(combinations[2] is ModIncompatibleWithAofA);
}
@ -94,7 +94,7 @@ namespace osu.Game.Tests.NonVisual
private class ModA : Mod
{
public override string Name => nameof(ModA);
public override string ShortenedName => nameof(ModA);
public override string Acronym => nameof(ModA);
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithA), typeof(ModIncompatibleWithAAndB) };
@ -103,7 +103,7 @@ namespace osu.Game.Tests.NonVisual
private class ModB : Mod
{
public override string Name => nameof(ModB);
public override string ShortenedName => nameof(ModB);
public override string Acronym => nameof(ModB);
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithAAndB) };
@ -112,7 +112,7 @@ namespace osu.Game.Tests.NonVisual
private class ModIncompatibleWithA : Mod
{
public override string Name => $"Incompatible With {nameof(ModA)}";
public override string ShortenedName => $"Incompatible With {nameof(ModA)}";
public override string Acronym => $"Incompatible With {nameof(ModA)}";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModA) };
@ -130,7 +130,7 @@ namespace osu.Game.Tests.NonVisual
private class ModIncompatibleWithAAndB : Mod
{
public override string Name => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
public override string ShortenedName => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
public override string Acronym => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModA), typeof(ModB) };

View File

@ -0,0 +1,166 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Tests.Scores.IO
{
public class ImportScoreTest
{
public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
[Test]
public void TestBasicImport()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestBasicImport"))
{
try
{
var osu = loadOsu(host);
var toImport = new ScoreInfo
{
Rank = ScoreRank.B,
TotalScore = 987654,
Accuracy = 0.8,
MaxCombo = 500,
Combo = 250,
User = new User { Username = "Test user" },
Date = DateTimeOffset.Now,
OnlineScoreID = 12345,
};
var imported = loadIntoOsu(osu, toImport);
Assert.AreEqual(toImport.Rank, imported.Rank);
Assert.AreEqual(toImport.TotalScore, imported.TotalScore);
Assert.AreEqual(toImport.Accuracy, imported.Accuracy);
Assert.AreEqual(toImport.MaxCombo, imported.MaxCombo);
Assert.AreEqual(toImport.Combo, imported.Combo);
Assert.AreEqual(toImport.User.Username, imported.User.Username);
Assert.AreEqual(toImport.Date, imported.Date);
Assert.AreEqual(toImport.OnlineScoreID, imported.OnlineScoreID);
}
finally
{
host.Exit();
}
}
}
[Test]
public void TestImportMods()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportMods"))
{
try
{
var osu = loadOsu(host);
var toImport = new ScoreInfo
{
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
};
var imported = loadIntoOsu(osu, toImport);
Assert.IsTrue(imported.Mods.Any(m => m is OsuModHardRock));
Assert.IsTrue(imported.Mods.Any(m => m is OsuModDoubleTime));
}
finally
{
host.Exit();
}
}
}
[Test]
public void TestImportStatistics()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportStatistics"))
{
try
{
var osu = loadOsu(host);
var toImport = new ScoreInfo
{
Statistics = new Dictionary<HitResult, object>
{
{ HitResult.Perfect, 100 },
{ HitResult.Miss, 50 }
}
};
var imported = loadIntoOsu(osu, toImport);
Assert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]);
Assert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]);
}
finally
{
host.Exit();
}
}
}
private ScoreInfo loadIntoOsu(OsuGameBase osu, ScoreInfo score)
{
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
score.Beatmap = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
score.Ruleset = new OsuRuleset().RulesetInfo;
var scoreManager = osu.Dependencies.Get<ScoreManager>();
scoreManager.Import(score);
return scoreManager.GetAllUsableScores().First();
}
private string createTemporaryBeatmap()
{
var temp = Path.GetTempFileName() + ".osz";
File.Copy(TEST_OSZ_PATH, temp, true);
Assert.IsTrue(File.Exists(temp));
return temp;
}
private OsuGameBase loadOsu(GameHost host)
{
var osu = new OsuGameBase();
Task.Run(() => host.Run(osu));
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
var beatmapFile = createTemporaryBeatmap();
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
beatmapManager.Import(beatmapFile);
return osu;
}
private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
{
Task task = Task.Run(() =>
{
while (!result()) Thread.Sleep(200);
});
Assert.IsTrue(task.Wait(timeout), failureMessage);
}
}
}

View File

@ -16,15 +16,16 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
namespace osu.Game.Tests.Visual
{
[System.ComponentModel.Description("in BeatmapOverlay")]
public class TestCaseBeatmapScoresContainer : OsuTestCase
{
private readonly IEnumerable<APIScore> scores;
private readonly IEnumerable<APIScore> anotherScores;
private readonly APIScore topScore;
private readonly IEnumerable<APIScoreInfo> scores;
private readonly IEnumerable<APIScoreInfo> anotherScores;
private readonly APIScoreInfo topScoreInfo;
private readonly Box background;
public TestCaseBeatmapScoresContainer()
@ -48,7 +49,7 @@ namespace osu.Game.Tests.Visual
AddStep("scores pack 1", () => scoresContainer.Scores = scores);
AddStep("scores pack 2", () => scoresContainer.Scores = anotherScores);
AddStep("only top score", () => scoresContainer.Scores = new[] { topScore });
AddStep("only top score", () => scoresContainer.Scores = new[] { topScoreInfo });
AddStep("remove scores", () => scoresContainer.Scores = null);
AddStep("resize to big", () => container.ResizeWidthTo(1, 300));
AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300));
@ -57,7 +58,7 @@ namespace osu.Game.Tests.Visual
scores = new[]
{
new APIScore
new APIScoreInfo
{
User = new User
{
@ -80,7 +81,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234567890,
Accuracy = 1,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -102,7 +103,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234789,
Accuracy = 0.9997,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -123,7 +124,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 12345678,
Accuracy = 0.9854,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -143,7 +144,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234567,
Accuracy = 0.8765,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -169,7 +170,7 @@ namespace osu.Game.Tests.Visual
anotherScores = new[]
{
new APIScore
new APIScoreInfo
{
User = new User
{
@ -191,7 +192,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234789,
Accuracy = 0.9997,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -214,7 +215,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234567890,
Accuracy = 1,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -230,7 +231,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 123456,
Accuracy = 0.6543,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -251,7 +252,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 12345678,
Accuracy = 0.9854,
},
new APIScore
new APIScoreInfo
{
User = new User
{
@ -279,7 +280,7 @@ namespace osu.Game.Tests.Visual
s.Statistics.Add(HitResult.Meh, RNG.Next(2000));
}
topScore = new APIScore
topScoreInfo = new APIScoreInfo
{
User = new User
{
@ -301,9 +302,9 @@ namespace osu.Game.Tests.Visual
TotalScore = 987654321,
Accuracy = 0.8487,
};
topScore.Statistics.Add(HitResult.Great, RNG.Next(2000));
topScore.Statistics.Add(HitResult.Good, RNG.Next(2000));
topScore.Statistics.Add(HitResult.Meh, RNG.Next(2000));
topScoreInfo.Statistics.Add(HitResult.Great, RNG.Next(2000));
topScoreInfo.Statistics.Add(HitResult.Good, RNG.Next(2000));
topScoreInfo.Statistics.Add(HitResult.Meh, RNG.Next(2000));
}
[BackgroundDependencyLoader]

View File

@ -16,6 +16,7 @@ using NUnit.Framework;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Framework.Configuration;
namespace osu.Game.Tests.Visual
{
@ -54,8 +55,9 @@ namespace osu.Game.Tests.Visual
linkColour = colours.Blue;
var chatManager = new ChannelManager();
chatManager.AvailableChannels.Add(new Channel { Name = "#english"});
chatManager.AvailableChannels.Add(new Channel { Name = "#japanese" });
BindableCollection<Channel> availableChannels = (BindableCollection<Channel>)chatManager.AvailableChannels;
availableChannels.Add(new Channel { Name = "#english"});
availableChannels.Add(new Channel { Name = "#japanese" });
Dependencies.Cache(chatManager);
Dependencies.Cache(new ChatOverlay());

View File

@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(SelectionBox),
typeof(SelectionHandler),
typeof(DragBox),
typeof(HitObjectComposer),
typeof(OsuHitObjectComposer),

View File

@ -0,0 +1,135 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Input;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseIdleTracker : ManualInputManagerTestCase
{
private readonly IdleTrackingBox box1;
private readonly IdleTrackingBox box2;
private readonly IdleTrackingBox box3;
private readonly IdleTrackingBox box4;
public TestCaseIdleTracker()
{
Children = new Drawable[]
{
box1 = new IdleTrackingBox(1000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Red,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
},
box2 = new IdleTrackingBox(2000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Green,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
},
box3 = new IdleTrackingBox(3000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Blue,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
},
box4 = new IdleTrackingBox(4000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Orange,
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
},
};
}
[Test]
public void TestNudge()
{
AddStep("move mouse to top left", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre));
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle");
AddStep("nudge mouse", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre + new Vector2(1)));
AddAssert("check not idle", () => !box1.IsIdle);
AddAssert("check idle", () => box2.IsIdle);
AddAssert("check idle", () => box3.IsIdle);
AddAssert("check idle", () => box4.IsIdle);
}
[Test]
public void TestMovement()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(box2.ScreenSpaceDrawQuad.Centre));
AddAssert("check not idle", () => box1.IsIdle);
AddAssert("check not idle", () => !box2.IsIdle);
AddAssert("check idle", () => box3.IsIdle);
AddAssert("check idle", () => box4.IsIdle);
AddStep("move mouse", () => InputManager.MoveMouseTo(box3.ScreenSpaceDrawQuad.Centre));
AddStep("move mouse", () => InputManager.MoveMouseTo(box4.ScreenSpaceDrawQuad.Centre));
AddAssert("check not idle", () => box1.IsIdle);
AddAssert("check not idle", () => !box2.IsIdle);
AddAssert("check idle", () => !box3.IsIdle);
AddAssert("check idle", () => !box4.IsIdle);
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle");
}
[Test]
public void TestTimings()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
AddAssert("check not idle", () => !box1.IsIdle && !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box1.IsIdle, "Wait for idle");
AddAssert("check not idle", () => !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box2.IsIdle, "Wait for idle");
AddAssert("check not idle", () => !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box3.IsIdle, "Wait for idle");
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle");
}
private class IdleTrackingBox : CompositeDrawable
{
private readonly IdleTracker idleTracker;
public bool IsIdle => idleTracker.IsIdle.Value;
public IdleTrackingBox(double timeToIdle)
{
Box box;
Alpha = 0.6f;
Scale = new Vector2(0.6f);
InternalChildren = new Drawable[]
{
idleTracker = new IdleTracker(timeToIdle),
box = new Box
{
Colour = Color4.White,
RelativeSizeAxes = Axes.Both,
},
};
idleTracker.IsIdle.BindValueChanged(idle => box.Colour = idle ? Color4.White : Color4.Black, true);
}
}
}
}

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
using osu.Framework.Allocation;
@ -13,6 +12,7 @@ using osuTK;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Scoring;
namespace osu.Game.Tests.Visual
{
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual
{
var scores = new[]
{
new Score
new ScoreInfo
{
Rank = ScoreRank.XH,
Accuracy = 1,
@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.X,
Accuracy = 1,
@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.SH,
Accuracy = 1,
@ -112,7 +112,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.S,
Accuracy = 1,
@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.A,
Accuracy = 1,
@ -148,7 +148,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.B,
Accuracy = 0.9826,
@ -166,7 +166,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.C,
Accuracy = 0.9654,
@ -184,7 +184,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.F,
Accuracy = 0.6025,
@ -202,7 +202,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.F,
Accuracy = 0.5140,
@ -220,7 +220,7 @@ namespace osu.Game.Tests.Visual
},
},
},
new Score
new ScoreInfo
{
Rank = ScoreRank.F,
Accuracy = 0.4222,

View File

@ -187,7 +187,7 @@ namespace osu.Game.Tests.Visual
private static int importId;
private int getImportId() => ++importId;
private void changeMods(params Mod[] mods) => AddStep($"change mods to {string.Join(", ", mods.Select(m => m.ShortenedName))}", () => selectedMods.Value = mods);
private void changeMods(params Mod[] mods) => AddStep($"change mods to {string.Join(", ", mods.Select(m => m.Acronym))}", () => selectedMods.Value = mods);
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id));

View File

@ -5,6 +5,7 @@ using System.ComponentModel;
using System.Linq;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
@ -19,13 +20,10 @@ namespace osu.Game.Tests.Visual
Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(Beatmap.Value);
// We have the replay
var replay = dummyRulesetContainer.Replay;
// Reset the mods
Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Where(m => !(m is ModAutoplay));
return new ReplayPlayer(replay);
return new ReplayPlayer(new Score { Replay = dummyRulesetContainer.Replay });
}
}
}

View File

@ -7,6 +7,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking;
using osu.Game.Users;
@ -19,7 +20,7 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Score),
typeof(ScoreInfo),
typeof(Results),
typeof(ResultsPage),
typeof(ResultsPageScore),
@ -40,7 +41,7 @@ namespace osu.Game.Tests.Visual
if (beatmapInfo != null)
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
Add(new Results(new Score
Add(new Results(new ScoreInfo
{
TotalScore = 2845370,
Accuracy = 0.98,

View File

@ -0,0 +1,119 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing.Input;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Screens.Match.Settings;
using osuTK.Input;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseRoomSettings : ManualInputManagerTestCase
{
private readonly Room room;
private readonly TestRoomSettingsOverlay overlay;
public TestCaseRoomSettings()
{
room = new Room
{
Name = { Value = "One Testing Room" },
Availability = { Value = RoomAvailability.Public },
Type = { Value = new GameTypeTeamVersus() },
MaxParticipants = { Value = 10 },
};
Add(overlay = new TestRoomSettingsOverlay(room)
{
RelativeSizeAxes = Axes.Both,
Height = 0.75f,
});
AddStep(@"show", overlay.Show);
assertAll();
AddStep(@"set name", () => overlay.CurrentName = @"Two Testing Room");
AddStep(@"set max", () => overlay.CurrentMaxParticipants = null);
AddStep(@"set availability", () => overlay.CurrentAvailability = RoomAvailability.InviteOnly);
AddStep(@"set type", () => overlay.CurrentType = new GameTypeTagTeam());
apply();
assertAll();
AddStep(@"show", overlay.Show);
AddStep(@"set room name", () => room.Name.Value = @"Room Changed Name!");
AddStep(@"set room availability", () => room.Availability.Value = RoomAvailability.Public);
AddStep(@"set room type", () => room.Type.Value = new GameTypeTag());
AddStep(@"set room max", () => room.MaxParticipants.Value = 100);
assertAll();
AddStep(@"set name", () => overlay.CurrentName = @"Unsaved Testing Room");
AddStep(@"set max", () => overlay.CurrentMaxParticipants = 20);
AddStep(@"set availability", () => overlay.CurrentAvailability = RoomAvailability.FriendsOnly);
AddStep(@"set type", () => overlay.CurrentType = new GameTypeVersus());
AddStep(@"hide", overlay.Hide);
AddWaitStep(5);
AddStep(@"show", overlay.Show);
assertAll();
AddStep(@"hide", overlay.Hide);
}
private void apply()
{
AddStep(@"apply", () =>
{
overlay.ClickApplyButton(InputManager);
});
}
private void assertAll()
{
AddAssert(@"name == room name", () => overlay.CurrentName == room.Name.Value);
AddAssert(@"max == room max", () => overlay.CurrentMaxParticipants == room.MaxParticipants.Value);
AddAssert(@"availability == room availability", () => overlay.CurrentAvailability == room.Availability.Value);
AddAssert(@"type == room type", () => Equals(overlay.CurrentType, room.Type.Value));
}
private class TestRoomSettingsOverlay : RoomSettingsOverlay
{
public string CurrentName
{
get => NameField.Text;
set => NameField.Text = value;
}
public int? CurrentMaxParticipants
{
get
{
if (int.TryParse(MaxParticipantsField.Text, out int max))
return max;
return null;
}
set => MaxParticipantsField.Text = value?.ToString();
}
public RoomAvailability CurrentAvailability
{
get => AvailabilityPicker.Current.Value;
set => AvailabilityPicker.Current.Value = value;
}
public GameType CurrentType
{
get => TypePicker.Current.Value;
set => TypePicker.Current.Value = value;
}
public TestRoomSettingsOverlay(Room room) : base(room)
{
}
public void ClickApplyButton(ManualInputManager inputManager)
{
inputManager.MoveMouseTo(ApplyButton);
inputManager.Click(MouseButton.Left);
}
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
@ -39,6 +40,8 @@ namespace osu.Game.Tournament.Components
public TournamentBeatmapPanel(BeatmapInfo beatmap, string mods = null)
{
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
Beatmap = beatmap;
this.mods = mods;
Width = 400;

View File

@ -0,0 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Tournament.Screens.Ladder.Components
{
/// <summary>
/// A pairing that may not necessarily occur.
/// </summary>
public class ConditionalMatchPairing : MatchPairing
{
}
}

View File

@ -199,6 +199,18 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
if (Pairing.Team1.Value == null || Pairing.Team2.Value == null)
Pairing.CancelMatchStart();
if (Pairing.ConditionalPairings.Count > 0)
{
foreach (var conditional in Pairing.ConditionalPairings)
{
var team1Match = conditional.Acronyms.Contains(Pairing.Team1Acronym);
var team2Match = conditional.Acronyms.Contains(Pairing.Team2Acronym);
if (team1Match && team2Match)
Pairing.Date.Value = conditional.Date;
}
}
Flow.Children = new[]
{
new DrawableMatchTeam(Pairing.Team1, Pairing, Pairing.Losers),
@ -226,7 +238,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
protected override bool OnClick(ClickEvent e)
{
if (editorInfo == null)
if (editorInfo == null || Pairing is ConditionalMatchPairing)
return false;
Selected = true;

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Newtonsoft.Json;
using osu.Framework.Configuration;
@ -17,6 +18,17 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{
public int ID;
public List<string> Acronyms
{
get
{
List<string> acronyms = new List<string>();
if (Team1Acronym != null) acronyms.Add(Team1Acronym);
if (Team2Acronym != null) acronyms.Add(Team2Acronym);
return acronyms;
}
}
[JsonIgnore]
public readonly Bindable<TournamentTeam> Team1 = new Bindable<TournamentTeam>();
@ -53,6 +65,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
public readonly Bindable<DateTimeOffset> Date = new Bindable<DateTimeOffset>();
public readonly BindableCollection<ConditionalMatchPairing> ConditionalPairings = new BindableCollection<ConditionalMatchPairing>();
public readonly Bindable<Point> Position = new Bindable<Point>();
public MatchPairing()
@ -74,7 +88,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
[JsonIgnore]
public TournamentTeam Loser => !Completed.Value ? null : Team1Score.Value > Team2Score.Value ? Team2.Value : Team1.Value;
public int PointsToWin => Grouping.Value.BestOf / 2 + 1;
public int PointsToWin => Grouping.Value == null ? 0 : Grouping.Value.BestOf / 2 + 1;
/// <summary>
/// Remove scores from the match, in case of a false click or false start.

View File

@ -56,6 +56,13 @@ namespace osu.Game.Tournament.Screens.Schedule
return;
}
var upcoming = ladder.Pairings.Where(p => !p.Completed.Value && p.Team1.Value != null && p.Team2.Value != null && Math.Abs(p.Date.Value.DayOfYear - DateTimeOffset.UtcNow.DayOfYear) < 4);
var conditionals = ladder.Pairings.Where(p => !p.Completed.Value && (p.Team1.Value == null || p.Team2.Value == null) && Math.Abs(p.Date.Value.DayOfYear - DateTimeOffset.UtcNow.DayOfYear) < 4)
.SelectMany(m => m.ConditionalPairings.Where(cp => m.Acronyms.TrueForAll(a => cp.Acronyms.Contains(a))));
upcoming = upcoming.Concat(conditionals);
upcoming = upcoming.OrderBy(p => p.Date.Value).Take(12);
mainContainer.Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
@ -77,7 +84,8 @@ namespace osu.Game.Tournament.Screens.Schedule
RelativeSizeAxes = Axes.Both,
Width = 0.4f,
ChildrenEnumerable = ladder.Pairings
.Where(p => p.Completed.Value && p.Team1.Value != null && p.Team2.Value != null && Math.Abs(p.Date.Value.DayOfYear - DateTimeOffset.UtcNow.DayOfYear) < 4)
.Where(p => p.Completed.Value && p.Team1.Value != null && p.Team2.Value != null
&& Math.Abs(p.Date.Value.DayOfYear - DateTimeOffset.UtcNow.DayOfYear) < 4)
.OrderByDescending(p => p.Date.Value)
.Take(8)
.Select(p => new SchedulePairing(p))
@ -86,11 +94,7 @@ namespace osu.Game.Tournament.Screens.Schedule
{
RelativeSizeAxes = Axes.Both,
Width = 0.6f,
ChildrenEnumerable = ladder.Pairings
.Where(p => !p.Completed.Value && p.Team1.Value != null && p.Team2.Value != null && Math.Abs(p.Date.Value.DayOfYear - DateTimeOffset.UtcNow.DayOfYear) < 4)
.OrderBy(p => p.Date.Value)
.Take(8)
.Select(p => new SchedulePairing(p))
ChildrenEnumerable = upcoming.Select(p => new SchedulePairing(p))
},
}
}
@ -129,6 +133,11 @@ namespace osu.Game.Tournament.Screens.Schedule
{
Flow.Direction = FillDirection.Horizontal;
bool conditional = pairing is ConditionalMatchPairing;
if (conditional)
Colour = OsuColour.Gray(0.5f);
if (showTimestamp)
{
AddInternal(new DrawableDate(Pairing.Date.Value)
@ -136,6 +145,7 @@ namespace osu.Game.Tournament.Screens.Schedule
Anchor = Anchor.TopRight,
Origin = Anchor.TopLeft,
Colour = Color4.Black,
Alpha = conditional ? 0.6f : 1,
Margin = new MarginPadding { Horizontal = 10, Vertical = 5 },
});
AddInternal(new OsuSpriteText
@ -143,8 +153,9 @@ namespace osu.Game.Tournament.Screens.Schedule
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomLeft,
Colour = Color4.Black,
Alpha = conditional ? 0.6f : 1,
Margin = new MarginPadding { Horizontal = 10, Vertical = 5 },
Text = pairing.Date.Value.ToUniversalTime().ToString("HH:mm UTC")
Text = pairing.Date.Value.ToUniversalTime().ToString("HH:mm UTC") + (conditional ? " (conditional)" : "")
});
}
}

View File

@ -78,6 +78,13 @@ namespace osu.Game.Tournament
{
pairing.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == pairing.Team1Acronym);
pairing.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == pairing.Team2Acronym);
foreach (var conditional in pairing.ConditionalPairings)
{
conditional.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == conditional.Team1Acronym);
conditional.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym == conditional.Team2Acronym);
conditional.Grouping.Value = pairing.Grouping.Value;
}
}
// assign progressions
@ -113,8 +120,8 @@ namespace osu.Game.Tournament
if (string.IsNullOrEmpty(p.Username))
{
var req = new GetUserRequest(p.Id);
req.Success += i => p.Username = i.Username;
req.Perform(API);
p.Username = req.Result.Username;
addedInfo = true;
}
@ -125,8 +132,8 @@ namespace osu.Game.Tournament
if (b.BeatmapInfo == null)
{
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
req.Success += i => b.BeatmapInfo = i.ToBeatmap(RulesetStore);
req.Perform(API);
b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);
addedInfo = true;
}

View File

@ -1,20 +1,17 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
using osu.Game.Database;
namespace osu.Game.Beatmaps
{
public class BeatmapDifficulty
public class BeatmapDifficulty : IHasPrimaryKey
{
/// <summary>
/// The default value used for all difficulty settings except <see cref="SliderMultiplier"/> and <see cref="SliderTickRate"/>.
/// </summary>
public const float DEFAULT_DIFFICULTY = 5;
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
public int ID { get; set; }
public float DrainRate { get; set; } = DEFAULT_DIFFICULTY;

View File

@ -15,8 +15,6 @@ namespace osu.Game.Beatmaps
[Serializable]
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
public int ID { get; set; }
public int BeatmapVersion;

Some files were not shown because too many files have changed in this diff Show More