1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-15 03:54:00 +08:00

Compare commits

...

1001 Commits

521 changed files with 13872 additions and 6518 deletions
+35 -10
View File
@@ -2,35 +2,60 @@
"version": "0.2.0",
"configurations": [
{
"name": "Launch VisualTests",
"name": "VisualTests (debug)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop.VisualTests/bin/Debug/osu!.exe",
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": "build",
"preLaunchTask": "Build (Debug)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "Launch Desktop",
"name": "VisualTests (release)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop.VisualTests/bin/Release/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "osu! (debug)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe",
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": "build",
"preLaunchTask": "Build (Debug)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "Attach",
"name": "osu! (release)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "attach",
"address": "localhost",
"port": 55555
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
}
]
}
+41 -15
View File
@@ -1,24 +1,50 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"taskSelector": "/t:",
"version": "2.0.0",
"problemMatcher": "$msCompile",
"isShellCommand": true,
"command": "msbuild",
"suppressTaskName": true,
"showOutput": "silent",
"args": [
"/property:GenerateFullPaths=true",
"/property:DebugType=portable"
],
"windows": {
"args": [
"/property:GenerateFullPaths=true",
"/property:DebugType=portable",
"/m" //parallel compiling support. doesn't work well with mono atm
]
},
"tasks": [
{
"taskName": "build",
"isShellCommand": true,
"showOutput": "silent",
"command": "xbuild",
"windows": {
"command": "msbuild"
},
"args": [
// Ask msbuild to generate full paths for file names.
"/property:GenerateFullPaths=true"
],
// Use the standard MS compiler pattern to detect errors, warnings and infos
"problemMatcher": "$msCompile",
"taskName": "Build (Debug)",
"isBuildCommand": true
},
{
"taskName": "Build (Release)",
"args": [
"/property:Configuration=Release"
]
},
{
"taskName": "Clean All",
"dependsOn": ["Clean (Debug)", "Clean (Release)"]
},
{
"taskName": "Clean (Debug)",
"args": [
"/target:Clean"
]
},
{
"taskName": "Clean (Release)",
"args": [
"/target:Clean",
"/property:Configuration=Release"
]
}
]
}
+5 -9
View File
@@ -1,10 +1,6 @@
# osu! [![Build status](https://ci.appveyor.com/api/projects/status/u2p01nx7l6og8buh?svg=true)](https://ci.appveyor.com/project/peppy/osu)
# osu! [![Build status](https://ci.appveyor.com/api/projects/status/u2p01nx7l6og8buh?svg=true)](https://ci.appveyor.com/project/peppy/osu) [![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu) [![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy)
[osu! on the web](https://osu.ppy.sh) | [dev chat](https://discord.gg/ppy)
Rhythm is just a *click* away. The future of osu! and the beginning of an open era!
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era!
# Status
@@ -12,14 +8,14 @@ This is still heavily under development and is not intended for end-user use. Th
# Requirements
- A desktop platform which can compile .NET 4.5.
- Visual Studio or MonoDevelop is recommended.
- A desktop platform which can compile .NET 4.5 (tested on macOS, linux and windows). We recommend using [Visual Studio Code](https://code.visualstudio.com/) (all platforms) or [Visual Studio Community Edition](https://www.visualstudio.com/) (windows only), both of which are free.
- Make sure you initialise and keep submodules up-to-date.
# Contributing
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted.
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://goo.gl/nFdoyI). If you're unsure of what you can help with, check out the [list](https://github.com/ppy/osu/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Abounty) of available issues with bounty.
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu-framework/issues).
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible.
@@ -22,6 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
-10
View File
@@ -4,11 +4,6 @@
using NUnit.Framework;
using osu.Desktop.VisualTests;
using osu.Framework.Desktop.Platform;
using osu.Game.Modes;
using osu.Game.Modes.Catch;
using osu.Game.Modes.Mania;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Taiko;
namespace osu.Desktop.Tests
{
@@ -20,11 +15,6 @@ namespace osu.Desktop.Tests
{
using (var host = new HeadlessGameHost())
{
Ruleset.Register(new OsuRuleset());
Ruleset.Register(new TaikoRuleset());
Ruleset.Register(new ManiaRuleset());
Ruleset.Register(new CatchRuleset());
host.Run(new AutomatedVisualTestGame());
}
}
+9 -8
View File
@@ -21,6 +21,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -74,21 +75,21 @@
<Project>{69051C69-12AE-4E7D-A3E6-460D2E282312}</Project>
<Name>osu.Desktop.VisualTests</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Catch\osu.Game.Modes.Catch.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project>
<Name>osu.Game.Modes.Catch</Name>
<Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
<Project>{48F4582B-7687-4621-9CBE-5C24197CB536}</Project>
<Name>osu.Game.Modes.Mania</Name>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Modes.Osu</Name>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Taiko\osu.Game.Modes.Taiko.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Modes.Taiko</Name>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
@@ -10,7 +10,7 @@ namespace osu.Desktop.VisualTests.Beatmaps
public class TestWorkingBeatmap : WorkingBeatmap
{
public TestWorkingBeatmap(Beatmap beatmap)
: base(beatmap.BeatmapInfo, beatmap.BeatmapInfo.BeatmapSet)
: base(beatmap.BeatmapInfo)
{
this.beatmap = beatmap;
}
-10
View File
@@ -4,11 +4,6 @@
using System;
using osu.Framework.Desktop;
using osu.Framework.Platform;
using osu.Game.Modes;
using osu.Game.Modes.Catch;
using osu.Game.Modes.Mania;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Taiko;
namespace osu.Desktop.VisualTests
{
@@ -21,11 +16,6 @@ namespace osu.Desktop.VisualTests
using (GameHost host = Host.GetSuitableHost(@"osu"))
{
Ruleset.Register(new OsuRuleset());
Ruleset.Register(new TaikoRuleset());
Ruleset.Register(new ManiaRuleset());
Ruleset.Register(new CatchRuleset());
if (benchmark)
host.Run(new AutomatedVisualTestGame());
else
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Screens.Select;
@@ -5,7 +5,6 @@ using System.Collections.Generic;
using osu.Framework.Testing;
using osu.Game.Screens.Tournament;
using osu.Game.Screens.Tournament.Teams;
using osu.Game.Users;
namespace osu.Desktop.VisualTests.Tests
{
@@ -25,57 +24,57 @@ namespace osu.Desktop.VisualTests.Tests
private class TestTeamList : ITeamList
{
public IEnumerable<Country> Teams { get; } = new[]
public IEnumerable<DrawingsTeam> Teams { get; } = new[]
{
new Country
new DrawingsTeam
{
FlagName = "GB",
FullName = "United Kingdom",
Acronym = "UK"
},
new Country
new DrawingsTeam
{
FlagName = "FR",
FullName = "France",
Acronym = "FRA"
},
new Country
new DrawingsTeam
{
FlagName = "CN",
FullName = "China",
Acronym = "CHN"
},
new Country
new DrawingsTeam
{
FlagName = "AU",
FullName = "Australia",
Acronym = "AUS"
},
new Country
new DrawingsTeam
{
FlagName = "JP",
FullName = "Japan",
Acronym = "JPN"
},
new Country
new DrawingsTeam
{
FlagName = "RO",
FullName = "Romania",
Acronym = "ROM"
},
new Country
new DrawingsTeam
{
FlagName = "IT",
FullName = "Italy",
Acronym = "PIZZA"
},
new Country
new DrawingsTeam
{
FlagName = "VE",
FullName = "Venezuela",
Acronym = "VNZ"
},
new Country
new DrawingsTeam
{
FlagName = "US",
FullName = "United States of America",
@@ -9,21 +9,31 @@ using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Modes.Catch.UI;
using osu.Game.Modes.Mania.UI;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Osu.UI;
using osu.Game.Modes.Taiko.UI;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Taiko.UI;
using System.Collections.Generic;
using osu.Desktop.VisualTests.Beatmaps;
using osu.Framework.Allocation;
using osu.Game.Beatmaps.Timing;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseGamefield : TestCase
{
private RulesetDatabase rulesets;
public override string Description => @"Showing hitobjects and what not.";
[BackgroundDependencyLoader]
private void load(RulesetDatabase rulesets)
{
this.rulesets = rulesets;
}
public override void Reset()
{
base.Reset();
@@ -36,26 +46,34 @@ namespace osu.Desktop.VisualTests.Tests
objects.Add(new HitCircle
{
StartTime = time,
Position = new Vector2(RNG.Next(0, 512), RNG.Next(0, 384)),
Position = new Vector2(RNG.Next(0, (int)OsuPlayfield.BASE_SIZE.X), RNG.Next(0, (int)OsuPlayfield.BASE_SIZE.Y)),
Scale = RNG.NextSingle(0.5f, 1.0f),
});
time += RNG.Next(50, 500);
}
TimingInfo timing = new TimingInfo();
timing.ControlPoints.Add(new ControlPoint
{
BeatLength = 200
});
WorkingBeatmap beatmap = new TestWorkingBeatmap(new Beatmap
{
HitObjects = objects,
BeatmapInfo = new BeatmapInfo
{
Difficulty = new BeatmapDifficulty(),
Ruleset = rulesets.Query<RulesetInfo>().First(),
Metadata = new BeatmapMetadata
{
Artist = @"Unknown",
Title = @"Sample Beatmap",
Author = @"peppy",
}
}
},
},
TimingInfo = timing
});
Add(new Drawable[]
@@ -67,25 +85,25 @@ namespace osu.Desktop.VisualTests.Tests
Clock = new FramedClock(),
Children = new Drawable[]
{
new OsuHitRenderer(beatmap)
new OsuHitRenderer(beatmap, false)
{
Scale = new Vector2(0.5f),
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft
},
new TaikoHitRenderer(beatmap)
new TaikoHitRenderer(beatmap, false)
{
Scale = new Vector2(0.5f),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight
},
new CatchHitRenderer(beatmap)
new CatchHitRenderer(beatmap, false)
{
Scale = new Vector2(0.5f),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft
},
new ManiaHitRenderer(beatmap)
new ManiaHitRenderer(beatmap, false)
{
Scale = new Vector2(0.5f),
Anchor = Anchor.BottomRight,
@@ -10,11 +10,10 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Osu.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using System.Collections.Generic;
namespace osu.Desktop.VisualTests.Tests
@@ -62,15 +61,12 @@ namespace osu.Desktop.VisualTests.Tests
add(new DrawableSlider(new Slider
{
StartTime = framedClock.CurrentTime + 600,
CurveObject = new CurvedHitObject
ControlPoints = new List<Vector2>
{
ControlPoints = new List<Vector2>
{
new Vector2(-200, 0),
new Vector2(400, 0),
},
Distance = 400
new Vector2(-200, 0),
new Vector2(400, 0),
},
Distance = 400,
Position = new Vector2(-200, 0),
Velocity = 1,
TickDistance = 100,
@@ -133,8 +129,6 @@ namespace osu.Desktop.VisualTests.Tests
};
Add(clockAdjustContainer);
load(mode);
}
private int depth;
@@ -4,9 +4,9 @@
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Mods;
using osu.Game.Modes.Scoring;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
@@ -0,0 +1,81 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using OpenTK.Graphics;
using OpenTK;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseManiaHitObjects : TestCase
{
public override void Reset()
{
base.Reset();
Add(new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
// Imagine that the containers containing the drawable notes are the "columns"
Children = new Drawable[]
{
new Container
{
Name = "Normal note column",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 50,
Children = new[]
{
new Container
{
Name = "Timing section",
RelativeSizeAxes = Axes.Both,
RelativeCoordinateSpace = new Vector2(1, 10000),
Children = new[]
{
new DrawableNote(new Note { StartTime = 5000 }) { AccentColour = Color4.Red },
new DrawableNote(new Note { StartTime = 6000 }) { AccentColour = Color4.Red }
}
}
}
},
new Container
{
Name = "Hold note column",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 50,
Children = new[]
{
new Container
{
Name = "Timing section",
RelativeSizeAxes = Axes.Both,
RelativeCoordinateSpace = new Vector2(1, 10000),
Children = new[]
{
new DrawableHoldNote(new HoldNote
{
StartTime = 5000,
Duration = 1000
}) { AccentColour = Color4.Red }
}
}
}
}
}
});
}
}
}
@@ -0,0 +1,98 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input;
using osu.Framework.Testing;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.UI;
using System;
using System.Collections.Generic;
using osu.Game.Beatmaps.Timing;
using OpenTK;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseManiaPlayfield : TestCase
{
public override string Description => @"Mania playfield";
protected override double TimePerAction => 200;
public override void Reset()
{
base.Reset();
Action<int, SpecialColumnPosition> createPlayfield = (cols, pos) =>
{
Clear();
Add(new ManiaPlayfield(cols, new List<ControlPoint>())
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
SpecialColumnPosition = pos,
Scale = new Vector2(1, -1)
});
};
Action<int, SpecialColumnPosition> createPlayfieldWithNotes = (cols, pos) =>
{
Clear();
ManiaPlayfield playField;
Add(playField = new ManiaPlayfield(cols, new List<ControlPoint> { new ControlPoint { BeatLength = 200 } })
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
SpecialColumnPosition = pos,
Scale = new Vector2(1, -1)
});
for (int i = 0; i < cols; i++)
{
playField.Add(new DrawableNote(new Note
{
StartTime = Time.Current + 1000,
Column = i
}));
}
};
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
AddStep("Right special style", () => createPlayfield(4, SpecialColumnPosition.Right));
AddStep("5 columns", () => createPlayfield(5, SpecialColumnPosition.Normal));
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal));
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
AddStep("Normal special style", () => createPlayfield(4, SpecialColumnPosition.Normal));
AddStep("Notes", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Normal));
AddWaitStep(10);
AddStep("Left special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Left));
AddWaitStep(10);
AddStep("Right special style", () => createPlayfieldWithNotes(4, SpecialColumnPosition.Right));
AddWaitStep(10);
}
private void triggerKeyDown(Column column)
{
column.TriggerKeyDown(new InputState(), new KeyDownEventArgs
{
Key = column.Key,
Repeat = false
});
}
private void triggerKeyUp(Column column)
{
column.TriggerKeyUp(new InputState(), new KeyUpEventArgs
{
Key = column.Key
});
}
}
}
@@ -12,7 +12,7 @@ namespace osu.Desktop.VisualTests.Tests
{
public override string Description => @"Tests pause and fail overlays";
private PauseOverlay pauseOverlay;
private PauseContainer.PauseOverlay pauseOverlay;
private FailOverlay failOverlay;
private int retryCount;
@@ -22,7 +22,7 @@ namespace osu.Desktop.VisualTests.Tests
retryCount = 0;
Add(pauseOverlay = new PauseOverlay
Add(pauseOverlay = new PauseContainer.PauseOverlay
{
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
@@ -1,35 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Game.Overlays.Mods;
using osu.Framework.Testing;
using osu.Game.Modes;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseModSelectOverlay : TestCase
{
public override string Description => @"Tests the mod select overlay";
private ModSelectOverlay modSelect;
public override void Reset()
{
base.Reset();
Add(modSelect = new ModSelectOverlay
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
});
AddStep("Toggle", modSelect.ToggleVisibility);
AddStep("osu!", () => modSelect.PlayMode.Value = PlayMode.Osu);
AddStep("osu!taiko", () => modSelect.PlayMode.Value = PlayMode.Taiko);
AddStep("osu!catch", () => modSelect.PlayMode.Value = PlayMode.Catch);
AddStep("osu!mania", () => modSelect.PlayMode.Value = PlayMode.Mania);
}
}
}
@@ -0,0 +1,57 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Overlays.Mods;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Screens.Play.HUD;
using OpenTK;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseMods : TestCase
{
public override string Description => @"Mod select overlay and in-game display";
private ModSelectOverlay modSelect;
private ModDisplay modDisplay;
private RulesetDatabase rulesets;
[BackgroundDependencyLoader]
private void load(RulesetDatabase rulesets)
{
this.rulesets = rulesets;
}
public override void Reset()
{
base.Reset();
Add(modSelect = new ModSelectOverlay
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
});
Add(modDisplay = new ModDisplay
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Position = new Vector2(0, 25),
});
modDisplay.Current.BindTo(modSelect.SelectedMods);
AddStep("Toggle", modSelect.ToggleVisibility);
foreach (var ruleset in rulesets.AllRulesets)
AddStep(ruleset.CreateInstance().Description, () => modSelect.Ruleset.Value = ruleset);
}
}
}
@@ -0,0 +1,47 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Testing;
using osu.Game.Overlays;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseOnScreenDisplay : TestCase
{
private FrameworkConfigManager config;
private Bindable<FrameSync> frameSyncMode;
public override string Description => @"Make it easier to see setting changes";
public override void Reset()
{
base.Reset();
Add(new OnScreenDisplay());
frameSyncMode = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync);
FrameSync initial = frameSyncMode.Value;
AddRepeatStep(@"Change frame limiter", setNextMode, 3);
AddStep(@"Restore frame limiter", () => frameSyncMode.Value = initial);
}
private void setNextMode()
{
var nextMode = frameSyncMode.Value + 1;
if (nextMode > FrameSync.Unlimited)
nextMode = FrameSync.VSync;
frameSyncMode.Value = nextMode;
}
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager config)
{
this.config = config;
}
}
}
@@ -6,7 +6,6 @@ using osu.Desktop.VisualTests.Platform;
using osu.Framework.Testing;
using osu.Framework.MathUtils;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
@@ -20,13 +19,19 @@ namespace osu.Desktop.VisualTests.Tests
public override string Description => @"with fake data";
private RulesetDatabase rulesets;
public override void Reset()
{
base.Reset();
if (db == null)
{
storage = new TestStorage(@"TestCasePlaySongSelect");
db = new BeatmapDatabase(storage);
var backingDatabase = storage.GetDatabase(@"client");
rulesets = new RulesetDatabase(storage, backingDatabase);
db = new BeatmapDatabase(storage, backingDatabase, rulesets);
var sets = new List<BeatmapSetInfo>();
@@ -72,7 +77,7 @@ namespace osu.Desktop.VisualTests.Tests
new BeatmapInfo
{
OnlineBeatmapID = 1234 + i,
Mode = PlayMode.Osu,
Ruleset = rulesets.Query<RulesetInfo>().First(),
Path = "normal.osu",
Version = "Normal",
Difficulty = new BeatmapDifficulty
@@ -83,7 +88,7 @@ namespace osu.Desktop.VisualTests.Tests
new BeatmapInfo
{
OnlineBeatmapID = 1235 + i,
Mode = PlayMode.Osu,
Ruleset = rulesets.Query<RulesetInfo>().First(),
Path = "hard.osu",
Version = "Hard",
Difficulty = new BeatmapDifficulty
@@ -94,7 +99,7 @@ namespace osu.Desktop.VisualTests.Tests
new BeatmapInfo
{
OnlineBeatmapID = 1236 + i,
Mode = PlayMode.Osu,
Ruleset = rulesets.Query<RulesetInfo>().First(),
Path = "insane.osu",
Version = "Insane",
Difficulty = new BeatmapDifficulty
@@ -9,12 +9,12 @@ using osu.Game.Beatmaps;
using OpenTK;
using osu.Framework.Graphics.Sprites;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Play;
using OpenTK.Graphics;
using osu.Desktop.VisualTests.Beatmaps;
using osu.Game.Rulesets.Osu.UI;
namespace osu.Desktop.VisualTests.Tests
{
@@ -22,12 +22,14 @@ namespace osu.Desktop.VisualTests.Tests
{
protected Player Player;
private BeatmapDatabase db;
private RulesetDatabase rulesets;
public override string Description => @"Showing everything to play the game.";
[BackgroundDependencyLoader]
private void load(BeatmapDatabase db)
private void load(BeatmapDatabase db, RulesetDatabase rulesets)
{
this.rulesets = rulesets;
this.db = db;
}
@@ -37,7 +39,7 @@ namespace osu.Desktop.VisualTests.Tests
WorkingBeatmap beatmap = null;
var beatmapInfo = db.Query<BeatmapInfo>().FirstOrDefault(b => b.Mode == PlayMode.Osu);
var beatmapInfo = db.Query<BeatmapInfo>().FirstOrDefault(b => b.RulesetID == 0);
if (beatmapInfo != null)
beatmap = db.GetWorkingBeatmap(beatmapInfo);
@@ -51,8 +53,8 @@ namespace osu.Desktop.VisualTests.Tests
objects.Add(new HitCircle
{
StartTime = time,
Position = new Vector2(i % 4 == 0 || i % 4 == 2 ? 0 : 512,
i % 4 < 2 ? 0 : 384),
Position = new Vector2(i % 4 == 0 || i % 4 == 2 ? 0 : OsuPlayfield.BASE_SIZE.X,
i % 4 < 2 ? 0 : OsuPlayfield.BASE_SIZE.Y),
NewCombo = i % 4 == 0
});
@@ -65,6 +67,7 @@ namespace osu.Desktop.VisualTests.Tests
BeatmapInfo = new BeatmapInfo
{
Difficulty = new BeatmapDifficulty(),
Ruleset = rulesets.Query<RulesetInfo>().First(),
Metadata = new BeatmapMetadata
{
Artist = @"Unknown",
@@ -2,8 +2,8 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Mods;
using osu.Game.Modes.Osu.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
@@ -0,0 +1,68 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Ranking;
using osu.Game.Users;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseResults : TestCase
{
private BeatmapDatabase db;
public override string Description => @"Results after playing.";
[BackgroundDependencyLoader]
private void load(BeatmapDatabase db)
{
this.db = db;
}
private WorkingBeatmap beatmap;
public override void Reset()
{
base.Reset();
if (beatmap == null)
{
var beatmapInfo = db.Query<BeatmapInfo>().FirstOrDefault(b => b.RulesetID == 0);
if (beatmapInfo != null)
beatmap = db.GetWorkingBeatmap(beatmapInfo);
}
base.Reset();
Add(new Results(new Score
{
TotalScore = 2845370,
Accuracy = 0.98,
MaxCombo = 123,
Rank = ScoreRank.A,
Date = DateTimeOffset.Now,
Statistics = new Dictionary<string, dynamic>()
{
{ "300", 50 },
{ "100", 20 },
{ "50", 50 },
{ "x", 1 }
},
User = new User
{
Username = "peppy",
}
})
{
Beatmap = beatmap
});
}
}
}
@@ -3,12 +3,11 @@
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Modes.UI;
using osu.Game.Screens.Play.HUD;
namespace osu.Desktop.VisualTests.Tests
{
@@ -6,18 +6,18 @@ using osu.Game.Overlays;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseOptions : TestCase
internal class TestCaseSettings : TestCase
{
public override string Description => @"Tests the options overlay";
public override string Description => @"Tests the settings overlay";
private OptionsOverlay options;
private SettingsOverlay settings;
public override void Reset()
{
base.Reset();
Children = new[] { options = new OptionsOverlay() };
options.ToggleVisibility();
Children = new[] { settings = new SettingsOverlay() };
settings.ToggleVisibility();
}
}
}
@@ -0,0 +1,67 @@
// 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.Graphics;
using osu.Framework.MathUtils;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseSongProgress : TestCase
{
public override string Description => @"With fake data";
private SongProgress progress;
private SongProgressGraph graph;
private StopwatchClock clock;
public override void Reset()
{
base.Reset();
clock = new StopwatchClock(true);
Add(progress = new SongProgress
{
RelativeSizeAxes = Axes.X,
AudioClock = new StopwatchClock(true),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
});
Add(graph = new SongProgressGraph
{
RelativeSizeAxes = Axes.X,
Height = 200,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
});
AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking);
AddWaitStep(5);
AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking);
AddWaitStep(2);
AddRepeatStep("New Values", displayNewValues, 5);
displayNewValues();
}
private void displayNewValues()
{
List<HitObject> objects = new List<HitObject>();
for (double i = 0; i < 5000; i += RNG.NextDouble() * 10 + i / 1000)
objects.Add(new HitObject { StartTime = i });
progress.Objects = objects;
graph.Objects = objects;
progress.AudioClock = clock;
progress.OnSeek = pos => clock.Seek(pos);
}
}
}
@@ -1,8 +1,8 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using OpenTK;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Testing;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
@@ -6,7 +6,7 @@ using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Modes.Taiko.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
namespace osu.Desktop.VisualTests.Tests
{
@@ -7,11 +7,11 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.Taiko.Objects.Drawables;
using osu.Game.Modes.Taiko.UI;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.Taiko.UI;
using System;
namespace osu.Desktop.VisualTests.Tests
@@ -0,0 +1,92 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Framework.Configuration;
using OpenTK;
using osu.Game.Graphics;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseTooltip : TestCase
{
public override string Description => "tests tooltips on various elements";
public override void Reset()
{
base.Reset();
OsuSliderBar<int> slider;
OsuSliderBar<double> sliderDouble;
const float width = 400;
Children = new Drawable[]
{
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
new TooltipTextContainer("text with a tooltip"),
new TooltipTextContainer("more text with another tooltip"),
new TooltipTextbox
{
Text = "a textbox with a tooltip",
Size = new Vector2(width,30),
},
slider = new OsuSliderBar<int>
{
Width = width,
},
sliderDouble = new OsuSliderBar<double>
{
Width = width,
},
},
},
};
slider.Current.BindTo(new BindableInt(5)
{
MaxValue = 10,
MinValue = 0
});
sliderDouble.Current.BindTo(new BindableDouble(0.5)
{
MaxValue = 1,
MinValue = 0
});
}
private class TooltipTextContainer : Container, IHasTooltip
{
private readonly OsuSpriteText text;
public string TooltipText => text.Text;
public TooltipTextContainer(string tooltipText)
{
AutoSizeAxes = Axes.Both;
Children = new[]
{
text = new OsuSpriteText
{
Text = tooltipText,
}
};
}
}
private class TooltipTextbox : OsuTextBox, IHasTooltip
{
public string TooltipText => Text;
}
}
}
@@ -16,7 +16,7 @@ namespace osu.Desktop.VisualTests.Tests
base.Reset();
Add(new BackButton());
Add(new SkipButton());
Add(new SkipButton(Clock.CurrentTime + 5000));
}
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ namespace osu.Desktop.VisualTests
host.DrawThread.InactiveHz = host.DrawThread.ActiveHz;
host.InputThread.InactiveHz = host.InputThread.ActiveHz;
host.Window.CursorState = CursorState.Hidden;
host.Window.CursorState |= CursorState.Hidden;
}
}
}
@@ -61,6 +61,7 @@
<RunCodeAnalysis>false</RunCodeAnalysis>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@@ -160,21 +161,21 @@
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
<Name>osu.Game.Modes.Osu</Name>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Catch\osu.Game.Modes.Catch.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
<Name>osu.Game.Modes.Catch</Name>
<Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
<Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
<Name>osu.Game.Modes.Mania</Name>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Taiko\osu.Game.Modes.Taiko.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
<Name>osu.Game.Modes.Taiko</Name>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0d3fbf8a-7464-4cf7-8c90-3e7886df2d4d}</Project>
@@ -189,25 +190,31 @@
<Compile Include="Tests\TestCaseDrawings.cs" />
<Compile Include="Tests\TestCaseGamefield.cs" />
<Compile Include="Tests\TestCaseGraph.cs" />
<Compile Include="Tests\TestCaseManiaHitObjects.cs" />
<Compile Include="Tests\TestCaseManiaPlayfield.cs" />
<Compile Include="Tests\TestCaseMenuOverlays.cs" />
<Compile Include="Tests\TestCaseMusicController.cs" />
<Compile Include="Tests\TestCaseNotificationManager.cs" />
<Compile Include="Tests\TestCaseOnScreenDisplay.cs" />
<Compile Include="Tests\TestCasePlayer.cs" />
<Compile Include="Tests\TestCaseHitObjects.cs" />
<Compile Include="Tests\TestCaseKeyCounter.cs" />
<Compile Include="Tests\TestCaseMenuButtonSystem.cs" />
<Compile Include="Tests\TestCaseReplay.cs" />
<Compile Include="Tests\TestCaseResults.cs" />
<Compile Include="Tests\TestCaseScoreCounter.cs" />
<Compile Include="Tests\TestCaseTabControl.cs" />
<Compile Include="Tests\TestCaseTaikoHitObjects.cs" />
<Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
<Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
<Compile Include="Tests\TestCaseTooltip.cs" />
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />
<Compile Include="VisualTestGame.cs" />
<Compile Include="Platform\TestStorage.cs" />
<Compile Include="Tests\TestCaseOptions.cs" />
<Compile Include="Tests\TestCaseModSelectOverlay.cs" />
<Compile Include="Tests\TestCaseSettings.cs" />
<Compile Include="Tests\TestCaseSongProgress.cs" />
<Compile Include="Tests\TestCaseMods.cs" />
<Compile Include="Tests\TestCaseDialogOverlay.cs" />
<Compile Include="Tests\TestCaseBeatmapOptionsOverlay.cs" />
<Compile Include="Tests\TestCaseLeaderboard.cs" />
@@ -14,7 +14,7 @@ namespace osu.Desktop.Beatmaps.IO
{
public static void Register() => AddReader<LegacyFilesystemReader>((storage, path) => Directory.Exists(path));
private string basePath { get; }
private readonly string basePath;
public LegacyFilesystemReader(string path)
{
+1 -1
View File
@@ -43,7 +43,7 @@ namespace osu.Desktop
var desktopWindow = host.Window as DesktopGameWindow;
if (desktopWindow != null)
{
desktopWindow.CursorState = CursorState.Hidden;
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
desktopWindow.Title = Name;
-10
View File
@@ -7,11 +7,6 @@ using osu.Desktop.Beatmaps.IO;
using osu.Framework.Desktop;
using osu.Framework.Desktop.Platform;
using osu.Game.IPC;
using osu.Game.Modes;
using osu.Game.Modes.Catch;
using osu.Game.Modes.Mania;
using osu.Game.Modes.Osu;
using osu.Game.Modes.Taiko;
namespace osu.Desktop
{
@@ -41,11 +36,6 @@ namespace osu.Desktop
}
else
{
Ruleset.Register(new OsuRuleset());
Ruleset.Register(new TaikoRuleset());
Ruleset.Register(new ManiaRuleset());
Ruleset.Register(new CatchRuleset());
host.Run(new OsuGameDesktop(args));
}
return 0;
+9 -8
View File
@@ -63,6 +63,7 @@
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<Commandlineparameters>
</Commandlineparameters>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
@@ -197,21 +198,21 @@
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
<Name>osu.Game.Modes.Osu</Name>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Catch\osu.Game.Modes.Catch.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
<Name>osu.Game.Modes.Catch</Name>
<Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
<Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
<Name>osu.Game.Modes.Mania</Name>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Taiko\osu.Game.Modes.Taiko.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
<Name>osu.Game.Modes.Taiko</Name>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0d3fbf8a-7464-4cf7-8c90-3e7886df2d4d}</Project>
@@ -1,20 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Catch.Objects;
using System.Collections.Generic;
namespace osu.Game.Modes.Catch.Beatmaps
{
internal class CatchBeatmapConverter : IBeatmapConverter<CatchBaseHit>
{
public Beatmap<CatchBaseHit> Convert(Beatmap original)
{
return new Beatmap<CatchBaseHit>(original)
{
HitObjects = new List<CatchBaseHit>() // Todo: Convert HitObjects
};
}
}
}
@@ -1,19 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Catch.Objects;
namespace osu.Game.Modes.Catch.Beatmaps
{
internal class CatchBeatmapProcessor : IBeatmapProcessor<CatchBaseHit>
{
public void SetDefaults(CatchBaseHit hitObject, Beatmap<CatchBaseHit> beatmap)
{
}
public void PostProcess(Beatmap<CatchBaseHit> beatmap)
{
}
}
}
@@ -1,20 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Mania.Objects;
using System.Collections.Generic;
namespace osu.Game.Modes.Mania.Beatmaps
{
internal class ManiaBeatmapConverter : IBeatmapConverter<ManiaBaseHit>
{
public Beatmap<ManiaBaseHit> Convert(Beatmap original)
{
return new Beatmap<ManiaBaseHit>(original)
{
HitObjects = new List<ManiaBaseHit>() // Todo: Implement
};
}
}
}
@@ -1,19 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Mania.Objects;
namespace osu.Game.Modes.Mania.Beatmaps
{
internal class ManiaBeatmapProcessor : IBeatmapProcessor<ManiaBaseHit>
{
public void SetDefaults(ManiaBaseHit hitObject, Beatmap<ManiaBaseHit> beatmap)
{
}
public void PostProcess(Beatmap<ManiaBaseHit> beatmap)
{
}
}
}
@@ -1,36 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics;
using OpenTK;
namespace osu.Game.Modes.Mania.Objects.Drawable
{
public class DrawableNote : Sprite
{
private readonly ManiaBaseHit note;
public DrawableNote(ManiaBaseHit note)
{
this.note = note;
Origin = Anchor.Centre;
Scale = new Vector2(0.1f);
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Texture = textures.Get(@"Menu/logo");
const double duration = 0;
Transforms.Add(new TransformPositionY { StartTime = note.StartTime - 200, EndTime = note.StartTime, StartValue = -0.1f, EndValue = 0.9f });
Transforms.Add(new TransformAlpha { StartTime = note.StartTime + duration + 200, EndTime = note.StartTime + duration + 400, StartValue = 1, EndValue = 0 });
Expire(true);
}
}
}
-9
View File
@@ -1,9 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Modes.Mania.Objects
{
public class HoldNote : Note
{
}
}
@@ -1,12 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Objects;
namespace osu.Game.Modes.Mania.Objects
{
public abstract class ManiaBaseHit : HitObject
{
public int Column;
}
}
@@ -1,26 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Mania.Judgements;
using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Mania.Scoring
{
internal class ManiaScoreProcessor : ScoreProcessor<ManiaBaseHit, ManiaJudgement>
{
public ManiaScoreProcessor()
{
}
public ManiaScoreProcessor(HitRenderer<ManiaBaseHit, ManiaJudgement> hitRenderer)
: base(hitRenderer)
{
}
protected override void OnNewJudgement(ManiaJudgement judgement)
{
}
}
}
@@ -1,35 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Mania.Beatmaps;
using osu.Game.Modes.Mania.Judgements;
using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.Mania.Scoring;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Mania.UI
{
public class ManiaHitRenderer : HitRenderer<ManiaBaseHit, ManiaJudgement>
{
private readonly int columns;
public ManiaHitRenderer(WorkingBeatmap beatmap, int columns = 5)
: base(beatmap)
{
this.columns = columns;
}
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
protected override IBeatmapConverter<ManiaBaseHit> CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override IBeatmapProcessor<ManiaBaseHit> CreateBeatmapProcessor() => new ManiaBeatmapProcessor();
protected override Playfield<ManiaBaseHit, ManiaJudgement> CreatePlayfield() => new ManiaPlayfield(columns);
protected override DrawableHitObject<ManiaBaseHit, ManiaJudgement> GetVisualRepresentation(ManiaBaseHit h) => null;
}
}
-36
View File
@@ -1,36 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.UI;
using OpenTK;
using OpenTK.Graphics;
using osu.Game.Modes.Mania.Judgements;
namespace osu.Game.Modes.Mania.UI
{
public class ManiaPlayfield : Playfield<ManiaBaseHit, ManiaJudgement>
{
public ManiaPlayfield(int columns)
{
Size = new Vector2(0.8f, 1f);
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
Add(new Box { RelativeSizeAxes = Axes.Both, Alpha = 0.5f });
for (int i = 0; i < columns; i++)
Add(new Box
{
RelativeSizeAxes = Axes.Y,
Size = new Vector2(2, 1),
RelativePositionAxes = Axes.Both,
Position = new Vector2((float)i / columns, 0),
Alpha = 0.5f,
Colour = Color4.Black
});
}
}
}
@@ -1,32 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Osu.Objects;
namespace osu.Game.Modes.Osu.Beatmaps
{
internal class OsuBeatmapProcessor : IBeatmapProcessor<OsuHitObject>
{
public void PostProcess(Beatmap<OsuHitObject> beatmap)
{
if (beatmap.ComboColors.Count == 0)
return;
int comboIndex = 0;
int colourIndex = 0;
foreach (var obj in beatmap.HitObjects)
{
if (obj.NewCombo)
{
comboIndex = 0;
colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count;
}
obj.ComboIndex = comboIndex++;
obj.ComboColour = beatmap.ComboColors[colourIndex];
}
}
}
}
@@ -1,155 +0,0 @@
// 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 osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Objects.Drawables.Pieces;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables
{
public class DrawableSpinner : DrawableOsuHitObject
{
private readonly Spinner spinner;
private readonly SpinnerDisc disc;
private readonly SpinnerBackground background;
private readonly Container circleContainer;
private readonly DrawableHitCircle circle;
public DrawableSpinner(Spinner s) : base(s)
{
AlwaysReceiveInput = true;
Origin = Anchor.Centre;
Position = s.Position;
//take up full playfield.
Size = new Vector2(512);
spinner = s;
Children = new Drawable[]
{
background = new SpinnerBackground
{
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
DiscColour = Color4.Black
},
disc = new SpinnerDisc
{
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
DiscColour = AccentColour
},
circleContainer = new Container
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new []
{
circle = new DrawableHitCircle(s)
{
Interactive = false,
Position = Vector2.Zero,
Anchor = Anchor.Centre,
}
}
}
};
background.Scale = scaleToCircle;
disc.Scale = scaleToCircle;
}
protected override void CheckJudgement(bool userTriggered)
{
if (Time.Current < HitObject.StartTime) return;
disc.ScaleTo(Interpolation.ValueAt(Math.Sqrt(Progress), scaleToCircle, Vector2.One, 0, 1), 100);
if (Progress >= 1)
disc.Complete = true;
if (!userTriggered && Time.Current >= spinner.EndTime)
{
if (Progress >= 1)
{
Judgement.Score = OsuScoreResult.Hit300;
Judgement.Result = HitResult.Hit;
}
else if (Progress > .9)
{
Judgement.Score = OsuScoreResult.Hit100;
Judgement.Result = HitResult.Hit;
}
else if (Progress > .75)
{
Judgement.Score = OsuScoreResult.Hit50;
Judgement.Result = HitResult.Hit;
}
else
{
Judgement.Score = OsuScoreResult.Miss;
if (Time.Current >= spinner.EndTime)
Judgement.Result = HitResult.Miss;
}
}
}
private Vector2 scaleToCircle => circle.Scale * circle.DrawWidth / DrawWidth * 0.95f;
private const float spins_per_minute_needed = 100 + 5 * 15; //TODO: read per-map OD and place it on the 5
private float rotationsNeeded => (float)(spins_per_minute_needed * (spinner.EndTime - spinner.StartTime) / 60000f);
public float Progress => MathHelper.Clamp(disc.RotationAbsolute / 360 / rotationsNeeded, 0, 1);
protected override void UpdatePreemptState()
{
base.UpdatePreemptState();
circleContainer.ScaleTo(1, 400, EasingTypes.OutElastic);
background.Delay(TIME_PREEMPT - 500);
background.ScaleTo(scaleToCircle * 1.2f, 400, EasingTypes.OutQuint);
background.FadeIn(200);
background.Delay(400);
background.ScaleTo(1, 250, EasingTypes.OutQuint);
disc.Delay(TIME_PREEMPT - 50);
disc.FadeIn(200);
}
protected override void UpdateState(ArmedState state)
{
base.UpdateState(state);
Delay(spinner.Duration, true);
FadeOut(160);
switch (state)
{
case ArmedState.Hit:
ScaleTo(Scale * 1.2f, 320, EasingTypes.Out);
Expire();
break;
case ArmedState.Miss:
ScaleTo(Scale * 0.8f, 320, EasingTypes.In);
Expire();
break;
}
}
}
}
@@ -1,10 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class SpinnerBackground : SpinnerDisc
{
public override bool HandleInput => false;
}
}
@@ -1,208 +0,0 @@
// 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.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Input;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class SpinnerDisc : CircularContainer
{
protected Sprite Disc;
public SRGBColour DiscColour
{
get { return Disc.Colour; }
set { Disc.Colour = value; }
}
private Color4 completeColour;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
completeColour = colours.YellowLight.Opacity(0.8f);
Masking = true;
}
private class SpinnerBorder : Container
{
public SpinnerBorder()
{
Origin = Anchor.Centre;
Anchor = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
layout();
}
private int lastLayoutDotCount;
private void layout()
{
int count = (int)(MathHelper.Pi * ScreenSpaceDrawQuad.Width / 9);
if (count == lastLayoutDotCount) return;
lastLayoutDotCount = count;
while (Children.Count() < count)
{
Add(new CircularContainer
{
Colour = Color4.White,
RelativePositionAxes = Axes.Both,
Masking = true,
Origin = Anchor.Centre,
Size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000),
Children = new[]
{
new Box
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
}
}
});
}
var size = new Vector2(1 / ScreenSpaceDrawQuad.Width * 2000);
int i = 0;
foreach (var d in Children)
{
d.Size = size;
d.Position = new Vector2(
0.5f + (float)Math.Sin((float)i / count * 2 * MathHelper.Pi) / 2,
0.5f + (float)Math.Cos((float)i / count * 2 * MathHelper.Pi) / 2
);
i++;
}
}
protected override void Update()
{
base.Update();
layout();
}
}
public SpinnerDisc()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{
Disc = new Box
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Alpha = 0.2f,
},
new SpinnerBorder()
};
}
private bool tracking;
public bool Tracking
{
get { return tracking; }
set
{
if (value == tracking) return;
tracking = value;
Disc.FadeTo(tracking ? 0.5f : 0.2f, 100);
}
}
private bool complete;
public bool Complete
{
get { return complete; }
set
{
if (value == complete) return;
complete = value;
Disc.FadeColour(completeColour, 200);
updateCompleteTick();
}
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
Tracking = true;
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
Tracking = false;
return base.OnMouseUp(state, args);
}
protected override bool OnMouseMove(InputState state)
{
Tracking |= state.Mouse.HasMainButtonPressed;
mousePosition = state.Mouse.Position;
return base.OnMouseMove(state);
}
private Vector2 mousePosition;
private float lastAngle;
private float currentRotation;
public float RotationAbsolute;
private int completeTick;
private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360));
protected override void Update()
{
base.Update();
var thisAngle = -(float)MathHelper.RadiansToDegrees(Math.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
if (tracking)
{
if (thisAngle - lastAngle > 180)
lastAngle += 360;
else if (lastAngle - thisAngle > 180)
lastAngle -= 360;
currentRotation += thisAngle - lastAngle;
RotationAbsolute += Math.Abs(thisAngle - lastAngle);
}
lastAngle = thisAngle;
if (Complete && updateCompleteTick())
{
Disc.Flush(flushType: typeof(TransformAlpha));
Disc.FadeTo(0.75f, 30, EasingTypes.OutExpo);
Disc.Delay(30);
Disc.FadeTo(0.5f, 250, EasingTypes.OutQuint);
}
RotateTo(currentRotation, 100, EasingTypes.OutExpo);
}
}
}
-310
View File
@@ -1,310 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Osu.Objects.Drawables;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using osu.Framework.Graphics;
using osu.Game.Modes.Objects.Types;
using osu.Game.Modes.Replays;
namespace osu.Game.Modes.Osu
{
public class OsuAutoReplay : Replay
{
private static readonly Vector2 spinner_centre = new Vector2(256, 192);
private const float spin_radius = 50;
private readonly Beatmap<OsuHitObject> beatmap;
public OsuAutoReplay(Beatmap<OsuHitObject> beatmap)
{
this.beatmap = beatmap;
createAutoReplay();
}
private class ReplayFrameComparer : IComparer<ReplayFrame>
{
public int Compare(ReplayFrame f1, ReplayFrame f2)
{
if (f1 == null) throw new NullReferenceException($@"{nameof(f1)} cannot be null");
if (f2 == null) throw new NullReferenceException($@"{nameof(f2)} cannot be null");
return f1.Time.CompareTo(f2.Time);
}
}
private static readonly IComparer<ReplayFrame> replay_frame_comparer = new ReplayFrameComparer();
private int findInsertionIndex(ReplayFrame frame)
{
int index = Frames.BinarySearch(frame, replay_frame_comparer);
if (index < 0)
{
index = ~index;
}
else
{
// Go to the first index which is actually bigger
while (index < Frames.Count && frame.Time == Frames[index].Time)
{
++index;
}
}
return index;
}
private void addFrameToReplay(ReplayFrame frame) => Frames.Insert(findInsertionIndex(frame), frame);
private static Vector2 circlePosition(double t, double radius) => new Vector2((float)(Math.Cos(t) * radius), (float)(Math.Sin(t) * radius));
private double applyModsToTime(double v) => v;
private double applyModsToRate(double v) => v;
public bool DelayedMovements; // ModManager.CheckActive(Mods.Relax2);
private void createAutoReplay()
{
int buttonIndex = 0;
EasingTypes preferredEasing = DelayedMovements ? EasingTypes.InOutCubic : EasingTypes.Out;
addFrameToReplay(new ReplayFrame(-100000, 256, 500, ReplayButtonState.None));
addFrameToReplay(new ReplayFrame(beatmap.HitObjects[0].StartTime - 1500, 256, 500, ReplayButtonState.None));
addFrameToReplay(new ReplayFrame(beatmap.HitObjects[0].StartTime - 1000, 256, 192, ReplayButtonState.None));
// We are using ApplyModsToRate and not ApplyModsToTime to counteract the speed up / slow down from HalfTime / DoubleTime so that we remain at a constant framerate of 60 fps.
float frameDelay = (float)applyModsToRate(1000.0 / 60.0);
// Already superhuman, but still somewhat realistic
int reactionTime = (int)applyModsToRate(100);
for (int i = 0; i < beatmap.HitObjects.Count; i++)
{
OsuHitObject h = beatmap.HitObjects[i];
//if (h.EndTime < InputManager.ReplayStartTime)
//{
// h.IsHit = true;
// continue;
//}
int endDelay = h is Spinner ? 1 : 0;
if (DelayedMovements && i > 0)
{
OsuHitObject last = beatmap.HitObjects[i - 1];
double endTime = (last as IHasEndTime)?.EndTime ?? last.StartTime;
//Make the cursor stay at a hitObject as long as possible (mainly for autopilot).
if (h.StartTime - h.HitWindowFor(OsuScoreResult.Miss) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
{
if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), last.EndPosition.X, last.EndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) addFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Miss), h.Position.X, h.Position.Y, ReplayButtonState.None));
}
else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50) > endTime + h.HitWindowFor(OsuScoreResult.Hit50) + 50)
{
if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit50), last.EndPosition.X, last.EndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) addFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit50), h.Position.X, h.Position.Y, ReplayButtonState.None));
}
else if (h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100) > endTime + h.HitWindowFor(OsuScoreResult.Hit100) + 50)
{
if (!(last is Spinner) && h.StartTime - endTime < 1000) addFrameToReplay(new ReplayFrame(endTime + h.HitWindowFor(OsuScoreResult.Hit100), last.EndPosition.X, last.EndPosition.Y, ReplayButtonState.None));
if (!(h is Spinner)) addFrameToReplay(new ReplayFrame(h.StartTime - h.HitWindowFor(OsuScoreResult.Hit100), h.Position.X, h.Position.Y, ReplayButtonState.None));
}
}
Vector2 targetPosition = h.Position;
EasingTypes easing = preferredEasing;
float spinnerDirection = -1;
if (h is Spinner)
{
targetPosition.X = Frames[Frames.Count - 1].MouseX;
targetPosition.Y = Frames[Frames.Count - 1].MouseY;
Vector2 difference = spinner_centre - targetPosition;
float differenceLength = difference.Length;
float newLength = (float)Math.Sqrt(differenceLength * differenceLength - spin_radius * spin_radius);
if (differenceLength > spin_radius)
{
float angle = (float)Math.Asin(spin_radius / differenceLength);
if (angle > 0)
{
spinnerDirection = -1;
}
else
{
spinnerDirection = 1;
}
difference.X = difference.X * (float)Math.Cos(angle) - difference.Y * (float)Math.Sin(angle);
difference.Y = difference.X * (float)Math.Sin(angle) + difference.Y * (float)Math.Cos(angle);
difference.Normalize();
difference *= newLength;
targetPosition += difference;
easing = EasingTypes.In;
}
else if (difference.Length > 0)
{
targetPosition = spinner_centre - difference * (spin_radius / difference.Length);
}
else
{
targetPosition = spinner_centre + new Vector2(0, -spin_radius);
}
}
// Do some nice easing for cursor movements
if (Frames.Count > 0)
{
ReplayFrame lastFrame = Frames[Frames.Count - 1];
// Wait until Auto could "see and react" to the next note.
double waitTime = h.StartTime - Math.Max(0.0, DrawableOsuHitObject.TIME_PREEMPT - reactionTime);
if (waitTime > lastFrame.Time)
{
lastFrame = new ReplayFrame(waitTime, lastFrame.MouseX, lastFrame.MouseY, lastFrame.ButtonState);
addFrameToReplay(lastFrame);
}
Vector2 lastPosition = new Vector2(lastFrame.MouseX, lastFrame.MouseY);
double timeDifference = applyModsToTime(h.StartTime - lastFrame.Time);
// Only "snap" to hitcircles if they are far enough apart. As the time between hitcircles gets shorter the snapping threshold goes up.
if (timeDifference > 0 && // Sanity checks
((lastPosition - targetPosition).Length > h.Radius * (1.5 + 100.0 / timeDifference) || // Either the distance is big enough
timeDifference >= 266)) // ... or the beats are slow enough to tap anyway.
{
// Perform eased movement
for (double time = lastFrame.Time + frameDelay; time < h.StartTime; time += frameDelay)
{
Vector2 currentPosition = Interpolation.ValueAt(time, lastPosition, targetPosition, lastFrame.Time, h.StartTime, easing);
addFrameToReplay(new ReplayFrame((int)time, currentPosition.X, currentPosition.Y, lastFrame.ButtonState));
}
buttonIndex = 0;
}
else
{
buttonIndex++;
}
}
ReplayButtonState button = buttonIndex % 2 == 0 ? ReplayButtonState.Left1 : ReplayButtonState.Right1;
double hEndTime = (h as IHasEndTime)?.EndTime ?? h.StartTime;
ReplayFrame newFrame = new ReplayFrame(h.StartTime, targetPosition.X, targetPosition.Y, button);
ReplayFrame endFrame = new ReplayFrame(hEndTime + endDelay, h.EndPosition.X, h.EndPosition.Y, ReplayButtonState.None);
// Decrement because we want the previous frame, not the next one
int index = findInsertionIndex(newFrame) - 1;
// Do we have a previous frame? No need to check for < replay.Count since we decremented!
if (index >= 0)
{
ReplayFrame previousFrame = Frames[index];
var previousButton = previousFrame.ButtonState;
// If a button is already held, then we simply alternate
if (previousButton != ReplayButtonState.None)
{
Debug.Assert(previousButton != (ReplayButtonState.Left1 | ReplayButtonState.Right1));
// Force alternation if we have the same button. Otherwise we can just keep the naturally to us assigned button.
if (previousButton == button)
{
button = (ReplayButtonState.Left1 | ReplayButtonState.Right1) & ~button;
newFrame.ButtonState = button;
}
// We always follow the most recent slider / spinner, so remove any other frames that occur while it exists.
int endIndex = findInsertionIndex(endFrame);
if (index < Frames.Count - 1)
Frames.RemoveRange(index + 1, Math.Max(0, endIndex - (index + 1)));
// After alternating we need to keep holding the other button in the future rather than the previous one.
for (int j = index + 1; j < Frames.Count; ++j)
{
// Don't affect frames which stop pressing a button!
if (j < Frames.Count - 1 || Frames[j].ButtonState == previousButton)
Frames[j].ButtonState = button;
}
}
}
addFrameToReplay(newFrame);
// We add intermediate frames for spinning / following a slider here.
if (h is Spinner)
{
Spinner s = h as Spinner;
Vector2 difference = targetPosition - spinner_centre;
float radius = difference.Length;
float angle = radius == 0 ? 0 : (float)Math.Atan2(difference.Y, difference.X);
double t;
for (double j = h.StartTime + frameDelay; j < s.EndTime; j += frameDelay)
{
t = applyModsToTime(j - h.StartTime) * spinnerDirection;
Vector2 pos = spinner_centre + circlePosition(t / 20 + angle, spin_radius);
addFrameToReplay(new ReplayFrame((int)j, pos.X, pos.Y, button));
}
t = applyModsToTime(s.EndTime - h.StartTime) * spinnerDirection;
Vector2 endPosition = spinner_centre + circlePosition(t / 20 + angle, spin_radius);
addFrameToReplay(new ReplayFrame(s.EndTime, endPosition.X, endPosition.Y, button));
endFrame.MouseX = endPosition.X;
endFrame.MouseY = endPosition.Y;
}
else if (h is Slider)
{
Slider s = h as Slider;
for (double j = frameDelay; j < s.Duration; j += frameDelay)
{
Vector2 pos = s.PositionAt(j / s.Duration);
addFrameToReplay(new ReplayFrame(h.StartTime + j, pos.X, pos.Y, button));
}
addFrameToReplay(new ReplayFrame(s.EndTime, s.EndPosition.X, s.EndPosition.Y, button));
}
// We only want to let go of our button if we are at the end of the current replay. Otherwise something is still going on after us so we need to keep the button pressed!
if (Frames[Frames.Count - 1].Time <= endFrame.Time)
addFrameToReplay(endFrame);
}
//Player.currentScore.Replay = InputManager.ReplayScore.Replay;
//Player.currentScore.PlayerName = "osu!";
}
}
}
-11
View File
@@ -1,11 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Scoring;
namespace osu.Game.Modes.Osu.Scoring
{
internal class OsuScore : Score
{
}
}
@@ -1,59 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Osu.Scoring
{
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgement>
{
public OsuScoreProcessor()
{
}
public OsuScoreProcessor(HitRenderer<OsuHitObject, OsuJudgement> hitRenderer)
: base(hitRenderer)
{
}
protected override void Reset()
{
base.Reset();
Health.Value = 1;
Accuracy.Value = 1;
}
protected override void OnNewJudgement(OsuJudgement judgement)
{
if (judgement != null)
{
switch (judgement.Result)
{
case HitResult.Hit:
Health.Value += 0.1f;
break;
case HitResult.Miss:
Health.Value -= 0.2f;
break;
}
}
int score = 0;
int maxScore = 0;
foreach (var j in Judgements)
{
score += j.ScoreValue;
maxScore += j.MaxScoreValue;
}
TotalScore.Value = score;
Accuracy.Value = (double)score / maxScore;
}
}
}
@@ -1,19 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Taiko.Objects;
namespace osu.Game.Modes.Taiko.Beatmaps
{
internal class TaikoBeatmapProcessor : IBeatmapProcessor<TaikoHitObject>
{
public void SetDefaults(TaikoHitObject hitObject, Beatmap<TaikoHitObject> beatmap)
{
}
public void PostProcess(Beatmap<TaikoHitObject> beatmap)
{
}
}
}
@@ -1,24 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Taiko.Beatmaps;
using osu.Game.Modes.Taiko.Objects;
using System.Collections.Generic;
namespace osu.Game.Modes.Taiko
{
public class TaikoDifficultyCalculator : DifficultyCalculator<TaikoHitObject>
{
public TaikoDifficultyCalculator(Beatmap beatmap) : base(beatmap)
{
}
protected override double CalculateInternal(Dictionary<string, string> categoryDifficulty)
{
return 0;
}
protected override IBeatmapConverter<TaikoHitObject> CreateBeatmapConverter() => new TaikoBeatmapConverter();
}
}
@@ -0,0 +1,23 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using System.Collections.Generic;
using System;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Catch.Beatmaps
{
internal class CatchBeatmapConverter : BeatmapConverter<CatchBaseHit>
{
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
protected override IEnumerable<CatchBaseHit> ConvertHitObject(HitObject original, Beatmap beatmap)
{
yield return null;
}
}
}
@@ -2,11 +2,12 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Catch.Beatmaps;
using osu.Game.Modes.Catch.Objects;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using System.Collections.Generic;
namespace osu.Game.Modes.Catch
namespace osu.Game.Rulesets.Catch
{
public class CatchDifficultyCalculator : DifficultyCalculator<CatchBaseHit>
{
@@ -19,6 +20,6 @@ namespace osu.Game.Modes.Catch
return 0;
}
protected override IBeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
}
}
@@ -4,20 +4,20 @@
using OpenTK.Input;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Modes.Catch.Mods;
using osu.Game.Modes.Catch.UI;
using osu.Game.Modes.Mods;
using osu.Game.Modes.UI;
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic;
using osu.Game.Modes.Catch.Scoring;
using osu.Game.Modes.Scoring;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Modes.Catch
namespace osu.Game.Rulesets.Catch
{
public class CatchRuleset : Ruleset
{
public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new CatchHitRenderer(beatmap);
public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchHitRenderer(beatmap, isForCurrentRuleset);
public override IEnumerable<Mod> GetModsFor(ModType type)
{
@@ -76,8 +76,6 @@ namespace osu.Game.Modes.Catch
}
}
protected override PlayMode PlayMode => PlayMode.Catch;
public override string Description => "osu!catch";
public override FontAwesome Icon => FontAwesome.fa_osu_fruits_o;
@@ -92,5 +90,7 @@ namespace osu.Game.Modes.Catch
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor();
public override int LegacyID => 2;
}
}
@@ -1,9 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Judgements;
using osu.Game.Rulesets.Judgements;
namespace osu.Game.Modes.Catch.Judgements
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchJudgement : Judgement
{
@@ -1,9 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Mods;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Modes.Catch.Mods
namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModNoFail : ModNoFail
{
@@ -1,9 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Objects;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Modes.Catch.Objects
namespace osu.Game.Rulesets.Catch.Objects
{
public abstract class CatchBaseHit : HitObject
{
@@ -8,7 +8,7 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Transforms;
using OpenTK;
namespace osu.Game.Modes.Catch.Objects.Drawable
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
internal class DrawableFruit : Sprite
{
@@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Modes.Catch.Objects
namespace osu.Game.Rulesets.Catch.Objects
{
public class Droplet : CatchBaseHit
{
@@ -1,7 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Modes.Catch.Objects
namespace osu.Game.Rulesets.Catch.Objects
{
public class Fruit : CatchBaseHit
{
@@ -7,11 +7,11 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Catch")]
[assembly: AssemblyTitle("osu.Game.Rulesets.Catch")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("osu.Game.Modes.Catch")]
[assembly: AssemblyProduct("osu.Game.Rulesets.Catch")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Catch.Judgements;
using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
namespace osu.Game.Modes.Catch.Scoring
namespace osu.Game.Rulesets.Catch.Scoring
{
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit, CatchJudgement>
{
@@ -2,28 +2,27 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Catch.Beatmaps;
using osu.Game.Modes.Catch.Judgements;
using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.Catch.Scoring;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Scoring;
using osu.Game.Modes.UI;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
namespace osu.Game.Modes.Catch.UI
namespace osu.Game.Rulesets.Catch.UI
{
public class CatchHitRenderer : HitRenderer<CatchBaseHit, CatchJudgement>
{
public CatchHitRenderer(WorkingBeatmap beatmap)
: base(beatmap)
public CatchHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(beatmap, isForCurrentRuleset)
{
}
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
protected override IBeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override IBeatmapProcessor<CatchBaseHit> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield();
@@ -3,12 +3,12 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.UI;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.UI;
using OpenTK;
using osu.Game.Modes.Catch.Judgements;
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Modes.Catch.UI
namespace osu.Game.Rulesets.Catch.UI
{
public class CatchPlayfield : Playfield<CatchBaseHit, CatchJudgement>
{
@@ -7,8 +7,8 @@
<ProjectGuid>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>osu.Game.Modes.Catch</RootNamespace>
<AssemblyName>osu.Game.Modes.Catch</AssemblyName>
<RootNamespace>osu.Game.Rulesets.Catch</RootNamespace>
<AssemblyName>osu.Game.Rulesets.Catch</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
@@ -21,6 +21,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -47,7 +48,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Beatmaps\CatchBeatmapConverter.cs" />
<Compile Include="Beatmaps\CatchBeatmapProcessor.cs" />
<Compile Include="CatchDifficultyCalculator.cs" />
<Compile Include="Scoring\CatchScoreProcessor.cs" />
<Compile Include="Judgements\CatchJudgement.cs" />
@@ -73,9 +73,9 @@
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
<Name>osu.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Modes.Osu</Name>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
@@ -0,0 +1,153 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using System;
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Database;
namespace osu.Game.Rulesets.Mania.Beatmaps
{
public class ManiaBeatmapConverter : BeatmapConverter<ManiaHitObject>
{
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
private Pattern lastPattern = new Pattern();
private FastRandom random;
private Beatmap beatmap;
private bool isForCurrentRuleset;
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original, bool isForCurrentRuleset)
{
this.isForCurrentRuleset = isForCurrentRuleset;
beatmap = original;
BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty;
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
random = new FastRandom(seed);
return base.ConvertBeatmap(original, isForCurrentRuleset);
}
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
{
var maniaOriginal = original as ManiaHitObject;
if (maniaOriginal != null)
{
yield return maniaOriginal;
yield break;
}
var objects = isForCurrentRuleset ? generateSpecific(original) : generateConverted(original);
if (objects == null)
yield break;
foreach (ManiaHitObject obj in objects)
yield return obj;
}
/// <summary>
/// Method that generates hit objects for osu!mania specific beatmaps.
/// </summary>
/// <param name="original">The original hit object.</param>
/// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original)
{
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern);
Pattern newPattern = generator.Generate();
lastPattern = newPattern;
return newPattern.HitObjects;
}
/// <summary>
/// Method that generates hit objects for non-osu!mania beatmaps.
/// </summary>
/// <param name="original">The original hit object.</param>
/// <returns>The hit objects generated.</returns>
private IEnumerable<ManiaHitObject> generateConverted(HitObject original)
{
var endTimeData = original as IHasEndTime;
var distanceData = original as IHasDistance;
var positionData = original as IHasPosition;
// Following lines currently commented out to appease resharper
//Patterns.PatternGenerator conversion = null;
if (distanceData != null)
{
// Slider
}
else if (endTimeData != null)
{
// Spinner
}
else if (positionData != null)
{
// Circle
}
//if (conversion == null)
return null;
//Pattern newPattern = conversion.Generate();
//lastPattern = newPattern;
//return newPattern.HitObjects;
}
/// <summary>
/// A pattern generator for osu!mania-specific beatmaps.
/// </summary>
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
{
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
: base(random, hitObject, beatmap, previousPattern)
{
}
public override Pattern Generate()
{
var endTimeData = HitObject as IHasEndTime;
var positionData = HitObject as IHasXPosition;
int column = GetColumn(positionData?.X ?? 0);
var pattern = new Pattern();
if (endTimeData != null)
{
pattern.Add(new HoldNote
{
StartTime = HitObject.StartTime,
Samples = HitObject.Samples,
Duration = endTimeData.Duration,
Column = column,
});
}
else if (positionData != null)
{
pattern.Add(new Note
{
StartTime = HitObject.StartTime,
Samples = HitObject.Samples,
Column = column
});
}
return pattern;
}
}
}
}
@@ -0,0 +1,106 @@
// 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.Database;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Objects;
using OpenTK;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
/// <summary>
/// A pattern generator for legacy hit objects.
/// </summary>
internal abstract class PatternGenerator : Patterns.PatternGenerator
{
/// <summary>
/// The column index at which to start generating random notes.
/// </summary>
protected readonly int RandomStart;
/// <summary>
/// The random number generator to use.
/// </summary>
protected readonly FastRandom Random;
protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
: base(hitObject, beatmap, previousPattern)
{
Random = random;
RandomStart = AvailableColumns == 8 ? 1 : 0;
}
/// <summary>
/// Converts an x-position into a column.
/// </summary>
/// <param name="position">The x-position.</param>
/// <param name="allowSpecial">Whether to treat as 7K + 1.</param>
/// <returns>The column.</returns>
protected int GetColumn(float position, bool allowSpecial = false)
{
if (allowSpecial && AvailableColumns == 8)
{
const float local_x_divisor = 512f / 7;
return MathHelper.Clamp((int)Math.Floor(position / local_x_divisor), 0, 6) + 1;
}
float localXDivisor = 512f / AvailableColumns;
return MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, AvailableColumns - 1);
}
/// <summary>
/// Generates a count of notes to be generated from probabilities.
/// </summary>
/// <param name="p2">Probability for 2 notes to be generated.</param>
/// <param name="p3">Probability for 3 notes to be generated.</param>
/// <param name="p4">Probability for 4 notes to be generated.</param>
/// <param name="p5">Probability for 5 notes to be generated.</param>
/// <param name="p6">Probability for 6 notes to be generated.</param>
/// <returns>The amount of notes to be generated.</returns>
protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0)
{
double val = Random.NextDouble();
if (val >= 1 - p6)
return 6;
if (val >= 1 - p5)
return 5;
if (val >= 1 - p4)
return 4;
if (val >= 1 - p3)
return 3;
return val >= 1 - p2 ? 2 : 1;
}
private double? conversionDifficulty;
/// <summary>
/// A difficulty factor used for various conversion methods from osu!stable.
/// </summary>
protected double ConversionDifficulty
{
get
{
if (conversionDifficulty != null)
return conversionDifficulty.Value;
HitObject lastObject = Beatmap.HitObjects.LastOrDefault();
HitObject firstObject = Beatmap.HitObjects.FirstOrDefault();
double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0);
drainTime -= Beatmap.EventInfo.TotalBreakTime;
if (drainTime == 0)
drainTime = 10000;
BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.Difficulty;
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15;
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
return conversionDifficulty.Value;
}
}
}
}
@@ -0,0 +1,65 @@
// 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;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{
/// <summary>
/// The type of pattern to generate. Used for legacy patterns.
/// </summary>
[Flags]
internal enum PatternType
{
None = 0,
/// <summary>
/// Keep the same as last row.
/// </summary>
ForceStack = 1,
/// <summary>
/// Keep different from last row.
/// </summary>
ForceNotStack = 2,
/// <summary>
/// Keep as single note at its original position.
/// </summary>
KeepSingle = 4,
/// <summary>
/// Use a lower random value.
/// </summary>
LowProbability = 8,
/// <summary>
/// Reserved.
/// </summary>
Alternate = 16,
/// <summary>
/// Ignore the repeat count.
/// </summary>
ForceSigSlider = 32,
/// <summary>
/// Convert slider to circle.
/// </summary>
ForceNotSlider = 64,
/// <summary>
/// Notes gathered together.
/// </summary>
Gathered = 128,
Mirror = 256,
/// <summary>
/// Change 0 -> 6.
/// </summary>
Reverse = 512,
/// <summary>
/// 1 -> 5 -> 1 -> 5 like reverse.
/// </summary>
Cycle = 1024,
/// <summary>
/// Next note will be at column + 1.
/// </summary>
Stair = 2048,
/// <summary>
/// Next note will be at column - 1.
/// </summary>
ReverseStair = 4096
}
}
@@ -0,0 +1,61 @@
// 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 System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Mania.Objects;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
{
/// <summary>
/// Creates a pattern containing hit objects.
/// </summary>
internal class Pattern
{
private readonly List<ManiaHitObject> hitObjects = new List<ManiaHitObject>();
/// <summary>
/// All the hit objects contained in this pattern.
/// </summary>
public IEnumerable<ManiaHitObject> HitObjects => hitObjects;
/// <summary>
/// Whether this pattern already contains a hit object in a code.
/// </summary>
/// <param name="column">The column index.</param>
/// <returns>Whether this pattern already contains a hit object in <paramref name="column"/></returns>
public bool IsFilled(int column) => hitObjects.Exists(h => h.Column == column);
/// <summary>
/// Amount of columns taken up by hit objects in this pattern.
/// </summary>
public int ColumnsFilled => HitObjects.GroupBy(h => h.Column).Count();
/// <summary>
/// Adds a hit object to this pattern.
/// </summary>
/// <param name="hitObject">The hit object to add.</param>
public void Add(ManiaHitObject hitObject) => hitObjects.Add(hitObject);
/// <summary>
/// Copies hit object from another pattern to this one.
/// </summary>
/// <param name="other">The other pattern.</param>
public void Add(Pattern other)
{
other.HitObjects.ForEach(Add);
}
/// <summary>
/// Clears this pattern, removing all hit objects.
/// </summary>
public void Clear() => hitObjects.Clear();
/// <summary>
/// Removes a hit object from this pattern.
/// </summary>
/// <param name="hitObject">The hit object to remove.</param>
public bool Remove(ManiaHitObject hitObject) => hitObjects.Remove(hitObject);
}
}
@@ -0,0 +1,50 @@
// 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 osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
{
/// <summary>
/// Generator to create a pattern <see cref="Pattern"/> from a hit object.
/// </summary>
internal abstract class PatternGenerator
{
/// <summary>
/// The number of columns available to create the pattern.
/// </summary>
protected readonly int AvailableColumns;
/// <summary>
/// The last pattern.
/// </summary>
protected readonly Pattern PreviousPattern;
/// <summary>
/// The hit object to create the pattern for.
/// </summary>
protected readonly HitObject HitObject;
/// <summary>
/// The beatmap which <see cref="HitObject"/> is a part of.
/// </summary>
protected readonly Beatmap Beatmap;
protected PatternGenerator(HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
{
PreviousPattern = previousPattern;
HitObject = hitObject;
Beatmap = beatmap;
AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize);
}
/// <summary>
/// Generates the pattern for <see cref="HitObject"/>, filled with hit objects.
/// </summary>
/// <returns>The <see cref="Pattern"/> containing the hit objects.</returns>
public abstract Pattern Generate();
}
}
@@ -0,0 +1,179 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Database;
namespace osu.Game.Rulesets.Mania.Judgements
{
public class HitWindows
{
#region Constants
/// <summary>
/// PERFECT hit window at OD = 10.
/// </summary>
private const double perfect_min = 27.8;
/// <summary>
/// PERFECT hit window at OD = 5.
/// </summary>
private const double perfect_mid = 38.8;
/// <summary>
/// PERFECT hit window at OD = 0.
/// </summary>
private const double perfect_max = 44.8;
/// <summary>
/// GREAT hit window at OD = 10.
/// </summary>
private const double great_min = 68;
/// <summary>
/// GREAT hit window at OD = 5.
/// </summary>
private const double great_mid = 98;
/// <summary>
/// GREAT hit window at OD = 0.
/// </summary>
private const double great_max = 128;
/// <summary>
/// GOOD hit window at OD = 10.
/// </summary>
private const double good_min = 134;
/// <summary>
/// GOOD hit window at OD = 5.
/// </summary>
private const double good_mid = 164;
/// <summary>
/// GOOD hit window at OD = 0.
/// </summary>
private const double good_max = 194;
/// <summary>
/// OK hit window at OD = 10.
/// </summary>
private const double ok_min = 194;
/// <summary>
/// OK hit window at OD = 5.
/// </summary>
private const double ok_mid = 224;
/// <summary>
/// OK hit window at OD = 0.
/// </summary>
private const double ok_max = 254;
/// <summary>
/// BAD hit window at OD = 10.
/// </summary>
private const double bad_min = 242;
/// <summary>
/// BAD hit window at OD = 5.
/// </summary>
private const double bad_mid = 272;
/// <summary>
/// BAD hit window at OD = 0.
/// </summary>
private const double bad_max = 302;
/// <summary>
/// MISS hit window at OD = 10.
/// </summary>
private const double miss_min = 316;
/// <summary>
/// MISS hit window at OD = 5.
/// </summary>
private const double miss_mid = 346;
/// <summary>
/// MISS hit window at OD = 0.
/// </summary>
private const double miss_max = 376;
#endregion
/// <summary>
/// Hit window for a PERFECT hit.
/// </summary>
public double Perfect = perfect_mid;
/// <summary>
/// Hit window for a GREAT hit.
/// </summary>
public double Great = great_mid;
/// <summary>
/// Hit window for a GOOD hit.
/// </summary>
public double Good = good_mid;
/// <summary>
/// Hit window for an OK hit.
/// </summary>
public double Ok = ok_mid;
/// <summary>
/// Hit window for a BAD hit.
/// </summary>
public double Bad = bad_mid;
/// <summary>
/// Hit window for a MISS hit.
/// </summary>
public double Miss = miss_mid;
/// <summary>
/// Constructs default hit windows.
/// </summary>
public HitWindows()
{
}
/// <summary>
/// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window.
/// </summary>
/// <param name="difficulty">The parameter.</param>
public HitWindows(double difficulty)
{
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, perfect_max, perfect_mid, perfect_min);
Great = BeatmapDifficulty.DifficultyRange(difficulty, great_max, great_mid, great_min);
Good = BeatmapDifficulty.DifficultyRange(difficulty, good_max, good_mid, good_min);
Ok = BeatmapDifficulty.DifficultyRange(difficulty, ok_max, ok_mid, ok_min);
Bad = BeatmapDifficulty.DifficultyRange(difficulty, bad_max, bad_mid, bad_min);
Miss = BeatmapDifficulty.DifficultyRange(difficulty, miss_max, miss_mid, miss_min);
}
/// <summary>
/// Constructs new hit windows which have been multiplied by a value.
/// </summary>
/// <param name="windows">The original hit windows.</param>
/// <param name="value">The value to multiply each hit window by.</param>
public static HitWindows operator *(HitWindows windows, double value)
{
return new HitWindows
{
Perfect = windows.Perfect * value,
Great = windows.Great * value,
Good = windows.Good * value,
Ok = windows.Ok * value,
Bad = windows.Bad * value,
Miss = windows.Miss * value
};
}
/// <summary>
/// Constructs new hit windows which have been divided by a value.
/// </summary>
/// <param name="windows">The original hit windows.</param>
/// <param name="value">The value to divide each hit window by.</param>
public static HitWindows operator /(HitWindows windows, double value)
{
return new HitWindows
{
Perfect = windows.Perfect / value,
Great = windows.Great / value,
Good = windows.Good / value,
Ok = windows.Ok / value,
Bad = windows.Bad / value,
Miss = windows.Miss / value
};
}
}
}
@@ -1,9 +1,9 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Modes.Judgements;
using osu.Game.Rulesets.Judgements;
namespace osu.Game.Modes.Mania.Judgements
namespace osu.Game.Rulesets.Mania.Judgements
{
public class ManiaJudgement : Judgement
{
@@ -2,13 +2,14 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Modes.Mania.Beatmaps;
using osu.Game.Modes.Mania.Objects;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using System.Collections.Generic;
namespace osu.Game.Modes.Mania
namespace osu.Game.Rulesets.Mania
{
public class ManiaDifficultyCalculator : DifficultyCalculator<ManiaBaseHit>
public class ManiaDifficultyCalculator : DifficultyCalculator<ManiaHitObject>
{
public ManiaDifficultyCalculator(Beatmap beatmap)
: base(beatmap)
@@ -20,6 +21,6 @@ namespace osu.Game.Modes.Mania
return 0;
}
protected override IBeatmapConverter<ManiaBaseHit> CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
}
}
@@ -3,20 +3,20 @@
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Modes.Mania.Mods;
using osu.Game.Modes.Mania.UI;
using osu.Game.Modes.Mods;
using osu.Game.Modes.UI;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
using System.Collections.Generic;
using osu.Game.Modes.Mania.Scoring;
using osu.Game.Modes.Scoring;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Modes.Mania
namespace osu.Game.Rulesets.Mania
{
public class ManiaRuleset : Ruleset
{
public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new ManiaHitRenderer(beatmap);
public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new ManiaHitRenderer(beatmap, isForCurrentRuleset);
public override IEnumerable<Mod> GetModsFor(ModType type)
{
@@ -96,8 +96,6 @@ namespace osu.Game.Modes.Mania
}
}
protected override PlayMode PlayMode => PlayMode.Mania;
public override string Description => "osu!mania";
public override FontAwesome Icon => FontAwesome.fa_osu_mania_o;
@@ -107,5 +105,7 @@ namespace osu.Game.Modes.Mania
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
public override int LegacyID => 3;
}
}
@@ -0,0 +1,92 @@
// 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;
namespace osu.Game.Rulesets.Mania.MathUtils
{
/// <summary>
/// A PRNG specified in http://heliosphan.org/fastrandom.html.
/// </summary>
internal class FastRandom
{
private const double uint_to_real = 1.0 / (uint.MaxValue + 1.0);
private const uint int_mask = 0x7FFFFFFF;
private const uint y = 842502087;
private const uint z = 3579807591;
private const uint w = 273326509;
private uint _x, _y = y, _z = z, _w = w;
public FastRandom(int seed)
{
_x = (uint)seed;
}
public FastRandom()
: this(Environment.TickCount)
{
}
/// <summary>
/// Generates a random unsigned integer within the range [<see cref="uint.MinValue"/>, <see cref="uint.MaxValue"/>).
/// </summary>
/// <returns>The random value.</returns>
public uint NextUInt()
{
uint t = _x ^ _x << 11;
_x = _y;
_y = _z;
_z = _w;
return _w = _w ^ _w >> 19 ^ t ^ t >> 8;
}
/// <summary>
/// Generates a random integer value within the range [0, <see cref="int.MaxValue"/>).
/// </summary>
/// <returns>The random value.</returns>
public int Next() => (int)(int_mask & NextUInt());
/// <summary>
/// Generates a random integer value within the range [0, <paramref name="upperBound"/>).
/// </summary>
/// <param name="upperBound">The upper bound.</param>
/// <returns>The random value.</returns>
public int Next(int upperBound) => (int)(NextDouble() * upperBound);
/// <summary>
/// Generates a random integer value within the range [<paramref name="lowerBound"/>, <paramref name="upperBound"/>).
/// </summary>
/// <param name="lowerBound">The lower bound of the range.</param>
/// <param name="upperBound">The upper bound of the range.</param>
/// <returns>The random value.</returns>
public int Next(int lowerBound, int upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound));
/// <summary>
/// Generates a random double value within the range [0, 1).
/// </summary>
/// <returns>The random value.</returns>
public double NextDouble() => uint_to_real * NextUInt();
private uint bitBuffer;
private int bitIndex = 32;
/// <summary>
/// Generates a reandom boolean value. Cached such that a random value is only generated once in every 32 calls.
/// </summary>
/// <returns>The random value.</returns>
public bool NextBool()
{
if (bitIndex == 32)
{
bitBuffer = NextUInt();
bitIndex = 1;
return (bitBuffer & 1) == 1;
}
bitIndex++;
return ((bitBuffer >>= 1) & 1) == 1;
}
}
}
@@ -2,10 +2,10 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Graphics;
using osu.Game.Modes.Mods;
using osu.Game.Rulesets.Mods;
using System;
namespace osu.Game.Modes.Mania.Mods
namespace osu.Game.Rulesets.Mania.Mods
{
public class ManiaModNoFail : ModNoFail
{
@@ -64,6 +64,7 @@ namespace osu.Game.Modes.Mania.Mods
{
public override string Name => "FadeIn";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
public override ModType Type => ModType.DifficultyIncrease;
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) };
@@ -0,0 +1,76 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>
{
private readonly NotePiece headPiece;
private readonly BodyPiece bodyPiece;
private readonly NotePiece tailPiece;
public DrawableHoldNote(HoldNote hitObject)
: base(hitObject)
{
RelativeSizeAxes = Axes.Both;
Height = (float)HitObject.Duration;
Add(new Drawable[]
{
// For now the body piece covers the entire height of the container
// whereas possibly in the future we don't want to extend under the head/tail.
// This will be fixed when new designs are given or the current design is finalized.
bodyPiece = new BodyPiece
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
headPiece = new NotePiece
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
},
tailPiece = new NotePiece
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.TopCentre
}
});
}
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
if (base.AccentColour == value)
return;
base.AccentColour = value;
headPiece.AccentColour = value;
bodyPiece.AccentColour = value;
tailPiece.AccentColour = value;
}
}
protected override void UpdateState(ArmedState state)
{
}
protected override void Update()
{
if (Time.Current > HitObject.StartTime)
headPiece.Colour = Color4.Green;
if (Time.Current > HitObject.EndTime)
{
bodyPiece.Colour = Color4.Green;
tailPiece.Colour = Color4.Green;
}
}
}
}
@@ -0,0 +1,38 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public abstract class DrawableManiaHitObject<TObject> : DrawableHitObject<ManiaHitObject, ManiaJudgement>
where TObject : ManiaHitObject
{
public new TObject HitObject;
protected DrawableManiaHitObject(TObject hitObject)
: base(hitObject)
{
HitObject = hitObject;
RelativePositionAxes = Axes.Y;
Y = (float)HitObject.StartTime;
}
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
if (base.AccentColour == value)
return;
base.AccentColour = value;
}
}
protected override ManiaJudgement CreateJudgement() => new ManiaJudgement();
}
}
@@ -0,0 +1,51 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public class DrawableNote : DrawableManiaHitObject<Note>
{
private readonly NotePiece headPiece;
public DrawableNote(Note hitObject)
: base(hitObject)
{
RelativeSizeAxes = Axes.Both;
Height = 100;
Add(headPiece = new NotePiece
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
});
}
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
if (base.AccentColour == value)
return;
base.AccentColour = value;
headPiece.AccentColour = value;
}
}
protected override void Update()
{
if (Time.Current > HitObject.StartTime)
Colour = Color4.Green;
}
protected override void UpdateState(ArmedState state)
{
}
}
}
@@ -0,0 +1,47 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
{
/// <summary>
/// Represents length-wise portion of a hold note.
/// </summary>
internal class BodyPiece : Container, IHasAccentColour
{
private readonly Box box;
public BodyPiece()
{
RelativeSizeAxes = Axes.Both;
Children = new[]
{
box = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.3f
}
};
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
box.Colour = accentColour;
}
}
}
}
@@ -0,0 +1,59 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
{
/// <summary>
/// Represents the static hit markers of notes.
/// </summary>
internal class NotePiece : Container, IHasAccentColour
{
private const float head_height = 10;
private const float head_colour_height = 6;
private readonly Box colouredBox;
public NotePiece()
{
RelativeSizeAxes = Axes.X;
Height = head_height;
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both
},
colouredBox = new Box
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Height = head_colour_height,
Alpha = 0.2f
}
};
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
colouredBox.Colour = AccentColour.Lighten(0.9f);
}
}
}
}
@@ -0,0 +1,37 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Mania.Objects
{
/// <summary>
/// Represents a hit object which requires pressing, holding, and releasing a key.
/// </summary>
public class HoldNote : Note, IHasEndTime
{
/// <summary>
/// Lenience of release hit windows. This is to make cases where the hold note release
/// is timed alongside presses of other hit objects less awkward.
/// </summary>
private const double release_window_lenience = 1.5;
public double Duration { get; set; }
public double EndTime => StartTime + Duration;
/// <summary>
/// The key-release hit windows for this hold note.
/// </summary>
protected HitWindows ReleaseHitWindows = new HitWindows();
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
ReleaseHitWindows = HitWindows * release_window_lenience;
}
}
}
@@ -0,0 +1,19 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mania.Objects.Types;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Objects
{
public abstract class ManiaHitObject : HitObject, IHasColumn
{
public int Column { get; set; }
/// <summary>
/// The number of other <see cref="ManiaHitObject"/> that start at
/// the same time as this hit object.
/// </summary>
public int Siblings { get; set; }
}
}
+27
View File
@@ -0,0 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps.Timing;
using osu.Game.Database;
using osu.Game.Rulesets.Mania.Judgements;
namespace osu.Game.Rulesets.Mania.Objects
{
/// <summary>
/// Represents a hit object which has a single hit press.
/// </summary>
public class Note : ManiaHitObject
{
/// <summary>
/// The key-press hit window for this note.
/// </summary>
protected HitWindows HitWindows = new HitWindows();
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
{
base.ApplyDefaults(timing, difficulty);
HitWindows = new HitWindows(difficulty.OverallDifficulty);
}
}
}
@@ -0,0 +1,16 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Mania.Objects.Types
{
/// <summary>
/// A type of hit object which lies in one of a number of predetermined columns.
/// </summary>
public interface IHasColumn
{
/// <summary>
/// The column which the hit object lies in.
/// </summary>
int Column { get; }
}
}
@@ -7,11 +7,11 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Modes.Mania")]
[assembly: AssemblyTitle("osu.Game.Rulesets.Mania")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("osu.Game.Modes.Mania")]
[assembly: AssemblyProduct("osu.Game.Rulesets.Mania")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -0,0 +1,26 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Scoring
{
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject, ManiaJudgement>
{
public ManiaScoreProcessor()
{
}
public ManiaScoreProcessor(HitRenderer<ManiaHitObject, ManiaJudgement> hitRenderer)
: base(hitRenderer)
{
}
protected override void OnNewJudgement(ManiaJudgement judgement)
{
}
}
}
@@ -0,0 +1,153 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Rulesets.Mania.Timing
{
/// <summary>
/// A container in which added drawables are put into a relative coordinate space spanned by a length of time.
/// <para>
/// This container contains <see cref="ControlPoint"/>s which scroll inside this container.
/// Drawables added to this container are moved inside the relevant <see cref="ControlPoint"/>,
/// and as such, will scroll along with the <see cref="ControlPoint"/>s.
/// </para>
/// </summary>
public class ControlPointContainer : Container<Drawable>
{
/// <summary>
/// The amount of time which this container spans.
/// </summary>
public double TimeSpan { get; set; }
private readonly List<DrawableControlPoint> drawableControlPoints;
public ControlPointContainer(IEnumerable<ControlPoint> timingChanges)
{
drawableControlPoints = timingChanges.Select(t => new DrawableControlPoint(t)).ToList();
Children = drawableControlPoints;
}
/// <summary>
/// Adds a drawable to this container. Note that the drawable added must have its Y-position be
/// an absolute unit of time that is _not_ relative to <see cref="TimeSpan"/>.
/// </summary>
/// <param name="drawable">The drawable to add.</param>
public override void Add(Drawable drawable)
{
// Always add timing sections to ourselves
if (drawable is DrawableControlPoint)
{
base.Add(drawable);
return;
}
var controlPoint = drawableControlPoints.LastOrDefault(t => t.CanContain(drawable)) ?? drawableControlPoints.FirstOrDefault();
if (controlPoint == null)
throw new Exception("Could not find suitable timing section to add object to.");
controlPoint.Add(drawable);
}
/// <summary>
/// A container that contains drawables within the time span of a timing section.
/// <para>
/// The content of this container will scroll relative to the current time.
/// </para>
/// </summary>
private class DrawableControlPoint : Container
{
private readonly ControlPoint timingChange;
protected override Container<Drawable> Content => content;
private readonly Container content;
/// <summary>
/// Creates a drawable control point. The height of this container will be proportional
/// to the beat length of the control point it is initialized with such that, e.g. a beat length
/// of 500ms results in this container being twice as high as its parent, which further means that
/// the content container will scroll at twice the normal rate.
/// </summary>
/// <param name="timingChange">The control point to create the drawable control point for.</param>
public DrawableControlPoint(ControlPoint timingChange)
{
this.timingChange = timingChange;
RelativeSizeAxes = Axes.Both;
AddInternal(content = new AutoTimeRelativeContainer
{
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Both,
Y = (float)timingChange.Time
});
}
protected override void Update()
{
var parent = (ControlPointContainer)Parent;
// Adjust our height to account for the speed changes
Height = (float)(1000 / timingChange.BeatLength / timingChange.SpeedMultiplier);
RelativeCoordinateSpace = new Vector2(1, (float)parent.TimeSpan);
// Scroll the content
content.Y = (float)(timingChange.Time - Time.Current);
}
public override void Add(Drawable drawable)
{
// The previously relatively-positioned drawable will now become relative to content, but since the drawable has no knowledge of content,
// we need to offset it back by content's position position so that it becomes correctly relatively-positioned to content
// This can be removed if hit objects were stored such that either their StartTime or their "beat offset" was relative to the timing change
// they belonged to, but this requires a radical change to the beatmap format which we're not ready to do just yet
drawable.Y -= (float)timingChange.Time;
base.Add(drawable);
}
/// <summary>
/// Whether this control point can contain a drawable. This control point can contain a drawable if the drawable is positioned "after" this control point.
/// </summary>
/// <param name="drawable">The drawable to check.</param>
public bool CanContain(Drawable drawable) => content.Y <= drawable.Y;
/// <summary>
/// A container which always keeps its height and relative coordinate space "auto-sized" to its children.
/// <para>
/// This is used in the case where children are relatively positioned/sized to time values (e.g. notes/bar lines) to keep
/// such children wrapped inside a container, otherwise they would disappear due to container flattening.
/// </para>
/// </summary>
private class AutoTimeRelativeContainer : Container
{
public override void InvalidateFromChild(Invalidation invalidation)
{
// We only want to re-compute our size when a child's size or position has changed
if ((invalidation & Invalidation.Geometry) == 0)
{
base.InvalidateFromChild(invalidation);
return;
}
if (!Children.Any())
return;
float height = Children.Select(child => child.Y + child.Height).Max();
Height = height;
RelativeCoordinateSpace = new Vector2(1, height);
base.InvalidateFromChild(invalidation);
}
}
}
}
}
+211
View File
@@ -0,0 +1,211 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Colour;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Timing;
using System.Collections.Generic;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Rulesets.Mania.UI
{
public class Column : Container, IHasAccentColour
{
private const float key_icon_size = 10;
private const float key_icon_corner_radius = 3;
private const float key_icon_border_radius = 2;
private const float hit_target_height = 10;
private const float hit_target_bar_height = 2;
private const float column_width = 45;
private const float special_column_width = 70;
public Key Key;
private readonly Box background;
private readonly Container hitTargetBar;
private readonly Container keyIcon;
public readonly ControlPointContainer ControlPointContainer;
public Column(IEnumerable<ControlPoint> timingChanges)
{
RelativeSizeAxes = Axes.Y;
Width = column_width;
Children = new Drawable[]
{
background = new Box
{
Name = "Foreground",
RelativeSizeAxes = Axes.Both,
Alpha = 0.2f
},
new Container
{
Name = "Hit target + hit objects",
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION},
Children = new Drawable[]
{
new Container
{
Name = "Hit target",
RelativeSizeAxes = Axes.X,
Height = hit_target_height,
Children = new Drawable[]
{
new Box
{
Name = "Background",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black
},
hitTargetBar = new Container
{
Name = "Bar",
RelativeSizeAxes = Axes.X,
Height = hit_target_bar_height,
Masking = true,
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both
}
}
}
}
},
ControlPointContainer = new ControlPointContainer(timingChanges)
{
Name = "Hit objects",
RelativeSizeAxes = Axes.Both,
},
}
},
new Container
{
Name = "Key",
RelativeSizeAxes = Axes.X,
Height = ManiaPlayfield.HIT_TARGET_POSITION,
Children = new Drawable[]
{
new Box
{
Name = "Key gradient",
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0)),
Alpha = 0.5f
},
keyIcon = new Container
{
Name = "Key icon",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(key_icon_size),
Masking = true,
CornerRadius = key_icon_corner_radius,
BorderThickness = 2,
BorderColour = Color4.White, // Not true
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
}
}
}
}
}
};
}
private bool isSpecial;
public bool IsSpecial
{
get { return isSpecial; }
set
{
if (isSpecial == value)
return;
isSpecial = value;
Width = isSpecial ? special_column_width : column_width;
}
}
private Color4 accentColour;
public Color4 AccentColour
{
get { return accentColour; }
set
{
if (accentColour == value)
return;
accentColour = value;
background.Colour = accentColour;
hitTargetBar.EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = accentColour.Opacity(0.5f),
};
keyIcon.EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Glow,
Radius = 5,
Colour = accentColour.Opacity(0.5f),
};
}
}
public void Add(DrawableHitObject<ManiaHitObject, ManiaJudgement> hitObject)
{
ControlPointContainer.Add(hitObject);
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat)
return false;
if (args.Key == Key)
{
background.FadeTo(background.Alpha + 0.2f, 50, EasingTypes.OutQuint);
keyIcon.ScaleTo(1.4f, 50, EasingTypes.OutQuint);
}
return false;
}
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
{
if (args.Key == Key)
{
background.FadeTo(0.2f, 800, EasingTypes.OutQuart);
keyIcon.ScaleTo(1f, 400, EasingTypes.OutQuart);
}
return false;
}
}
}
@@ -0,0 +1,92 @@
// 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 OpenTK;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.UI
{
public class ManiaHitRenderer : HitRenderer<ManiaHitObject, ManiaJudgement>
{
public int? Columns;
public ManiaHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(beatmap, isForCurrentRuleset)
{
}
protected override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield()
{
ControlPoint firstTimingChange = Beatmap.TimingInfo.ControlPoints.FirstOrDefault(t => t.TimingChange);
if (firstTimingChange == null)
throw new Exception("The Beatmap contains no timing points!");
// Generate the timing points, making non-timing changes use the previous timing change
var timingChanges = Beatmap.TimingInfo.ControlPoints.Select(c =>
{
ControlPoint t = c.Clone();
if (c.TimingChange)
firstTimingChange = c;
else
t.BeatLength = firstTimingChange.BeatLength;
return t;
});
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
// Perform some post processing of the timing changes
timingChanges = timingChanges
// Collapse sections after the last hit object
.Where(s => s.Time <= lastObjectTime)
// Collapse sections with the same start time
.GroupBy(s => s.Time).Select(g => g.Last()).OrderBy(s => s.Time)
// Collapse sections with the same beat length
.GroupBy(s => s.BeatLength * s.SpeedMultiplier).Select(g => g.First())
.ToList();
return new ManiaPlayfield(Columns ?? (int)Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize), timingChanges)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
// Invert by default for now (should be moved to config/skin later)
Scale = new Vector2(1, -1)
};
}
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override DrawableHitObject<ManiaHitObject, ManiaJudgement> GetVisualRepresentation(ManiaHitObject h)
{
var holdNote = h as HoldNote;
if (holdNote != null)
return new DrawableHoldNote(holdNote);
var note = h as Note;
if (note != null)
return new DrawableNote(note);
return null;
}
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f);
}
}

Some files were not shown because too many files have changed in this diff Show More