1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 02:02:53 +08:00

Merge branch 'master' into fix-count-not-updating-when-deleting

This commit is contained in:
Dean Herbert 2023-04-11 09:04:02 +09:00 committed by GitHub
commit 52bb7891f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 413 additions and 120 deletions

View File

@ -48,7 +48,6 @@ namespace osu.Game.Rulesets.Catch.Edit
private void load()
{
// todo: enable distance spacing once catch supports applying it to its existing distance snap grid implementation.
RightSideToolboxContainer.Alpha = 0;
DistanceSpacingMultiplier.Disabled = true;
LayerBelowRuleset.Add(new PlayfieldBorder

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -8,6 +8,5 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModNightcore : ModNightcore<CatchHitObject>
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.5;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => 1;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.5;
}
}

View File

@ -8,6 +8,5 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModNightcore : ModNightcore<ManiaHitObject>
{
public override double ScoreMultiplier => 1;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -8,6 +8,5 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModNightcore : ModNightcore<OsuHitObject>
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModDaycore : ModDaycore
{
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModDoubleTime : ModDoubleTime
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
}
}

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModHalfTime : ModHalfTime
{
public override double ScoreMultiplier => 0.3;
}
}

View File

@ -8,6 +8,5 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public class TaikoModNightcore : ModNightcore<TaikoHitObject>
{
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
}
}

View File

@ -14,6 +14,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Testing;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
@ -26,7 +27,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
namespace osu.Game.Tests.Visual.Online
{
public partial class TestSceneBeatmapSetOverlay : OsuTestScene
public partial class TestSceneBeatmapSetOverlay : OsuManualInputManagerTestScene
{
private readonly TestBeatmapSetOverlay overlay;
@ -281,6 +282,22 @@ namespace osu.Game.Tests.Visual.Online
AddAssert(@"type is correct", () => type == lookupType.ToString());
}
[Test]
public void TestBeatmapSetWithGuestDifficulty()
{
AddStep("show map", () => overlay.ShowBeatmapSet(createBeatmapSetWithGuestDifficulty()));
AddStep("move mouse to host difficulty", () =>
{
InputManager.MoveMouseTo(overlay.ChildrenOfType<DifficultyIcon>().ElementAt(0));
});
AddAssert("guest mapper information not shown", () => overlay.ChildrenOfType<BeatmapPicker>().Single().ChildrenOfType<OsuSpriteText>().All(s => s.Text != "BanchoBot"));
AddStep("move mouse to guest difficulty", () =>
{
InputManager.MoveMouseTo(overlay.ChildrenOfType<DifficultyIcon>().ElementAt(1));
});
AddAssert("guest mapper information shown", () => overlay.ChildrenOfType<BeatmapPicker>().Single().ChildrenOfType<OsuSpriteText>().Any(s => s.Text == "BanchoBot"));
}
private APIBeatmapSet createManyDifficultiesBeatmapSet()
{
var set = getBeatmapSet();
@ -320,6 +337,60 @@ namespace osu.Game.Tests.Visual.Online
return beatmapSet;
}
private APIBeatmapSet createBeatmapSetWithGuestDifficulty()
{
var set = getBeatmapSet();
var beatmaps = new List<APIBeatmap>();
var guestUser = new APIUser
{
Username = @"BanchoBot",
Id = 3,
};
set.RelatedUsers = new[]
{
set.Author, guestUser
};
beatmaps.Add(new APIBeatmap
{
OnlineID = 1145,
DifficultyName = "Host Diff",
RulesetID = Ruleset.Value.OnlineID,
StarRating = 1.4,
OverallDifficulty = 3.5f,
AuthorID = set.AuthorID,
FailTimes = new APIFailTimes
{
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
},
Status = BeatmapOnlineStatus.Graveyard
});
beatmaps.Add(new APIBeatmap
{
OnlineID = 1919,
DifficultyName = "Guest Diff",
RulesetID = Ruleset.Value.OnlineID,
StarRating = 8.1,
OverallDifficulty = 3.5f,
AuthorID = 3,
FailTimes = new APIFailTimes
{
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
},
Status = BeatmapOnlineStatus.Graveyard
});
set.Beatmaps = beatmaps.ToArray();
return set;
}
private void downloadAssert(bool shown)
{
AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.HeaderContent.DownloadButtonsVisible == shown);

View File

@ -99,6 +99,16 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString TimelineTicks => new TranslatableString(getKey(@"timeline_ticks"), @"Ticks");
/// <summary>
/// "{0:0.0}&#176;"
/// </summary>
public static LocalisableString RotationUnsnapped(float newRotation) => new TranslatableString(getKey(@"rotation_unsnapped"), @"{0:0.0}°", newRotation);
/// <summary>
/// "{0:0.0}&#176; (snapped)"
/// </summary>
public static LocalisableString RotationSnapped(float newRotation) => new TranslatableString(getKey(@"rotation_snapped"), @"{0:0.0}° (snapped)", newRotation);
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@ -107,7 +107,7 @@ namespace osu.Game.Overlays.BeatmapListing
Padding = new MarginPadding
{
Vertical = 20,
Horizontal = 40,
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING,
},
Child = new FillFlowContainer
{

View File

@ -31,6 +31,7 @@ namespace osu.Game.Overlays.BeatmapSet
private const float tile_spacing = 2;
private readonly OsuSpriteText version, starRating, starRatingText;
private readonly LinkFlowContainer guestMapperContainer;
private readonly FillFlowContainer starRatingContainer;
private readonly Statistic plays, favourites;
@ -88,6 +89,14 @@ namespace osu.Game.Overlays.BeatmapSet
Origin = Anchor.BottomLeft,
Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold)
},
guestMapperContainer = new LinkFlowContainer(s =>
s.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 11))
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Bottom = 1 },
},
starRatingContainer = new FillFlowContainer
{
Anchor = Anchor.BottomLeft,
@ -198,8 +207,21 @@ namespace osu.Game.Overlays.BeatmapSet
updateDifficultyButtons();
}
private void showBeatmap(IBeatmapInfo? beatmapInfo)
private void showBeatmap(APIBeatmap? beatmapInfo)
{
guestMapperContainer.Clear();
if (beatmapInfo?.AuthorID != BeatmapSet?.AuthorID)
{
APIUser? user = BeatmapSet?.RelatedUsers?.SingleOrDefault(u => u.OnlineID == beatmapInfo?.AuthorID);
if (user != null)
{
guestMapperContainer.AddText("mapped by ");
guestMapperContainer.AddUserLink(user);
}
}
version.Text = beatmapInfo?.DifficultyName ?? string.Empty;
}

View File

@ -97,8 +97,8 @@ namespace osu.Game.Overlays.BeatmapSet
Padding = new MarginPadding
{
Vertical = BeatmapSetOverlay.Y_PADDING,
Left = BeatmapSetOverlay.X_PADDING,
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
Left = WaveOverlayContainer.HORIZONTAL_PADDING,
Right = WaveOverlayContainer.HORIZONTAL_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
},
Children = new Drawable[]
{
@ -170,7 +170,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = BeatmapSetOverlay.Y_PADDING, Right = BeatmapSetOverlay.X_PADDING },
Margin = new MarginPadding { Top = BeatmapSetOverlay.Y_PADDING, Right = WaveOverlayContainer.HORIZONTAL_PADDING },
Direction = FillDirection.Vertical,
Spacing = new Vector2(10),
Children = new Drawable[]

View File

@ -55,7 +55,7 @@ namespace osu.Game.Overlays.BeatmapSet
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = 15, Horizontal = BeatmapSetOverlay.X_PADDING },
Padding = new MarginPadding { Top = 15, Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING },
Children = new Drawable[]
{
new Container

View File

@ -116,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Horizontal = 50 },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING },
Margin = new MarginPadding { Vertical = 20 },
Children = new Drawable[]
{

View File

@ -25,7 +25,6 @@ namespace osu.Game.Overlays
{
public partial class BeatmapSetOverlay : OnlineOverlay<BeatmapSetHeader>
{
public const float X_PADDING = 40;
public const float Y_PADDING = 25;
public const float RIGHT_WIDTH = 275;

View File

@ -18,8 +18,6 @@ namespace osu.Game.Overlays.Changelog
{
public partial class ChangelogBuild : FillFlowContainer
{
public const float HORIZONTAL_PADDING = 70;
public Action<APIChangelogBuild> SelectBuild;
protected readonly APIChangelogBuild Build;
@ -33,7 +31,7 @@ namespace osu.Game.Overlays.Changelog
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Vertical;
Padding = new MarginPadding { Horizontal = HORIZONTAL_PADDING };
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING };
Children = new Drawable[]
{

View File

@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Changelog
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding
{
Horizontal = 65,
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING - ChangelogUpdateStreamItem.PADDING,
Vertical = 20
},
Child = Streams = new ChangelogUpdateStreamControl { Current = currentStream },

View File

@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Changelog
{
RelativeSizeAxes = Axes.X,
Height = 1,
Padding = new MarginPadding { Horizontal = ChangelogBuild.HORIZONTAL_PADDING },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING },
Margin = new MarginPadding { Top = 30 },
Child = new Box
{

View File

@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Changelog
Padding = new MarginPadding
{
Vertical = 20,
Horizontal = 50,
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING,
};
}
@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Changelog
Direction = FillDirection.Vertical,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Padding = new MarginPadding { Right = 50 + image_container_width },
Padding = new MarginPadding { Right = WaveOverlayContainer.HORIZONTAL_PADDING + image_container_width },
Children = new Drawable[]
{
new OsuSpriteText

View File

@ -99,7 +99,7 @@ namespace osu.Game.Overlays.Comments
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = 50, Vertical = 20 },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING, Vertical = 20 },
Children = new Drawable[]
{
avatar = new UpdateableAvatar(api.LocalUser.Value)
@ -152,7 +152,7 @@ namespace osu.Game.Overlays.Comments
ShowDeleted = { BindTarget = ShowDeleted },
Margin = new MarginPadding
{
Horizontal = 70,
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING,
Vertical = 10
}
},
@ -393,7 +393,7 @@ namespace osu.Game.Overlays.Comments
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 50 },
Margin = new MarginPadding { Left = WaveOverlayContainer.HORIZONTAL_PADDING },
Text = CommentsStrings.Empty
}
});

View File

@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Comments
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 50 },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING },
Children = new Drawable[]
{
new OverlaySortTabControl<CommentsSortCriteria>

View File

@ -537,7 +537,7 @@ namespace osu.Game.Overlays.Comments
{
return new MarginPadding
{
Horizontal = 70,
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING,
Vertical = 15
};
}

View File

@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Comments
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Left = 50 },
Margin = new MarginPadding { Left = WaveOverlayContainer.HORIZONTAL_PADDING },
Spacing = new Vector2(5, 0),
Children = new Drawable[]
{

View File

@ -60,7 +60,7 @@ namespace osu.Game.Overlays.Dashboard
new Container<BasicSearchTextBox>
{
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding(padding),
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING, Vertical = padding },
Child = searchTextBox = new BasicSearchTextBox
{
RelativeSizeAxes = Axes.X,

View File

@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Dashboard.Friends
Padding = new MarginPadding
{
Top = 20,
Horizontal = 45
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING - FriendsOnlineStatusItem.PADDING
},
Child = onlineStreamControl = new FriendOnlineStreamControl(),
}
@ -129,7 +129,7 @@ namespace osu.Game.Overlays.Dashboard.Friends
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = 50 }
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING }
},
loading = new LoadingLayer(true)
}

View File

@ -43,7 +43,7 @@ namespace osu.Game.Overlays.News.Displays
{
Vertical = 20,
Left = 30,
Right = 50
Right = WaveOverlayContainer.HORIZONTAL_PADDING
};
InternalChild = new FillFlowContainer

View File

@ -89,7 +89,7 @@ namespace osu.Game.Overlays
}
});
ContentSidePadding = 50;
ContentSidePadding = WaveOverlayContainer.HORIZONTAL_PADDING;
}
[BackgroundDependencyLoader]

View File

@ -55,7 +55,7 @@ namespace osu.Game.Overlays
Padding = new MarginPadding
{
Vertical = 20,
Left = 50,
Left = WaveOverlayContainer.HORIZONTAL_PADDING,
Right = 30
},
Child = CreateContent()

View File

@ -39,12 +39,14 @@ namespace osu.Game.Overlays
private FillFlowContainer<SpriteText> text;
private ExpandingBar expandingBar;
public const float PADDING = 5;
protected OverlayStreamItem(T value)
: base(value)
{
Height = 50;
Width = 90;
Margin = new MarginPadding(5);
Margin = new MarginPadding(PADDING);
}
[BackgroundDependencyLoader]

View File

@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Profile.Header
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(10, 10),
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Top = 10 },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING, Top = 10 },
}
};
}

View File

@ -55,7 +55,7 @@ namespace osu.Game.Overlays.Profile.Header
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING, Vertical = 10 },
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{

View File

@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Profile.Header
RelativeSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding { Vertical = 10 },
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
Margin = new MarginPadding { Left = WaveOverlayContainer.HORIZONTAL_PADDING },
Spacing = new Vector2(10, 0),
Children = new Drawable[]
{
@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Profile.Header
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN },
Margin = new MarginPadding { Right = WaveOverlayContainer.HORIZONTAL_PADDING },
Children = new Drawable[]
{
levelBadge = new LevelBadge
@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Profile.Header
Origin = Anchor.CentreRight,
Width = 200,
Height = 6,
Margin = new MarginPadding { Right = 50 },
Margin = new MarginPadding { Right = WaveOverlayContainer.HORIZONTAL_PADDING },
Child = new LevelProgressBar
{
RelativeSizeAxes = Axes.Both,

View File

@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Profile.Header
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING, Vertical = 10 },
Child = new GridContainer
{
RelativeSizeAxes = Axes.X,

View File

@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Profile.Header
Direction = FillDirection.Horizontal,
Padding = new MarginPadding
{
Left = UserProfileOverlay.CONTENT_X_MARGIN,
Left = WaveOverlayContainer.HORIZONTAL_PADDING,
Vertical = vertical_padding
},
Height = content_height + 2 * vertical_padding,

View File

@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Profile
public ProfileHeader()
{
ContentSidePadding = UserProfileOverlay.CONTENT_X_MARGIN;
ContentSidePadding = WaveOverlayContainer.HORIZONTAL_PADDING;
TabControl.AddItem(LayoutStrings.HeaderUsersShow);

View File

@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Profile
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding
{
Horizontal = UserProfileOverlay.CONTENT_X_MARGIN - outer_gutter_width,
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING - outer_gutter_width,
Top = 20,
Bottom = 20,
},
@ -97,7 +97,7 @@ namespace osu.Game.Overlays.Profile
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding
{
Horizontal = UserProfileOverlay.CONTENT_X_MARGIN - outer_gutter_width,
Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING - outer_gutter_width,
Bottom = 20
}
},

View File

@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Rankings
Origin = Anchor.CentreLeft,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
Margin = new MarginPadding { Left = WaveOverlayContainer.HORIZONTAL_PADDING },
Children = new Drawable[]
{
new OsuSpriteText

View File

@ -63,7 +63,7 @@ namespace osu.Game.Overlays.Rankings
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN },
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING },
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,

View File

@ -23,7 +23,6 @@ namespace osu.Game.Overlays.Rankings.Tables
public abstract partial class RankingsTable<TModel> : TableContainer
{
protected const int TEXT_SIZE = 12;
private const float horizontal_inset = 20;
private const float row_height = 32;
private const float row_spacing = 3;
private const int items_per_page = 50;
@ -39,7 +38,7 @@ namespace osu.Game.Overlays.Rankings.Tables
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Padding = new MarginPadding { Horizontal = horizontal_inset };
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING };
RowSize = new Dimension(GridSizeMode.Absolute, row_height + row_spacing);
}

View File

@ -45,8 +45,6 @@ namespace osu.Game.Overlays
[Resolved]
private RulesetStore rulesets { get; set; } = null!;
public const float CONTENT_X_MARGIN = 50;
public UserProfileOverlay()
: base(OverlayColourScheme.Pink)
{
@ -184,7 +182,7 @@ namespace osu.Game.Overlays
public ProfileSectionTabControl()
{
Height = 40;
Padding = new MarginPadding { Horizontal = CONTENT_X_MARGIN };
Padding = new MarginPadding { Horizontal = HORIZONTAL_PADDING };
TabContainer.Spacing = new Vector2(20);
}

View File

@ -22,6 +22,8 @@ namespace osu.Game.Overlays
protected override string PopInSampleName => "UI/wave-pop-in";
public const float HORIZONTAL_PADDING = 50;
protected WaveOverlayContainer()
{
AddInternal(Waves = new WaveContainer

View File

@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Wiki
{
Vertical = 20,
Left = 30,
Right = 50,
Right = WaveOverlayContainer.HORIZONTAL_PADDING,
},
OnAddHeading = sidebar.AddEntry,
}

View File

@ -145,7 +145,7 @@ namespace osu.Game.Overlays
Padding = new MarginPadding
{
Vertical = 20,
Horizontal = 50,
Horizontal = HORIZONTAL_PADDING,
},
});
}

View File

@ -11,8 +11,6 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
@ -47,8 +45,6 @@ namespace osu.Game.Rulesets.Edit
IBindable<double> IDistanceSnapProvider.DistanceSpacingMultiplier => DistanceSpacingMultiplier;
protected ExpandingToolboxContainer RightSideToolboxContainer { get; private set; }
private ExpandableSlider<double, SizeSlider<double>> distanceSpacingSlider;
private ExpandableButton currentDistanceSpacingButton;
@ -67,47 +63,29 @@ namespace osu.Game.Rulesets.Edit
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
AddInternal(new Container
RightToolbox.Add(new EditorToolboxGroup("snapping")
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1,
Children = new Drawable[]
{
new Box
distanceSpacingSlider = new ExpandableSlider<double, SizeSlider<double>>
{
Colour = colourProvider.Background5,
RelativeSizeAxes = Axes.Both,
KeyboardStep = adjust_step,
// Manual binding in LoadComplete to handle one-way event flow.
Current = DistanceSpacingMultiplier.GetUnboundCopy(),
},
RightSideToolboxContainer = new ExpandingToolboxContainer(130, 250)
currentDistanceSpacingButton = new ExpandableButton
{
Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1,
Child = new EditorToolboxGroup("snapping")
Action = () =>
{
Children = new Drawable[]
{
distanceSpacingSlider = new ExpandableSlider<double, SizeSlider<double>>
{
KeyboardStep = adjust_step,
// Manual binding in LoadComplete to handle one-way event flow.
Current = DistanceSpacingMultiplier.GetUnboundCopy(),
},
currentDistanceSpacingButton = new ExpandableButton
{
Action = () =>
{
(HitObject before, HitObject after)? objects = getObjectsOnEitherSideOfCurrentTime();
(HitObject before, HitObject after)? objects = getObjectsOnEitherSideOfCurrentTime();
Debug.Assert(objects != null);
Debug.Assert(objects != null);
DistanceSpacingMultiplier.Value = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after);
DistanceSnapToggle.Value = TernaryState.True;
},
RelativeSizeAxes = Axes.X,
}
}
}
DistanceSpacingMultiplier.Value = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after);
DistanceSnapToggle.Value = TernaryState.True;
},
RelativeSizeAxes = Axes.X,
}
}
});
@ -261,7 +239,8 @@ namespace osu.Game.Rulesets.Edit
public virtual float GetBeatSnapDistanceAt(HitObject referenceObject, bool useReferenceSliderVelocity = true)
{
return (float)(100 * (useReferenceSliderVelocity ? referenceObject.DifficultyControlPoint.SliderVelocity : 1) * EditorBeatmap.Difficulty.SliderMultiplier * 1 / BeatSnapProvider.BeatDivisor);
return (float)(100 * (useReferenceSliderVelocity ? referenceObject.DifficultyControlPoint.SliderVelocity : 1) * EditorBeatmap.Difficulty.SliderMultiplier * 1
/ BeatSnapProvider.BeatDivisor);
}
public virtual float DurationToDistance(HitObject referenceObject, double duration)

View File

@ -58,8 +58,15 @@ namespace osu.Game.Rulesets.Edit
[Resolved]
protected IBeatSnapProvider BeatSnapProvider { get; private set; }
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
protected ExpandingToolboxContainer LeftToolbox { get; private set; }
protected ExpandingToolboxContainer RightToolbox { get; private set; }
private DrawableEditorRulesetWrapper<TObject> drawableRulesetWrapper;
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
@ -82,7 +89,7 @@ namespace osu.Game.Rulesets.Edit
dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider, OsuConfigManager config)
private void load(OsuConfigManager config)
{
autoSeekOnPlacement = config.GetBindable<bool>(OsuSetting.EditorAutoSeekOnPlacement);
@ -131,7 +138,7 @@ namespace osu.Game.Rulesets.Edit
Colour = colourProvider.Background5,
RelativeSizeAxes = Axes.Both,
},
new ExpandingToolboxContainer(60, 200)
LeftToolbox = new ExpandingToolboxContainer(60, 200)
{
Children = new Drawable[]
{
@ -153,6 +160,28 @@ namespace osu.Game.Rulesets.Edit
},
}
},
new Container
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Children = new Drawable[]
{
new Box
{
Colour = colourProvider.Background5,
RelativeSizeAxes = Axes.Both,
},
RightToolbox = new ExpandingToolboxContainer(130, 250)
{
Child = new EditorToolboxGroup("inspector")
{
Child = new HitObjectInspector()
},
}
}
}
};
toolboxCollection.Items = CompositionTools

View File

@ -0,0 +1,146 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Screens.Edit;
namespace osu.Game.Rulesets.Edit
{
internal partial class HitObjectInspector : CompositeDrawable
{
private OsuTextFlowContainer inspectorText = null!;
[Resolved]
protected EditorBeatmap EditorBeatmap { get; private set; } = null!;
[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
[BackgroundDependencyLoader]
private void load()
{
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
InternalChild = inspectorText = new OsuTextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
};
}
protected override void LoadComplete()
{
base.LoadComplete();
EditorBeatmap.SelectedHitObjects.CollectionChanged += (_, _) => updateInspectorText();
EditorBeatmap.TransactionBegan += updateInspectorText;
EditorBeatmap.TransactionEnded += updateInspectorText;
updateInspectorText();
}
private ScheduledDelegate? rollingTextUpdate;
private void updateInspectorText()
{
inspectorText.Clear();
rollingTextUpdate?.Cancel();
rollingTextUpdate = null;
switch (EditorBeatmap.SelectedHitObjects.Count)
{
case 0:
addValue("No selection");
break;
case 1:
var selected = EditorBeatmap.SelectedHitObjects.Single();
addHeader("Type");
addValue($"{selected.GetType().ReadableName()}");
addHeader("Time");
addValue($"{selected.StartTime:#,0.##}ms");
switch (selected)
{
case IHasPosition pos:
addHeader("Position");
addValue($"x:{pos.X:#,0.##} y:{pos.Y:#,0.##}");
break;
case IHasXPosition x:
addHeader("Position");
addValue($"x:{x.X:#,0.##} ");
break;
case IHasYPosition y:
addHeader("Position");
addValue($"y:{y.Y:#,0.##}");
break;
}
if (selected is IHasDistance distance)
{
addHeader("Distance");
addValue($"{distance.Distance:#,0.##}px");
}
if (selected is IHasRepeats repeats)
{
addHeader("Repeats");
addValue($"{repeats.RepeatCount:#,0.##}");
}
if (selected is IHasDuration duration)
{
addHeader("End Time");
addValue($"{duration.EndTime:#,0.##}ms");
addHeader("Duration");
addValue($"{duration.Duration:#,0.##}ms");
}
// I'd hope there's a better way to do this, but I don't want to bind to each and every property above to watch for changes.
// This is a good middle-ground for the time being.
rollingTextUpdate ??= Scheduler.AddDelayed(updateInspectorText, 250);
break;
default:
addHeader("Selected Objects");
addValue($"{EditorBeatmap.SelectedHitObjects.Count:#,0.##}");
addHeader("Start Time");
addValue($"{EditorBeatmap.SelectedHitObjects.Min(o => o.StartTime):#,0.##}ms");
addHeader("End Time");
addValue($"{EditorBeatmap.SelectedHitObjects.Max(o => o.GetEndTime()):#,0.##}ms");
break;
}
void addHeader(string header) => inspectorText.AddParagraph($"{header}: ", s =>
{
s.Padding = new MarginPadding { Top = 2 };
s.Font = s.Font.With(size: 12);
s.Colour = colourProvider.Content2;
});
void addValue(string value) => inspectorText.AddParagraph(value, s =>
{
s.Font = s.Font.With(weight: FontWeight.SemiBold);
s.Colour = colourProvider.Content1;
});
}
}
}

View File

@ -24,5 +24,22 @@ namespace osu.Game.Rulesets.Mods
MaxValue = 2,
Precision = 0.01,
};
public override double ScoreMultiplier
{
get
{
// Round to the nearest multiple of 0.1.
double value = (int)(SpeedChange.Value * 10) / 10.0;
// Offset back to 0.
value -= 1;
// Each 0.1 multiple changes score multiplier by 0.02.
value /= 5;
return 1 + value;
}
}
}
}

View File

@ -24,5 +24,19 @@ namespace osu.Game.Rulesets.Mods
MaxValue = 0.99,
Precision = 0.01,
};
public override double ScoreMultiplier
{
get
{
// Round to the nearest multiple of 0.1.
double value = (int)(SpeedChange.Value * 10) / 10.0;
// Offset back to 0.
value -= 1;
return 1 + value;
}
}
}
}

View File

@ -7,14 +7,15 @@ using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Localisation;
using osuTK;
using osuTK.Graphics;
using Key = osuTK.Input.Key;
namespace osu.Game.Screens.Edit.Compose.Components
{
@ -26,6 +27,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
private SpriteIcon icon;
private const float snap_step = 15;
private readonly Bindable<float?> cumulativeRotation = new Bindable<float?>();
[Resolved]
@ -50,18 +53,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
});
}
protected override void LoadComplete()
{
base.LoadComplete();
cumulativeRotation.BindValueChanged(_ => updateTooltipText(), true);
}
protected override void UpdateHoverState()
{
base.UpdateHoverState();
icon.FadeColour(!IsHeld && IsHovered ? Color4.White : Color4.Black, TRANSFORM_DURATION, Easing.OutQuint);
}
private float rawCumulativeRotation;
protected override bool OnDragStart(DragStartEvent e)
{
bool handle = base.OnDragStart(e);
@ -74,21 +73,36 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
base.OnDrag(e);
float instantaneousAngle = convertDragEventToAngleOfRotation(e);
cumulativeRotation.Value += instantaneousAngle;
rawCumulativeRotation += convertDragEventToAngleOfRotation(e);
if (cumulativeRotation.Value < -180)
cumulativeRotation.Value += 360;
else if (cumulativeRotation.Value > 180)
cumulativeRotation.Value -= 360;
applyRotation(shouldSnap: e.ShiftPressed);
}
HandleRotate?.Invoke(instantaneousAngle);
protected override bool OnKeyDown(KeyDownEvent e)
{
if (IsDragged && (e.Key == Key.ShiftLeft || e.Key == Key.ShiftRight))
{
applyRotation(shouldSnap: true);
return true;
}
return base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyUpEvent e)
{
base.OnKeyUp(e);
if (IsDragged && (e.Key == Key.ShiftLeft || e.Key == Key.ShiftRight))
applyRotation(shouldSnap: false);
}
protected override void OnDragEnd(DragEndEvent e)
{
base.OnDragEnd(e);
cumulativeRotation.Value = null;
rawCumulativeRotation = 0;
TooltipText = default;
}
private float convertDragEventToAngleOfRotation(DragEvent e)
@ -100,9 +114,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
return (endAngle - startAngle) * 180 / MathF.PI;
}
private void updateTooltipText()
private void applyRotation(bool shouldSnap)
{
TooltipText = cumulativeRotation.Value?.ToLocalisableString("0.0°") ?? default;
float oldRotation = cumulativeRotation.Value ?? 0;
float newRotation = shouldSnap ? snap(rawCumulativeRotation, snap_step) : rawCumulativeRotation;
newRotation = (newRotation - 180) % 360 + 180;
cumulativeRotation.Value = newRotation;
HandleRotate?.Invoke(newRotation - oldRotation);
TooltipText = shouldSnap ? EditorStrings.RotationSnapped(newRotation) : EditorStrings.RotationUnsnapped(newRotation);
}
private float snap(float value, float step) => MathF.Round(value / step) * step;
}
}