mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:17:26 +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.
|
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:
|
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
|
- [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-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
|
- [`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()
|
public override void PostProcess()
|
||||||
{
|
{
|
||||||
base.PostProcess();
|
base.PostProcess();
|
||||||
|
@ -155,6 +155,33 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
Scale = LegacyRulesetExtensions.CalculateScaleFromCircleSize(difficulty.CircleSize);
|
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;
|
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||||
|
|
||||||
#region Hit object conversion
|
#region Hit object conversion
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osuTK;
|
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()
|
public override void PostProcess()
|
||||||
{
|
{
|
||||||
base.PostProcess();
|
base.PostProcess();
|
||||||
@ -95,15 +113,15 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
{
|
{
|
||||||
int n = i;
|
int n = i;
|
||||||
/* We should check every note which has not yet got a stack.
|
/* We should check every note which has not yet got a stack.
|
||||||
* Consider the case we have two interwound stacks and this will make sense.
|
* Consider the case we have two interwound stacks and this will make sense.
|
||||||
*
|
*
|
||||||
* o <-1 o <-2
|
* o <-1 o <-2
|
||||||
* o <-3 o <-4
|
* o <-3 o <-4
|
||||||
*
|
*
|
||||||
* We first process starting from 4 and handle 2,
|
* We first process starting from 4 and handle 2,
|
||||||
* then we come backwards on the i loop iteration until we reach 3 and handle 1.
|
* then we come backwards on the i loop iteration until we reach 3 and handle 1.
|
||||||
* 2 and 1 will be ignored in the i loop because they already have a stack value.
|
* 2 and 1 will be ignored in the i loop because they already have a stack value.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OsuHitObject objectI = beatmap.HitObjects[i];
|
OsuHitObject objectI = beatmap.HitObjects[i];
|
||||||
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
||||||
@ -111,9 +129,9 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
|
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
|
||||||
|
|
||||||
/* If this object is a hitcircle, then we enter this "special" case.
|
/* If this object is a hitcircle, then we enter this "special" case.
|
||||||
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
||||||
* Any other case is handled by the "is Slider" code below this.
|
* Any other case is handled by the "is Slider" code below this.
|
||||||
*/
|
*/
|
||||||
if (objectI is HitCircle)
|
if (objectI is HitCircle)
|
||||||
{
|
{
|
||||||
while (--n >= 0)
|
while (--n >= 0)
|
||||||
@ -135,10 +153,10 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This is a special case where hticircles are moved DOWN and RIGHT (negative stacking) if they are under the *last* slider in a stacked pattern.
|
/* This is a special case where hticircles are moved DOWN and RIGHT (negative stacking) if they are under the *last* slider in a stacked pattern.
|
||||||
* o==o <- slider is at original location
|
* o==o <- slider is at original location
|
||||||
* o <- hitCircle has stack of -1
|
* o <- hitCircle has stack of -1
|
||||||
* o <- hitCircle has stack of -2
|
* o <- hitCircle has stack of -2
|
||||||
*/
|
*/
|
||||||
if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
|
if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
|
||||||
{
|
{
|
||||||
int offset = objectI.StackHeight - objectN.StackHeight + 1;
|
int offset = objectI.StackHeight - objectN.StackHeight + 1;
|
||||||
@ -169,8 +187,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
else if (objectI is Slider)
|
else if (objectI is Slider)
|
||||||
{
|
{
|
||||||
/* We have hit the first slider in a possible stack.
|
/* We have hit the first slider in a possible stack.
|
||||||
* From this point on, we ALWAYS stack positive regardless.
|
* From this point on, we ALWAYS stack positive regardless.
|
||||||
*/
|
*/
|
||||||
while (--n >= startIndex)
|
while (--n >= startIndex)
|
||||||
{
|
{
|
||||||
OsuHitObject objectN = beatmap.HitObjects[n];
|
OsuHitObject objectN = beatmap.HitObjects[n];
|
||||||
|
@ -159,9 +159,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
if (allowSelection)
|
if (allowSelection)
|
||||||
d.RequestSelection = selectionRequested;
|
d.RequestSelection = selectionRequested;
|
||||||
|
|
||||||
d.DragStarted = dragStarted;
|
d.DragStarted = DragStarted;
|
||||||
d.DragInProgress = dragInProgress;
|
d.DragInProgress = DragInProgress;
|
||||||
d.DragEnded = dragEnded;
|
d.DragEnded = DragEnded;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Connections.Add(new PathControlPointConnectionPiece<T>(hitObject, e.NewStartingIndex + i));
|
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 int draggedControlPointIndex;
|
||||||
private HashSet<PathControlPoint> selectedControlPoints;
|
private HashSet<PathControlPoint> selectedControlPoints;
|
||||||
|
|
||||||
private void dragStarted(PathControlPoint controlPoint)
|
public void DragStarted(PathControlPoint controlPoint)
|
||||||
{
|
{
|
||||||
dragStartPositions = hitObject.Path.ControlPoints.Select(point => point.Position).ToArray();
|
dragStartPositions = hitObject.Path.ControlPoints.Select(point => point.Position).ToArray();
|
||||||
dragPathTypes = hitObject.Path.ControlPoints.Select(point => point.Type).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();
|
changeHandler?.BeginChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dragInProgress(DragEvent e)
|
public void DragInProgress(DragEvent e)
|
||||||
{
|
{
|
||||||
Vector2[] oldControlPoints = hitObject.Path.ControlPoints.Select(cp => cp.Position).ToArray();
|
Vector2[] oldControlPoints = hitObject.Path.ControlPoints.Select(cp => cp.Position).ToArray();
|
||||||
var oldPosition = hitObject.Position;
|
var oldPosition = hitObject.Position;
|
||||||
@ -341,7 +341,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
hitObject.Path.ControlPoints[i].Type = dragPathTypes[i];
|
hitObject.Path.ControlPoints[i].Type = dragPathTypes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dragEnded() => changeHandler?.EndChange();
|
public void DragEnded() => changeHandler?.EndChange();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -39,9 +39,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
protected PathControlPointVisualiser<Slider> ControlPointVisualiser { get; private set; }
|
protected PathControlPointVisualiser<Slider> ControlPointVisualiser { get; private set; }
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
|
||||||
private IPositionSnapProvider positionSnapProvider { get; set; }
|
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IDistanceSnapProvider distanceSnapProvider { get; set; }
|
private IDistanceSnapProvider distanceSnapProvider { get; set; }
|
||||||
|
|
||||||
@ -191,21 +188,30 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private PathControlPoint placementControlPoint;
|
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)
|
protected override void OnDrag(DragEvent e)
|
||||||
{
|
{
|
||||||
|
base.OnDrag(e);
|
||||||
|
|
||||||
if (placementControlPoint != null)
|
if (placementControlPoint != null)
|
||||||
{
|
ControlPointVisualiser?.DragInProgress(e);
|
||||||
var result = positionSnapProvider?.FindSnappedPositionAndTime(ToScreenSpace(e.MousePosition));
|
|
||||||
placementControlPoint.Position = ToLocalSpace(result?.ScreenSpacePosition ?? ToScreenSpace(e.MousePosition)) - HitObject.Position;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnMouseUp(MouseUpEvent e)
|
protected override void OnMouseUp(MouseUpEvent e)
|
||||||
{
|
{
|
||||||
if (placementControlPoint != null)
|
if (placementControlPoint != null)
|
||||||
{
|
{
|
||||||
|
if (IsDragged)
|
||||||
|
ControlPointVisualiser?.DragEnded();
|
||||||
|
|
||||||
placementControlPoint = null;
|
placementControlPoint = null;
|
||||||
changeHandler?.EndChange();
|
changeHandler?.EndChange();
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,33 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
Scale = LegacyRulesetExtensions.CalculateScaleFromCircleSize(difficulty.CircleSize, true);
|
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();
|
protected override HitWindows CreateHitWindows() => new OsuHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Beatmaps.Formats;
|
|||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets.Catch;
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
@ -433,12 +434,12 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
new OsuBeatmapProcessor(converted).PreProcess();
|
new OsuBeatmapProcessor(converted).PreProcess();
|
||||||
new OsuBeatmapProcessor(converted).PostProcess();
|
new OsuBeatmapProcessor(converted).PostProcess();
|
||||||
|
|
||||||
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
Assert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
Assert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
Assert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(6, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(11, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
Assert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(14, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).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).PreProcess();
|
||||||
new CatchBeatmapProcessor(converted).PostProcess();
|
new CatchBeatmapProcessor(converted).PostProcess();
|
||||||
|
|
||||||
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
Assert.AreEqual(1, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
Assert.AreEqual(2, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
Assert.AreEqual(3, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(6, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(11, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
Assert.AreEqual(8, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndexWithOffsets);
|
||||||
Assert.AreEqual(14, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).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));
|
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
|
private class TestHitObjectWithCombo : ConvertHitObject, IHasComboInformation
|
||||||
{
|
{
|
||||||
public bool NewCombo { get; set; }
|
|
||||||
public int ComboOffset => 0;
|
|
||||||
|
|
||||||
public Bindable<int> IndexInCurrentComboBindable { get; } = new Bindable<int>();
|
public Bindable<int> IndexInCurrentComboBindable { get; } = new Bindable<int>();
|
||||||
|
|
||||||
public int IndexInCurrentCombo
|
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]
|
[HitObjects]
|
||||||
// Circle with combo offset (3)
|
// Circle with combo offset (3)
|
||||||
255,193,1000,49,0,0:0:0:0:
|
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
|
// Spinner with new combo followed by circle with no new combo
|
||||||
256,192,2000,12,0,2000,0:0:0:0:
|
256,192,2000,12,0,2000,0:0:0:0:
|
||||||
255,193,3000,1,0,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
|
// Spinner without new combo followed by circle with no new combo
|
||||||
256,192,4000,8,0,5000,0:0:0:0:
|
256,192,4000,8,0,5000,0:0:0:0:
|
||||||
255,193,6000,1,0,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
|
// Spinner without new combo followed by circle with new combo
|
||||||
256,192,7000,8,0,8000,0:0:0:0:
|
256,192,7000,8,0,8000,0:0:0:0:
|
||||||
255,193,9000,5,0,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)
|
// 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:
|
256,192,10000,28,0,11000,0:0:0:0:
|
||||||
255,193,12000,53,0,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
|
// 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,13000,44,0,14000,0:0:0:0:
|
||||||
256,192,15000,8,0,16000,0:0:0:0:
|
256,192,15000,8,0,16000,0:0:0:0:
|
||||||
255,193,17000,1,0,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);
|
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();
|
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
private partial class TestSkinEditorChangeHandler : SkinEditorChangeHandler
|
private partial class TestSkinEditorChangeHandler : SkinEditorChangeHandler
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -26,8 +24,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
difficulty = value;
|
difficulty = value;
|
||||||
|
|
||||||
if (beatmapInfo != null)
|
beatmapInfo.Difficulty = difficulty.Clone();
|
||||||
beatmapInfo.Difficulty = difficulty.Clone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +37,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
beatmapInfo = value;
|
beatmapInfo = value;
|
||||||
|
|
||||||
if (beatmapInfo?.Difficulty != null)
|
Difficulty = beatmapInfo.Difficulty.Clone();
|
||||||
Difficulty = beatmapInfo.Difficulty.Clone();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,12 +115,11 @@ namespace osu.Game.Beatmaps
|
|||||||
IBeatmap IBeatmap.Clone() => Clone();
|
IBeatmap IBeatmap.Clone() => Clone();
|
||||||
|
|
||||||
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();
|
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();
|
||||||
|
|
||||||
|
public override string ToString() => BeatmapInfo.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Beatmap : Beatmap<HitObject>
|
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>())
|
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);
|
obj.UpdateComboInformation(lastObj);
|
||||||
lastObj = obj;
|
lastObj = obj;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,8 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
// The parsing order of hitobjects matters in mania difficulty calculation
|
// The parsing order of hitobjects matters in mania difficulty calculation
|
||||||
this.beatmap.HitObjects = this.beatmap.HitObjects.OrderBy(h => h.StartTime).ToList();
|
this.beatmap.HitObjects = this.beatmap.HitObjects.OrderBy(h => h.StartTime).ToList();
|
||||||
|
|
||||||
|
postProcessBreaks(this.beatmap);
|
||||||
|
|
||||||
foreach (var hitObject in this.beatmap.HitObjects)
|
foreach (var hitObject in this.beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
applyDefaults(hitObject);
|
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)
|
private void applyDefaults(HitObject hitObject)
|
||||||
{
|
{
|
||||||
DifficultyControlPoint difficultyControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.DifficultyPointAt(hitObject.StartTime) ?? DifficultyControlPoint.DEFAULT;
|
DifficultyControlPoint difficultyControlPoint = (beatmap.ControlPointInfo as LegacyControlPointInfo)?.DifficultyPointAt(hitObject.StartTime) ?? DifficultyControlPoint.DEFAULT;
|
||||||
|
@ -510,6 +510,9 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
|
|
||||||
protected void Paste()
|
protected void Paste()
|
||||||
{
|
{
|
||||||
|
if (!canPaste.Value)
|
||||||
|
return;
|
||||||
|
|
||||||
changeHandler?.BeginChange();
|
changeHandler?.BeginChange();
|
||||||
|
|
||||||
var drawableInfo = JsonConvert.DeserializeObject<SerialisedDrawableInfo[]>(clipboard.Content.Value);
|
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.
|
// 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.
|
// 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 = beatmapSkins.BeginLease(true);
|
||||||
leasedBeatmapSkins.Value = false;
|
leasedBeatmapSkins.Value = false;
|
||||||
}
|
}
|
||||||
|
@ -9,16 +9,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy osu!catch Hit-type, used for parsing Beatmaps.
|
/// Legacy osu!catch Hit-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo
|
internal sealed class ConvertHit : ConvertHitObject, IHasPosition
|
||||||
{
|
{
|
||||||
public float X => Position.X;
|
public float X => Position.X;
|
||||||
|
|
||||||
public float Y => Position.Y;
|
public float Y => Position.Y;
|
||||||
|
|
||||||
public Vector2 Position { get; set; }
|
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>
|
/// </summary>
|
||||||
public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||||
{
|
{
|
||||||
|
private ConvertHitObject lastObject;
|
||||||
|
|
||||||
public ConvertHitObjectParser(double offset, int formatVersion)
|
public ConvertHitObjectParser(double offset, int formatVersion)
|
||||||
: base(offset, formatVersion)
|
: base(offset, formatVersion)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool forceNewCombo;
|
|
||||||
private int extraComboOffset;
|
|
||||||
|
|
||||||
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
|
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
return lastObject = new ConvertHit
|
||||||
comboOffset += extraComboOffset;
|
|
||||||
|
|
||||||
forceNewCombo = false;
|
|
||||||
extraComboOffset = 0;
|
|
||||||
|
|
||||||
return new ConvertHit
|
|
||||||
{
|
{
|
||||||
Position = position,
|
Position = position,
|
||||||
NewCombo = newCombo,
|
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||||
ComboOffset = comboOffset
|
ComboOffset = newCombo ? comboOffset : 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
|
||||||
IList<IList<HitSampleInfo>> nodeSamples)
|
IList<IList<HitSampleInfo>> nodeSamples)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
return lastObject = new ConvertSlider
|
||||||
comboOffset += extraComboOffset;
|
|
||||||
|
|
||||||
forceNewCombo = false;
|
|
||||||
extraComboOffset = 0;
|
|
||||||
|
|
||||||
return new ConvertSlider
|
|
||||||
{
|
{
|
||||||
Position = position,
|
Position = position,
|
||||||
NewCombo = FirstObject || newCombo,
|
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||||
ComboOffset = comboOffset,
|
ComboOffset = newCombo ? comboOffset : 0,
|
||||||
Path = new SliderPath(controlPoints, length),
|
Path = new SliderPath(controlPoints, length),
|
||||||
NodeSamples = nodeSamples,
|
NodeSamples = nodeSamples,
|
||||||
RepeatCount = repeatCount
|
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)
|
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
|
return lastObject = new ConvertSpinner
|
||||||
// Their combo offset is still added to that next hitobject's combo index
|
|
||||||
forceNewCombo |= FormatVersion <= 8 || newCombo;
|
|
||||||
extraComboOffset += comboOffset;
|
|
||||||
|
|
||||||
return 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)
|
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>
|
/// <summary>
|
||||||
/// Legacy osu!catch Slider-type, used for parsing Beatmaps.
|
/// Legacy osu!catch Slider-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasCombo
|
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition
|
||||||
{
|
{
|
||||||
public float X => Position.X;
|
public float X => Position.X;
|
||||||
|
|
||||||
public float Y => Position.Y;
|
public float Y => Position.Y;
|
||||||
|
|
||||||
public Vector2 Position { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
|
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasXPosition, IHasCombo
|
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasXPosition
|
||||||
{
|
{
|
||||||
public double EndTime => StartTime + Duration;
|
public double EndTime => StartTime + Duration;
|
||||||
|
|
||||||
public double Duration { get; set; }
|
public double Duration { get; set; }
|
||||||
|
|
||||||
public float X => 256; // Required for CatchBeatmapConverter
|
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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy
|
namespace osu.Game.Rulesets.Objects.Legacy
|
||||||
@ -9,8 +10,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A hit object only used for conversion, not actual gameplay.
|
/// A hit object only used for conversion, not actual gameplay.
|
||||||
/// </summary>
|
/// </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();
|
public override Judgement CreateJudgement() => new IgnoreJudgement();
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||||
|
@ -9,16 +9,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy osu! Hit-type, used for parsing Beatmaps.
|
/// Legacy osu! Hit-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo
|
internal sealed class ConvertHit : ConvertHitObject, IHasPosition
|
||||||
{
|
{
|
||||||
public Vector2 Position { get; set; }
|
public Vector2 Position { get; set; }
|
||||||
|
|
||||||
public float X => Position.X;
|
public float X => Position.X;
|
||||||
|
|
||||||
public float Y => Position.Y;
|
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>
|
/// </summary>
|
||||||
public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
public class ConvertHitObjectParser : Legacy.ConvertHitObjectParser
|
||||||
{
|
{
|
||||||
|
private ConvertHitObject lastObject;
|
||||||
|
|
||||||
public ConvertHitObjectParser(double offset, int formatVersion)
|
public ConvertHitObjectParser(double offset, int formatVersion)
|
||||||
: base(offset, formatVersion)
|
: base(offset, formatVersion)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool forceNewCombo;
|
|
||||||
private int extraComboOffset;
|
|
||||||
|
|
||||||
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
|
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
return lastObject = new ConvertHit
|
||||||
comboOffset += extraComboOffset;
|
|
||||||
|
|
||||||
forceNewCombo = false;
|
|
||||||
extraComboOffset = 0;
|
|
||||||
|
|
||||||
return new ConvertHit
|
|
||||||
{
|
{
|
||||||
Position = position,
|
Position = position,
|
||||||
NewCombo = FirstObject || newCombo,
|
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||||
ComboOffset = comboOffset
|
ComboOffset = newCombo ? comboOffset : 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
|
||||||
IList<IList<HitSampleInfo>> nodeSamples)
|
IList<IList<HitSampleInfo>> nodeSamples)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
return lastObject = new ConvertSlider
|
||||||
comboOffset += extraComboOffset;
|
|
||||||
|
|
||||||
forceNewCombo = false;
|
|
||||||
extraComboOffset = 0;
|
|
||||||
|
|
||||||
return new ConvertSlider
|
|
||||||
{
|
{
|
||||||
Position = position,
|
Position = position,
|
||||||
NewCombo = FirstObject || newCombo,
|
NewCombo = FirstObject || lastObject is ConvertSpinner || newCombo,
|
||||||
ComboOffset = comboOffset,
|
ComboOffset = newCombo ? comboOffset : 0,
|
||||||
Path = new SliderPath(controlPoints, length),
|
Path = new SliderPath(controlPoints, length),
|
||||||
NodeSamples = nodeSamples,
|
NodeSamples = nodeSamples,
|
||||||
RepeatCount = repeatCount
|
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)
|
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
|
return lastObject = new ConvertSpinner
|
||||||
// Their combo offset is still added to that next hitobject's combo index
|
|
||||||
forceNewCombo |= FormatVersion <= 8 || newCombo;
|
|
||||||
extraComboOffset += comboOffset;
|
|
||||||
|
|
||||||
return new ConvertSpinner
|
|
||||||
{
|
{
|
||||||
Position = position,
|
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)
|
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>
|
/// <summary>
|
||||||
/// Legacy osu! Slider-type, used for parsing Beatmaps.
|
/// Legacy osu! Slider-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasCombo, IHasGenerateTicks
|
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasGenerateTicks
|
||||||
{
|
{
|
||||||
public Vector2 Position { get; set; }
|
public Vector2 Position { get; set; }
|
||||||
|
|
||||||
@ -17,10 +17,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
|
|
||||||
public float Y => Position.Y;
|
public float Y => Position.Y;
|
||||||
|
|
||||||
public bool NewCombo { get; set; }
|
|
||||||
|
|
||||||
public int ComboOffset { get; set; }
|
|
||||||
|
|
||||||
public bool GenerateTicks { get; set; } = true;
|
public bool GenerateTicks { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
|
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasPosition, IHasCombo
|
internal sealed class ConvertSpinner : ConvertHitObject, IHasDuration, IHasPosition
|
||||||
{
|
{
|
||||||
public double Duration { get; set; }
|
public double Duration { get; set; }
|
||||||
|
|
||||||
@ -20,9 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
public float X => Position.X;
|
public float X => Position.X;
|
||||||
|
|
||||||
public float Y => Position.Y;
|
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.Framework.Graphics.Containers;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Localisation.SkinComponents;
|
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.Overlays.Settings;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Users.Drawables;
|
using osu.Game.Users.Drawables;
|
||||||
@ -29,6 +31,14 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
private const float default_size = 80f;
|
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()
|
public PlayerAvatar()
|
||||||
{
|
{
|
||||||
Size = new Vector2(default_size);
|
Size = new Vector2(default_size);
|
||||||
@ -41,9 +51,15 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameplayState gameplayState)
|
private void load()
|
||||||
{
|
{
|
||||||
avatar.User = gameplayState.Score.ScoreInfo.User;
|
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()
|
protected override void LoadComplete()
|
||||||
|
@ -2,8 +2,11 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Users.Drawables;
|
using osu.Game.Users.Drawables;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -12,13 +15,24 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
public partial class PlayerFlag : CompositeDrawable, ISerialisableDrawable
|
public partial class PlayerFlag : CompositeDrawable, ISerialisableDrawable
|
||||||
{
|
{
|
||||||
|
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => false;
|
||||||
|
|
||||||
private readonly UpdateableFlag flag;
|
private readonly UpdateableFlag flag;
|
||||||
|
|
||||||
private const float default_size = 40f;
|
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()
|
public PlayerFlag()
|
||||||
{
|
{
|
||||||
Size = new Vector2(default_size, default_size / 1.4f);
|
Size = new Vector2(default_size, default_size / 1.4f);
|
||||||
|
|
||||||
InternalChild = flag = new UpdateableFlag
|
InternalChild = flag = new UpdateableFlag
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -26,9 +40,15 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameplayState gameplayState)
|
private void load()
|
||||||
{
|
{
|
||||||
flag.CountryCode = gameplayState.Score.ScoreInfo.User.CountryCode;
|
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; }
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
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_top_layer_colour = Color4Extensions.FromHex("#353535");
|
||||||
private static readonly Color4 contracted_middle_layer_colour = Color4Extensions.FromHex("#353535");
|
private static readonly Color4 contracted_middle_layer_colour = Color4Extensions.FromHex("#353535");
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
public event Action<PanelState> StateChanged;
|
public event Action<PanelState> StateChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Skinning.Components
|
namespace osu.Game.Skinning.Components
|
||||||
@ -15,6 +18,14 @@ namespace osu.Game.Skinning.Components
|
|||||||
{
|
{
|
||||||
private readonly OsuSpriteText text;
|
private readonly OsuSpriteText text;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameplayState? gameplayState { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
|
private IBindable<APIUser>? apiUser;
|
||||||
|
|
||||||
public PlayerName()
|
public PlayerName()
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
@ -30,9 +41,15 @@ namespace osu.Game.Skinning.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameplayState gameplayState)
|
private void load()
|
||||||
{
|
{
|
||||||
text.Text = gameplayState.Score.ScoreInfo.User.Username;
|
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);
|
protected override void SetFont(FontUsage font) => text.Font = font.With(size: 40);
|
||||||
|
Loading…
Reference in New Issue
Block a user