1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 00:47:24 +08:00

Merge branch 'master' into judgement-revamp

This commit is contained in:
Dan Balasescu 2017-09-12 18:57:37 +09:00 committed by GitHub
commit ee8ec31c6e
9 changed files with 214 additions and 16 deletions

View File

@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Mania
{ {
Mods = new Mod[] Mods = new Mod[]
{ {
new ModAutoplay(), new ManiaModAutoplay(),
new ModCinema(), new ModCinema(),
}, },
}, },

View File

@ -4,6 +4,13 @@
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using System; using System;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Mods namespace osu.Game.Rulesets.Mania.Mods
{ {
@ -154,4 +161,24 @@ namespace osu.Game.Rulesets.Mania.Mods
public override double ScoreMultiplier => 1; public override double ScoreMultiplier => 1;
public override bool Ranked => true; public override bool Ranked => true;
} }
public class ManiaModAutoplay : ModAutoplay<ManiaHitObject>
{
private int availableColumns;
public override void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{
// Todo: This shouldn't be done, we should be getting a ManiaBeatmap which should store AvailableColumns
// But this is dependent on a _lot_ of refactoring
var maniaRulesetContainer = (ManiaRulesetContainer)rulesetContainer;
availableColumns = maniaRulesetContainer.AvailableColumns;
base.ApplyToRulesetContainer(rulesetContainer);
}
protected override Score CreateReplayScore(Beatmap<ManiaHitObject> beatmap) => new Score
{
User = new User { Username = "osu!topus!" },
Replay = new ManiaAutoGenerator(beatmap, availableColumns).Generate(),
};
}
} }

View File

@ -0,0 +1,133 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Users;
namespace osu.Game.Rulesets.Mania.Replays
{
internal class ManiaAutoGenerator : AutoGenerator<ManiaHitObject>
{
private const double release_delay = 20;
private readonly int availableColumns;
public ManiaAutoGenerator(Beatmap<ManiaHitObject> beatmap, int availableColumns)
: base(beatmap)
{
this.availableColumns = availableColumns;
Replay = new Replay { User = new User { Username = @"Autoplay" } };
}
protected Replay Replay;
public override Replay Generate()
{
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
Replay.Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None));
double[] holdEndTimes = new double[availableColumns];
for (int i = 0; i < availableColumns; i++)
holdEndTimes[i] = double.NegativeInfinity;
// Notes are handled row-by-row
foreach (var objGroup in Beatmap.HitObjects.GroupBy(h => h.StartTime))
{
double groupTime = objGroup.Key;
int activeColumns = 0;
// Get the previously held-down active columns
for (int i = 0; i < availableColumns; i++)
{
if (holdEndTimes[i] > groupTime)
activeColumns |= 1 << i;
}
// Add on the group columns, keeping track of the held notes for the next rows
foreach (var obj in objGroup)
{
var holdNote = obj as HoldNote;
if (holdNote != null)
holdEndTimes[obj.Column] = Math.Max(holdEndTimes[obj.Column], holdNote.EndTime);
activeColumns |= 1 << obj.Column;
}
Replay.Frames.Add(new ReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None));
// Add the release frames. We can't do this with the loop above because we need activeColumns to be fully populated
foreach (var obj in objGroup.GroupBy(h => (h as IHasEndTime)?.EndTime ?? h.StartTime + release_delay).OrderBy(h => h.Key))
{
var groupEndTime = obj.Key;
int activeColumnsAtEnd = 0;
for (int i = 0; i < availableColumns; i++)
{
if (holdEndTimes[i] > groupEndTime)
activeColumnsAtEnd |= 1 << i;
}
Replay.Frames.Add(new ReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None));
}
}
Replay.Frames = Replay.Frames
// Pick the maximum activeColumns for all frames at the same time
.GroupBy(f => f.Time)
.Select(g => new ReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None))
// The addition of release frames above maybe result in unordered frames, but we need them ordered
.OrderBy(f => f.Time)
.ToList();
return Replay;
}
/// <summary>
/// Finds the maximum <see cref="ReplayFrame.MouseX"/> by count of bits from a grouping of <see cref="ReplayFrame"/>s.
/// </summary>
/// <param name="group">The <see cref="ReplayFrame"/> grouping to search.</param>
/// <returns>The maximum <see cref="ReplayFrame.MouseX"/> by count of bits.</returns>
private float maxMouseX(IGrouping<double, ReplayFrame> group)
{
int currentCount = -1;
int currentMax = 0;
foreach (var val in group)
{
int newCount = countBits((int)(val.MouseX ?? 0));
if (newCount > currentCount)
{
currentCount = newCount;
currentMax = (int)(val.MouseX ?? 0);
}
}
return currentMax;
}
/// <summary>
/// Counts the number of bits set in a value.
/// </summary>
/// <param name="value">The value to count.</param>
/// <returns>The number of set bits.</returns>
private int countBits(int value)
{
int count = 0;
while (value > 0)
{
if ((value & 1) > 0)
count++;
value >>= 1;
}
return count;
}
}
}

View File

@ -0,0 +1,35 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Input;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Mania.Replays
{
internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler
{
public ManiaFramedReplayInputHandler(Replay replay)
: base(replay)
{
}
public override List<InputState> GetPendingStates()
{
var actions = new List<ManiaAction>();
int activeColumns = (int)(CurrentFrame.MouseX ?? 0);
int counter = 0;
while (activeColumns > 0)
{
if ((activeColumns & 1) > 0)
actions.Add(ManiaAction.Key1 + counter);
counter++;
activeColumns >>= 1;
}
return new List<InputState> { new ReplayState<ManiaAction> { PressedActions = actions } };
}
}
}

View File

@ -270,6 +270,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
base.Reset(); base.Reset();
Health.Value = 1; Health.Value = 1;
Accuracy.Value = 1;
bonusScore = 0; bonusScore = 0;
comboPortion = 0; comboPortion = 0;

View File

@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
base.LoadComplete(); base.LoadComplete();
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500); this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500).Expire();
inner.FadeOut(250); inner.FadeOut(250);
} }
} }

View File

@ -17,10 +17,12 @@ using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Mania.Timing; using osu.Game.Rulesets.Mania.Timing;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -33,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.UI
/// The number of columns which the <see cref="ManiaPlayfield"/> should display, and which /// The number of columns which the <see cref="ManiaPlayfield"/> should display, and which
/// the beatmap converter will attempt to convert beatmaps to use. /// the beatmap converter will attempt to convert beatmaps to use.
/// </summary> /// </summary>
private int availableColumns; public int AvailableColumns { get; private set; }
public IEnumerable<DrawableBarLine> BarLines; public IEnumerable<DrawableBarLine> BarLines;
@ -74,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.UI
BarLines.ForEach(Playfield.Add); BarLines.ForEach(Playfield.Add);
} }
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(availableColumns) protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(AvailableColumns)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -82,26 +84,26 @@ namespace osu.Game.Rulesets.Mania.UI
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this); public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, availableColumns); public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, AvailableColumns);
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter()
{ {
if (IsForCurrentRuleset) if (IsForCurrentRuleset)
availableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize)); AvailableColumns = (int)Math.Max(1, Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize));
else else
{ {
float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count; float percentSliderOrSpinner = (float)WorkingBeatmap.Beatmap.HitObjects.Count(h => h is IHasEndTime) / WorkingBeatmap.Beatmap.HitObjects.Count;
if (percentSliderOrSpinner < 0.2) if (percentSliderOrSpinner < 0.2)
availableColumns = 7; AvailableColumns = 7;
else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5) else if (percentSliderOrSpinner < 0.3 || Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.CircleSize) >= 5)
availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6; AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 5 ? 7 : 6;
else if (percentSliderOrSpinner > 0.6) else if (percentSliderOrSpinner > 0.6)
availableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4; AvailableColumns = Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) > 4 ? 5 : 4;
else else
availableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7)); AvailableColumns = Math.Max(4, Math.Min((int)Math.Round(WorkingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty) + 1, 7));
} }
return new ManiaBeatmapConverter(IsForCurrentRuleset, availableColumns); return new ManiaBeatmapConverter(IsForCurrentRuleset, AvailableColumns);
} }
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h) protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
@ -122,5 +124,7 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f); protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f);
protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic); protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic);
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
} }
} }

View File

@ -73,6 +73,8 @@
<Compile Include="Objects\Drawables\Pieces\LaneGlowPiece.cs" /> <Compile Include="Objects\Drawables\Pieces\LaneGlowPiece.cs" />
<Compile Include="Objects\Drawables\Pieces\NotePiece.cs" /> <Compile Include="Objects\Drawables\Pieces\NotePiece.cs" />
<Compile Include="Objects\Types\IHasColumn.cs" /> <Compile Include="Objects\Types\IHasColumn.cs" />
<Compile Include="Replays\ManiaAutoGenerator.cs" />
<Compile Include="Replays\ManiaFramedReplayInputHandler.cs" />
<Compile Include="Scoring\ManiaScoreProcessor.cs" /> <Compile Include="Scoring\ManiaScoreProcessor.cs" />
<Compile Include="Objects\BarLine.cs" /> <Compile Include="Objects\BarLine.cs" />
<Compile Include="Objects\HoldNote.cs" /> <Compile Include="Objects\HoldNote.cs" />
@ -99,10 +101,6 @@
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project> <Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
<Name>osu.Framework</Name> <Name>osu.Framework</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj"> <ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project> <Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
<Name>osu.Game</Name> <Name>osu.Game</Name>

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mods
{ {
protected abstract Score CreateReplayScore(Beatmap<T> beatmap); protected abstract Score CreateReplayScore(Beatmap<T> beatmap);
public void ApplyToRulesetContainer(RulesetContainer<T> rulesetContainer) public virtual void ApplyToRulesetContainer(RulesetContainer<T> rulesetContainer)
{ {
rulesetContainer.SetReplay(CreateReplayScore(rulesetContainer.Beatmap)?.Replay); rulesetContainer.SetReplay(CreateReplayScore(rulesetContainer.Beatmap)?.Replay);
} }