mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 16:12:57 +08:00
Merge branch 'master' into realm-block-timeout-assert-failure
This commit is contained in:
commit
bda77fb6b3
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -15,9 +16,26 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
|
||||
private const float default_flashlight_size = 350;
|
||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||
{
|
||||
MinValue = 0.5f,
|
||||
MaxValue = 1.5f,
|
||||
Default = 1f,
|
||||
Value = 1f,
|
||||
Precision = 0.1f
|
||||
};
|
||||
|
||||
public override Flashlight CreateFlashlight() => new CatchFlashlight(playfield);
|
||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||
{
|
||||
Default = true,
|
||||
Value = true
|
||||
};
|
||||
|
||||
public override float DefaultFlashlightSize => 350;
|
||||
|
||||
protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield);
|
||||
|
||||
private CatchPlayfield playfield;
|
||||
|
||||
@ -31,10 +49,11 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
private readonly CatchPlayfield playfield;
|
||||
|
||||
public CatchFlashlight(CatchPlayfield playfield)
|
||||
public CatchFlashlight(CatchModFlashlight modFlashlight, CatchPlayfield playfield)
|
||||
: base(modFlashlight)
|
||||
{
|
||||
this.playfield = playfield;
|
||||
FlashlightSize = new Vector2(0, getSizeFor(0));
|
||||
FlashlightSize = new Vector2(0, GetSizeFor(0));
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -44,19 +63,9 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
FlashlightPosition = playfield.CatcherArea.ToSpaceOfOtherDrawable(playfield.Catcher.DrawPosition, this);
|
||||
}
|
||||
|
||||
private float getSizeFor(int combo)
|
||||
{
|
||||
if (combo > 200)
|
||||
return default_flashlight_size * 0.8f;
|
||||
else if (combo > 100)
|
||||
return default_flashlight_size * 0.9f;
|
||||
else
|
||||
return default_flashlight_size;
|
||||
}
|
||||
|
||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||
{
|
||||
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||
this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||
}
|
||||
|
||||
protected override string FragmentShader => "CircularFlashlight";
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osuTK;
|
||||
@ -16,17 +17,35 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
||||
|
||||
private const float default_flashlight_size = 180;
|
||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||
{
|
||||
MinValue = 0.5f,
|
||||
MaxValue = 3f,
|
||||
Default = 1f,
|
||||
Value = 1f,
|
||||
Precision = 0.1f
|
||||
};
|
||||
|
||||
public override Flashlight CreateFlashlight() => new ManiaFlashlight();
|
||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||
{
|
||||
Default = false,
|
||||
Value = false
|
||||
};
|
||||
|
||||
public override float DefaultFlashlightSize => 50;
|
||||
|
||||
protected override Flashlight CreateFlashlight() => new ManiaFlashlight(this);
|
||||
|
||||
private class ManiaFlashlight : Flashlight
|
||||
{
|
||||
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
||||
|
||||
public ManiaFlashlight()
|
||||
public ManiaFlashlight(ManiaModFlashlight modFlashlight)
|
||||
: base(modFlashlight)
|
||||
{
|
||||
FlashlightSize = new Vector2(0, default_flashlight_size);
|
||||
FlashlightSize = new Vector2(DrawWidth, GetSizeFor(0));
|
||||
|
||||
AddLayout(flashlightProperties);
|
||||
}
|
||||
@ -46,6 +65,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
|
||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||
{
|
||||
this.TransformTo(nameof(FlashlightSize), new Vector2(DrawWidth, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||
}
|
||||
|
||||
protected override string FragmentShader => "RectangularFlashlight";
|
||||
|
@ -12,7 +12,6 @@ using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
@ -21,27 +20,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
|
||||
private const float default_flashlight_size = 180;
|
||||
|
||||
private const double default_follow_delay = 120;
|
||||
|
||||
private OsuFlashlight flashlight;
|
||||
|
||||
public override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight();
|
||||
|
||||
public void ApplyToDrawableHitObject(DrawableHitObject drawable)
|
||||
{
|
||||
if (drawable is DrawableSlider s)
|
||||
s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
|
||||
}
|
||||
|
||||
public override void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||
{
|
||||
base.ApplyToDrawableRuleset(drawableRuleset);
|
||||
|
||||
flashlight.FollowDelay = FollowDelay.Value;
|
||||
}
|
||||
|
||||
[SettingSource("Follow delay", "Milliseconds until the flashlight reaches the cursor")]
|
||||
public BindableNumber<double> FollowDelay { get; } = new BindableDouble(default_follow_delay)
|
||||
{
|
||||
@ -50,13 +30,45 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
Precision = default_follow_delay,
|
||||
};
|
||||
|
||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||
{
|
||||
MinValue = 0.5f,
|
||||
MaxValue = 2f,
|
||||
Default = 1f,
|
||||
Value = 1f,
|
||||
Precision = 0.1f
|
||||
};
|
||||
|
||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||
{
|
||||
Default = true,
|
||||
Value = true
|
||||
};
|
||||
|
||||
public override float DefaultFlashlightSize => 180;
|
||||
|
||||
private OsuFlashlight flashlight;
|
||||
|
||||
protected override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight(this);
|
||||
|
||||
public void ApplyToDrawableHitObject(DrawableHitObject drawable)
|
||||
{
|
||||
if (drawable is DrawableSlider s)
|
||||
s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
|
||||
}
|
||||
|
||||
private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
|
||||
{
|
||||
public double FollowDelay { private get; set; }
|
||||
private readonly double followDelay;
|
||||
|
||||
public OsuFlashlight()
|
||||
public OsuFlashlight(OsuModFlashlight modFlashlight)
|
||||
: base(modFlashlight)
|
||||
{
|
||||
FlashlightSize = new Vector2(0, getSizeFor(0));
|
||||
followDelay = modFlashlight.FollowDelay.Value;
|
||||
|
||||
FlashlightSize = new Vector2(0, GetSizeFor(0));
|
||||
}
|
||||
|
||||
public void OnSliderTrackingChange(ValueChangedEvent<bool> e)
|
||||
@ -71,24 +83,14 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
var destination = e.MousePosition;
|
||||
|
||||
FlashlightPosition = Interpolation.ValueAt(
|
||||
Math.Min(Math.Abs(Clock.ElapsedFrameTime), FollowDelay), position, destination, 0, FollowDelay, Easing.Out);
|
||||
Math.Min(Math.Abs(Clock.ElapsedFrameTime), followDelay), position, destination, 0, followDelay, Easing.Out);
|
||||
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
private float getSizeFor(int combo)
|
||||
{
|
||||
if (combo > 200)
|
||||
return default_flashlight_size * 0.8f;
|
||||
else if (combo > 100)
|
||||
return default_flashlight_size * 0.9f;
|
||||
else
|
||||
return default_flashlight_size;
|
||||
}
|
||||
|
||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||
{
|
||||
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||
this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
||||
}
|
||||
|
||||
protected override string FragmentShader => "CircularFlashlight";
|
||||
|
@ -4,6 +4,7 @@
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
@ -16,9 +17,26 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
|
||||
private const float default_flashlight_size = 250;
|
||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
||||
{
|
||||
MinValue = 0.5f,
|
||||
MaxValue = 1.5f,
|
||||
Default = 1f,
|
||||
Value = 1f,
|
||||
Precision = 0.1f
|
||||
};
|
||||
|
||||
public override Flashlight CreateFlashlight() => new TaikoFlashlight(playfield);
|
||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||
public override BindableBool ComboBasedSize { get; } = new BindableBool
|
||||
{
|
||||
Default = true,
|
||||
Value = true
|
||||
};
|
||||
|
||||
public override float DefaultFlashlightSize => 250;
|
||||
|
||||
protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield);
|
||||
|
||||
private TaikoPlayfield playfield;
|
||||
|
||||
@ -33,7 +51,8 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
|
||||
private readonly TaikoPlayfield taikoPlayfield;
|
||||
|
||||
public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
|
||||
public TaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPlayfield)
|
||||
: base(modFlashlight)
|
||||
{
|
||||
this.taikoPlayfield = taikoPlayfield;
|
||||
FlashlightSize = getSizeFor(0);
|
||||
@ -43,15 +62,8 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
|
||||
private Vector2 getSizeFor(int combo)
|
||||
{
|
||||
float size = default_flashlight_size;
|
||||
|
||||
if (combo > 200)
|
||||
size *= 0.8f;
|
||||
else if (combo > 100)
|
||||
size *= 0.9f;
|
||||
|
||||
// Preserve flashlight size through the playfield's aspect adjustment.
|
||||
return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
|
||||
return new Vector2(0, GetSizeFor(combo) * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||
|
@ -600,6 +600,38 @@ namespace osu.Game.Tests.Database
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportThenReimportAfterMissingFiles()
|
||||
{
|
||||
RunTestWithRealmAsync(async (realmFactory, storage) =>
|
||||
{
|
||||
using var importer = new BeatmapModelManager(realmFactory, storage);
|
||||
using var store = new RulesetStore(realmFactory, storage);
|
||||
|
||||
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
|
||||
|
||||
deleteBeatmapSet(imported, realmFactory.Context);
|
||||
|
||||
Assert.IsTrue(imported.DeletePending);
|
||||
|
||||
// intentionally nuke all files
|
||||
storage.DeleteDirectory("files");
|
||||
|
||||
Assert.That(imported.Files.All(f => !storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));
|
||||
|
||||
var importedSecondTime = await LoadOszIntoStore(importer, realmFactory.Context);
|
||||
|
||||
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
|
||||
Assert.IsTrue(imported.ID == importedSecondTime.ID);
|
||||
Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID);
|
||||
Assert.IsFalse(imported.DeletePending);
|
||||
Assert.IsFalse(importedSecondTime.DeletePending);
|
||||
|
||||
// check that the files now exist, even though they were deleted above.
|
||||
Assert.That(importedSecondTime.Files.All(f => storage.GetStorageForDirectory("files").Exists(f.File.GetStoragePath())));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestImportThenDeleteThenImportNonOptimisedPath()
|
||||
{
|
||||
|
@ -142,19 +142,28 @@ namespace osu.Game.Tests.NonVisual
|
||||
|
||||
Assert.That(osuStorage, Is.Not.Null);
|
||||
|
||||
// In the following tests, realm files are ignored as
|
||||
// - in the case of checking the source, interacting with the pipe files (client.realm.note) may
|
||||
// lead to unexpected behaviour.
|
||||
// - in the case of checking the destination, the files may have already been recreated by the game
|
||||
// as part of the standard migration flow.
|
||||
|
||||
foreach (string file in osuStorage.IgnoreFiles)
|
||||
{
|
||||
// avoid touching realm files which may be a pipe and break everything.
|
||||
// this is also done locally inside OsuStorage via the IgnoreFiles list.
|
||||
if (file.EndsWith(".ini", StringComparison.Ordinal))
|
||||
if (!file.Contains("realm", StringComparison.Ordinal))
|
||||
{
|
||||
Assert.That(File.Exists(Path.Combine(originalDirectory, file)));
|
||||
Assert.That(storage.Exists(file), Is.False);
|
||||
Assert.That(storage.Exists(file), Is.False, () => $"{file} exists in destination when it was expected to be ignored");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string dir in osuStorage.IgnoreDirectories)
|
||||
{
|
||||
Assert.That(Directory.Exists(Path.Combine(originalDirectory, dir)));
|
||||
Assert.That(storage.ExistsDirectory(dir), Is.False);
|
||||
if (!dir.Contains("realm", StringComparison.Ordinal))
|
||||
{
|
||||
Assert.That(Directory.Exists(Path.Combine(originalDirectory, dir)));
|
||||
Assert.That(storage.Exists(dir), Is.False, () => $"{dir} exists in destination when it was expected to be ignored");
|
||||
}
|
||||
}
|
||||
|
||||
Assert.That(new StreamReader(Path.Combine(originalDirectory, "storage.ini")).ReadToEnd().Contains($"FullPath = {customPath}"));
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.OpenGL.Vertices;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -32,9 +33,17 @@ namespace osu.Game.Rulesets.Mods
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Restricted view area.";
|
||||
|
||||
internal ModFlashlight()
|
||||
{
|
||||
}
|
||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||
public abstract BindableNumber<float> SizeMultiplier { get; }
|
||||
|
||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||
public abstract BindableBool ComboBasedSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The default size of the flashlight in ruleset-appropriate dimensions.
|
||||
/// <see cref="SizeMultiplier"/> and <see cref="ComboBasedSize"/> will apply their adjustments on top of this size.
|
||||
/// </summary>
|
||||
public abstract float DefaultFlashlightSize { get; }
|
||||
}
|
||||
|
||||
public abstract class ModFlashlight<T> : ModFlashlight, IApplicableToDrawableRuleset<T>, IApplicableToScoreProcessor
|
||||
@ -79,7 +88,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
flashlight.Breaks = drawableRuleset.Beatmap.Breaks;
|
||||
}
|
||||
|
||||
public abstract Flashlight CreateFlashlight();
|
||||
protected abstract Flashlight CreateFlashlight();
|
||||
|
||||
public abstract class Flashlight : Drawable
|
||||
{
|
||||
@ -93,6 +102,17 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public List<BreakPeriod> Breaks;
|
||||
|
||||
private readonly float defaultFlashlightSize;
|
||||
private readonly float sizeMultiplier;
|
||||
private readonly bool comboBasedSize;
|
||||
|
||||
protected Flashlight(ModFlashlight modFlashlight)
|
||||
{
|
||||
defaultFlashlightSize = modFlashlight.DefaultFlashlightSize;
|
||||
sizeMultiplier = modFlashlight.SizeMultiplier.Value;
|
||||
comboBasedSize = modFlashlight.ComboBasedSize.Value;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ShaderManager shaderManager)
|
||||
{
|
||||
@ -124,6 +144,21 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
protected abstract string FragmentShader { get; }
|
||||
|
||||
protected float GetSizeFor(int combo)
|
||||
{
|
||||
float size = defaultFlashlightSize * sizeMultiplier;
|
||||
|
||||
if (comboBasedSize)
|
||||
{
|
||||
if (combo > 200)
|
||||
size *= 0.8f;
|
||||
else if (combo > 100)
|
||||
size *= 0.9f;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private Vector2 flashlightPosition;
|
||||
|
||||
protected Vector2 FlashlightPosition
|
||||
|
@ -342,7 +342,8 @@ namespace osu.Game.Stores
|
||||
// note that this should really be checking filesizes on disk (of existing files) for some degree of sanity.
|
||||
// or alternatively doing a faster hash check. either of these require database changes and reprocessing of existing files.
|
||||
if (CanSkipImport(existing, item) &&
|
||||
getFilenames(existing.Files).SequenceEqual(getShortenedFilenames(archive).Select(p => p.shortened).OrderBy(f => f)))
|
||||
getFilenames(existing.Files).SequenceEqual(getShortenedFilenames(archive).Select(p => p.shortened).OrderBy(f => f)) &&
|
||||
checkAllFilesExist(existing))
|
||||
{
|
||||
LogForModel(item, @$"Found existing (optimised) {HumanisedModelName} for {item} (ID {existing.ID}) – skipping import.");
|
||||
|
||||
@ -459,7 +460,6 @@ namespace osu.Game.Stores
|
||||
if (!(prefix.EndsWith('/') || prefix.EndsWith('\\')))
|
||||
prefix = string.Empty;
|
||||
|
||||
// import files to manager
|
||||
foreach (string file in reader.Filenames)
|
||||
yield return (file, file.Substring(prefix.Length).ToStandardisedPath());
|
||||
}
|
||||
@ -519,7 +519,11 @@ namespace osu.Game.Stores
|
||||
// for the best or worst, we copy and import files of a new import before checking whether
|
||||
// it is a duplicate. so to check if anything has changed, we can just compare all File IDs.
|
||||
getIDs(existing.Files).SequenceEqual(getIDs(import.Files)) &&
|
||||
getFilenames(existing.Files).SequenceEqual(getFilenames(import.Files));
|
||||
getFilenames(existing.Files).SequenceEqual(getFilenames(import.Files)) &&
|
||||
checkAllFilesExist(existing);
|
||||
|
||||
private bool checkAllFilesExist(TModel model) =>
|
||||
model.Files.All(f => Files.Storage.Exists(f.File.GetStoragePath()));
|
||||
|
||||
/// <summary>
|
||||
/// Whether this specified path should be removed after successful import.
|
||||
|
Loading…
Reference in New Issue
Block a user