mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 16:12:57 +08:00
Merge branch 'master' into fix-badge-container
This commit is contained in:
commit
eb7fe0b9e2
@ -1,4 +1,3 @@
|
||||
# 2017-09-14
|
||||
clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2017
|
||||
|
@ -1,4 +1,8 @@
|
||||
# 2017-09-14
|
||||
branches:
|
||||
only:
|
||||
- release
|
||||
skip_tags: true
|
||||
skip_branch_with_pr: true
|
||||
clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2017
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 16e6a453db9a8f4454238a2911eb5f1444b7ec2a
|
||||
Subproject commit f1751c27ffe2c5febece74129368596b5ad3a4e2
|
@ -7,6 +7,7 @@ using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.IO.Network;
|
||||
using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
|
||||
@ -99,6 +100,7 @@ namespace osu.Desktop.Deploy
|
||||
|
||||
write("Updating AssemblyInfo...");
|
||||
updateCsprojVersion(version);
|
||||
updateAppveyorVersion(version);
|
||||
|
||||
write("Running build process...");
|
||||
foreach (string targetName in TargetNames.Split(','))
|
||||
@ -404,6 +406,25 @@ namespace osu.Desktop.Deploy
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static bool updateAppveyorVersion(string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (PowerShell ps = PowerShell.Create())
|
||||
{
|
||||
ps.AddScript($"Update-AppveyorBuild -Version \"{version}\"");
|
||||
ps.Invoke();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// we don't have appveyor and don't care
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void write(string message, ConsoleColor col = ConsoleColor.Gray)
|
||||
{
|
||||
if (sw.ElapsedMilliseconds > 0)
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.Game.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<TargetFrameworks>net461</TargetFrameworks>
|
||||
@ -14,5 +14,6 @@
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
|
||||
<PackageReference Include="System.Management.Automation.dll" Version="10.0.10586" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -7,7 +7,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
public class OsuEditPlayfield : OsuPlayfield
|
||||
{
|
||||
protected override bool ProxyApproachCircles => false;
|
||||
protected override bool DisplayJudgements => false;
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
Background = new SpinnerBackground
|
||||
{
|
||||
|
@ -21,9 +21,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||
private readonly ConnectionRenderer<OsuHitObject> connectionLayer;
|
||||
|
||||
// Todo: This should not be a thing, but is currently required for the editor
|
||||
// https://github.com/ppy/osu-framework/issues/1283
|
||||
protected virtual bool ProxyApproachCircles => true;
|
||||
protected virtual bool DisplayJudgements => true;
|
||||
|
||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||
@ -59,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
h.OnJudgement += onJudgement;
|
||||
|
||||
var c = h as IDrawableHitObjectWithProxiedApproach;
|
||||
if (c != null && ProxyApproachCircles)
|
||||
if (c != null)
|
||||
approachCircles.Add(c.ProxiedLayer.CreateProxy());
|
||||
|
||||
base.Add(h);
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
return output;
|
||||
}
|
||||
|
||||
protected abstract void ParseStreamInto(StreamReader stream, TOutput beatmap);
|
||||
protected abstract void ParseStreamInto(StreamReader stream, TOutput output);
|
||||
}
|
||||
|
||||
public abstract class Decoder
|
||||
|
@ -13,15 +13,15 @@ namespace osu.Game.Beatmaps.Formats
|
||||
AddDecoder<Beatmap>("{", m => new JsonBeatmapDecoder());
|
||||
}
|
||||
|
||||
protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap)
|
||||
protected override void ParseStreamInto(StreamReader stream, Beatmap output)
|
||||
{
|
||||
stream.BaseStream.Position = 0;
|
||||
stream.DiscardBufferedData();
|
||||
|
||||
stream.ReadToEnd().DeserializeInto(beatmap);
|
||||
stream.ReadToEnd().DeserializeInto(output);
|
||||
|
||||
foreach (var hitObject in beatmap.HitObjects)
|
||||
hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty);
|
||||
foreach (var hitObject in output.HitObjects)
|
||||
hitObject.ApplyDefaults(output.ControlPointInfo, output.BeatmapInfo.BaseDifficulty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
FormatVersion = version;
|
||||
}
|
||||
|
||||
protected override void ParseStreamInto(StreamReader stream, T beatmap)
|
||||
protected override void ParseStreamInto(StreamReader stream, T output)
|
||||
{
|
||||
Section section = Section.None;
|
||||
|
||||
@ -33,14 +33,21 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section))
|
||||
{
|
||||
Logger.Log($"Unknown section \"{line}\" in {beatmap}");
|
||||
Logger.Log($"Unknown section \"{line}\" in {output}");
|
||||
section = Section.None;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ParseLine(beatmap, section, line);
|
||||
try
|
||||
{
|
||||
ParseLine(output, section, line);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $"Failed to process line \"{line}\" into {output}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,9 +71,9 @@ namespace osu.Game.Graphics.Containers
|
||||
switch (linkType)
|
||||
{
|
||||
case LinkAction.OpenBeatmap:
|
||||
// todo: replace this with overlay.ShowBeatmap(id) once an appropriate API call is implemented.
|
||||
if (int.TryParse(linkArgument, out int beatmapId))
|
||||
Process.Start($"https://osu.ppy.sh/b/{beatmapId}");
|
||||
// TODO: proper query params handling
|
||||
if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId))
|
||||
game?.ShowBeatmap(beatmapId);
|
||||
break;
|
||||
case LinkAction.OpenBeatmapSet:
|
||||
if (int.TryParse(linkArgument, out int setId))
|
||||
|
@ -5,13 +5,21 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetBeatmapSetRequest : APIRequest<APIResponseBeatmapSet>
|
||||
{
|
||||
private readonly int beatmapSetId;
|
||||
private readonly int id;
|
||||
private readonly BeatmapSetLookupType type;
|
||||
|
||||
public GetBeatmapSetRequest(int beatmapSetId)
|
||||
public GetBeatmapSetRequest(int id, BeatmapSetLookupType type = BeatmapSetLookupType.SetId)
|
||||
{
|
||||
this.beatmapSetId = beatmapSetId;
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmapsets/{beatmapSetId}";
|
||||
protected override string Target => type == BeatmapSetLookupType.SetId ? $@"beatmapsets/{id}" : $@"beatmapsets/lookup?beatmap_id={id}";
|
||||
}
|
||||
|
||||
public enum BeatmapSetLookupType
|
||||
{
|
||||
SetId,
|
||||
BeatmapId,
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Online.API.Requests
|
||||
public class GetMessagesRequest : APIRequest<List<Message>>
|
||||
{
|
||||
private readonly List<Channel> channels;
|
||||
private long? since;
|
||||
private readonly long? since;
|
||||
|
||||
public GetMessagesRequest(List<Channel> channels, long? sinceId)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserRequest : APIRequest<User>
|
||||
{
|
||||
private long? userId;
|
||||
private readonly long? userId;
|
||||
|
||||
public GetUserRequest(long? userId = null)
|
||||
{
|
||||
|
@ -166,6 +166,12 @@ namespace osu.Game
|
||||
/// <param name="userId">The user to display.</param>
|
||||
public void ShowUser(long userId) => userProfile.ShowUser(userId);
|
||||
|
||||
/// <summary>
|
||||
/// Show a beatmap's set as an overlay, displaying the given beatmap.
|
||||
/// </summary>
|
||||
/// <param name="beatmapId">The beatmap to show.</param>
|
||||
public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId);
|
||||
|
||||
protected void LoadScore(Score s)
|
||||
{
|
||||
scoreLoad?.Cancel();
|
||||
|
@ -17,21 +17,39 @@ using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class BeatmapSetOverlay : WaveOverlayContainer
|
||||
{
|
||||
private const int fade_duration = 300;
|
||||
|
||||
public const float X_PADDING = 40;
|
||||
public const float RIGHT_WIDTH = 275;
|
||||
|
||||
private readonly Header header;
|
||||
private readonly Info info;
|
||||
|
||||
private APIAccess api;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
private readonly ScrollContainer scroll;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
{
|
||||
get => beatmapSet;
|
||||
set
|
||||
{
|
||||
if (value == beatmapSet)
|
||||
return;
|
||||
|
||||
header.BeatmapSet = info.BeatmapSet = beatmapSet = value;
|
||||
}
|
||||
}
|
||||
|
||||
// receive input outside our bounds so we can trigger a close event on ourselves.
|
||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
@ -107,7 +125,8 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
base.PopOut();
|
||||
header.Details.StopPreview();
|
||||
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out);
|
||||
|
||||
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
@ -116,17 +135,31 @@ namespace osu.Game.Overlays
|
||||
return true;
|
||||
}
|
||||
|
||||
public void FetchAndShowBeatmap(int beatmapId)
|
||||
{
|
||||
BeatmapSet = null;
|
||||
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
|
||||
req.Success += res =>
|
||||
{
|
||||
ShowBeatmapSet(res.ToBeatmapSet(rulesets));
|
||||
header.Picker.Beatmap.Value = header.BeatmapSet.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
|
||||
};
|
||||
api.Queue(req);
|
||||
Show();
|
||||
}
|
||||
|
||||
public void FetchAndShowBeatmapSet(int beatmapSetId)
|
||||
{
|
||||
// todo: display the overlay while we are loading here. we need to support setting BeatmapSet to null for this to work.
|
||||
BeatmapSet = null;
|
||||
var req = new GetBeatmapSetRequest(beatmapSetId);
|
||||
req.Success += res => ShowBeatmapSet(res.ToBeatmapSet(rulesets));
|
||||
api.Queue(req);
|
||||
Show();
|
||||
}
|
||||
|
||||
public void ShowBeatmapSet(BeatmapSetInfo set)
|
||||
{
|
||||
header.BeatmapSet = info.BeatmapSet = set;
|
||||
BeatmapSet = set;
|
||||
Show();
|
||||
scroll.ScrollTo(0);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
base.UpdateAfterChildrenLife();
|
||||
|
||||
// We need to calculate this as soon as possible after lifetimes so that hitobjects get the final say in their positions
|
||||
speedChangeVisualiser.ComputePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize);
|
||||
speedChangeVisualiser.UpdatePositions(AliveObjects, direction, Time.Current, TimeRange, DrawSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,24 +10,23 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
public interface ISpeedChangeVisualiser
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the states of <see cref="DrawableHitObject"/>s that are constant, such as lifetime and spatial length.
|
||||
/// Computes the states of <see cref="DrawableHitObject"/>s that remain constant while scrolling, such as lifetime and spatial length.
|
||||
/// This is invoked once whenever <paramref name="timeRange"/> or <paramref name="length"/> changes.
|
||||
/// </summary>
|
||||
/// <param name="hitObjects">The <see cref="DrawableHitObject"/>s whose states should be computed.</param>
|
||||
/// <param name="direction">The scrolling direction.</param>
|
||||
/// <param name="timeRange">The duration required to scroll through one length of the screen before any control point adjustments.</param>
|
||||
/// <param name="timeRange">The duration required to scroll through one length of the screen before any speed adjustments.</param>
|
||||
/// <param name="length">The length of the screen that is scrolled through.</param>
|
||||
void ComputeInitialStates(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double timeRange, Vector2 length);
|
||||
|
||||
/// <summary>
|
||||
/// Computes the states of <see cref="DrawableHitObject"/>s that change depending on <paramref name="currentTime"/>, such as position.
|
||||
/// This is invoked once per frame.
|
||||
/// Updates the positions of <see cref="DrawableHitObject"/>s, depending on the current time. This is invoked once per frame.
|
||||
/// </summary>
|
||||
/// <param name="hitObjects">The <see cref="DrawableHitObject"/>s whose states should be computed.</param>
|
||||
/// <param name="hitObjects">The <see cref="DrawableHitObject"/>s whose positions should be computed.</param>
|
||||
/// <param name="direction">The scrolling direction.</param>
|
||||
/// <param name="currentTime">The current time.</param>
|
||||
/// <param name="timeRange">The duration required to scroll through one length of the screen before any control point adjustments.</param>
|
||||
/// <param name="timeRange">The duration required to scroll through one length of the screen before any speed adjustments.</param>
|
||||
/// <param name="length">The length of the screen that is scrolled through.</param>
|
||||
void ComputePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length);
|
||||
void UpdatePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Lists;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Timing;
|
||||
using OpenTK;
|
||||
|
||||
@ -22,24 +23,45 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
{
|
||||
foreach (var obj in hitObjects)
|
||||
{
|
||||
var controlPoint = controlPointAt(obj.HitObject.StartTime);
|
||||
obj.LifetimeStart = obj.HitObject.StartTime - timeRange / controlPoint.Multiplier;
|
||||
// The total amount of time that the hitobject will remain visible within the timeRange, which decreases as the speed multiplier increases
|
||||
double visibleDuration = timeRange / controlPointAt(obj.HitObject.StartTime).Multiplier;
|
||||
|
||||
obj.LifetimeStart = obj.HitObject.StartTime - visibleDuration;
|
||||
|
||||
if (obj.HitObject is IHasEndTime endTime)
|
||||
{
|
||||
// At the hitobject's end time, the hitobject will be positioned such that its end rests at the origin.
|
||||
// This results in a negative-position value, and the absolute of it indicates the length of the hitobject.
|
||||
var hitObjectLength = -hitObjectPositionAt(obj, endTime.EndTime, timeRange);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
case ScrollingDirection.Down:
|
||||
obj.Height = (float)(hitObjectLength * length.Y);
|
||||
break;
|
||||
case ScrollingDirection.Left:
|
||||
case ScrollingDirection.Right:
|
||||
obj.Width = (float)(hitObjectLength * length.X);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.HasNestedHitObjects)
|
||||
{
|
||||
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
||||
ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||
|
||||
// Nested hitobjects don't need to scroll, but they do need accurate positions
|
||||
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ComputePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
|
||||
public void UpdatePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
|
||||
{
|
||||
foreach (var obj in hitObjects)
|
||||
{
|
||||
var controlPoint = controlPointAt(obj.HitObject.StartTime);
|
||||
|
||||
var position = (obj.HitObject.StartTime - currentTime) * controlPoint.Multiplier / timeRange;
|
||||
var position = hitObjectPositionAt(obj, currentTime, timeRange);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
@ -59,7 +81,28 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the position of a <see cref="DrawableHitObject"/> at a point in time.
|
||||
/// <para>
|
||||
/// At t < startTime, position > 0. <br />
|
||||
/// At t = startTime, position = 0. <br />
|
||||
/// At t > startTime, position < 0.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="DrawableHitObject"/>.</param>
|
||||
/// <param name="time">The time to find the position of <paramref name="obj"/> at.</param>
|
||||
/// <param name="timeRange">The amount of time visualised by the scrolling area.</param>
|
||||
/// <returns>The position of <paramref name="obj"/> in the scrolling area at time = <paramref name="time"/>.</returns>
|
||||
private double hitObjectPositionAt(DrawableHitObject obj, double time, double timeRange)
|
||||
=> (obj.HitObject.StartTime - time) / timeRange * controlPointAt(obj.HitObject.StartTime).Multiplier;
|
||||
|
||||
private readonly MultiplierControlPoint searchPoint = new MultiplierControlPoint();
|
||||
|
||||
/// <summary>
|
||||
/// Finds the <see cref="MultiplierControlPoint"/> which affects the speed of hitobjects at a specific time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time which the <see cref="MultiplierControlPoint"/> should affect.</param>
|
||||
/// <returns>The <see cref="MultiplierControlPoint"/>.</returns>
|
||||
private MultiplierControlPoint controlPointAt(double time)
|
||||
{
|
||||
if (controlPoints.Count == 0)
|
||||
|
@ -25,23 +25,25 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
{
|
||||
foreach (var obj in hitObjects)
|
||||
{
|
||||
// To reduce iterations when updating hitobject positions later on, their initial positions are cached
|
||||
var startPosition = hitObjectPositions[obj] = positionAt(obj.HitObject.StartTime, timeRange);
|
||||
|
||||
// Todo: This is approximate and will be incorrect in the case of extreme speed changes
|
||||
obj.LifetimeStart = obj.HitObject.StartTime - timeRange - 1000;
|
||||
|
||||
if (obj.HitObject is IHasEndTime endTime)
|
||||
{
|
||||
var diff = positionAt(endTime.EndTime, timeRange) - startPosition;
|
||||
var hitObjectLength = positionAt(endTime.EndTime, timeRange) - startPosition;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
case ScrollingDirection.Down:
|
||||
obj.Height = (float)(diff * length.Y);
|
||||
obj.Height = (float)(hitObjectLength * length.Y);
|
||||
break;
|
||||
case ScrollingDirection.Left:
|
||||
case ScrollingDirection.Right:
|
||||
obj.Width = (float)(diff * length.X);
|
||||
obj.Width = (float)(hitObjectLength * length.X);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -49,12 +51,14 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
if (obj.HasNestedHitObjects)
|
||||
{
|
||||
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
|
||||
ComputePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||
|
||||
// Nested hitobjects don't need to scroll, but they do need accurate positions
|
||||
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ComputePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
|
||||
public void UpdatePositions(IEnumerable<DrawableHitObject> hitObjects, ScrollingDirection direction, double currentTime, double timeRange, Vector2 length)
|
||||
{
|
||||
var timelinePosition = positionAt(currentTime, timeRange);
|
||||
|
||||
@ -80,21 +84,38 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the position which corresponds to a point in time.
|
||||
/// This is a non-linear operation that depends on all the control points up to and including the one active at the time value.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to find the position at.</param>
|
||||
/// <param name="timeRange">The amount of time visualised by the scrolling area.</param>
|
||||
/// <returns>A positive value indicating the position at <paramref name="time"/>.</returns>
|
||||
private double positionAt(double time, double timeRange)
|
||||
{
|
||||
double length = 0;
|
||||
|
||||
// We need to consider all timing points until the specified time and not just the currently-active one,
|
||||
// since each timing point individually affects the positions of _all_ hitobjects after its start time
|
||||
for (int i = 0; i < controlPoints.Count; i++)
|
||||
{
|
||||
var current = controlPoints[i];
|
||||
var next = i < controlPoints.Count - 1 ? controlPoints[i + 1] : null;
|
||||
|
||||
// We don't need to consider any control points beyond the current time, since it will not yet
|
||||
// affect any hitobjects
|
||||
if (i > 0 && current.StartTime > time)
|
||||
continue;
|
||||
|
||||
// Duration of the current control point
|
||||
var currentDuration = (next?.StartTime ?? double.PositiveInfinity) - current.StartTime;
|
||||
|
||||
length += Math.Min(currentDuration, time - current.StartTime) * current.Multiplier / timeRange;
|
||||
// We want to consider the minimal amount of time that this control point has affected,
|
||||
// which may be either its duration, or the amount of time that has passed within it
|
||||
var durationInCurrent = Math.Min(currentDuration, time - current.StartTime);
|
||||
|
||||
// Figure out how much of the time range the duration represents, and adjust it by the speed multiplier
|
||||
length += durationInCurrent / timeRange * current.Multiplier;
|
||||
}
|
||||
|
||||
return length;
|
||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
|
||||
var dragLayer = new DragLayer(maskContainer.Select);
|
||||
dragLayer.DragEnd += () => maskSelection.UpdateVisibility();
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
InternalChildren = new[]
|
||||
{
|
||||
dragLayer,
|
||||
maskSelection,
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
@ -43,6 +44,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
|
||||
|
||||
public override void Add(HitObjectMask drawable)
|
||||
{
|
||||
if (drawable == null) throw new ArgumentNullException(nameof(drawable));
|
||||
|
||||
base.Add(drawable);
|
||||
|
||||
drawable.Selected += onMaskSelected;
|
||||
@ -51,8 +54,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers
|
||||
drawable.DragRequested += onDragRequested;
|
||||
}
|
||||
|
||||
public override bool Remove(HitObjectMask drawable)
|
||||
public override bool Remove([NotNull] HitObjectMask drawable)
|
||||
{
|
||||
if (drawable == null) throw new ArgumentNullException(nameof(drawable));
|
||||
|
||||
var result = base.Remove(drawable);
|
||||
|
||||
if (result)
|
||||
|
@ -39,6 +39,7 @@ namespace osu.Game.Screens.Menu
|
||||
private Bindable<bool> menuVoice;
|
||||
private Bindable<bool> menuMusic;
|
||||
private Track track;
|
||||
private WorkingBeatmap beatmap;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game)
|
||||
@ -69,9 +70,8 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
}
|
||||
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
|
||||
|
||||
track = Beatmap.Value.Track;
|
||||
beatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
|
||||
track = beatmap.Track;
|
||||
|
||||
welcome = audio.Sample.Get(@"welcome");
|
||||
seeya = audio.Sample.Get(@"seeya");
|
||||
@ -81,6 +81,8 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
Game.Beatmap.Value = beatmap;
|
||||
|
||||
if (menuVoice)
|
||||
welcome.Play();
|
||||
|
||||
|
@ -223,11 +223,11 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
private class DateTimeDisplay : Container
|
||||
{
|
||||
private DateTime datetime;
|
||||
private readonly DateTime date;
|
||||
|
||||
public DateTimeDisplay(DateTime datetime)
|
||||
public DateTimeDisplay(DateTime date)
|
||||
{
|
||||
this.datetime = datetime;
|
||||
this.date = date;
|
||||
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
@ -251,7 +251,7 @@ namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Text = datetime.ToShortDateString(),
|
||||
Text = date.ToShortDateString(),
|
||||
Padding = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||
Colour = Color4.White,
|
||||
},
|
||||
@ -259,7 +259,7 @@ namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
Origin = Anchor.CentreRight,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Text = datetime.ToShortTimeString(),
|
||||
Text = date.ToShortTimeString(),
|
||||
Padding = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||
Colour = Color4.White,
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
@ -35,6 +36,8 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
private Triangles triangles;
|
||||
private StarCounter starCounter;
|
||||
|
||||
private BeatmapSetOverlay beatmapOverlay;
|
||||
|
||||
public DrawableCarouselBeatmap(CarouselBeatmap panel) : base(panel)
|
||||
{
|
||||
beatmap = panel.Beatmap;
|
||||
@ -42,8 +45,10 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(SongSelect songSelect, BeatmapManager manager)
|
||||
private void load(SongSelect songSelect, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay)
|
||||
{
|
||||
this.beatmapOverlay = beatmapOverlay;
|
||||
|
||||
if (songSelect != null)
|
||||
{
|
||||
startRequested = songSelect.FinaliseSelection;
|
||||
@ -171,6 +176,10 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
new OsuMenuItem("Play", MenuItemType.Highlighted, () => startRequested?.Invoke(beatmap)),
|
||||
new OsuMenuItem("Edit", MenuItemType.Standard, () => editRequested?.Invoke(beatmap)),
|
||||
new OsuMenuItem("Hide", MenuItemType.Destructive, () => hideRequested?.Invoke(beatmap)),
|
||||
new OsuMenuItem("Details", MenuItemType.Standard, () =>
|
||||
{
|
||||
if (beatmap.OnlineBeatmapID.HasValue) beatmapOverlay?.FetchAndShowBeatmap(beatmap.OnlineBeatmapID.Value);
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
}
|
||||
|
||||
protected override void ParseLine(SkinConfiguration output, Section section, string line)
|
||||
protected override void ParseLine(SkinConfiguration skin, Section section, string line)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
@ -22,17 +22,17 @@ namespace osu.Game.Skinning
|
||||
switch (pair.Key)
|
||||
{
|
||||
case @"Name":
|
||||
output.SkinInfo.Name = pair.Value;
|
||||
skin.SkinInfo.Name = pair.Value;
|
||||
break;
|
||||
case @"Author":
|
||||
output.SkinInfo.Creator = pair.Value;
|
||||
skin.SkinInfo.Creator = pair.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
base.ParseLine(output, section, line);
|
||||
base.ParseLine(skin, section, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user