mirror of
https://github.com/ppy/osu.git
synced 2025-01-19 12:22:57 +08:00
Merge remote-tracking branch 'upstream/master' into cursor-trail
This commit is contained in:
commit
d1a115f4ec
@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5));
|
||||
|
||||
// spinning doesn't match 1:1 with stable, so let's fudge them easier for the time being.
|
||||
SpinsRequired = (int)(SpinsRequired * 0.6);
|
||||
SpinsRequired = (int)Math.Max(1, SpinsRequired * 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +82,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
return;
|
||||
|
||||
int countHit = NestedHitObjects.Count(o => o.IsHit);
|
||||
|
||||
if (countHit > HitObject.RequiredGoodHits)
|
||||
if (countHit >= HitObject.RequiredGoodHits)
|
||||
{
|
||||
AddJudgement(new TaikoJudgement { Result = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good });
|
||||
if (HitObject.IsStrong)
|
||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
[Test]
|
||||
public void TestDecodeBeatmapGeneral()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
{
|
||||
@ -110,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
[Test]
|
||||
public void TestDecodeBeatmapEvents()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
{
|
||||
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
[Test]
|
||||
public void TestDecodeBeatmapTimingPoints()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
{
|
||||
@ -187,7 +187,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
[Test]
|
||||
public void TestDecodeBeatmapHitObjects()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
{
|
||||
|
@ -159,7 +159,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
using (var sr = new StreamReader(stream))
|
||||
{
|
||||
|
||||
var legacyDecoded = new LegacyBeatmapDecoder().DecodeBeatmap(sr);
|
||||
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.DecodeBeatmap(sr);
|
||||
using (var ms = new MemoryStream())
|
||||
using (var sw = new StreamWriter(ms))
|
||||
using (var sr2 = new StreamReader(ms))
|
||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||
Assert.AreEqual("Deif", meta.AuthorString);
|
||||
Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile);
|
||||
Assert.AreEqual(164471, meta.PreviewTime);
|
||||
Assert.AreEqual(164471 + LegacyBeatmapDecoder.UniversalOffset, meta.PreviewTime);
|
||||
Assert.AreEqual(string.Empty, meta.Source);
|
||||
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags);
|
||||
Assert.AreEqual("Renatus", meta.Title);
|
||||
|
@ -8,6 +8,7 @@ using OpenTK.Graphics;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Framework;
|
||||
|
||||
namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
@ -21,6 +22,19 @@ namespace osu.Game.Beatmaps.Formats
|
||||
private LegacySampleBank defaultSampleBank;
|
||||
private int defaultSampleVolume = 100;
|
||||
|
||||
/// <summary>
|
||||
/// lazer's audio timings in general doesn't match stable. this is the result of user testing, albeit limited.
|
||||
/// This only seems to be required on windows. We need to eventually figure out why, with a bit of luck.
|
||||
/// </summary>
|
||||
public static int UniversalOffset => RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? -22 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not beatmap or runtime offsets should be applied. Defaults on; only disable for testing purposes.
|
||||
/// </summary>
|
||||
public bool ApplyOffsets = true;
|
||||
|
||||
private readonly int offset = UniversalOffset;
|
||||
|
||||
public LegacyBeatmapDecoder()
|
||||
{
|
||||
}
|
||||
@ -28,6 +42,9 @@ namespace osu.Game.Beatmaps.Formats
|
||||
public LegacyBeatmapDecoder(string header)
|
||||
{
|
||||
BeatmapVersion = int.Parse(header.Substring(17));
|
||||
|
||||
// BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off)
|
||||
offset += BeatmapVersion < 5 ? 24 : 0;
|
||||
}
|
||||
|
||||
protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap)
|
||||
@ -102,7 +119,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value);
|
||||
break;
|
||||
case @"PreviewTime":
|
||||
metadata.PreviewTime = int.Parse(pair.Value);
|
||||
metadata.PreviewTime = getOffsetTime(int.Parse(pair.Value));
|
||||
break;
|
||||
case @"Countdown":
|
||||
beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1;
|
||||
@ -257,8 +274,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
case EventType.Break:
|
||||
var breakEvent = new BreakPeriod
|
||||
{
|
||||
StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo),
|
||||
EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo)
|
||||
StartTime = getOffsetTime(double.Parse(split[1], NumberFormatInfo.InvariantInfo)),
|
||||
EndTime = getOffsetTime(double.Parse(split[2], NumberFormatInfo.InvariantInfo))
|
||||
};
|
||||
|
||||
if (!breakEvent.HasEffect)
|
||||
@ -273,7 +290,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
string[] split = line.Split(',');
|
||||
|
||||
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
||||
double time = getOffsetTime(double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo));
|
||||
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
||||
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
||||
|
||||
@ -396,7 +413,14 @@ namespace osu.Game.Beatmaps.Formats
|
||||
var obj = parser.Parse(line);
|
||||
|
||||
if (obj != null)
|
||||
{
|
||||
obj.StartTime = getOffsetTime(obj.StartTime);
|
||||
beatmap.HitObjects.Add(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private int getOffsetTime(int time) => time + (ApplyOffsets ? offset : 0);
|
||||
|
||||
private double getOffsetTime(double time) => time + (ApplyOffsets ? offset : 0);
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount;
|
||||
|
||||
content.Position = Interpolation.ValueAt(Clock.ElapsedFrameTime, content.Position, offset, 0, 1000, Easing.OutQuint);
|
||||
content.Position = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), content.Position, offset, 0, 1000, Easing.OutQuint);
|
||||
content.Scale = new Vector2(1 + ParallaxAmount);
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
protected virtual IEnumerable<SampleInfo> GetSamples() => HitObject.Samples;
|
||||
|
||||
private List<DrawableHitObject> nestedHitObjects;
|
||||
public IReadOnlyList<DrawableHitObject> NestedHitObjects => nestedHitObjects;
|
||||
private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>();
|
||||
public bool HasNestedHitObjects => nestedHitObjects.IsValueCreated;
|
||||
public IReadOnlyList<DrawableHitObject> NestedHitObjects => nestedHitObjects.Value;
|
||||
|
||||
public event Action<DrawableHitObject, Judgement> OnJudgement;
|
||||
public event Action<DrawableHitObject, Judgement> OnJudgementRemoved;
|
||||
@ -52,12 +53,12 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// <summary>
|
||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been hit.
|
||||
/// </summary>
|
||||
public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && (NestedHitObjects?.All(n => n.IsHit) ?? true);
|
||||
public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && (!HasNestedHitObjects || NestedHitObjects.All(n => n.IsHit));
|
||||
|
||||
/// <summary>
|
||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
|
||||
/// </summary>
|
||||
public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (NestedHitObjects?.All(h => h.AllJudged) ?? true);
|
||||
public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (!HasNestedHitObjects || NestedHitObjects.All(h => h.AllJudged));
|
||||
|
||||
/// <summary>
|
||||
/// Whether this <see cref="DrawableHitObject"/> can be judged.
|
||||
@ -160,14 +161,11 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
protected virtual void AddNested(DrawableHitObject h)
|
||||
{
|
||||
if (nestedHitObjects == null)
|
||||
nestedHitObjects = new List<DrawableHitObject>();
|
||||
|
||||
h.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j);
|
||||
h.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(d, j);
|
||||
h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
|
||||
|
||||
nestedHitObjects.Add(h);
|
||||
nestedHitObjects.Value.Add(h);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -211,7 +209,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
if (AllJudged)
|
||||
return false;
|
||||
|
||||
if (NestedHitObjects != null)
|
||||
if (HasNestedHitObjects)
|
||||
foreach (var d in NestedHitObjects)
|
||||
judgementOccurred |= d.UpdateJudgement(userTriggered);
|
||||
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
var controlPoint = controlPointAt(obj.HitObject.StartTime);
|
||||
obj.LifetimeStart = obj.HitObject.StartTime - timeRange / controlPoint.Multiplier;
|
||||
|
||||
if (obj.NestedHitObjects != null)
|
||||
if (obj.HasNestedHitObjects)
|
||||
{
|
||||
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
||||
ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.NestedHitObjects != null)
|
||||
if (obj.HasNestedHitObjects)
|
||||
{
|
||||
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
||||
ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||
|
@ -22,16 +22,14 @@ namespace osu.Game.Skinning
|
||||
public LegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager)
|
||||
: base(skin)
|
||||
{
|
||||
storage = new LegacySkinResourceStore(skin, storage);
|
||||
samples = audioManager.GetSampleManager(storage);
|
||||
textures = new TextureStore(new RawTextureLoaderStore(storage));
|
||||
}
|
||||
|
||||
private string getPathForFile(string filename) =>
|
||||
SkinInfo.Files.FirstOrDefault(f => string.Equals(Path.GetFileNameWithoutExtension(f.Filename), filename, StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
||||
|
||||
public override Drawable GetDrawableComponent(string componentName)
|
||||
{
|
||||
var texture = textures.Get(getPathForFile(componentName.Split('/').Last()));
|
||||
var texture = textures.Get(componentName);
|
||||
if (texture == null) return null;
|
||||
|
||||
return new Sprite
|
||||
@ -42,6 +40,25 @@ namespace osu.Game.Skinning
|
||||
};
|
||||
}
|
||||
|
||||
public override SampleChannel GetSample(string sampleName) => samples.Get(getPathForFile(sampleName.Split('/').Last()));
|
||||
public override SampleChannel GetSample(string sampleName) => samples.Get(sampleName);
|
||||
|
||||
private class LegacySkinResourceStore : IResourceStore<byte[]>
|
||||
{
|
||||
private readonly SkinInfo skin;
|
||||
private readonly IResourceStore<byte[]> underlyingStore;
|
||||
|
||||
private string getPathForFile(string filename) =>
|
||||
skin.Files.FirstOrDefault(f => string.Equals(Path.GetFileNameWithoutExtension(f.Filename), filename.Split('/').Last(), StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath;
|
||||
|
||||
public LegacySkinResourceStore(SkinInfo skin, IResourceStore<byte[]> underlyingStore)
|
||||
{
|
||||
this.skin = skin;
|
||||
this.underlyingStore = underlyingStore;
|
||||
}
|
||||
|
||||
public Stream GetStream(string name) => underlyingStore.GetStream(getPathForFile(name));
|
||||
|
||||
byte[] IResourceStore<byte[]>.Get(string name) => underlyingStore.Get(getPathForFile(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ namespace osu.Game.Storyboards.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
private DependencyContainer dependencies;
|
||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
|
||||
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Storyboards.Drawables
|
||||
public bool FlipH { get; set; }
|
||||
public bool FlipV { get; set; }
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
protected override Vector2 DrawScale
|
||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y);
|
||||
|
||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Storyboards.Drawables
|
||||
public bool FlipH { get; set; }
|
||||
public bool FlipV { get; set; }
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
protected override Vector2 DrawScale
|
||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y);
|
||||
|
||||
|
@ -109,7 +109,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
|
||||
private Beatmap getBeatmap(string name)
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder();
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
|
||||
using (var stream = new StreamReader(resStream))
|
||||
return decoder.DecodeBeatmap(stream);
|
||||
|
Loading…
Reference in New Issue
Block a user