mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 23:24:04 +09:00
Merge branch 'master' into editor-context-menu-on-select
This commit is contained in:
@ -92,7 +92,7 @@ namespace osu.Game.Screens.Edit
|
||||
{
|
||||
int beat = index % beatDivisor;
|
||||
|
||||
foreach (var divisor in BindableBeatDivisor.VALID_DIVISORS)
|
||||
foreach (int divisor in BindableBeatDivisor.VALID_DIVISORS)
|
||||
{
|
||||
if ((beat * divisor) % beatDivisor == 0)
|
||||
return divisor;
|
||||
|
@ -205,7 +205,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
foreach (var t in availableDivisors)
|
||||
foreach (int t in availableDivisors)
|
||||
{
|
||||
AddInternal(new Tick
|
||||
{
|
||||
@ -287,7 +287,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
private void handleMouseInput(Vector2 screenSpaceMousePosition)
|
||||
{
|
||||
// copied from SliderBar so we can do custom spacing logic.
|
||||
var xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth;
|
||||
float xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth;
|
||||
|
||||
CurrentNumber.Value = availableDivisors.OrderBy(d => Math.Abs(getMappedPosition(d) - xPosition)).First();
|
||||
OnUserChange(Current.Value);
|
||||
|
@ -58,13 +58,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
switch (args.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
foreach (var o in args.NewItems)
|
||||
foreach (object o in args.NewItems)
|
||||
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Select();
|
||||
|
||||
break;
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
foreach (var o in args.OldItems)
|
||||
foreach (object o in args.OldItems)
|
||||
SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Deselect();
|
||||
|
||||
break;
|
||||
@ -477,7 +477,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
if (snapProvider != null)
|
||||
{
|
||||
// check for positional snap for every object in selection (for things like object-object snapping)
|
||||
for (var i = 0; i < movementBlueprintOriginalPositions.Length; i++)
|
||||
for (int i = 0; i < movementBlueprintOriginalPositions.Length; i++)
|
||||
{
|
||||
Vector2 originalPosition = movementBlueprintOriginalPositions[i];
|
||||
var testPosition = originalPosition + distanceTravelled;
|
||||
|
@ -132,8 +132,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
protected ColourInfo GetColourForIndexFromPlacement(int placementIndex)
|
||||
{
|
||||
var timingPoint = beatmap.ControlPointInfo.TimingPointAt(StartTime);
|
||||
var beatLength = timingPoint.BeatLength / beatDivisor.Value;
|
||||
var beatIndex = (int)Math.Round((StartTime - timingPoint.Time) / beatLength);
|
||||
double beatLength = timingPoint.BeatLength / beatDivisor.Value;
|
||||
int beatIndex = (int)Math.Round((StartTime - timingPoint.Time) / beatLength);
|
||||
|
||||
var colour = BindableBeatDivisor.GetColourFor(BindableBeatDivisor.GetDivisorForBeatIndex(beatIndex + placementIndex + 1, beatDivisor.Value), Colours);
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
/// </summary>
|
||||
private void createStateBindables()
|
||||
{
|
||||
foreach (var sampleName in HitSampleInfo.AllAdditions)
|
||||
foreach (string sampleName in HitSampleInfo.AllAdditions)
|
||||
{
|
||||
var bindable = new Bindable<TernaryState>
|
||||
{
|
||||
@ -102,7 +102,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
SelectionNewComboState.Value = GetStateFromSelection(SelectedItems.OfType<IHasComboInformation>(), h => h.NewCombo);
|
||||
|
||||
foreach (var (sampleName, bindable) in SelectionSampleStates)
|
||||
foreach ((string sampleName, var bindable) in SelectionSampleStates)
|
||||
{
|
||||
bindable.Value = GetStateFromSelection(SelectedItems, h => h.Samples.Any(s => s.Name == sampleName));
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
if (timeline != null)
|
||||
{
|
||||
var timelineQuad = timeline.ScreenSpaceDrawQuad;
|
||||
var mouseX = e.ScreenSpaceMousePosition.X;
|
||||
float mouseX = e.ScreenSpaceMousePosition.X;
|
||||
|
||||
// scroll if in a drag and dragging outside visible extents
|
||||
if (mouseX > timelineQuad.TopRight.X)
|
||||
|
@ -397,7 +397,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
if (hitObject.DifficultyControlPoint == DifficultyControlPoint.DEFAULT)
|
||||
hitObject.DifficultyControlPoint = new DifficultyControlPoint();
|
||||
|
||||
var newVelocity = hitObject.DifficultyControlPoint.SliderVelocity * (repeatHitObject.Duration / proposedDuration);
|
||||
double newVelocity = hitObject.DifficultyControlPoint.SliderVelocity * (repeatHitObject.Duration / proposedDuration);
|
||||
|
||||
if (Precision.AlmostEquals(newVelocity, hitObject.DifficultyControlPoint.SliderVelocity))
|
||||
return;
|
||||
@ -408,8 +408,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
else
|
||||
{
|
||||
// find the number of repeats which can fit in the requested time.
|
||||
var lengthOfOneRepeat = repeatHitObject.Duration / (repeatHitObject.RepeatCount + 1);
|
||||
var proposedCount = Math.Max(0, (int)Math.Round(proposedDuration / lengthOfOneRepeat) - 1);
|
||||
double lengthOfOneRepeat = repeatHitObject.Duration / (repeatHitObject.RepeatCount + 1);
|
||||
int proposedCount = Math.Max(0, (int)Math.Round(proposedDuration / lengthOfOneRepeat) - 1);
|
||||
|
||||
if (proposedCount == repeatHitObject.RepeatCount)
|
||||
return;
|
||||
@ -421,7 +421,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
break;
|
||||
|
||||
case IHasDuration endTimeHitObject:
|
||||
var snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time));
|
||||
double snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time));
|
||||
|
||||
if (endTimeHitObject.EndTime == snappedTime || Precision.AlmostEquals(snappedTime, hitObject.StartTime, beatmap.GetBeatLengthAtTime(snappedTime)))
|
||||
return;
|
||||
|
@ -104,10 +104,10 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
nextMinTick = null;
|
||||
nextMaxTick = null;
|
||||
|
||||
for (var i = 0; i < beatmap.ControlPointInfo.TimingPoints.Count; i++)
|
||||
for (int i = 0; i < beatmap.ControlPointInfo.TimingPoints.Count; i++)
|
||||
{
|
||||
var point = beatmap.ControlPointInfo.TimingPoints[i];
|
||||
var until = i + 1 < beatmap.ControlPointInfo.TimingPoints.Count ? beatmap.ControlPointInfo.TimingPoints[i + 1].Time : working.Value.Track.Length;
|
||||
double until = i + 1 < beatmap.ControlPointInfo.TimingPoints.Count ? beatmap.ControlPointInfo.TimingPoints[i + 1].Time : working.Value.Track.Length;
|
||||
|
||||
int beat = 0;
|
||||
|
||||
@ -127,7 +127,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
int indexInBar = beat % ((int)point.TimeSignature * beatDivisor.Value);
|
||||
|
||||
var divisor = BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value);
|
||||
int divisor = BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value);
|
||||
var colour = BindableBeatDivisor.GetColourFor(divisor, colours);
|
||||
|
||||
// even though "bar lines" take up the full vertical space, we render them in two pieces because it allows for less anchor/origin churn.
|
||||
|
@ -301,7 +301,7 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
editorBeatmap.SelectedHitObjects.BindCollectionChanged((_, __) =>
|
||||
{
|
||||
var hasObjects = editorBeatmap.SelectedHitObjects.Count > 0;
|
||||
bool hasObjects = editorBeatmap.SelectedHitObjects.Count > 0;
|
||||
|
||||
cutMenuItem.Action.Disabled = !hasObjects;
|
||||
copyMenuItem.Action.Disabled = !hasObjects;
|
||||
|
@ -183,7 +183,7 @@ namespace osu.Game.Screens.Edit
|
||||
public void Add(HitObject hitObject)
|
||||
{
|
||||
// Preserve existing sorting order in the beatmap
|
||||
var insertionIndex = findInsertionIndex(PlayableBeatmap.HitObjects, hitObject.StartTime);
|
||||
int insertionIndex = findInsertionIndex(PlayableBeatmap.HitObjects, hitObject.StartTime);
|
||||
Insert(insertionIndex + 1, hitObject);
|
||||
}
|
||||
|
||||
@ -332,7 +332,7 @@ namespace osu.Game.Screens.Edit
|
||||
// For now we'll remove and re-add the hitobject. This is not optimal and can be improved if required.
|
||||
mutableHitObjects.Remove(hitObject);
|
||||
|
||||
var insertionIndex = findInsertionIndex(PlayableBeatmap.HitObjects, hitObject.StartTime);
|
||||
int insertionIndex = findInsertionIndex(PlayableBeatmap.HitObjects, hitObject.StartTime);
|
||||
mutableHitObjects.Insert(insertionIndex + 1, hitObject);
|
||||
|
||||
Update(hitObject);
|
||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Screens.Edit
|
||||
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||
new LegacyBeatmapEncoder(editorBeatmap, editorBeatmap.BeatmapSkin).Encode(sw);
|
||||
|
||||
var newState = stream.ToArray();
|
||||
byte[] newState = stream.ToArray();
|
||||
|
||||
// if the previous state is binary equal we don't need to push a new one, unless this is the initial state.
|
||||
if (savedStates.Count > 0 && newState.SequenceEqual(savedStates[currentState])) return;
|
||||
|
@ -82,7 +82,7 @@ namespace osu.Game.Screens.Edit
|
||||
if (toAdd.Count > 0)
|
||||
{
|
||||
IBeatmap newBeatmap = readBeatmap(newState);
|
||||
foreach (var i in toAdd)
|
||||
foreach (int i in toAdd)
|
||||
editorBeatmap.Insert(i, newBeatmap.HitObjects[i]);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
if (!isNew)
|
||||
return;
|
||||
|
||||
if (double.TryParse(sender.Text, out var newTime))
|
||||
if (double.TryParse(sender.Text, out double newTime))
|
||||
{
|
||||
changeSelectedGroupTime(newTime);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Overlays.Settings;
|
||||
|
||||
@ -16,7 +17,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
{
|
||||
private readonly SettingsSlider<T> slider;
|
||||
|
||||
public SliderWithTextBoxInput(string labelText)
|
||||
public SliderWithTextBoxInput(LocalisableString labelText)
|
||||
{
|
||||
LabelledTextBox textbox;
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Screens.Menu
|
||||
private readonly Bindable<User> currentUser = new Bindable<User>();
|
||||
private FillFlowContainer fill;
|
||||
|
||||
private readonly List<Drawable> expendableText = new List<Drawable>();
|
||||
private readonly List<ITextPart> expendableText = new List<ITextPart>();
|
||||
|
||||
public Disclaimer(OsuScreen nextScreen = null)
|
||||
{
|
||||
@ -97,7 +97,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
textFlow.AddText("this is osu!", t => t.Font = t.Font.With(Typeface.Torus, 30, FontWeight.Regular));
|
||||
|
||||
expendableText.AddRange(textFlow.AddText("lazer", t =>
|
||||
expendableText.Add(textFlow.AddText("lazer", t =>
|
||||
{
|
||||
t.Font = t.Font.With(Typeface.Torus, 30, FontWeight.Regular);
|
||||
t.Colour = colours.PinkLight;
|
||||
@ -114,7 +114,7 @@ namespace osu.Game.Screens.Menu
|
||||
t.Font = t.Font.With(Typeface.Torus, 20, FontWeight.SemiBold);
|
||||
t.Colour = colours.Pink;
|
||||
});
|
||||
expendableText.AddRange(textFlow.AddText(" coming to osu!", formatRegular));
|
||||
expendableText.Add(textFlow.AddText(" coming to osu!", formatRegular));
|
||||
textFlow.AddText(".", formatRegular);
|
||||
|
||||
textFlow.NewParagraph();
|
||||
@ -152,7 +152,7 @@ namespace osu.Game.Screens.Menu
|
||||
t.Font = t.Font.With(size: 20);
|
||||
t.Origin = Anchor.Centre;
|
||||
t.Colour = colours.Pink;
|
||||
}).First();
|
||||
}).Drawables.First();
|
||||
|
||||
if (IsLoaded)
|
||||
animateHeart();
|
||||
@ -193,7 +193,7 @@ namespace osu.Game.Screens.Menu
|
||||
using (BeginDelayedSequence(520 + 160))
|
||||
{
|
||||
fill.MoveToOffset(new Vector2(0, 15), 160, Easing.OutQuart);
|
||||
Schedule(() => expendableText.ForEach(t =>
|
||||
Schedule(() => expendableText.SelectMany(t => t.Drawables).ForEach(t =>
|
||||
{
|
||||
t.FadeOut(100);
|
||||
t.ScaleTo(new Vector2(0, 1), 100, Easing.OutQuart);
|
||||
|
@ -211,7 +211,7 @@ namespace osu.Game.Screens.Menu
|
||||
else
|
||||
{
|
||||
const int quick_appear = 350;
|
||||
var initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0;
|
||||
int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0;
|
||||
|
||||
logo.MoveTo(new Vector2(0.5f), initialMovementTime, Easing.OutQuint);
|
||||
|
||||
|
@ -272,7 +272,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
lastBeatIndex = beatIndex;
|
||||
|
||||
var beatLength = timingPoint.BeatLength;
|
||||
double beatLength = timingPoint.BeatLength;
|
||||
|
||||
float amplitudeAdjust = Math.Min(1, 0.4f + amplitudes.Maximum);
|
||||
|
||||
@ -337,7 +337,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
if (musicController.CurrentTrack.IsRunning)
|
||||
{
|
||||
var maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentTrack.CurrentAmplitudes.Maximum : 0;
|
||||
float maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentTrack.CurrentAmplitudes.Maximum : 0;
|
||||
logoAmplitudeContainer.Scale = new Vector2((float)Interpolation.Damp(logoAmplitudeContainer.Scale.X, 1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 0.9f, Time.Elapsed));
|
||||
|
||||
if (maxAmplitude > velocity_adjust_cutoff)
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Chat;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Components
|
||||
@ -69,24 +68,14 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
textFlow.AddLink(new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new RomanisableString(beatmap.Value.Metadata.ArtistUnicode, beatmap.Value.Metadata.Artist),
|
||||
Font = OsuFont.GetFont(size: TextSize),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = " - ",
|
||||
Font = OsuFont.GetFont(size: TextSize),
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new RomanisableString(beatmap.Value.Metadata.TitleUnicode, beatmap.Value.Metadata.Title),
|
||||
Font = OsuFont.GetFont(size: TextSize),
|
||||
}
|
||||
}, LinkAction.OpenBeatmap, beatmap.Value.OnlineID.ToString(), "Open beatmap");
|
||||
var metadataInfo = beatmap.Value.Metadata;
|
||||
|
||||
string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode;
|
||||
string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode;
|
||||
|
||||
var title = new RomanisableString($"{artistUnicode} - {titleUnicode}".Trim(), $"{metadataInfo.Artist} - {metadataInfo.Title}".Trim());
|
||||
|
||||
textFlow.AddLink(title, LinkAction.OpenBeatmap, beatmap.Value.OnlineID.ToString(), "Open beatmap");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
|
||||
public override bool OnExiting(IScreen next)
|
||||
{
|
||||
var result = base.OnExiting(next);
|
||||
bool result = base.OnExiting(next);
|
||||
this.MoveToX(0);
|
||||
return result;
|
||||
}
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.Rooms;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Components
|
||||
{
|
||||
public abstract class ReadyButton : TriangleButton
|
||||
public abstract class ReadyButton : TriangleButton, IHasTooltip
|
||||
{
|
||||
public new readonly BindableBool Enabled = new BindableBool();
|
||||
|
||||
@ -24,6 +26,18 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
Enabled.BindValueChanged(_ => updateState(), true);
|
||||
}
|
||||
|
||||
private void updateState() => base.Enabled.Value = availability.Value.State == DownloadState.LocallyAvailable && Enabled.Value;
|
||||
private void updateState() =>
|
||||
base.Enabled.Value = availability.Value.State == DownloadState.LocallyAvailable && Enabled.Value;
|
||||
|
||||
public virtual LocalisableString TooltipText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Enabled.Value)
|
||||
return string.Empty;
|
||||
|
||||
return "Beatmap not downloaded";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
{
|
||||
private OsuSpriteText attemptDisplay;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
public RoomLocalUserInfo()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
@ -54,6 +57,9 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
{
|
||||
int remaining = MaxAttempts.Value.Value - UserScore.Value.PlaylistItemAttempts.Sum(a => a.Attempts);
|
||||
attemptDisplay.Text += $" ({remaining} remaining)";
|
||||
|
||||
if (remaining == 0)
|
||||
attemptDisplay.Colour = colours.RedLight;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -105,13 +105,12 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
|
||||
private void refresh()
|
||||
{
|
||||
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods) { Size = new Vector2(32) };
|
||||
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
|
||||
|
||||
beatmapText.Clear();
|
||||
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString(), null, text =>
|
||||
{
|
||||
text.Truncate = true;
|
||||
text.RelativeSizeAxes = Axes.X;
|
||||
});
|
||||
|
||||
authorText.Clear();
|
||||
@ -182,8 +181,11 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
{
|
||||
beatmapText = new LinkFlowContainer(fontParameters)
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
// workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
|
||||
// TODO: remove when text/link flow can support truncation with ellipsis natively.
|
||||
Height = OsuFont.DEFAULT_FONT_SIZE,
|
||||
Masking = true
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
@ -248,10 +250,7 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
protected virtual IEnumerable<Drawable> CreateButtons() =>
|
||||
new Drawable[]
|
||||
{
|
||||
new PlaylistDownloadButton(Item)
|
||||
{
|
||||
Size = new Vector2(50, 30)
|
||||
},
|
||||
new PlaylistDownloadButton(Item),
|
||||
new PlaylistRemoveButton
|
||||
{
|
||||
Size = new Vector2(30, 30),
|
||||
@ -282,28 +281,33 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
return true;
|
||||
}
|
||||
|
||||
private class PlaylistDownloadButton : BeatmapPanelDownloadButton
|
||||
private sealed class PlaylistDownloadButton : BeatmapPanelDownloadButton
|
||||
{
|
||||
private readonly PlaylistItem playlistItem;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; }
|
||||
|
||||
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
||||
// required for download tracking, as this button hides itself. can probably be removed with a bit of consideration.
|
||||
public override bool IsPresent => true;
|
||||
|
||||
private const float width = 50;
|
||||
|
||||
public PlaylistDownloadButton(PlaylistItem playlistItem)
|
||||
: base(playlistItem.Beatmap.Value.BeatmapSet)
|
||||
{
|
||||
this.playlistItem = playlistItem;
|
||||
|
||||
Size = new Vector2(width, 30);
|
||||
Alpha = 0;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
State.BindValueChanged(stateChanged, true);
|
||||
FinishTransforms(true);
|
||||
|
||||
// base implementation calls FinishTransforms, so should be run after the above state update.
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
private void stateChanged(ValueChangedEvent<DownloadState> state)
|
||||
@ -315,12 +319,16 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
if (beatmapManager.QueryBeatmap(b => b.MD5Hash == playlistItem.Beatmap.Value.MD5Hash) == null)
|
||||
State.Value = DownloadState.NotDownloaded;
|
||||
else
|
||||
this.FadeTo(0, 500);
|
||||
{
|
||||
this.FadeTo(0, 500)
|
||||
.ResizeWidthTo(0, 500, Easing.OutQuint);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
this.FadeTo(1, 500);
|
||||
this.ResizeWidthTo(width, 500, Easing.OutQuint)
|
||||
.FadeTo(1, 500);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -333,13 +341,14 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
|
||||
public PanelBackground()
|
||||
{
|
||||
UpdateableBeatmapBackgroundSprite backgroundSprite;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new UpdateableBeatmapBackgroundSprite
|
||||
backgroundSprite = new UpdateableBeatmapBackgroundSprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
Beatmap = { BindTarget = Beatmap }
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
@ -374,6 +383,10 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// manual binding required as playlists don't expose IBeatmapInfo currently.
|
||||
// may be removed in the future if this changes.
|
||||
Beatmap.BindValueChanged(beatmap => backgroundSprite.Beatmap.Value = beatmap.NewValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,7 +353,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
// workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
|
||||
// TODO: remove when text/link flow can support truncation with ellipsis natively.
|
||||
Height = 16,
|
||||
Masking = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -385,7 +388,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
creationParameters: s =>
|
||||
{
|
||||
s.Truncate = true;
|
||||
s.RelativeSizeAxes = Axes.X;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Collections.Specialized;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@ -46,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
private void updateCount(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
count.Clear();
|
||||
count.AddText(Playlist.Count.ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold));
|
||||
count.AddText(Playlist.Count.ToLocalisableString(), s => s.Font = s.Font.With(weight: FontWeight.Bold));
|
||||
count.AddText(" ");
|
||||
count.AddText("Beatmap".ToQuantity(Playlist.Count, ShowQuantityAs.None));
|
||||
}
|
||||
|
@ -65,9 +65,9 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||
|
||||
[Cached]
|
||||
protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; private set; }
|
||||
private OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker { get; set; }
|
||||
|
||||
protected IBindable<BeatmapAvailability> BeatmapAvailability => BeatmapAvailabilityTracker.Availability;
|
||||
protected IBindable<BeatmapAvailability> BeatmapAvailability => beatmapAvailabilityTracker.Availability;
|
||||
|
||||
public readonly Room Room;
|
||||
private readonly bool allowEdit;
|
||||
@ -88,7 +88,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
|
||||
Padding = new MarginPadding { Top = Header.HEIGHT };
|
||||
|
||||
BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
||||
beatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
||||
{
|
||||
SelectedItem = { BindTarget = SelectedItem }
|
||||
};
|
||||
@ -103,7 +103,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
BeatmapAvailabilityTracker,
|
||||
beatmapAvailabilityTracker,
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
@ -186,7 +186,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
||||
|
||||
var ruleset = rulesets.GetRuleset(Room.Settings.RulesetID).CreateInstance();
|
||||
|
||||
var currentModeRank = User.User?.RulesetsStatistics?.GetValueOrDefault(ruleset.ShortName)?.GlobalRank;
|
||||
int? currentModeRank = User.User?.RulesetsStatistics?.GetValueOrDefault(ruleset.ShortName)?.GlobalRank;
|
||||
userRankText.Text = currentModeRank != null ? $"#{currentModeRank.Value:N0}" : string.Empty;
|
||||
|
||||
userStateDisplay.UpdateStatus(User.State, User.BeatmapAvailability);
|
||||
|
@ -180,11 +180,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
|
||||
{
|
||||
// Seek the master clock to the gameplay time.
|
||||
// This is chosen as the first available frame in the players' replays, which matches the seek by each individual SpectatorPlayer.
|
||||
var startTime = instances.Where(i => i.Score != null)
|
||||
.SelectMany(i => i.Score.Replay.Frames)
|
||||
.Select(f => f.Time)
|
||||
.DefaultIfEmpty(0)
|
||||
.Min();
|
||||
double startTime = instances.Where(i => i.Score != null)
|
||||
.SelectMany(i => i.Score.Replay.Frames)
|
||||
.Select(f => f.Time)
|
||||
.DefaultIfEmpty(0)
|
||||
.Min();
|
||||
|
||||
masterClockContainer.Seek(startTime);
|
||||
masterClockContainer.Start();
|
||||
|
@ -2,8 +2,10 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.Rooms;
|
||||
@ -16,6 +18,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
[Resolved(typeof(Room), nameof(Room.EndDate))]
|
||||
private Bindable<DateTimeOffset?> endDate { get; set; }
|
||||
|
||||
[Resolved(typeof(Room), nameof(Room.MaxAttempts))]
|
||||
private Bindable<int?> maxAttempts { get; set; }
|
||||
|
||||
[Resolved(typeof(Room), nameof(Room.UserScore))]
|
||||
private Bindable<PlaylistAggregateScore> userScore { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> gameBeatmap { get; set; }
|
||||
|
||||
@ -32,11 +40,49 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
Triangles.ColourLight = colours.GreenLight;
|
||||
}
|
||||
|
||||
private bool hasRemainingAttempts = true;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
userScore.BindValueChanged(aggregate =>
|
||||
{
|
||||
if (maxAttempts.Value == null)
|
||||
return;
|
||||
|
||||
int remaining = maxAttempts.Value.Value - aggregate.NewValue.PlaylistItemAttempts.Sum(a => a.Attempts);
|
||||
|
||||
hasRemainingAttempts = remaining > 0;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Enabled.Value = endDate.Value != null && DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(gameBeatmap.Value.Track.Length) < endDate.Value;
|
||||
Enabled.Value = hasRemainingAttempts && enoughTimeLeft;
|
||||
}
|
||||
|
||||
public override LocalisableString TooltipText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Enabled.Value)
|
||||
return string.Empty;
|
||||
|
||||
if (!enoughTimeLeft)
|
||||
return "No time left!";
|
||||
|
||||
if (!hasRemainingAttempts)
|
||||
return "Attempts exhausted!";
|
||||
|
||||
return base.TooltipText;
|
||||
}
|
||||
}
|
||||
|
||||
private bool enoughTimeLeft =>
|
||||
// This should probably consider the length of the currently selected item, rather than a constant 30 seconds.
|
||||
endDate.Value != null && DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(gameBeatmap.Value.Track.Length) < endDate.Value;
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
private MatchLeaderboard leaderboard;
|
||||
private SelectionPollingComponent selectionPollingComponent;
|
||||
|
||||
private FillFlowContainer progressSection;
|
||||
|
||||
public PlaylistsRoomSubScreen(Room room)
|
||||
: base(room, false) // Editing is temporarily not allowed.
|
||||
{
|
||||
@ -67,6 +69,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
Schedule(() => SelectedItem.Value = Room.Playlist.FirstOrDefault());
|
||||
}
|
||||
}, true);
|
||||
|
||||
Room.MaxAttempts.BindValueChanged(attempts => progressSection.Alpha = Room.MaxAttempts.Value != null ? 1 : 0, true);
|
||||
}
|
||||
|
||||
protected override Drawable CreateMainContent() => new GridContainer
|
||||
@ -153,6 +157,22 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
},
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
progressSection = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Alpha = 0,
|
||||
Margin = new MarginPadding { Bottom = 10 },
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OverlinedHeader("Progress"),
|
||||
new RoomLocalUserInfo(),
|
||||
}
|
||||
},
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
new OverlinedHeader("Leaderboard")
|
||||
},
|
||||
@ -162,6 +182,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(),
|
||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play.Break
|
||||
|
||||
private void currentValueChanged(ValueChangedEvent<T> e)
|
||||
{
|
||||
var newText = prefix + Format(e.NewValue);
|
||||
string newText = prefix + Format(e.NewValue);
|
||||
|
||||
if (valueText.Text == newText)
|
||||
return;
|
||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private void updateBreakTime()
|
||||
{
|
||||
var time = Clock.CurrentTime;
|
||||
double time = Clock.CurrentTime;
|
||||
|
||||
isBreakTime.Value = breaks?.IsInAny(time) == true
|
||||
|| time < gameplayStartTime
|
||||
|
@ -10,6 +10,7 @@ using ManagedBass.Fx;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@ -83,7 +84,7 @@ namespace osu.Game.Screens.Play
|
||||
Content,
|
||||
redFlashLayer = new Box
|
||||
{
|
||||
Colour = Color4.Red,
|
||||
Colour = Color4.Red.Opacity(0.6f),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Depth = float.MinValue,
|
||||
|
@ -90,7 +90,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
private void updateState()
|
||||
{
|
||||
// Don't display ever if the ruleset is not using a draining health display.
|
||||
var showLayer = HealthProcessor is DrainingHealthProcessor && fadePlayfieldWhenHealthLow.Value && ShowHealth.Value;
|
||||
bool showLayer = HealthProcessor is DrainingHealthProcessor && fadePlayfieldWhenHealthLow.Value && ShowHealth.Value;
|
||||
this.FadeTo(showLayer ? 1 : 0, fade_time, Easing.OutQuint);
|
||||
}
|
||||
|
||||
|
@ -157,11 +157,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||
// max to avoid div-by-zero.
|
||||
maxHitWindow = Math.Max(1, windows.First().length);
|
||||
|
||||
for (var i = 0; i < windows.Length; i++)
|
||||
for (int i = 0; i < windows.Length; i++)
|
||||
{
|
||||
var (result, length) = windows[i];
|
||||
(var result, double length) = windows[i];
|
||||
|
||||
var hitWindow = (float)(length / maxHitWindow);
|
||||
float hitWindow = (float)(length / maxHitWindow);
|
||||
|
||||
colourBarsEarly.Add(createColourBar(result, hitWindow, i == 0));
|
||||
colourBarsLate.Add(createColourBar(result, hitWindow, i == 0));
|
||||
|
@ -133,7 +133,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
var winningBar = Team1Score.Value > Team2Score.Value ? score1Bar : score2Bar;
|
||||
var losingBar = Team1Score.Value <= Team2Score.Value ? score1Bar : score2Bar;
|
||||
|
||||
var diff = Math.Max(Team1Score.Value, Team2Score.Value) - Math.Min(Team1Score.Value, Team2Score.Value);
|
||||
int diff = Math.Max(Team1Score.Value, Team2Score.Value) - Math.Min(Team1Score.Value, Team2Score.Value);
|
||||
|
||||
losingBar.ResizeWidthTo(0, 400, Easing.OutQuint);
|
||||
winningBar.ResizeWidthTo(Math.Min(0.4f, MathF.Pow(diff / 1500000f, 0.5f) / 2), 400, Easing.OutQuint);
|
||||
|
@ -148,7 +148,7 @@ namespace osu.Game.Screens.Play.HUD
|
||||
switch (e.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
foreach (var userId in e.OldItems.OfType<int>())
|
||||
foreach (int userId in e.OldItems.OfType<int>())
|
||||
{
|
||||
spectatorClient.StopWatchingUser(userId);
|
||||
|
||||
|
@ -223,7 +223,7 @@ namespace osu.Game.Screens.Play
|
||||
onlineBeatmapRequest.Success += res => Schedule(() =>
|
||||
{
|
||||
onlineBeatmap = res.ToBeatmapSet(rulesets);
|
||||
beatmapPanelContainer.Child = new GridBeatmapPanel(onlineBeatmap);
|
||||
beatmapPanelContainer.Child = new GridBeatmapPanel(res);
|
||||
checkForAutomaticDownload();
|
||||
});
|
||||
|
||||
|
@ -24,17 +24,17 @@ namespace osu.Game.Screens.Play
|
||||
if (!objects.Any())
|
||||
return;
|
||||
|
||||
var firstHit = objects.First().StartTime;
|
||||
var lastHit = objects.Max(o => o.GetEndTime());
|
||||
double firstHit = objects.First().StartTime;
|
||||
double lastHit = objects.Max(o => o.GetEndTime());
|
||||
|
||||
if (lastHit == 0)
|
||||
lastHit = objects.Last().StartTime;
|
||||
|
||||
var interval = (lastHit - firstHit + 1) / granularity;
|
||||
double interval = (lastHit - firstHit + 1) / granularity;
|
||||
|
||||
foreach (var h in objects)
|
||||
{
|
||||
var endTime = h.GetEndTime();
|
||||
double endTime = h.GetEndTime();
|
||||
|
||||
Debug.Assert(endTime >= h.StartTime);
|
||||
|
||||
|
@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var time = gameplayClock?.CurrentTime ?? Time.Current;
|
||||
double time = gameplayClock?.CurrentTime ?? Time.Current;
|
||||
|
||||
double songCurrentTime = time - startTime;
|
||||
int currentPercent = Math.Max(0, Math.Min(100, (int)(songCurrentTime / songLength * 100)));
|
||||
|
@ -165,7 +165,7 @@ namespace osu.Game.Screens.Play
|
||||
return;
|
||||
}
|
||||
|
||||
var max = values.Max();
|
||||
int max = values.Max();
|
||||
|
||||
float step = values.Length / (float)ColumnCount;
|
||||
|
||||
|
@ -116,7 +116,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
public override bool OnExiting(IScreen next)
|
||||
{
|
||||
var exiting = base.OnExiting(next);
|
||||
bool exiting = base.OnExiting(next);
|
||||
|
||||
submitScore(Score.DeepClone());
|
||||
|
||||
|
@ -62,12 +62,12 @@ namespace osu.Game.Screens.Ranking.Expanded
|
||||
{
|
||||
var beatmap = score.BeatmapInfo;
|
||||
var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata;
|
||||
var creator = metadata.Author?.Username;
|
||||
string creator = metadata.Author?.Username;
|
||||
|
||||
var topStatistics = new List<StatisticDisplay>
|
||||
{
|
||||
new AccuracyStatistic(score.Accuracy),
|
||||
new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out var missCount) || missCount == 0),
|
||||
new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0),
|
||||
new PerformanceStatistic(score),
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online;
|
||||
@ -12,13 +13,17 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
public class ReplayDownloadButton : DownloadTrackingComposite<ScoreInfo, ScoreManager>
|
||||
public class ReplayDownloadButton : CompositeDrawable
|
||||
{
|
||||
public Bindable<ScoreInfo> Score => Model;
|
||||
public readonly Bindable<ScoreInfo> Score = new Bindable<ScoreInfo>();
|
||||
|
||||
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
||||
|
||||
private DownloadButton button;
|
||||
private ShakeContainer shakeContainer;
|
||||
|
||||
private ScoreDownloadTracker downloadTracker;
|
||||
|
||||
private ReplayAvailability replayAvailability
|
||||
{
|
||||
get
|
||||
@ -26,7 +31,7 @@ namespace osu.Game.Screens.Ranking
|
||||
if (State.Value == DownloadState.LocallyAvailable)
|
||||
return ReplayAvailability.Local;
|
||||
|
||||
if (!string.IsNullOrEmpty(Model.Value?.Hash))
|
||||
if (!string.IsNullOrEmpty(Score.Value?.Hash))
|
||||
return ReplayAvailability.Online;
|
||||
|
||||
return ReplayAvailability.NotAvailable;
|
||||
@ -34,8 +39,8 @@ namespace osu.Game.Screens.Ranking
|
||||
}
|
||||
|
||||
public ReplayDownloadButton(ScoreInfo score)
|
||||
: base(score)
|
||||
{
|
||||
Score.Value = score;
|
||||
Size = new Vector2(50, 30);
|
||||
}
|
||||
|
||||
@ -56,11 +61,11 @@ namespace osu.Game.Screens.Ranking
|
||||
switch (State.Value)
|
||||
{
|
||||
case DownloadState.LocallyAvailable:
|
||||
game?.PresentScore(Model.Value, ScorePresentType.Gameplay);
|
||||
game?.PresentScore(Score.Value, ScorePresentType.Gameplay);
|
||||
break;
|
||||
|
||||
case DownloadState.NotDownloaded:
|
||||
scores.Download(Model.Value, false);
|
||||
scores.Download(Score.Value, false);
|
||||
break;
|
||||
|
||||
case DownloadState.Importing:
|
||||
@ -70,17 +75,25 @@ namespace osu.Game.Screens.Ranking
|
||||
}
|
||||
};
|
||||
|
||||
State.BindValueChanged(state =>
|
||||
Score.BindValueChanged(score =>
|
||||
{
|
||||
button.State.Value = state.NewValue;
|
||||
downloadTracker?.RemoveAndDisposeImmediately();
|
||||
|
||||
if (score.NewValue != null)
|
||||
{
|
||||
AddInternal(downloadTracker = new ScoreDownloadTracker(score.NewValue)
|
||||
{
|
||||
State = { BindTarget = State }
|
||||
});
|
||||
}
|
||||
|
||||
button.Enabled.Value = replayAvailability != ReplayAvailability.NotAvailable;
|
||||
updateTooltip();
|
||||
}, true);
|
||||
|
||||
Model.BindValueChanged(_ =>
|
||||
State.BindValueChanged(state =>
|
||||
{
|
||||
button.Enabled.Value = replayAvailability != ReplayAvailability.NotAvailable;
|
||||
|
||||
button.State.Value = state.NewValue;
|
||||
updateTooltip();
|
||||
}, true);
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ namespace osu.Game.Screens.Ranking
|
||||
detachedPanelContainer.Add(expandedPanel);
|
||||
|
||||
// Move into its original location in the local container first, then to the final location.
|
||||
var origLocation = detachedPanelContainer.ToLocalSpace(screenSpacePos).X;
|
||||
float origLocation = detachedPanelContainer.ToLocalSpace(screenSpacePos).X;
|
||||
expandedPanel.MoveToX(origLocation)
|
||||
.Then()
|
||||
.MoveToX(StatisticsPanel.SIDE_PADDING, 150, Easing.OutQuint);
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking
|
||||
return null;
|
||||
|
||||
getScoreRequest = new GetScoresRequest(Score.BeatmapInfo, Score.Ruleset);
|
||||
getScoreRequest.Success += r => scoresCallback?.Invoke(r.Scores.Where(s => s.OnlineScoreID != Score.OnlineScoreID).Select(s => s.CreateScoreInfo(rulesets)));
|
||||
getScoreRequest.Success += r => scoresCallback?.Invoke(r.Scores.Where(s => s.OnlineID != Score.OnlineScoreID).Select(s => s.CreateScoreInfo(rulesets, Beatmap.Value.BeatmapInfo)));
|
||||
return getScoreRequest;
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,8 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
public UnstableRate(IEnumerable<HitEvent> hitEvents)
|
||||
: base("Unstable Rate")
|
||||
{
|
||||
var timeOffsets = hitEvents.Where(e => !(e.HitObject.HitWindows is HitWindows.EmptyHitWindows) && e.Result.IsHit())
|
||||
.Select(ev => ev.TimeOffset).ToArray();
|
||||
double[] timeOffsets = hitEvents.Where(e => !(e.HitObject.HitWindows is HitWindows.EmptyHitWindows) && e.Result.IsHit())
|
||||
.Select(ev => ev.TimeOffset).ToArray();
|
||||
Value = 10 * standardDeviation(timeOffsets);
|
||||
}
|
||||
|
||||
@ -30,8 +30,8 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
if (timeOffsets.Length == 0)
|
||||
return double.NaN;
|
||||
|
||||
var mean = timeOffsets.Average();
|
||||
var squares = timeOffsets.Select(offset => Math.Pow(offset - mean, 2)).Sum();
|
||||
double mean = timeOffsets.Average();
|
||||
double squares = timeOffsets.Select(offset => Math.Pow(offset - mean, 2)).Sum();
|
||||
return Math.Sqrt(squares / timeOffsets.Length);
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Screens.Select
|
||||
beatmapInfo = value;
|
||||
|
||||
failTimes = beatmapInfo?.OnlineInfo?.FailTimes;
|
||||
ratings = beatmapInfo?.BeatmapSet?.Ratings;
|
||||
ratings = beatmapInfo?.BeatmapSet?.OnlineInfo?.Ratings;
|
||||
|
||||
Scheduler.AddOnce(updateStatistics);
|
||||
}
|
||||
@ -182,7 +182,7 @@ namespace osu.Game.Screens.Select
|
||||
source.Text = BeatmapInfo?.Metadata?.Source;
|
||||
tags.Text = BeatmapInfo?.Metadata?.Tags;
|
||||
|
||||
// metrics may have been previously fetched
|
||||
// failTimes may have been previously fetched
|
||||
if (ratings != null && failTimes != null)
|
||||
{
|
||||
updateMetrics();
|
||||
@ -233,7 +233,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private void updateMetrics()
|
||||
{
|
||||
var hasMetrics = (failTimes?.Retries?.Any() ?? false) || (failTimes?.Fails?.Any() ?? false);
|
||||
bool hasMetrics = (failTimes?.Retries?.Any() ?? false) || (failTimes?.Fails?.Any() ?? false);
|
||||
|
||||
if (ratings?.Any() ?? false)
|
||||
{
|
||||
|
@ -188,8 +188,8 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
titleBinding = localisation.GetLocalisedString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
|
||||
artistBinding = localisation.GetLocalisedString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
|
||||
titleBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.TitleUnicode, metadata.Title));
|
||||
artistBinding = localisation.GetLocalisedBindableString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist));
|
||||
|
||||
const float top_height = 0.7f;
|
||||
|
||||
|
@ -57,9 +57,9 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
|
||||
if (match)
|
||||
{
|
||||
var terms = BeatmapInfo.GetSearchableTerms();
|
||||
string[] terms = BeatmapInfo.GetSearchableTerms();
|
||||
|
||||
foreach (var criteriaTerm in criteria.SearchTerms)
|
||||
foreach (string criteriaTerm in criteria.SearchTerms)
|
||||
match &= terms.Any(term => term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
// if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs.
|
||||
@ -89,7 +89,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
{
|
||||
default:
|
||||
case SortMode.Difficulty:
|
||||
var ruleset = BeatmapInfo.RulesetID.CompareTo(otherBeatmap.BeatmapInfo.RulesetID);
|
||||
int ruleset = BeatmapInfo.RulesetID.CompareTo(otherBeatmap.BeatmapInfo.RulesetID);
|
||||
if (ruleset != 0) return ruleset;
|
||||
|
||||
return BeatmapInfo.StarDifficulty.CompareTo(otherBeatmap.BeatmapInfo.StarDifficulty);
|
||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case SortMode.Author:
|
||||
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase);
|
||||
return string.Compare(BeatmapSet.Metadata.Author?.Username, otherSet.BeatmapSet.Metadata.Author?.Username, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case SortMode.Source:
|
||||
return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase);
|
||||
@ -95,8 +95,8 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
|
||||
private int compareUsingAggregateMax(CarouselBeatmapSet other, Func<BeatmapInfo, double> func)
|
||||
{
|
||||
var ourBeatmaps = ValidBeatmaps.Any();
|
||||
var otherBeatmaps = other.ValidBeatmaps.Any();
|
||||
bool ourBeatmaps = ValidBeatmaps.Any();
|
||||
bool otherBeatmaps = other.ValidBeatmaps.Any();
|
||||
|
||||
if (!ourBeatmaps && !otherBeatmaps) return 0;
|
||||
if (!ourBeatmaps) return -1;
|
||||
|
@ -142,7 +142,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author.Username}",
|
||||
Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author?.Username ?? string.Empty}",
|
||||
Font = OsuFont.GetFont(italics: true),
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft
|
||||
|
@ -241,7 +241,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
|
||||
TernaryState state;
|
||||
|
||||
var countExisting = beatmapSet.Beatmaps.Count(b => collection.Beatmaps.Contains(b));
|
||||
int countExisting = beatmapSet.Beatmaps.Count(b => collection.Beatmaps.Contains(b));
|
||||
|
||||
if (countExisting == beatmapSet.Beatmaps.Count)
|
||||
state = TernaryState.True;
|
||||
|
@ -38,9 +38,9 @@ namespace osu.Game.Screens.Select.Details
|
||||
protected readonly StatisticRow FirstValue, HpDrain, Accuracy, ApproachRate;
|
||||
private readonly StatisticRow starDifficulty;
|
||||
|
||||
private BeatmapInfo beatmapInfo;
|
||||
private IBeatmapInfo beatmapInfo;
|
||||
|
||||
public BeatmapInfo BeatmapInfo
|
||||
public IBeatmapInfo BeatmapInfo
|
||||
{
|
||||
get => beatmapInfo;
|
||||
set
|
||||
@ -94,9 +94,6 @@ namespace osu.Game.Screens.Select.Details
|
||||
modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue);
|
||||
modSettingChangeTracker.SettingChanged += m =>
|
||||
{
|
||||
if (!(m is IApplicableToDifficulty))
|
||||
return;
|
||||
|
||||
debouncedStatisticsUpdate?.Cancel();
|
||||
debouncedStatisticsUpdate = Scheduler.AddDelayed(updateStatistics, 100);
|
||||
};
|
||||
@ -106,7 +103,7 @@ namespace osu.Game.Screens.Select.Details
|
||||
|
||||
private void updateStatistics()
|
||||
{
|
||||
IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.BaseDifficulty;
|
||||
IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.Difficulty;
|
||||
BeatmapDifficulty adjustedDifficulty = null;
|
||||
|
||||
if (baseDifficulty != null && mods.Value.Any(m => m is IApplicableToDifficulty))
|
||||
@ -117,7 +114,7 @@ namespace osu.Game.Screens.Select.Details
|
||||
mod.ApplyToDifficulty(adjustedDifficulty);
|
||||
}
|
||||
|
||||
switch (BeatmapInfo?.Ruleset?.ID ?? 0)
|
||||
switch (BeatmapInfo?.Ruleset.OnlineID)
|
||||
{
|
||||
case 3:
|
||||
// Account for mania differences locally for now
|
||||
|
@ -27,9 +27,9 @@ namespace osu.Game.Screens.Select.Details
|
||||
|
||||
failTimes = value;
|
||||
|
||||
var retries = FailTimes?.Retries ?? Array.Empty<int>();
|
||||
var fails = FailTimes?.Fails ?? Array.Empty<int>();
|
||||
var retriesAndFails = sumRetriesAndFails(retries, fails);
|
||||
int[] retries = FailTimes?.Retries ?? Array.Empty<int>();
|
||||
int[] fails = FailTimes?.Fails ?? Array.Empty<int>();
|
||||
int[] retriesAndFails = sumRetriesAndFails(retries, fails);
|
||||
|
||||
float maxValue = retriesAndFails.Any() ? retriesAndFails.Max() : 0;
|
||||
failGraph.MaxValue = maxValue;
|
||||
@ -42,7 +42,7 @@ namespace osu.Game.Screens.Select.Details
|
||||
|
||||
private int[] sumRetriesAndFails(int[] retries, int[] fails)
|
||||
{
|
||||
var result = new int[Math.Max(retries.Length, fails.Length)];
|
||||
int[] result = new int[Math.Max(retries.Length, fails.Length)];
|
||||
|
||||
for (int i = 0; i < retries.Length; ++i)
|
||||
result[i] = retries[i];
|
||||
|
@ -45,8 +45,8 @@ namespace osu.Game.Screens.Select.Details
|
||||
{
|
||||
var usableRange = Ratings.Skip(1).Take(rating_range); // adjust for API returning weird empty data at 0.
|
||||
|
||||
var negativeCount = usableRange.Take(rating_range / 2).Sum();
|
||||
var totalCount = usableRange.Sum();
|
||||
int negativeCount = usableRange.Take(rating_range / 2).Sum();
|
||||
int totalCount = usableRange.Sum();
|
||||
|
||||
negativeRatings.Text = negativeCount.ToLocalisableString(@"N0");
|
||||
positiveRatings.Text = (totalCount - negativeCount).ToLocalisableString(@"N0");
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
Debug.Assert(ruleset.Value.ID != null);
|
||||
|
||||
var query = searchTextBox.Text;
|
||||
string query = searchTextBox.Text;
|
||||
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
|
@ -22,9 +22,9 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
foreach (Match match in query_syntax_regex.Matches(query))
|
||||
{
|
||||
var key = match.Groups["key"].Value.ToLower();
|
||||
string key = match.Groups["key"].Value.ToLower();
|
||||
var op = parseOperator(match.Groups["op"].Value);
|
||||
var value = match.Groups["value"].Value;
|
||||
string value = match.Groups["value"].Value;
|
||||
|
||||
if (tryParseKeywordCriteria(criteria, key, value, op))
|
||||
query = query.Replace(match.ToString(), "");
|
||||
@ -310,10 +310,10 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private static bool tryUpdateLengthRange(FilterCriteria criteria, Operator op, string val)
|
||||
{
|
||||
if (!tryParseDoubleWithPoint(val.TrimEnd('m', 's', 'h'), out var length))
|
||||
if (!tryParseDoubleWithPoint(val.TrimEnd('m', 's', 'h'), out double length))
|
||||
return false;
|
||||
|
||||
var scale = getLengthScale(val);
|
||||
int scale = getLengthScale(val);
|
||||
return tryUpdateCriteriaRange(ref criteria.Length, op, length * scale, scale / 2.0);
|
||||
}
|
||||
}
|
||||
|
@ -192,14 +192,14 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
|
||||
req.Success += r =>
|
||||
{
|
||||
scoreManager.OrderByTotalScoreAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token)
|
||||
scoreManager.OrderByTotalScoreAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets, BeatmapInfo)).ToArray(), loadCancellationSource.Token)
|
||||
.ContinueWith(ordered => Schedule(() =>
|
||||
{
|
||||
if (loadCancellationSource.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
scoresCallback?.Invoke(ordered.Result);
|
||||
TopScore = r.UserScore?.CreateScoreInfo(rulesets);
|
||||
TopScore = r.UserScore?.CreateScoreInfo(rulesets, BeatmapInfo);
|
||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
||||
};
|
||||
|
||||
|
@ -76,7 +76,7 @@ namespace osu.Game.Screens.Spectate
|
||||
managerUpdated = beatmaps.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(beatmapUpdated);
|
||||
|
||||
foreach (var (id, _) in userMap)
|
||||
foreach ((int id, var _) in userMap)
|
||||
spectatorClient.WatchUser(id);
|
||||
}));
|
||||
}
|
||||
@ -86,7 +86,7 @@ namespace osu.Game.Screens.Spectate
|
||||
if (!e.NewValue.TryGetTarget(out var beatmapSet))
|
||||
return;
|
||||
|
||||
foreach (var (userId, _) in userMap)
|
||||
foreach ((int userId, var _) in userMap)
|
||||
{
|
||||
if (!playingUserStates.TryGetValue(userId, out var userState))
|
||||
continue;
|
||||
@ -101,20 +101,20 @@ namespace osu.Game.Screens.Spectate
|
||||
switch (e.Action)
|
||||
{
|
||||
case NotifyDictionaryChangedAction.Add:
|
||||
foreach (var (userId, state) in e.NewItems.AsNonNull())
|
||||
foreach ((int userId, var state) in e.NewItems.AsNonNull())
|
||||
onUserStateAdded(userId, state);
|
||||
break;
|
||||
|
||||
case NotifyDictionaryChangedAction.Remove:
|
||||
foreach (var (userId, _) in e.OldItems.AsNonNull())
|
||||
foreach ((int userId, var _) in e.OldItems.AsNonNull())
|
||||
onUserStateRemoved(userId);
|
||||
break;
|
||||
|
||||
case NotifyDictionaryChangedAction.Replace:
|
||||
foreach (var (userId, _) in e.OldItems.AsNonNull())
|
||||
foreach ((int userId, var _) in e.OldItems.AsNonNull())
|
||||
onUserStateRemoved(userId);
|
||||
|
||||
foreach (var (userId, state) in e.NewItems.AsNonNull())
|
||||
foreach ((int userId, var state) in e.NewItems.AsNonNull())
|
||||
onUserStateAdded(userId, state);
|
||||
break;
|
||||
}
|
||||
@ -219,7 +219,7 @@ namespace osu.Game.Screens.Spectate
|
||||
|
||||
if (spectatorClient != null)
|
||||
{
|
||||
foreach (var (userId, _) in userMap)
|
||||
foreach ((int userId, var _) in userMap)
|
||||
spectatorClient.StopWatchingUser(userId);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user