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:
commit
a0c6fd22cd
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@ -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
|
||||||
|
1
.github/workflows/report-nunit.yml
vendored
1
.github/workflows/report-nunit.yml
vendored
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user