1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 17:47:29 +08:00

Merge branch 'master' into Private_Messages

This commit is contained in:
miterosan 2018-06-30 16:17:56 +02:00 committed by GitHub
commit 621f4218a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 830 additions and 183 deletions

View File

@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Tests
private DrawableFruit createDrawable(int index)
{
Fruit fruit = index == 5
? new BananaShower.Banana
? new Banana
{
StartTime = 1000000000000,
IndexInBeatmap = index,

View File

@ -49,9 +49,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
switch (obj)
{
case BananaShower bananaShower:
foreach (var nested in bananaShower.NestedHitObjects)
foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
{
((BananaShower.Banana)nested).X = (float)rng.NextDouble();
banana.X = (float)rng.NextDouble();
rng.Next(); // osu!stable retrieved a random banana type
rng.Next(); // osu!stable retrieved a random banana rotation
rng.Next(); // osu!stable retrieved a random banana colour

View File

@ -0,0 +1,36 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchBananaJudgement : CatchJudgement
{
public override bool AffectsCombo => false;
public override bool ShouldExplode => true;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 1100;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 8;
}
}
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchDropletJudgement : CatchJudgement
{
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 30;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 7;
}
}
}
}

View File

@ -2,11 +2,51 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchJudgement : Judgement
{
// todo: wangs
public override HitResult MaxResult => HitResult.Perfect;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 300;
}
}
/// <summary>
/// The base health increase for the result achieved.
/// </summary>
public float HealthIncrease => HealthIncreaseFor(Result);
/// <summary>
/// Whether fruit on the platter should explode or drop.
/// Note that this is only checked if the owning object is also <see cref="IHasComboInformation.LastInCombo" />
/// </summary>
public virtual bool ShouldExplode => IsHit;
/// <summary>
/// Convert a <see cref="HitResult"/> to a base health increase.
/// </summary>
/// <param name="result">The value to convert.</param>
/// <returns>The base health increase.</returns>
protected virtual float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 10.2f;
}
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchTinyDropletJudgement : CatchJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 10;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 4;
}
}
}
}

View File

@ -0,0 +1,10 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Catch.Objects
{
public class Banana : Fruit
{
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
}
}

View File

@ -37,10 +37,5 @@ namespace osu.Game.Rulesets.Catch.Objects
public double EndTime => StartTime + Duration;
public double Duration { get; set; }
public class Banana : Fruit
{
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
}
}
}

View File

@ -0,0 +1,17 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
public class DrawableBanana : DrawableFruit
{
public DrawableBanana(Banana h)
: base(h)
{
}
protected override CatchJudgement CreateJudgement() => new CatchBananaJudgement();
}
}

View File

@ -5,9 +5,7 @@ using System;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
@ -24,15 +22,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
foreach (var b in s.NestedHitObjects.Cast<BananaShower.Banana>())
foreach (var b in s.NestedHitObjects.Cast<Banana>())
AddNested(getVisualRepresentation?.Invoke(b));
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
{
if (timeOffset >= 0)
AddJudgement(new Judgement { Result = NestedHitObjects.Cast<DrawableCatchHitObject>().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss });
}
protected override bool ProvidesJudgement => false;
protected override void AddNested(DrawableHitObject h)
{

View File

@ -2,14 +2,14 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using OpenTK;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
@ -58,8 +58,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
if (CheckPosition == null) return;
if (timeOffset >= 0)
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
{
var judgement = CreateJudgement();
judgement.Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss;
AddJudgement(judgement);
}
}
protected virtual CatchJudgement CreateJudgement() => new CatchJudgement();
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
@ -23,6 +24,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
Masking = false;
}
protected override CatchJudgement CreateJudgement() => new CatchDropletJudgement();
[BackgroundDependencyLoader]
private void load()
{

View File

@ -0,0 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
public class DrawableTinyDroplet : DrawableDroplet
{
public DrawableTinyDroplet(Droplet h)
: base(h)
{
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
}
protected override CatchJudgement CreateJudgement() => new CatchTinyDropletJudgement();
}
}

View File

@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Replays
return;
}
if (h is BananaShower.Banana)
if (h is Banana)
{
// auto bananas unrealistically warp to catch 100% combo.
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Catch.Replays
{
switch (nestedObj)
{
case BananaShower.Banana _:
case Banana _:
case TinyDroplet _:
case Droplet _:
case Fruit _:

View File

@ -1,10 +1,12 @@
// 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 System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
@ -17,28 +19,57 @@ namespace osu.Game.Rulesets.Catch.Scoring
{
}
private float hpDrainRate;
protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap)
{
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
foreach (var obj in beatmap.HitObjects)
{
switch (obj)
{
case JuiceStream stream:
foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>())
foreach (var nestedObject in stream.NestedHitObjects)
switch (nestedObject)
{
case TinyDroplet _:
AddJudgement(new CatchTinyDropletJudgement { Result = HitResult.Perfect });
break;
case Droplet _:
AddJudgement(new CatchDropletJudgement { Result = HitResult.Perfect });
break;
case Fruit _:
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
break;
}
break;
case BananaShower shower:
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
AddJudgement(new CatchBananaJudgement { Result = HitResult.Perfect });
break;
case Fruit _:
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
break;
}
}
}
base.SimulateAutoplay(beatmap);
private const double harshness = 0.01;
protected override void OnNewJudgement(Judgement judgement)
{
base.OnNewJudgement(judgement);
if (judgement.Result == HitResult.Miss)
{
if (!judgement.IsBonus)
Health.Value -= hpDrainRate * (harshness * 2);
return;
}
if (judgement is CatchJudgement catchJudgement)
Health.Value += Math.Max(catchJudgement.HealthIncrease - hpDrainRate, 0) * harshness;
}
}
}

View File

@ -38,14 +38,16 @@ namespace osu.Game.Rulesets.Catch.UI
{
switch (h)
{
case Banana banana:
return new DrawableBanana(banana);
case Fruit fruit:
return new DrawableFruit(fruit);
case JuiceStream stream:
return new DrawableJuiceStream(stream, GetVisualRepresentation);
case BananaShower banana:
return new DrawableBananaShower(banana, GetVisualRepresentation);
case BananaShower shower:
return new DrawableBananaShower(shower, GetVisualRepresentation);
case TinyDroplet tiny:
return new DrawableDroplet(tiny) { Scale = new Vector2(0.5f) };
return new DrawableTinyDroplet(tiny);
case Droplet droplet:
return new DrawableDroplet(droplet);
}

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.Replays;
@ -78,12 +79,11 @@ namespace osu.Game.Rulesets.Catch.UI
if (!fruit.StaysOnPlate)
runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
}
if (fruit.HitObject.LastInCombo)
{
if (judgement.IsHit)
if (((CatchJudgement)judgement).ShouldExplode)
runAfterLoaded(() => MovableCatcher.Explode());
else
MovableCatcher.Drop();

View File

@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mania.Judgements
public class HoldNoteJudgement : ManiaJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 0;
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
@ -12,11 +11,6 @@ namespace osu.Game.Rulesets.Osu.Judgements
{
public override HitResult MaxResult => HitResult.Great;
/// <summary>
/// The positional hit offset.
/// </summary>
public Vector2 PositionOffset;
protected override int NumericResultFor(HitResult result)
{
switch (result)

View File

@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Osu.Judgements
public class OsuSliderTailJudgement : OsuJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 0;
}
}

View File

@ -93,7 +93,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
AddJudgement(new OsuJudgement
{
Result = result,
PositionOffset = Vector2.Zero //todo: set to correct value
});
}

View File

@ -54,9 +54,9 @@ namespace osu.Game.Rulesets.Osu.Objects
public virtual bool NewCombo { get; set; }
public int IndexInCurrentCombo { get; set; }
public virtual int IndexInCurrentCombo { get; set; }
public int ComboIndex { get; set; }
public virtual int ComboIndex { get; set; }
public bool LastInCombo { get; set; }

View File

@ -26,6 +26,28 @@ namespace osu.Game.Rulesets.Osu.Objects
public Vector2 StackedPositionAt(double t) => StackedPosition + this.CurvePositionAt(t);
public override Vector2 EndPosition => Position + this.CurvePositionAt(1);
public override int ComboIndex
{
get => base.ComboIndex;
set
{
base.ComboIndex = value;
foreach (var n in NestedHitObjects.OfType<IHasComboInformation>())
n.ComboIndex = value;
}
}
public override int IndexInCurrentCombo
{
get => base.IndexInCurrentCombo;
set
{
base.IndexInCurrentCombo = value;
foreach (var n in NestedHitObjects.OfType<IHasComboInformation>())
n.IndexInCurrentCombo = value;
}
}
public SliderCurve Curve { get; } = new SliderCurve();
public List<Vector2> ControlPoints
@ -147,7 +169,8 @@ namespace osu.Game.Rulesets.Osu.Objects
var distanceProgress = d / length;
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL)
?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
var sampleList = new List<SampleInfo>();
if (firstSample != null)

View File

@ -11,7 +11,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
using osu.Game.Rulesets.UI;
using System.Linq;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Judgements;
namespace osu.Game.Rulesets.Osu.UI
{
@ -75,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.UI
DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject)
{
Origin = Anchor.Centre,
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + ((OsuJudgement)judgement).PositionOffset
Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition
};
judgementLayer.Add(explosion);

View File

@ -66,8 +66,8 @@ namespace osu.Game.Beatmaps
// General
public int AudioLeadIn { get; set; }
public bool Countdown { get; set; }
public float StackLeniency { get; set; }
public bool Countdown { get; set; } = true;
public float StackLeniency { get; set; } = 0.7f;
public bool SpecialStyle { get; set; }
public int RulesetID { get; set; }

View File

@ -13,7 +13,13 @@ namespace osu.Game.Beatmaps
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public int? OnlineBeatmapSetID { get; set; }
private int? onlineBeatmapSetID;
public int? OnlineBeatmapSetID
{
get { return onlineBeatmapSetID; }
set { onlineBeatmapSetID = value > 0 ? value : null; }
}
public BeatmapMetadata Metadata { get; set; }

View File

@ -18,6 +18,8 @@ namespace osu.Game.Graphics.Containers
private SampleChannel samplePopIn;
private SampleChannel samplePopOut;
protected virtual bool PlaySamplesOnStateChange => true;
private PreviewTrackManager previewTrackManager;
protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
@ -69,12 +71,14 @@ namespace osu.Game.Graphics.Containers
{
case Visibility.Visible:
if (OverlayActivationMode != OverlayActivation.Disabled)
samplePopIn?.Play();
{
if (PlaySamplesOnStateChange) samplePopIn?.Play();
}
else
State = Visibility.Hidden;
break;
case Visibility.Hidden:
samplePopOut?.Play();
if (PlaySamplesOnStateChange) samplePopOut?.Play();
break;
}
}

View File

@ -0,0 +1,376 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using osu.Game.Database;
namespace osu.Game.Migrations
{
[DbContext(typeof(OsuDbContext))]
[Migration("20180628011956_RemoveNegativeSetIDs")]
partial class RemoveNegativeSetIDs
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846");
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<float>("ApproachRate");
b.Property<float>("CircleSize");
b.Property<float>("DrainRate");
b.Property<float>("OverallDifficulty");
b.Property<double>("SliderMultiplier");
b.Property<double>("SliderTickRate");
b.HasKey("ID");
b.ToTable("BeatmapDifficulty");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("AudioLeadIn");
b.Property<int>("BaseDifficultyID");
b.Property<int>("BeatDivisor");
b.Property<int>("BeatmapSetInfoID");
b.Property<bool>("Countdown");
b.Property<double>("DistanceSpacing");
b.Property<int>("GridSize");
b.Property<string>("Hash");
b.Property<bool>("Hidden");
b.Property<bool>("LetterboxInBreaks");
b.Property<string>("MD5Hash");
b.Property<int?>("MetadataID");
b.Property<int?>("OnlineBeatmapID");
b.Property<string>("Path");
b.Property<int>("RulesetID");
b.Property<bool>("SpecialStyle");
b.Property<float>("StackLeniency");
b.Property<double>("StarDifficulty");
b.Property<string>("StoredBookmarks");
b.Property<double>("TimelineZoom");
b.Property<string>("Version");
b.Property<bool>("WidescreenStoryboard");
b.HasKey("ID");
b.HasIndex("BaseDifficultyID");
b.HasIndex("BeatmapSetInfoID");
b.HasIndex("Hash");
b.HasIndex("MD5Hash");
b.HasIndex("MetadataID");
b.HasIndex("OnlineBeatmapID")
.IsUnique();
b.HasIndex("RulesetID");
b.ToTable("BeatmapInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Artist");
b.Property<string>("ArtistUnicode");
b.Property<string>("AudioFile");
b.Property<string>("AuthorString")
.HasColumnName("Author");
b.Property<string>("BackgroundFile");
b.Property<int>("PreviewTime");
b.Property<string>("Source");
b.Property<string>("Tags");
b.Property<string>("Title");
b.Property<string>("TitleUnicode");
b.HasKey("ID");
b.ToTable("BeatmapMetadata");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("BeatmapSetInfoID");
b.Property<int>("FileInfoID");
b.Property<string>("Filename")
.IsRequired();
b.HasKey("ID");
b.HasIndex("BeatmapSetInfoID");
b.HasIndex("FileInfoID");
b.ToTable("BeatmapSetFileInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<bool>("DeletePending");
b.Property<string>("Hash");
b.Property<int?>("MetadataID");
b.Property<int?>("OnlineBeatmapSetID");
b.Property<bool>("Protected");
b.HasKey("ID");
b.HasIndex("DeletePending");
b.HasIndex("Hash")
.IsUnique();
b.HasIndex("MetadataID");
b.HasIndex("OnlineBeatmapSetID")
.IsUnique();
b.ToTable("BeatmapSetInfo");
});
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("IntKey")
.HasColumnName("Key");
b.Property<int?>("RulesetID");
b.Property<string>("StringValue")
.HasColumnName("Value");
b.Property<int?>("Variant");
b.HasKey("ID");
b.HasIndex("RulesetID", "Variant");
b.ToTable("Settings");
});
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("IntAction")
.HasColumnName("Action");
b.Property<string>("KeysString")
.HasColumnName("Keys");
b.Property<int?>("RulesetID");
b.Property<int?>("Variant");
b.HasKey("ID");
b.HasIndex("IntAction");
b.HasIndex("RulesetID", "Variant");
b.ToTable("KeyBinding");
});
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Hash");
b.Property<int>("ReferenceCount");
b.HasKey("ID");
b.HasIndex("Hash")
.IsUnique();
b.HasIndex("ReferenceCount");
b.ToTable("FileInfo");
});
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
{
b.Property<int?>("ID")
.ValueGeneratedOnAdd();
b.Property<bool>("Available");
b.Property<string>("InstantiationInfo");
b.Property<string>("Name");
b.Property<string>("ShortName");
b.HasKey("ID");
b.HasIndex("Available");
b.HasIndex("ShortName")
.IsUnique();
b.ToTable("RulesetInfo");
});
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("FileInfoID");
b.Property<string>("Filename")
.IsRequired();
b.Property<int>("SkinInfoID");
b.HasKey("ID");
b.HasIndex("FileInfoID");
b.HasIndex("SkinInfoID");
b.ToTable("SkinFileInfo");
});
modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Creator");
b.Property<bool>("DeletePending");
b.Property<string>("Name");
b.HasKey("ID");
b.ToTable("SkinInfo");
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
.WithMany()
.HasForeignKey("BaseDifficultyID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
.WithMany("Beatmaps")
.HasForeignKey("BeatmapSetInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
.WithMany("Beatmaps")
.HasForeignKey("MetadataID");
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
.WithMany()
.HasForeignKey("RulesetID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
.WithMany("Files")
.HasForeignKey("BeatmapSetInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
.WithMany()
.HasForeignKey("FileInfoID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
.WithMany("BeatmapSets")
.HasForeignKey("MetadataID");
});
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
{
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
.WithMany()
.HasForeignKey("FileInfoID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("osu.Game.Skinning.SkinInfo")
.WithMany("Files")
.HasForeignKey("SkinInfoID")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace osu.Game.Migrations
{
public partial class RemoveNegativeSetIDs : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
// There was a change that baetmaps were being loaded with "-1" online IDs, which is completely incorrect.
// This ensures there will not be unique key conflicts as a result of these incorrectly imported beatmaps.
migrationBuilder.Sql("UPDATE BeatmapSetInfo SET OnlineBeatmapSetID = null WHERE OnlineBeatmapSetID <= 0");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

View File

@ -85,7 +85,7 @@ namespace osu.Game
private OnScreenDisplay onscreenDisplay;
private Bindable<int> configRuleset;
public Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private Bindable<int> configSkin;
@ -147,10 +147,13 @@ namespace osu.Game
dependencies.CacheAs(this);
dependencies.CacheAs(ruleset);
dependencies.CacheAs<IBindable<RulesetInfo>>(ruleset);
// bind config int to database RulesetInfo
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
// bind config int to database SkinInfo
configSkin = LocalConfig.GetBindable<int>(OsuSetting.Skin);
@ -210,7 +213,7 @@ namespace osu.Game
return;
}
Ruleset.Value = s.Ruleset;
ruleset.Value = s.Ruleset;
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(s.Beatmap);
Beatmap.Value.Mods.Value = s.Mods;
@ -544,7 +547,7 @@ namespace osu.Game
// the use case for not applying is in visual/unit tests.
bool applyRestrictions = !currentScreen?.AllowBeatmapRulesetChange ?? false;
Ruleset.Disabled = applyRestrictions;
ruleset.Disabled = applyRestrictions;
Beatmap.Disabled = applyRestrictions;
mainContent.Padding = new MarginPadding { Top = ToolbarOffset };

View File

@ -30,6 +30,8 @@ namespace osu.Game.Overlays
State = Visibility.Visible;
}
protected override bool PlaySamplesOnStateChange => false;
private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v)
{
if (v != Visibility.Hidden) return;

View File

@ -35,16 +35,14 @@ namespace osu.Game.Overlays.Direct
}
[BackgroundDependencyLoader(true)]
private void load(OsuGame game, RulesetStore rulesets, OsuColour colours)
private void load(RulesetStore rulesets, OsuColour colours, Bindable<RulesetInfo> ruleset)
{
DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;
Ruleset.Value = game?.Ruleset.Value ?? rulesets.GetRuleset(0);
Ruleset.Value = ruleset ?? rulesets.GetRuleset(0);
foreach (var r in rulesets.AvailableRulesets)
{
modeButtons.Add(new RulesetToggleButton(Ruleset, r));
}
}
private class RulesetToggleButton : OsuClickableContainer
{

View File

@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Mods
}
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, OsuGame osu, RulesetStore rulesets, AudioManager audio)
private void load(OsuColour colours, Bindable<RulesetInfo> ruleset, RulesetStore rulesets, AudioManager audio)
{
SelectedMods.ValueChanged += selectedModsChanged;
@ -60,8 +60,8 @@ namespace osu.Game.Overlays.Mods
HighMultiplierColour = colours.Green;
UnrankedLabel.Colour = colours.Blue;
if (osu != null)
Ruleset.BindTo(osu.Ruleset);
if (ruleset != null)
Ruleset.BindTo(ruleset);
else
Ruleset.Value = rulesets.AvailableRulesets.First();

View File

@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Toolbar
}
[BackgroundDependencyLoader(true)]
private void load(RulesetStore rulesets, OsuGame game)
private void load(RulesetStore rulesets, Bindable<RulesetInfo> parentRuleset)
{
this.rulesets = rulesets;
foreach (var r in rulesets.AvailableRulesets)
@ -83,8 +83,8 @@ namespace osu.Game.Overlays.Toolbar
ruleset.ValueChanged += rulesetChanged;
ruleset.DisabledChanged += disabledChanged;
if (game != null)
ruleset.BindTo(game.Ruleset);
if (parentRuleset != null)
ruleset.BindTo(parentRuleset);
else
ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault();
}

View File

@ -45,11 +45,15 @@ namespace osu.Game.Rulesets.Judgements
public double TimeOffset { get; set; }
/// <summary>
/// Whether the <see cref="Result"/> should affect the combo portion of the score.
/// If false, the <see cref="Result"/> will be considered for the bonus portion of the score.
/// Whether the <see cref="Result"/> should affect the current combo.
/// </summary>
public virtual bool AffectsCombo => true;
/// <summary>
/// Whether the <see cref="Result"/> should be counted as base (combo) or bonus score.
/// </summary>
public virtual bool IsBonus => !AffectsCombo;
/// <summary>
/// The numeric representation for the result achieved.
/// </summary>

View File

@ -1,26 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Objects.Types
{
/// <summary>
/// A HitObject that is part of a combo and has extended information about its position relative to other combo objects.
/// </summary>
public interface IHasComboIndex : IHasCombo
{
/// <summary>
/// The offset of this hitobject in the current combo.
/// </summary>
int IndexInCurrentCombo { get; set; }
/// <summary>
/// The offset of this hitobject in the current combo.
/// </summary>
int ComboIndex { get; set; }
/// <summary>
/// Whether this is the last object in the current combo.
/// </summary>
bool LastInCombo { get; set; }
}
}

View File

@ -261,14 +261,20 @@ namespace osu.Game.Rulesets.Scoring
break;
}
baseScore += judgement.NumericResult;
rollingMaxBaseScore += judgement.MaxNumericResult;
JudgedHits++;
}
else if (judgement.IsHit)
if (judgement.IsBonus)
{
if (judgement.IsHit)
bonusScore += judgement.NumericResult;
}
else
{
baseScore += judgement.NumericResult;
rollingMaxBaseScore += judgement.MaxNumericResult;
}
}
/// <summary>
/// Removes a judgement. This should reverse everything in <see cref="OnNewJudgement(Judgement)"/>.
@ -280,14 +286,18 @@ namespace osu.Game.Rulesets.Scoring
HighestCombo.Value = judgement.HighestComboAtJudgement;
if (judgement.AffectsCombo)
JudgedHits--;
if (judgement.IsBonus)
{
if (judgement.IsHit)
bonusScore -= judgement.NumericResult;
}
else
{
baseScore -= judgement.NumericResult;
rollingMaxBaseScore -= judgement.MaxNumericResult;
JudgedHits--;
}
else if (judgement.IsHit)
bonusScore -= judgement.NumericResult;
}
private void updateScore()

View File

@ -82,22 +82,24 @@ namespace osu.Game.Screens
private SampleChannel sampleExit;
[BackgroundDependencyLoader(true)]
private void load(BindableBeatmap beatmap, OsuGame osuGame, AudioManager audio)
private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset)
{
if (beatmap != null)
Beatmap.BindTo(beatmap);
if (osuGame != null)
if (ruleset != null)
Ruleset.BindTo(ruleset);
if (osu != null)
{
Ruleset.BindTo(osuGame.Ruleset);
OverlayActivationMode.BindTo(osuGame.OverlayActivationMode);
OverlayActivationMode.BindTo(osu.OverlayActivationMode);
updateOverlayStates = () =>
{
if (HideOverlaysOnEnter)
osuGame.CloseAllOverlays();
osu.CloseAllOverlays();
else
osuGame.Toolbar.State = Visibility.Visible;
osu.Toolbar.State = Visibility.Visible;
};
}

View File

@ -158,6 +158,7 @@ namespace osu.Game.Screens.Play
userAudioOffset.TriggerChange();
ScoreProcessor = RulesetContainer.CreateScoreProcessor();
if (!ScoreProcessor.Mode.Disabled)
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
Children = new Drawable[]

View File

@ -53,10 +53,10 @@ namespace osu.Game.Screens.Select
}
[BackgroundDependencyLoader(true)]
private void load([CanBeNull] OsuGame osuGame)
private void load([CanBeNull] Bindable<RulesetInfo> parentRuleset)
{
if (osuGame != null)
ruleset.BindTo(osuGame.Ruleset);
if (parentRuleset != null)
ruleset.BindTo(parentRuleset);
ruleset.ValueChanged += _ => updateDisplay();
}

View File

@ -62,7 +62,7 @@ namespace osu.Game.Screens.Select
Sort = sort,
SearchText = searchTextBox.Text,
AllowConvertedBeatmaps = showConverted,
Ruleset = ruleset
Ruleset = ruleset.Value
};
public Action Exit;
@ -163,24 +163,23 @@ namespace osu.Game.Screens.Select
searchTextBox.HoldFocus = true;
}
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private readonly IBindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private Bindable<bool> showConverted;
public readonly Box Background;
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, OsuGame osu, OsuConfigManager config)
private void load(OsuColour colours, IBindable<RulesetInfo> parentRuleset, OsuConfigManager config)
{
sortTabs.AccentColour = colours.GreenLight;
showConverted = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps);
showConverted.ValueChanged += val => updateCriteria();
if (osu != null)
ruleset.BindTo(osu.Ruleset);
ruleset.ValueChanged += val => updateCriteria();
ruleset.TriggerChange();
if (parentRuleset != null)
ruleset.BindTo(parentRuleset);
ruleset.BindValueChanged(val => updateCriteria(), true);
}
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());

View File

@ -19,7 +19,6 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Logging;
using osu.Game.Rulesets;
namespace osu.Game.Screens.Select.Leaderboards
@ -33,7 +32,7 @@ namespace osu.Game.Screens.Select.Leaderboards
private FillFlowContainer<LeaderboardScore> scrollFlow;
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private readonly IBindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
public Action<Score> ScoreSelected;
@ -174,9 +173,8 @@ namespace osu.Game.Screens.Select.Leaderboards
private APIAccess api;
private BeatmapInfo beatmap;
private OsuGame osuGame;
private ScheduledDelegate pendingBeatmapSwitch;
private ScheduledDelegate pendingUpdateScores;
public BeatmapInfo Beatmap
{
@ -189,21 +187,19 @@ namespace osu.Game.Screens.Select.Leaderboards
beatmap = value;
Scores = null;
pendingBeatmapSwitch?.Cancel();
pendingBeatmapSwitch = Schedule(updateScores);
updateScores();
}
}
[BackgroundDependencyLoader(permitNulls: true)]
private void load(APIAccess api, OsuGame osuGame)
private void load(APIAccess api, IBindable<RulesetInfo> parentRuleset)
{
this.api = api;
this.osuGame = osuGame;
if (osuGame != null)
ruleset.BindTo(osuGame.Ruleset);
if (parentRuleset != null)
ruleset.BindTo(parentRuleset);
ruleset.ValueChanged += r => updateScores();
ruleset.ValueChanged += _ => updateScores();
if (api != null)
api.OnStateChange += handleApiStateChange;
@ -230,6 +226,12 @@ namespace osu.Game.Screens.Select.Leaderboards
}
private void updateScores()
{
getScoresRequest?.Cancel();
getScoresRequest = null;
pendingUpdateScores?.Cancel();
pendingUpdateScores = Schedule(() =>
{
if (Scope == LeaderboardScope.Local)
{
@ -259,7 +261,7 @@ namespace osu.Game.Screens.Select.Leaderboards
PlaceholderState = PlaceholderState.Retrieving;
loading.Show();
getScoresRequest = new GetScoresRequest(Beatmap, osuGame?.Ruleset.Value ?? Beatmap.Ruleset, Scope);
getScoresRequest = new GetScoresRequest(Beatmap, ruleset.Value ?? Beatmap.Ruleset, Scope);
getScoresRequest.Success += r => Schedule(() =>
{
Scores = r.Scores;
@ -272,10 +274,10 @@ namespace osu.Game.Screens.Select.Leaderboards
return;
PlaceholderState = PlaceholderState.NetworkFailure;
Logger.Error(e, @"Couldn't fetch beatmap scores!");
});
api.Queue(getScoresRequest);
});
}
private Placeholder currentPlaceholder;

View File

@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
@ -17,6 +18,7 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Menu;
@ -62,6 +64,8 @@ namespace osu.Game.Screens.Select
private SampleChannel sampleChangeDifficulty;
private SampleChannel sampleChangeBeatmap;
protected new readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
@ -123,7 +127,7 @@ namespace osu.Game.Screens.Select
Size = new Vector2(carousel_width, 1),
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
SelectionChanged = carouselSelectionChanged,
SelectionChanged = updateSelectedBeatmap,
BeatmapSetsChanged = carouselBeatmapsLoaded,
},
FilterControl = new FilterControl
@ -177,9 +181,13 @@ namespace osu.Game.Screens.Select
}
[BackgroundDependencyLoader(true)]
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours)
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuColour colours)
{
dependencies.CacheAs(this);
dependencies.CacheAs(Ruleset);
dependencies.CacheAs<IBindable<RulesetInfo>>(Ruleset);
base.Ruleset.ValueChanged += r => updateSelectedBeatmap(beatmapNoDebounce);
if (Footer != null)
{
@ -192,9 +200,6 @@ namespace osu.Game.Screens.Select
if (this.beatmaps == null)
this.beatmaps = beatmaps;
if (osu != null)
Ruleset.BindTo(osu.Ruleset);
this.beatmaps.ItemAdded += onBeatmapSetAdded;
this.beatmaps.ItemRemoved += onBeatmapSetRemoved;
this.beatmaps.BeatmapHidden += onBeatmapHidden;
@ -250,9 +255,6 @@ namespace osu.Game.Screens.Select
private ScheduledDelegate selectionChangedDebounce;
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo beatmapNoDebounce;
private void workingBeatmapChanged(WorkingBeatmap beatmap)
{
if (beatmap is DummyWorkingBeatmap) return;
@ -266,11 +268,17 @@ namespace osu.Game.Screens.Select
}
}
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo beatmapNoDebounce;
private RulesetInfo rulesetNoDebounce;
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// selection has been changed as the result of a user interaction.
/// </summary>
private void carouselSelectionChanged(BeatmapInfo beatmap)
private void updateSelectedBeatmap(BeatmapInfo beatmap)
{
var ruleset = base.Ruleset.Value;
void performLoad()
{
// We may be arriving here due to another component changing the bindable Beatmap.
@ -283,15 +291,18 @@ namespace osu.Game.Screens.Select
ensurePlayingSelected(preview);
}
Ruleset.Value = ruleset;
UpdateBeatmap(Beatmap.Value);
}
if (beatmap?.Equals(beatmapNoDebounce) == true)
if (beatmap?.Equals(beatmapNoDebounce) == true && ruleset?.Equals(rulesetNoDebounce) == true)
return;
selectionChangedDebounce?.Cancel();
beatmapNoDebounce = beatmap;
rulesetNoDebounce = ruleset;
if (beatmap == null)
performLoad();
@ -460,7 +471,7 @@ namespace osu.Game.Screens.Select
{
// in the case random selection failed, we want to trigger selectionChanged
// to show the dummy beatmap (we have nothing else to display).
carouselSelectionChanged(null);
updateSelectedBeatmap(null);
}
}

View File

@ -19,7 +19,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="ppy.osu.Framework" Version="2018.626.0" />
<PackageReference Include="SharpCompress" Version="0.21.1" />
<PackageReference Include="SharpCompress" Version="0.17.1" />
<PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
</ItemGroup>