mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:07:52 +08:00
Merge branch 'master' into hp-drain-fix-breaks
This commit is contained in:
commit
e3217bc82e
@ -59,7 +59,7 @@ The [issue tracker](https://github.com/ppy/osu/issues) should provide plenty of
|
||||
|
||||
In the case of simple issues, a direct PR is okay. However, if you decide to work on an existing issue which doesn't seem trivial, **please ask us first**. This way we can try to estimate if it is a good fit for you and provide the correct direction on how to address it. In addition, note that while we do not rule out external contributors from working on roadmapped issues, we will generally prefer to handle them ourselves unless they're not very time sensitive.
|
||||
|
||||
If you'd like to propose a subjective change to one of the visual aspects of the game, or there is a bigger task you'd like to work on, but there is no corresponding issue or discussion thread yet for it, **please open a discussion or issue first** to avoid wasted effort. This in particular applies if you want to work on [one of the available designs from the osu! public Figma library](https://www.figma.com/file/6m10GiGEncVFWmgOoSyakH/osu!-Figma-Library).
|
||||
If you'd like to propose a subjective change to one of the visual aspects of the game, or there is a bigger task you'd like to work on, but there is no corresponding issue or discussion thread yet for it, **please open a discussion or issue first** to avoid wasted effort. This in particular applies if you want to work on [one of the available designs from the osu! Figma master library](https://www.figma.com/file/VIkXMYNPMtQem2RJg9k2iQ/Master-Library).
|
||||
|
||||
Aside from the above, below is a brief checklist of things to watch out when you're preparing your code changes:
|
||||
|
||||
@ -85,4 +85,4 @@ If you're uncertain about some part of the codebase or some inner workings of th
|
||||
- [Development roadmap](https://github.com/orgs/ppy/projects/7/views/6): What the core team is currently working on
|
||||
- [`ppy/osu-framework` wiki](https://github.com/ppy/osu-framework/wiki): Contains introductory information about osu!framework, the bespoke 2D game framework we use for the game
|
||||
- [`ppy/osu` wiki](https://github.com/ppy/osu/wiki): Contains articles about various technical aspects of the game
|
||||
- [Public Figma library](https://www.figma.com/file/6m10GiGEncVFWmgOoSyakH/osu!-Figma-Library): Contains finished and draft designs for osu!
|
||||
- [Figma master library](https://www.figma.com/file/VIkXMYNPMtQem2RJg9k2iQ/Master-Library): Contains finished and draft designs for osu!
|
||||
|
@ -23,6 +23,22 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
{
|
||||
}
|
||||
|
||||
public override void PreProcess()
|
||||
{
|
||||
IHasComboInformation? lastObj = null;
|
||||
|
||||
// For sanity, ensures that both the first hitobject and the first hitobject after a banana shower start a new combo.
|
||||
// This is normally enforced by the legacy decoder, but is not enforced by the editor.
|
||||
foreach (var obj in Beatmap.HitObjects.OfType<IHasComboInformation>())
|
||||
{
|
||||
if (obj is not BananaShower && (lastObj == null || lastObj is BananaShower))
|
||||
obj.NewCombo = true;
|
||||
lastObj = obj;
|
||||
}
|
||||
|
||||
base.PreProcess();
|
||||
}
|
||||
|
||||
public override void PostProcess()
|
||||
{
|
||||
base.PostProcess();
|
||||
|
@ -155,6 +155,33 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
Scale = LegacyRulesetExtensions.CalculateScaleFromCircleSize(difficulty.CircleSize);
|
||||
}
|
||||
|
||||
public void UpdateComboInformation(IHasComboInformation? lastObj)
|
||||
{
|
||||
// Note that this implementation is shared with the osu! ruleset's implementation.
|
||||
// If a change is made here, OsuHitObject.cs should also be updated.
|
||||
ComboIndex = lastObj?.ComboIndex ?? 0;
|
||||
ComboIndexWithOffsets = lastObj?.ComboIndexWithOffsets ?? 0;
|
||||
IndexInCurrentCombo = (lastObj?.IndexInCurrentCombo + 1) ?? 0;
|
||||
|
||||
if (this is BananaShower)
|
||||
{
|
||||
// For the purpose of combo colours, spinners never start a new combo even if they are flagged as doing so.
|
||||
return;
|
||||
}
|
||||
|
||||
// At decode time, the first hitobject in the beatmap and the first hitobject after a banana shower are both enforced to be a new combo,
|
||||
// but this isn't directly enforced by the editor so the extra checks against the last hitobject are duplicated here.
|
||||
if (NewCombo || lastObj == null || lastObj is BananaShower)
|
||||
{
|
||||
IndexInCurrentCombo = 0;
|
||||
ComboIndex++;
|
||||
ComboIndexWithOffsets += ComboOffset + 1;
|
||||
|
||||
if (lastObj != null)
|
||||
lastObj.LastInCombo = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
#region Hit object conversion
|
||||
|
@ -2,9 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osuTK;
|
||||
|
||||
@ -19,6 +21,22 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
{
|
||||
}
|
||||
|
||||
public override void PreProcess()
|
||||
{
|
||||
IHasComboInformation? lastObj = null;
|
||||
|
||||
// For sanity, ensures that both the first hitobject and the first hitobject after a spinner start a new combo.
|
||||
// This is normally enforced by the legacy decoder, but is not enforced by the editor.
|
||||
foreach (var obj in Beatmap.HitObjects.OfType<IHasComboInformation>())
|
||||
{
|
||||
if (obj is not Spinner && (lastObj == null || lastObj is Spinner))
|
||||
obj.NewCombo = true;
|
||||
lastObj = obj;
|
||||
}
|
||||
|
||||
base.PreProcess();
|
||||
}
|
||||
|
||||
public override void PostProcess()
|
||||
{
|
||||
base.PostProcess();
|
||||
|
@ -159,9 +159,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
if (allowSelection)
|
||||
d.RequestSelection = selectionRequested;
|
||||
|
||||
d.DragStarted = dragStarted;
|
||||
d.DragInProgress = dragInProgress;
|
||||
d.DragEnded = dragEnded;
|
||||
d.DragStarted = DragStarted;
|
||||
d.DragInProgress = DragInProgress;
|
||||
d.DragEnded = DragEnded;
|
||||
}));
|
||||
|
||||
Connections.Add(new PathControlPointConnectionPiece<T>(hitObject, e.NewStartingIndex + i));
|
||||
@ -267,7 +267,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
private int draggedControlPointIndex;
|
||||
private HashSet<PathControlPoint> selectedControlPoints;
|
||||
|
||||
private void dragStarted(PathControlPoint controlPoint)
|
||||
public void DragStarted(PathControlPoint controlPoint)
|
||||
{
|
||||
dragStartPositions = hitObject.Path.ControlPoints.Select(point => point.Position).ToArray();
|
||||
dragPathTypes = hitObject.Path.ControlPoints.Select(point => point.Type).ToArray();
|
||||
@ -279,7 +279,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
changeHandler?.BeginChange();
|
||||
}
|
||||
|
||||
private void dragInProgress(DragEvent e)
|
||||
public void DragInProgress(DragEvent e)
|
||||
{
|
||||
Vector2[] oldControlPoints = hitObject.Path.ControlPoints.Select(cp => cp.Position).ToArray();
|
||||
var oldPosition = hitObject.Position;
|
||||
@ -341,7 +341,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
hitObject.Path.ControlPoints[i].Type = dragPathTypes[i];
|
||||
}
|
||||
|
||||
private void dragEnded() => changeHandler?.EndChange();
|
||||
public void DragEnded() => changeHandler?.EndChange();
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -39,9 +39,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
[CanBeNull]
|
||||
protected PathControlPointVisualiser<Slider> ControlPointVisualiser { get; private set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IPositionSnapProvider positionSnapProvider { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IDistanceSnapProvider distanceSnapProvider { get; set; }
|
||||
|
||||
@ -191,21 +188,30 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
[CanBeNull]
|
||||
private PathControlPoint placementControlPoint;
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e) => placementControlPoint != null;
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
if (placementControlPoint == null)
|
||||
return base.OnDragStart(e);
|
||||
|
||||
ControlPointVisualiser?.DragStarted(placementControlPoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
base.OnDrag(e);
|
||||
|
||||
if (placementControlPoint != null)
|
||||
{
|
||||
var result = positionSnapProvider?.FindSnappedPositionAndTime(ToScreenSpace(e.MousePosition));
|
||||
placementControlPoint.Position = ToLocalSpace(result?.ScreenSpacePosition ?? ToScreenSpace(e.MousePosition)) - HitObject.Position;
|
||||
}
|
||||
ControlPointVisualiser?.DragInProgress(e);
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
if (placementControlPoint != null)
|
||||
{
|
||||
if (IsDragged)
|
||||
ControlPointVisualiser?.DragEnded();
|
||||
|
||||
placementControlPoint = null;
|
||||
changeHandler?.EndChange();
|
||||
}
|
||||
|
@ -159,6 +159,33 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
Scale = LegacyRulesetExtensions.CalculateScaleFromCircleSize(difficulty.CircleSize, true);
|
||||
}
|
||||
|
||||
public void UpdateComboInformation(IHasComboInformation? lastObj)
|
||||
{
|
||||
// Note that this implementation is shared with the osu!catch ruleset's implementation.
|
||||
// If a change is made here, CatchHitObject.cs should also be updated.
|
||||
ComboIndex = lastObj?.ComboIndex ?? 0;
|
||||
ComboIndexWithOffsets = lastObj?.ComboIndexWithOffsets ?? 0;
|
||||
IndexInCurrentCombo = (lastObj?.IndexInCurrentCombo + 1) ?? 0;
|
||||
|
||||
if (this is Spinner)
|
||||
{
|
||||
// For the purpose of combo colours, spinners never start a new combo even if they are flagged as doing so.
|
||||
return;
|
||||
}
|
||||
|
||||
// At decode time, the first hitobject in the beatmap and the first hitobject after a spinner are both enforced to be a new combo,
|
||||
// but this isn't directly enforced by the editor so the extra checks against the last hitobject are duplicated here.
|
||||
if (NewCombo || lastObj == null || lastObj is Spinner)
|
||||
{
|
||||
IndexInCurrentCombo = 0;
|
||||
ComboIndex++;
|
||||
ComboIndexWithOffsets += ComboOffset + 1;
|
||||
|
||||
if (lastObj != null)
|
||||
lastObj.LastInCombo = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override HitWindows CreateHitWindows() => new OsuHitWindows();
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -433,12 +434,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
new OsuBeatmapProcessor(converted).PreProcess();
|
||||
new OsuBeatmapProcessor(converted).PostProcess();
|
||||
|
||||
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(6, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(11, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(14, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(9, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,12 +457,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
new CatchBeatmapProcessor(converted).PreProcess();
|
||||
new CatchBeatmapProcessor(converted).PostProcess();
|
||||
|
||||
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(6, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(11, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(14, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
||||
Assert.AreEqual(9, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndexWithOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1093,5 +1094,67 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.That(hitObject.Samples.Select(s => s.Volume), Has.All.EqualTo(70));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNewComboAfterBreak()
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("break-between-objects.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
var beatmap = decoder.Decode(stream);
|
||||
Assert.That(((IHasCombo)beatmap.HitObjects[0]).NewCombo, Is.True);
|
||||
Assert.That(((IHasCombo)beatmap.HitObjects[1]).NewCombo, Is.True);
|
||||
Assert.That(((IHasCombo)beatmap.HitObjects[2]).NewCombo, Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test cases that involve a spinner between two hitobjects.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSpinnerNewComboBetweenObjects([Values("osu", "catch")] string rulesetName)
|
||||
{
|
||||
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||
|
||||
using (var resStream = TestResources.OpenResource("spinner-between-objects.osu"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
{
|
||||
Ruleset ruleset;
|
||||
|
||||
switch (rulesetName)
|
||||
{
|
||||
case "osu":
|
||||
ruleset = new OsuRuleset();
|
||||
break;
|
||||
|
||||
case "catch":
|
||||
ruleset = new CatchRuleset();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(rulesetName), rulesetName, null);
|
||||
}
|
||||
|
||||
var working = new TestWorkingBeatmap(decoder.Decode(stream));
|
||||
var playable = working.GetPlayableBeatmap(ruleset.RulesetInfo, Array.Empty<Mod>());
|
||||
|
||||
// There's no good way to figure out these values other than to compare (in code) with osu!stable...
|
||||
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[0]).ComboIndexWithOffsets, Is.EqualTo(1));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[2]).ComboIndexWithOffsets, Is.EqualTo(2));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[3]).ComboIndexWithOffsets, Is.EqualTo(2));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[5]).ComboIndexWithOffsets, Is.EqualTo(3));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[6]).ComboIndexWithOffsets, Is.EqualTo(3));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[8]).ComboIndexWithOffsets, Is.EqualTo(4));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[9]).ComboIndexWithOffsets, Is.EqualTo(4));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[11]).ComboIndexWithOffsets, Is.EqualTo(5));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[12]).ComboIndexWithOffsets, Is.EqualTo(6));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[14]).ComboIndexWithOffsets, Is.EqualTo(7));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[15]).ComboIndexWithOffsets, Is.EqualTo(8));
|
||||
Assert.That(((IHasComboInformation)playable.HitObjects[17]).ComboIndexWithOffsets, Is.EqualTo(9));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,9 +94,6 @@ namespace osu.Game.Tests.Gameplay
|
||||
|
||||
private class TestHitObjectWithCombo : ConvertHitObject, IHasComboInformation
|
||||
{
|
||||
public bool NewCombo { get; set; }
|
||||
public int ComboOffset => 0;
|
||||
|
||||
public Bindable<int> IndexInCurrentComboBindable { get; } = new Bindable<int>();
|
||||
|
||||
public int IndexInCurrentCombo
|
||||
|
15
osu.Game.Tests/Resources/break-between-objects.osu
Normal file
15
osu.Game.Tests/Resources/break-between-objects.osu
Normal file
@ -0,0 +1,15 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
Mode: 0
|
||||
|
||||
[Events]
|
||||
2,200,1200
|
||||
|
||||
[TimingPoints]
|
||||
0,307.692307692308,4,2,1,60,1,0
|
||||
|
||||
[HitObjects]
|
||||
142,99,0,1,0,0:0:0:0:
|
||||
323,88,3000,1,0,0:0:0:0:
|
||||
323,88,4000,1,0,0:0:0:0:
|
@ -3,30 +3,30 @@ osu file format v14
|
||||
[HitObjects]
|
||||
// Circle with combo offset (3)
|
||||
255,193,1000,49,0,0:0:0:0:
|
||||
// Combo index = 4
|
||||
// Combo index = 1
|
||||
|
||||
// Spinner with new combo followed by circle with no new combo
|
||||
256,192,2000,12,0,2000,0:0:0:0:
|
||||
255,193,3000,1,0,0:0:0:0:
|
||||
// Combo index = 5
|
||||
// Combo index = 2
|
||||
|
||||
// Spinner without new combo followed by circle with no new combo
|
||||
256,192,4000,8,0,5000,0:0:0:0:
|
||||
255,193,6000,1,0,0:0:0:0:
|
||||
// Combo index = 5
|
||||
// Combo index = 3
|
||||
|
||||
// Spinner without new combo followed by circle with new combo
|
||||
256,192,7000,8,0,8000,0:0:0:0:
|
||||
255,193,9000,5,0,0:0:0:0:
|
||||
// Combo index = 6
|
||||
// Combo index = 4
|
||||
|
||||
// Spinner with new combo and offset (1) followed by circle with new combo and offset (3)
|
||||
256,192,10000,28,0,11000,0:0:0:0:
|
||||
255,193,12000,53,0,0:0:0:0:
|
||||
// Combo index = 11
|
||||
// Combo index = 8
|
||||
|
||||
// Spinner with new combo and offset (2) followed by slider with no new combo followed by circle with no new combo
|
||||
256,192,13000,44,0,14000,0:0:0:0:
|
||||
256,192,15000,8,0,16000,0:0:0:0:
|
||||
255,193,17000,1,0,0:0:0:0:
|
||||
// Combo index = 14
|
||||
// Combo index = 9
|
38
osu.Game.Tests/Resources/spinner-between-objects.osu
Normal file
38
osu.Game.Tests/Resources/spinner-between-objects.osu
Normal file
@ -0,0 +1,38 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
Mode: 0
|
||||
|
||||
[TimingPoints]
|
||||
0,571.428571428571,4,2,1,5,1,0
|
||||
|
||||
[HitObjects]
|
||||
// +C -> +C -> +C
|
||||
104,95,0,5,0,0:0:0:0:
|
||||
256,192,1000,12,0,2000,0:0:0:0:
|
||||
178,171,3000,5,0,0:0:0:0:
|
||||
|
||||
// -C -> +C -> +C
|
||||
178,171,4000,1,0,0:0:0:0:
|
||||
256,192,5000,12,0,6000,0:0:0:0:
|
||||
178,171,7000,5,0,0:0:0:0:
|
||||
|
||||
// -C -> -C -> +C
|
||||
178,171,8000,1,0,0:0:0:0:
|
||||
256,192,9000,8,0,10000,0:0:0:0:
|
||||
178,171,11000,5,0,0:0:0:0:
|
||||
|
||||
// -C -> -C -> -C
|
||||
178,171,12000,1,0,0:0:0:0:
|
||||
256,192,13000,8,0,14000,0:0:0:0:
|
||||
178,171,15000,1,0,0:0:0:0:
|
||||
|
||||
// +C -> -C -> -C
|
||||
178,171,16000,5,0,0:0:0:0:
|
||||
256,192,17000,8,0,18000,0:0:0:0:
|
||||
178,171,19000,1,0,0:0:0:0:
|
||||
|
||||
// +C -> +C -> -C
|
||||
178,171,20000,5,0,0:0:0:0:
|
||||
256,192,21000,12,0,22000,0:0:0:0:
|
||||
178,171,23000,1,0,0:0:0:0:
|
@ -335,6 +335,40 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCopyPaste()
|
||||
{
|
||||
AddStep("paste", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.LControl);
|
||||
InputManager.Key(Key.V);
|
||||
InputManager.ReleaseKey(Key.LControl);
|
||||
});
|
||||
// no assertions. just make sure nothing crashes.
|
||||
|
||||
AddStep("select bar hit error blueprint", () =>
|
||||
{
|
||||
var blueprint = skinEditor.ChildrenOfType<SkinBlueprint>().First(b => b.Item is BarHitErrorMeter);
|
||||
skinEditor.SelectedComponents.Clear();
|
||||
skinEditor.SelectedComponents.Add(blueprint.Item);
|
||||
});
|
||||
AddStep("copy", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.LControl);
|
||||
InputManager.Key(Key.C);
|
||||
InputManager.ReleaseKey(Key.LControl);
|
||||
});
|
||||
AddStep("paste", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.LControl);
|
||||
InputManager.Key(Key.V);
|
||||
InputManager.ReleaseKey(Key.LControl);
|
||||
});
|
||||
AddAssert("three hit error meters present",
|
||||
() => skinEditor.ChildrenOfType<SkinBlueprint>().Count(b => b.Item is BarHitErrorMeter),
|
||||
() => Is.EqualTo(3));
|
||||
}
|
||||
|
||||
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
|
||||
|
||||
private partial class TestSkinEditorChangeHandler : SkinEditorChangeHandler
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -26,7 +24,6 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
difficulty = value;
|
||||
|
||||
if (beatmapInfo != null)
|
||||
beatmapInfo.Difficulty = difficulty.Clone();
|
||||
}
|
||||
}
|
||||
@ -40,7 +37,6 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
beatmapInfo = value;
|
||||
|
||||
if (beatmapInfo?.Difficulty != null)
|
||||
Difficulty = beatmapInfo.Difficulty.Clone();
|
||||
}
|
||||
}
|
||||
@ -119,12 +115,11 @@ namespace osu.Game.Beatmaps
|
||||
IBeatmap IBeatmap.Clone() => Clone();
|
||||
|
||||
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();
|
||||
|
||||
public override string ToString() => BeatmapInfo.ToString();
|
||||
}
|
||||
|
||||
public class Beatmap : Beatmap<HitObject>
|
||||
{
|
||||
public new Beatmap Clone() => (Beatmap)base.Clone();
|
||||
|
||||
public override string ToString() => BeatmapInfo?.ToString() ?? base.ToString();
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,6 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
foreach (var obj in Beatmap.HitObjects.OfType<IHasComboInformation>())
|
||||
{
|
||||
if (lastObj == null)
|
||||
{
|
||||
// first hitobject should always be marked as a new combo for sanity.
|
||||
obj.NewCombo = true;
|
||||
}
|
||||
|
||||
obj.UpdateComboInformation(lastObj);
|
||||
lastObj = obj;
|
||||
}
|
||||
|
@ -93,6 +93,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
// The parsing order of hitobjects matters in mania difficulty calculation
|
||||
this.beatmap.HitObjects = this.beatmap.HitObjects.OrderBy(h => h.StartTime).ToList();
|
||||
|
||||
postProcessBreaks(this.beatmap);
|
||||
|
||||
foreach (var hitObject in this.beatmap.HitObjects)
|
||||
{
|
||||
applyDefaults(hitObject);
|
||||
@ -100,6 +102,27 @@ namespace osu.Game.Beatmaps.Formats
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the beatmap such that a new combo is started the first hitobject following each break.
|
||||
/// </summary>
|
||||
private void postProcessBreaks(Beatmap beatmap)
|
||||
{
|
||||
int currentBreak = 0;
|
||||
bool forceNewCombo = false;
|
||||
|
||||
foreach (var h in beatmap.HitObjects.OfType<ConvertHitObject>())
|
||||
{
|
||||
while (currentBreak < beatmap.Breaks.Count && beatmap.Breaks[currentBreak].EndTime < h.StartTime)
|
||||
{
|
||||
forceNewCombo = true;
|
||||
currentBreak++;
|
||||
}
|
||||
|
||||
h.NewCombo |= forceNewCombo;
|
||||
forceNewCombo = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void applyDefaults(HitObject hitObject)
|
||||
{
|
||||
DifficultyControlPoint difficultyControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.DifficultyPointAt(hitObject.StartTime) ?? DifficultyControlPoint.DEFAULT;
|
||||
|
@ -510,6 +510,9 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
|
||||
protected void Paste()
|
||||
{
|
||||
if (!canPaste.Value)
|
||||
return;
|
||||
|
||||
changeHandler?.BeginChange();
|
||||
|
||||
var drawableInfo = JsonConvert.DeserializeObject<SerialisedDrawableInfo[]>(clipboard.Content.Value);
|
||||
|
@ -210,6 +210,9 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
|
||||
// The skin editor doesn't work well if beatmap skins are being applied to the player screen.
|
||||
// To keep things simple, disable the setting game-wide while using the skin editor.
|
||||
//
|
||||
// This causes a full reload of the skin, which is pretty ugly.
|
||||
// TODO: Investigate if we can avoid this when a beatmap skin is not being applied by the current beatmap.
|
||||
leasedBeatmapSkins = beatmapSkins.BeginLease(true);
|
||||
leasedBeatmapSkins.Value = false;
|
||||
}
|
||||
|
@ -9,16 +9,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertHit : ConvertHitObject, IHasPosition
|
||||
{
|
||||
public float X => Position.X;
|
||||
|
||||
public float Y => Position.Y;
|
||||
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -14,44 +14,31 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// </summary>
|
||||
public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||
{
|
||||
private ConvertHitObject lastObject;
|
||||
|
||||
public ConvertHitObjectParser(double offset, int formatVersion)
|
||||
: base(offset, formatVersion)
|
||||
{
|
||||
}
|
||||
|
||||
private bool forceNewCombo;
|
||||
private int extraComboOffset;
|
||||
|
||||
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
|
||||
{
|
||||
newCombo |= forceNewCombo;
|
||||
comboOffset += extraComboOffset;
|
||||
|
||||
forceNewCombo = false;
|
||||
extraComboOffset = 0;
|
||||
|
||||
return new ConvertHit
|
||||
return lastObject = new ConvertHit
|
||||
{
|
||||
Position = position,
|
||||
NewCombo = newCombo,
|
||||
ComboOffset = comboOffset
|
||||
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||
ComboOffset = newCombo ? comboOffset : 0
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
|
||||
IList<IList<HitSampleInfo>> nodeSamples)
|
||||
{
|
||||
newCombo |= forceNewCombo;
|
||||
comboOffset += extraComboOffset;
|
||||
|
||||
forceNewCombo = false;
|
||||
extraComboOffset = 0;
|
||||
|
||||
return new ConvertSlider
|
||||
return lastObject = new ConvertSlider
|
||||
{
|
||||
Position = position,
|
||||
NewCombo = FirstObject || newCombo,
|
||||
ComboOffset = comboOffset,
|
||||
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||
ComboOffset = newCombo ? comboOffset : 0,
|
||||
Path = new SliderPath(controlPoints, length),
|
||||
NodeSamples = nodeSamples,
|
||||
RepeatCount = repeatCount
|
||||
@ -60,20 +47,17 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
|
||||
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||
{
|
||||
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
|
||||
// Their combo offset is still added to that next hitobject's combo index
|
||||
forceNewCombo |= FormatVersion <= 8 || newCombo;
|
||||
extraComboOffset += comboOffset;
|
||||
|
||||
return new ConvertSpinner
|
||||
return lastObject = new ConvertSpinner
|
||||
{
|
||||
Duration = duration
|
||||
Duration = duration,
|
||||
NewCombo = newCombo
|
||||
// Spinners cannot have combo offset.
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||
{
|
||||
return null;
|
||||
return lastObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,16 +9,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Slider-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition
|
||||
{
|
||||
public float X => Position.X;
|
||||
|
||||
public float Y => Position.Y;
|
||||
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
||||
/// <summary>
|
||||
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasXPosition, IHasCombo
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasXPosition
|
||||
{
|
||||
public double EndTime => StartTime + Duration;
|
||||
|
||||
public double Duration { get; set; }
|
||||
|
||||
public float X => 256; // Required for CatchBeatmapConverter
|
||||
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Legacy
|
||||
@ -9,8 +10,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
/// <summary>
|
||||
/// A hit object only used for conversion, not actual gameplay.
|
||||
/// </summary>
|
||||
internal abstract class ConvertHitObject : HitObject
|
||||
internal abstract class ConvertHitObject : HitObject, IHasCombo
|
||||
{
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
||||
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
@ -9,16 +9,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Hit-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertHit : ConvertHitObject, IHasPosition
|
||||
{
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
public float X => Position.X;
|
||||
|
||||
public float Y => Position.Y;
|
||||
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -14,44 +14,31 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// </summary>
|
||||
public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||
{
|
||||
private ConvertHitObject lastObject;
|
||||
|
||||
public ConvertHitObjectParser(double offset, int formatVersion)
|
||||
: base(offset, formatVersion)
|
||||
{
|
||||
}
|
||||
|
||||
private bool forceNewCombo;
|
||||
private int extraComboOffset;
|
||||
|
||||
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
|
||||
{
|
||||
newCombo |= forceNewCombo;
|
||||
comboOffset += extraComboOffset;
|
||||
|
||||
forceNewCombo = false;
|
||||
extraComboOffset = 0;
|
||||
|
||||
return new ConvertHit
|
||||
return lastObject = new ConvertHit
|
||||
{
|
||||
Position = position,
|
||||
NewCombo = FirstObject || newCombo,
|
||||
ComboOffset = comboOffset
|
||||
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||
ComboOffset = newCombo ? comboOffset : 0
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
|
||||
IList<IList<HitSampleInfo>> nodeSamples)
|
||||
{
|
||||
newCombo |= forceNewCombo;
|
||||
comboOffset += extraComboOffset;
|
||||
|
||||
forceNewCombo = false;
|
||||
extraComboOffset = 0;
|
||||
|
||||
return new ConvertSlider
|
||||
return lastObject = new ConvertSlider
|
||||
{
|
||||
Position = position,
|
||||
NewCombo = FirstObject || newCombo,
|
||||
ComboOffset = comboOffset,
|
||||
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||
ComboOffset = newCombo ? comboOffset : 0,
|
||||
Path = new SliderPath(controlPoints, length),
|
||||
NodeSamples = nodeSamples,
|
||||
RepeatCount = repeatCount
|
||||
@ -60,21 +47,18 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
|
||||
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||
{
|
||||
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
|
||||
// Their combo offset is still added to that next hitobject's combo index
|
||||
forceNewCombo |= FormatVersion <= 8 || newCombo;
|
||||
extraComboOffset += comboOffset;
|
||||
|
||||
return new ConvertSpinner
|
||||
return lastObject = new ConvertSpinner
|
||||
{
|
||||
Position = position,
|
||||
Duration = duration
|
||||
Duration = duration,
|
||||
NewCombo = newCombo
|
||||
// Spinners cannot have combo offset.
|
||||
};
|
||||
}
|
||||
|
||||
protected override HitObject CreateHold(Vector2 position, bool newCombo, int comboOffset, double duration)
|
||||
{
|
||||
return null;
|
||||
return lastObject = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Slider-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasCombo, IHasGenerateTicks
|
||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasGenerateTicks
|
||||
{
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
@ -17,10 +17,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
|
||||
public float Y => Position.Y;
|
||||
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
|
||||
public bool GenerateTicks { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
/// <summary>
|
||||
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
|
||||
/// </summary>
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasPosition, IHasCombo
|
||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasPosition
|
||||
{
|
||||
public double Duration { get; set; }
|
||||
|
||||
@ -20,9 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
||||
public float X => Position.X;
|
||||
|
||||
public float Y => Position.Y;
|
||||
|
||||
public bool NewCombo { get; set; }
|
||||
|
||||
public int ComboOffset { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Localisation.SkinComponents;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users.Drawables;
|
||||
@ -29,6 +31,14 @@ namespace osu.Game.Screens.Play.HUD
|
||||
|
||||
private const float default_size = 80f;
|
||||
|
||||
[Resolved]
|
||||
private GameplayState? gameplayState { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
private IBindable<APIUser>? apiUser;
|
||||
|
||||
public PlayerAvatar()
|
||||
{
|
||||
Size = new Vector2(default_size);
|
||||
@ -41,9 +51,15 @@ namespace osu.Game.Screens.Play.HUD
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameplayState gameplayState)
|
||||
private void load()
|
||||
{
|
||||
if (gameplayState != null)
|
||||
avatar.User = gameplayState.Score.ScoreInfo.User;
|
||||
else
|
||||
{
|
||||
apiUser = api.LocalUser.GetBoundCopy();
|
||||
apiUser.BindValueChanged(u => avatar.User = u.NewValue, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
@ -2,8 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osuTK;
|
||||
@ -12,13 +15,24 @@ namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
public partial class PlayerFlag : CompositeDrawable, ISerialisableDrawable
|
||||
{
|
||||
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => false;
|
||||
|
||||
private readonly UpdateableFlag flag;
|
||||
|
||||
private const float default_size = 40f;
|
||||
|
||||
[Resolved]
|
||||
private GameplayState? gameplayState { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
private IBindable<APIUser>? apiUser;
|
||||
|
||||
public PlayerFlag()
|
||||
{
|
||||
Size = new Vector2(default_size, default_size / 1.4f);
|
||||
|
||||
InternalChild = flag = new UpdateableFlag
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -26,9 +40,15 @@ namespace osu.Game.Screens.Play.HUD
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameplayState gameplayState)
|
||||
private void load()
|
||||
{
|
||||
if (gameplayState != null)
|
||||
flag.CountryCode = gameplayState.Score.ScoreInfo.User.CountryCode;
|
||||
else
|
||||
{
|
||||
apiUser = api.LocalUser.GetBoundCopy();
|
||||
apiUser.BindValueChanged(u => flag.CountryCode = u.NewValue.CountryCode, true);
|
||||
}
|
||||
}
|
||||
|
||||
public bool UsesFixedAnchor { get; set; }
|
||||
|
@ -4,6 +4,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
@ -82,6 +83,7 @@ namespace osu.Game.Screens.Ranking
|
||||
private static readonly Color4 contracted_top_layer_colour = Color4Extensions.FromHex("#353535");
|
||||
private static readonly Color4 contracted_middle_layer_colour = Color4Extensions.FromHex("#353535");
|
||||
|
||||
[CanBeNull]
|
||||
public event Action<PanelState> StateChanged;
|
||||
|
||||
/// <summary>
|
||||
|
@ -3,9 +3,12 @@
|
||||
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Skinning.Components
|
||||
@ -15,6 +18,14 @@ namespace osu.Game.Skinning.Components
|
||||
{
|
||||
private readonly OsuSpriteText text;
|
||||
|
||||
[Resolved]
|
||||
private GameplayState? gameplayState { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
private IBindable<APIUser>? apiUser;
|
||||
|
||||
public PlayerName()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
@ -30,9 +41,15 @@ namespace osu.Game.Skinning.Components
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameplayState gameplayState)
|
||||
private void load()
|
||||
{
|
||||
if (gameplayState != null)
|
||||
text.Text = gameplayState.Score.ScoreInfo.User.Username;
|
||||
else
|
||||
{
|
||||
apiUser = api.LocalUser.GetBoundCopy();
|
||||
apiUser.BindValueChanged(u => text.Text = u.NewValue.Username, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetFont(FontUsage font) => text.Font = font.With(size: 40);
|
||||
|
Loading…
Reference in New Issue
Block a user