mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 19:22:54 +08:00
Merge branch 'master' into fix-notification-count
This commit is contained in:
commit
a413c7a3e6
@ -52,7 +52,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.908.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.916.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
@ -1,9 +1,8 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -21,32 +20,36 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
public const int SPACING = 32;
|
||||
public const double PREEMPT = 800;
|
||||
|
||||
public DrawablePool<FollowPoint> Pool;
|
||||
public DrawablePool<FollowPoint>? Pool { private get; set; }
|
||||
|
||||
protected override void OnApply(FollowPointLifetimeEntry entry)
|
||||
{
|
||||
base.OnApply(entry);
|
||||
|
||||
entry.Invalidated += onEntryInvalidated;
|
||||
refreshPoints();
|
||||
entry.Invalidated += scheduleRefresh;
|
||||
|
||||
// Our clock may not be correct at this point if `LoadComplete` has not run yet.
|
||||
// Without a schedule, animations referencing FollowPoint's clock (see `IAnimationTimeReference`) would be incorrect on first pool usage.
|
||||
scheduleRefresh();
|
||||
}
|
||||
|
||||
protected override void OnFree(FollowPointLifetimeEntry entry)
|
||||
{
|
||||
base.OnFree(entry);
|
||||
|
||||
entry.Invalidated -= onEntryInvalidated;
|
||||
entry.Invalidated -= scheduleRefresh;
|
||||
// Return points to the pool.
|
||||
ClearInternal(false);
|
||||
}
|
||||
|
||||
private void onEntryInvalidated() => Scheduler.AddOnce(refreshPoints);
|
||||
|
||||
private void refreshPoints()
|
||||
private void scheduleRefresh() => Scheduler.AddOnce(() =>
|
||||
{
|
||||
Debug.Assert(Pool != null);
|
||||
|
||||
ClearInternal(false);
|
||||
|
||||
var entry = Entry;
|
||||
|
||||
if (entry?.End == null) return;
|
||||
|
||||
OsuHitObject start = entry.Start;
|
||||
@ -95,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
}
|
||||
|
||||
entry.LifetimeEnd = finalTransformEndTime;
|
||||
}
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Computes the fade time of follow point positioned between two hitobjects.
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
@ -66,6 +67,18 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddUntilStep("Scroll container is loaded", () => scrollContainer.LoadState >= LoadState.Loaded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInitialZoomOutOfRange()
|
||||
{
|
||||
AddStep("Invalid ZoomableScrollContainer throws ArgumentException", () =>
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
_ = new ZoomableScrollContainer(1, 60, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWidthInitialization()
|
||||
{
|
||||
|
@ -51,7 +51,15 @@ namespace osu.Game.Database
|
||||
ID = id;
|
||||
}
|
||||
|
||||
public bool Equals(Live<T>? other) => ID == other?.ID;
|
||||
public bool Equals(Live<T>? other)
|
||||
{
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (other == null) return false;
|
||||
|
||||
return ID == other.ID;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(ID);
|
||||
|
||||
public override string ToString() => PerformRead(i => i.ToString());
|
||||
}
|
||||
|
@ -10,6 +10,9 @@ using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an aggregate score for a user based off all beatmaps that have been played in the playlist.
|
||||
/// </summary>
|
||||
public class APIUserScoreAggregate
|
||||
{
|
||||
[JsonProperty("attempts")]
|
||||
|
@ -15,6 +15,8 @@ using osu.Framework.Localisation;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Configuration;
|
||||
|
||||
namespace osu.Game.Online.Leaderboards
|
||||
{
|
||||
@ -24,6 +26,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
private FillFlowContainer<HitResultCell> topScoreStatistics = null!;
|
||||
private FillFlowContainer<HitResultCell> bottomScoreStatistics = null!;
|
||||
private FillFlowContainer<ModCell> modStatistics = null!;
|
||||
private readonly Bindable<bool> prefer24HourTime = new Bindable<bool>();
|
||||
|
||||
public LeaderboardScoreTooltip()
|
||||
{
|
||||
@ -36,8 +39,9 @@ namespace osu.Game.Online.Leaderboards
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OsuConfigManager configManager)
|
||||
{
|
||||
configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime);
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
@ -92,6 +96,13 @@ namespace osu.Game.Online.Leaderboards
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
prefer24HourTime.BindValueChanged(_ => updateTimestampLabel(), true);
|
||||
}
|
||||
|
||||
private ScoreInfo? displayedScore;
|
||||
|
||||
public void SetContent(ScoreInfo score)
|
||||
@ -101,7 +112,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
|
||||
displayedScore = score;
|
||||
|
||||
timestampLabel.Text = $"Played on {score.Date.ToLocalTime():d MMMM yyyy HH:mm}";
|
||||
updateTimestampLabel();
|
||||
|
||||
modStatistics.Clear();
|
||||
topScoreStatistics.Clear();
|
||||
@ -121,6 +132,16 @@ namespace osu.Game.Online.Leaderboards
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTimestampLabel()
|
||||
{
|
||||
if (displayedScore != null)
|
||||
{
|
||||
timestampLabel.Text = prefer24HourTime.Value
|
||||
? $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy HH:mm}"
|
||||
: $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy h:mm tt}";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn() => this.FadeIn(20, Easing.OutQuint);
|
||||
protected override void PopOut() => this.FadeOut(80, Easing.OutQuint);
|
||||
|
||||
|
@ -56,14 +56,12 @@ using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Skinning.Editor;
|
||||
using osu.Game.Updater;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Utils;
|
||||
using osuTK.Graphics;
|
||||
using Sentry;
|
||||
using Logger = osu.Framework.Logging.Logger;
|
||||
|
||||
namespace osu.Game
|
||||
{
|
||||
@ -294,25 +292,13 @@ namespace osu.Game
|
||||
|
||||
Ruleset.ValueChanged += r => configRuleset.Value = r.NewValue.ShortName;
|
||||
|
||||
// bind config int to database SkinInfo
|
||||
configSkin = LocalConfig.GetBindable<string>(OsuSetting.Skin);
|
||||
|
||||
// Transfer skin from config to realm instance once on startup.
|
||||
SkinManager.SetSkinFromConfiguration(configSkin.Value);
|
||||
|
||||
// Transfer any runtime changes back to configuration file.
|
||||
SkinManager.CurrentSkinInfo.ValueChanged += skin => configSkin.Value = skin.NewValue.ID.ToString();
|
||||
configSkin.ValueChanged += skinId =>
|
||||
{
|
||||
Live<SkinInfo> skinInfo = null;
|
||||
|
||||
if (Guid.TryParse(skinId.NewValue, out var guid))
|
||||
skinInfo = SkinManager.Query(s => s.ID == guid);
|
||||
|
||||
if (skinInfo == null)
|
||||
{
|
||||
if (guid == SkinInfo.CLASSIC_SKIN)
|
||||
skinInfo = DefaultLegacySkin.CreateInfo().ToLiveUnmanaged();
|
||||
}
|
||||
|
||||
SkinManager.CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.CreateInfo().ToLiveUnmanaged();
|
||||
};
|
||||
configSkin.TriggerChange();
|
||||
|
||||
IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true);
|
||||
|
||||
|
@ -14,7 +14,6 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
@ -36,9 +35,6 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
Icon = FontAwesome.Solid.PaintBrush
|
||||
};
|
||||
|
||||
private readonly Bindable<Live<SkinInfo>> dropdownBindable = new Bindable<Live<SkinInfo>> { Default = DefaultSkin.CreateInfo().ToLiveUnmanaged() };
|
||||
private readonly Bindable<string> configBindable = new Bindable<string>();
|
||||
|
||||
private static readonly Live<SkinInfo> random_skin_info = new SkinInfo
|
||||
{
|
||||
ID = SkinInfo.RANDOM_SKIN,
|
||||
@ -56,13 +52,14 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
private IDisposable realmSubscription;
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(OsuConfigManager config, [CanBeNull] SkinEditorOverlay skinEditor)
|
||||
private void load([CanBeNull] SkinEditorOverlay skinEditor)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
skinDropdown = new SkinSettingsDropdown
|
||||
{
|
||||
LabelText = SkinSettingsStrings.CurrentSkin,
|
||||
Current = skins.CurrentSkinInfo,
|
||||
Keywords = new[] { @"skins" }
|
||||
},
|
||||
new SettingsButton
|
||||
@ -73,47 +70,28 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
new ExportSkinButton(),
|
||||
new DeleteSkinButton(),
|
||||
};
|
||||
|
||||
config.BindWith(OsuSetting.Skin, configBindable);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
skinDropdown.Current = dropdownBindable;
|
||||
|
||||
realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All<SkinInfo>()
|
||||
.Where(s => !s.DeletePending)
|
||||
.OrderByDescending(s => s.Protected) // protected skins should be at the top.
|
||||
.ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged);
|
||||
|
||||
configBindable.BindValueChanged(_ => Scheduler.AddOnce(updateSelectedSkinFromConfig));
|
||||
|
||||
dropdownBindable.BindValueChanged(dropdownSelectionChanged);
|
||||
}
|
||||
|
||||
private void dropdownSelectionChanged(ValueChangedEvent<Live<SkinInfo>> skin)
|
||||
{
|
||||
// Only handle cases where it's clear the user has intent to change skins.
|
||||
if (skin.OldValue == null) return;
|
||||
|
||||
if (skin.NewValue.Equals(random_skin_info))
|
||||
skinDropdown.Current.BindValueChanged(skin =>
|
||||
{
|
||||
var skinBefore = skins.CurrentSkinInfo.Value;
|
||||
|
||||
skins.SelectRandomSkin();
|
||||
|
||||
if (skinBefore == skins.CurrentSkinInfo.Value)
|
||||
if (skin.NewValue == random_skin_info)
|
||||
{
|
||||
// the random selection didn't change the skin, so we should manually update the dropdown to match.
|
||||
dropdownBindable.Value = skins.CurrentSkinInfo.Value;
|
||||
// before selecting random, set the skin back to the previous selection.
|
||||
// this is done because at this point it will be random_skin_info, and would
|
||||
// cause SelectRandomSkin to be unable to skip the previous selection.
|
||||
skins.CurrentSkinInfo.Value = skin.OldValue;
|
||||
skins.SelectRandomSkin();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
configBindable.Value = skin.NewValue.ID.ToString();
|
||||
});
|
||||
}
|
||||
|
||||
private void skinsChanged(IRealmCollection<SkinInfo> sender, ChangeSet changes, Exception error)
|
||||
@ -132,25 +110,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
dropdownItems.Add(skin.ToLive(realm));
|
||||
dropdownItems.Insert(protectedCount, random_skin_info);
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
skinDropdown.Items = dropdownItems;
|
||||
|
||||
updateSelectedSkinFromConfig();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateSelectedSkinFromConfig()
|
||||
{
|
||||
if (!skinDropdown.Items.Any())
|
||||
return;
|
||||
|
||||
Live<SkinInfo> skin = null;
|
||||
|
||||
if (Guid.TryParse(configBindable.Value, out var configId))
|
||||
skin = skinDropdown.Items.FirstOrDefault(s => s.ID == configId);
|
||||
|
||||
dropdownBindable.Value = skin ?? skinDropdown.Items.First();
|
||||
Schedule(() => skinDropdown.Items = dropdownItems);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
|
@ -196,7 +196,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000);
|
||||
|
||||
float initialZoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom);
|
||||
float initialZoom = (float)(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom == 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom));
|
||||
float minimumZoom = getZoomLevelForVisibleMilliseconds(10000);
|
||||
float maximumZoom = getZoomLevelForVisibleMilliseconds(500);
|
||||
|
||||
|
@ -87,6 +87,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
if (minimum > maximum)
|
||||
throw new ArgumentException($"{nameof(minimum)} ({minimum}) must be less than {nameof(maximum)} ({maximum})");
|
||||
|
||||
if (initial < minimum || initial > maximum)
|
||||
throw new ArgumentException($"{nameof(initial)} ({initial}) must be between {nameof(minimum)} ({minimum}) and {nameof(maximum)} ({maximum})");
|
||||
|
||||
minZoom = minimum;
|
||||
maxZoom = maximum;
|
||||
CurrentZoom = zoomTarget = initial;
|
||||
|
@ -110,6 +110,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
if (Client != null)
|
||||
{
|
||||
Client.RoomUpdated -= invokeOnRoomUpdated;
|
||||
Client.LoadRequested -= invokeOnRoomLoadRequested;
|
||||
Client.UserLeft -= invokeUserLeft;
|
||||
Client.UserKicked -= invokeUserKicked;
|
||||
Client.UserJoined -= invokeUserJoined;
|
||||
|
@ -119,7 +119,9 @@ namespace osu.Game.Skinning
|
||||
Realm.Run(r =>
|
||||
{
|
||||
// choose from only user skins, removing the current selection to ensure a new one is chosen.
|
||||
var randomChoices = r.All<SkinInfo>().Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray();
|
||||
var randomChoices = r.All<SkinInfo>()
|
||||
.Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID)
|
||||
.ToArray();
|
||||
|
||||
if (randomChoices.Length == 0)
|
||||
{
|
||||
@ -297,5 +299,21 @@ namespace osu.Game.Skinning
|
||||
Delete(items.ToList(), silent);
|
||||
});
|
||||
}
|
||||
|
||||
public void SetSkinFromConfiguration(string guidString)
|
||||
{
|
||||
Live<SkinInfo> skinInfo = null;
|
||||
|
||||
if (Guid.TryParse(guidString, out var guid))
|
||||
skinInfo = Query(s => s.ID == guid);
|
||||
|
||||
if (skinInfo == null)
|
||||
{
|
||||
if (guid == SkinInfo.CLASSIC_SKIN)
|
||||
skinInfo = DefaultLegacySkin.SkinInfo;
|
||||
}
|
||||
|
||||
CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.SkinInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="10.15.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.908.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.916.1" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
|
||||
<PackageReference Include="Sentry" Version="3.20.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
||||
|
@ -61,7 +61,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.908.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.916.1" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.831.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
||||
@ -82,7 +82,7 @@
|
||||
<PackageReference Include="DiffPlex" Version="1.7.1" />
|
||||
<PackageReference Include="Humanizer" Version="2.14.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.908.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.916.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.32.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user