1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-31 02:23:05 +08:00

Merge branch 'master' into osu-target-mod

This commit is contained in:
Henry Lin 2021-06-24 12:06:58 +08:00 committed by GitHub
commit a0c6fd22cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 23 deletions

View File

@ -15,6 +15,7 @@ jobs:
- { prettyname: macOS, fullname: macos-latest } - { prettyname: macOS, fullname: macos-latest }
- { prettyname: Linux, fullname: ubuntu-latest } - { prettyname: Linux, fullname: ubuntu-latest }
threadingMode: ['SingleThread', 'MultiThreaded'] threadingMode: ['SingleThread', 'MultiThreaded']
timeout-minutes: 60
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -21,6 +21,7 @@ jobs:
- { prettyname: macOS } - { prettyname: macOS }
- { prettyname: Linux } - { prettyname: Linux }
threadingMode: ['SingleThread', 'MultiThreaded'] threadingMode: ['SingleThread', 'MultiThreaded']
timeout-minutes: 5
steps: steps:
- name: Annotate CI run with test results - name: Annotate CI run with test results
uses: dorny/test-reporter@v1.4.2 uses: dorny/test-reporter@v1.4.2

View File

@ -5,11 +5,12 @@ using System.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModDifficultyAdjust : ModDifficultyAdjust public class CatchModDifficultyAdjust : ModDifficultyAdjust, IApplicableToBeatmapProcessor
{ {
[SettingSource("Circle Size", "Override a beatmap's set CS.", FIRST_SETTING_ORDER - 1)] [SettingSource("Circle Size", "Override a beatmap's set CS.", FIRST_SETTING_ORDER - 1)]
public BindableNumber<float> CircleSize { get; } = new BindableFloatWithLimitExtension public BindableNumber<float> CircleSize { get; } = new BindableFloatWithLimitExtension
@ -31,6 +32,9 @@ namespace osu.Game.Rulesets.Catch.Mods
Value = 5, Value = 5,
}; };
[SettingSource("Spicy Patterns", "Adjust the patterns as if Hard Rock is enabled.")]
public BindableBool HardRockOffsets { get; } = new BindableBool();
protected override void ApplyLimits(bool extended) protected override void ApplyLimits(bool extended)
{ {
base.ApplyLimits(extended); base.ApplyLimits(extended);
@ -45,12 +49,14 @@ namespace osu.Game.Rulesets.Catch.Mods
{ {
string circleSize = CircleSize.IsDefault ? string.Empty : $"CS {CircleSize.Value:N1}"; string circleSize = CircleSize.IsDefault ? string.Empty : $"CS {CircleSize.Value:N1}";
string approachRate = ApproachRate.IsDefault ? string.Empty : $"AR {ApproachRate.Value:N1}"; string approachRate = ApproachRate.IsDefault ? string.Empty : $"AR {ApproachRate.Value:N1}";
string spicyPatterns = HardRockOffsets.IsDefault ? string.Empty : "Spicy patterns";
return string.Join(", ", new[] return string.Join(", ", new[]
{ {
circleSize, circleSize,
base.SettingDescription, base.SettingDescription,
approachRate approachRate,
spicyPatterns,
}.Where(s => !string.IsNullOrEmpty(s))); }.Where(s => !string.IsNullOrEmpty(s)));
} }
} }
@ -70,5 +76,11 @@ namespace osu.Game.Rulesets.Catch.Mods
ApplySetting(CircleSize, cs => difficulty.CircleSize = cs); ApplySetting(CircleSize, cs => difficulty.CircleSize = cs);
ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar); ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar);
} }
public void ApplyToBeatmapProcessor(IBeatmapProcessor beatmapProcessor)
{
var catchProcessor = (CatchBeatmapProcessor)beatmapProcessor;
catchProcessor.HardRockOffsets = HardRockOffsets.Value;
}
} }
} }

View File

@ -35,6 +35,7 @@ namespace osu.Game.Collections
private const int database_version = 30000000; private const int database_version = 30000000;
private const string database_name = "collection.db"; private const string database_name = "collection.db";
private const string database_backup_name = "collection.db.bak";
public readonly BindableList<BeatmapCollection> Collections = new BindableList<BeatmapCollection>(); public readonly BindableList<BeatmapCollection> Collections = new BindableList<BeatmapCollection>();
@ -56,6 +57,17 @@ namespace osu.Game.Collections
{ {
Collections.CollectionChanged += collectionsChanged; Collections.CollectionChanged += collectionsChanged;
if (storage.Exists(database_backup_name))
{
// If a backup file exists, it means the previous write operation didn't run to completion.
// Always prefer the backup file in such a case as it's the most recent copy that is guaranteed to not be malformed.
//
// The database is saved 100ms after any change, and again when the game is closed, so there shouldn't be a large diff between the two files in the worst case.
if (storage.Exists(database_name))
storage.Delete(database_name);
File.Copy(storage.GetFullPath(database_backup_name), storage.GetFullPath(database_name));
}
if (storage.Exists(database_name)) if (storage.Exists(database_name))
{ {
List<BeatmapCollection> beatmapCollections; List<BeatmapCollection> beatmapCollections;
@ -68,7 +80,7 @@ namespace osu.Game.Collections
} }
} }
private void collectionsChanged(object sender, NotifyCollectionChangedEventArgs e) private void collectionsChanged(object sender, NotifyCollectionChangedEventArgs e) => Schedule(() =>
{ {
switch (e.Action) switch (e.Action)
{ {
@ -92,7 +104,7 @@ namespace osu.Game.Collections
} }
backgroundSave(); backgroundSave();
} });
/// <summary> /// <summary>
/// Set an endpoint for notifications to be posted to. /// Set an endpoint for notifications to be posted to.
@ -257,11 +269,14 @@ namespace osu.Game.Collections
{ {
Interlocked.Increment(ref lastSave); Interlocked.Increment(ref lastSave);
// This is NOT thread-safe!!
try try
{ {
// This is NOT thread-safe!! var tempPath = Path.GetTempFileName();
using (var sw = new SerializationWriter(storage.GetStream(database_name, FileAccess.Write))) using (var ms = new MemoryStream())
{
using (var sw = new SerializationWriter(ms, true))
{ {
sw.Write(database_version); sw.Write(database_version);
@ -280,6 +295,26 @@ namespace osu.Game.Collections
} }
} }
using (var fs = File.OpenWrite(tempPath))
ms.WriteTo(fs);
var databasePath = storage.GetFullPath(database_name);
var databaseBackupPath = storage.GetFullPath(database_backup_name);
// Back up the existing database, clearing any existing backup.
if (File.Exists(databaseBackupPath))
File.Delete(databaseBackupPath);
if (File.Exists(databasePath))
File.Move(databasePath, databaseBackupPath);
// Move the new database in-place of the existing one.
File.Move(tempPath, databasePath);
// If everything succeeded up to this point, remove the backup file.
if (File.Exists(databaseBackupPath))
File.Delete(databaseBackupPath);
}
if (saveFailures < 10) if (saveFailures < 10)
saveFailures = 0; saveFailures = 0;
return true; return true;

View File

@ -18,8 +18,8 @@ namespace osu.Game.IO.Legacy
/// handle null strings and simplify use with ISerializable. </summary> /// handle null strings and simplify use with ISerializable. </summary>
public class SerializationWriter : BinaryWriter public class SerializationWriter : BinaryWriter
{ {
public SerializationWriter(Stream s) public SerializationWriter(Stream s, bool leaveOpen = false)
: base(s, Encoding.UTF8) : base(s, Encoding.UTF8, leaveOpen)
{ {
} }

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets; using osu.Game.Rulesets;
@ -22,14 +23,21 @@ namespace osu.Game.Overlays.BeatmapListing
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(RulesetStore rulesets) private void load(RulesetStore rulesets)
{ {
AddItem(new RulesetInfo AddTabItem(new RulesetFilterTabItemAny());
{
Name = @"Any"
});
foreach (var r in rulesets.AvailableRulesets) foreach (var r in rulesets.AvailableRulesets)
AddItem(r); AddItem(r);
} }
} }
private class RulesetFilterTabItemAny : FilterTabItem<RulesetInfo>
{
protected override LocalisableString LabelFor(RulesetInfo info) => BeatmapsStrings.ModeAny;
public RulesetFilterTabItemAny()
: base(new RulesetInfo())
{
}
}
} }
} }