1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 06:17:23 +08:00

Merge branch 'master' into multi-polling-request-refactor

This commit is contained in:
Dean Herbert 2021-08-17 16:23:46 +09:00 committed by GitHub
commit a901fca54a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 133 additions and 43 deletions

View File

@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Difficulty.Skills
{
public class Movement : StrainSkill
public class Movement : StrainDecaySkill
{
private const float absolute_player_positioning_error = 16f;
private const float normalized_hitobject_radius = 41.0f;

View File

@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Mania.Difficulty.Skills
{
public class Strain : StrainSkill
public class Strain : StrainDecaySkill
{
private const double individual_decay_base = 0.125;
private const double overall_decay_base = 0.30;
@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills
return individualStrain + overallStrain - CurrentStrain;
}
protected override double GetPeakStrain(double offset)
protected override double CalculateInitialStrain(double offset)
=> applyDecay(individualStrain, offset - Previous[0].StartTime, individual_decay_base)
+ applyDecay(overallStrain, offset - Previous[0].StartTime, overall_decay_base);

View File

@ -10,7 +10,7 @@ using osu.Framework.Utils;
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
{
public abstract class OsuStrainSkill : StrainSkill
public abstract class OsuStrainSkill : StrainDecaySkill
{
/// <summary>
/// The number of sections with the highest strains, which the peak strain reductions will apply to.

View File

@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
/// <summary>
/// Calculates the colour coefficient of taiko difficulty.
/// </summary>
public class Colour : StrainSkill
public class Colour : StrainDecaySkill
{
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.4;

View File

@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
/// <summary>
/// Calculates the rhythm coefficient of taiko difficulty.
/// </summary>
public class Rhythm : StrainSkill
public class Rhythm : StrainDecaySkill
{
protected override double SkillMultiplier => 10;
protected override double StrainDecayBase => 0;

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
/// <remarks>
/// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit).
/// </remarks>
public class Stamina : StrainSkill
public class Stamina : StrainDecaySkill
{
protected override double SkillMultiplier => 1;
protected override double StrainDecayBase => 0.4;

View File

@ -6,13 +6,17 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Play.PlayerSettings;
using osu.Game.Tests.Beatmaps.IO;
using osu.Game.Users;
@ -23,6 +27,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Resolved]
private OsuGameBase game { get; set; }
[Resolved]
private OsuConfigManager config { get; set; }
[Resolved]
private BeatmapManager beatmapManager { get; set; }
@ -80,6 +87,32 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddWaitStep("wait a bit", 20);
}
[Test]
public void TestSpectatorPlayerInteractiveElementsHidden()
{
HUDVisibilityMode originalConfigValue = default;
AddStep("get original config hud visibility", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
AddStep("set config hud visibility to always", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always));
start(new[] { PLAYER_1_ID, PLAYER_2_ID });
loadSpectateScreen(false);
AddUntilStep("wait for player loaders", () => this.ChildrenOfType<PlayerLoader>().Count() == 2);
AddAssert("all player loader settings hidden", () => this.ChildrenOfType<PlayerLoader>().All(l => !l.ChildrenOfType<FillFlowContainer<PlayerSettingsGroup>>().Any()));
AddUntilStep("wait for players to load", () => spectatorScreen.AllPlayersLoaded);
// components wrapped in skinnable target containers load asynchronously, potentially taking more than one frame to load.
// therefore use until step rather than direct assert to account for that.
AddUntilStep("all interactive elements removed", () => this.ChildrenOfType<Player>().All(p =>
!p.ChildrenOfType<PlayerSettingsOverlay>().Any() &&
!p.ChildrenOfType<HoldForMenuButton>().Any() &&
p.ChildrenOfType<SongProgressBar>().SingleOrDefault()?.ShowHandle == false));
AddStep("restore config hud visibility", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
}
[Test]
public void TestTeamDisplay()
{

View File

@ -0,0 +1,54 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Difficulty.Skills
{
/// <summary>
/// Used to processes strain values of <see cref="DifficultyHitObject"/>s, keep track of strain levels caused by the processed objects
/// and to calculate a final difficulty value representing the difficulty of hitting all the processed objects.
/// </summary>
public abstract class StrainDecaySkill : StrainSkill
{
/// <summary>
/// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
/// </summary>
protected abstract double SkillMultiplier { get; }
/// <summary>
/// Determines how quickly strain decays for the given skill.
/// For example a value of 0.15 indicates that strain decays to 15% of its original value in one second.
/// </summary>
protected abstract double StrainDecayBase { get; }
/// <summary>
/// The current strain level.
/// </summary>
protected double CurrentStrain { get; private set; } = 1;
protected StrainDecaySkill(Mod[] mods)
: base(mods)
{
}
protected override double CalculateInitialStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime);
protected override double StrainValueAt(DifficultyHitObject current)
{
CurrentStrain *= strainDecay(current.DeltaTime);
CurrentStrain += StrainValueOf(current) * SkillMultiplier;
return CurrentStrain;
}
/// <summary>
/// Calculates the strain value of a <see cref="DifficultyHitObject"/>. This value is affected by previously processed objects.
/// </summary>
protected abstract double StrainValueOf(DifficultyHitObject current);
private double strainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000);
}
}

View File

@ -15,27 +15,11 @@ namespace osu.Game.Rulesets.Difficulty.Skills
/// </summary>
public abstract class StrainSkill : Skill
{
/// <summary>
/// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other.
/// </summary>
protected abstract double SkillMultiplier { get; }
/// <summary>
/// Determines how quickly strain decays for the given skill.
/// For example a value of 0.15 indicates that strain decays to 15% of its original value in one second.
/// </summary>
protected abstract double StrainDecayBase { get; }
/// <summary>
/// The weight by which each strain value decays.
/// </summary>
protected virtual double DecayWeight => 0.9;
/// <summary>
/// The current strain level.
/// </summary>
protected double CurrentStrain { get; private set; } = 1;
/// <summary>
/// The length of each strain section.
/// </summary>
@ -52,6 +36,11 @@ namespace osu.Game.Rulesets.Difficulty.Skills
{
}
/// <summary>
/// Returns the strain value at <see cref="DifficultyHitObject"/>. This value is calculated with or without respect to previous objects.
/// </summary>
protected abstract double StrainValueAt(DifficultyHitObject current);
/// <summary>
/// Process a <see cref="DifficultyHitObject"/> and update current strain values accordingly.
/// </summary>
@ -68,10 +57,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills
currentSectionEnd += SectionLength;
}
CurrentStrain *= strainDecay(current.DeltaTime);
CurrentStrain += StrainValueOf(current) * SkillMultiplier;
currentSectionPeak = Math.Max(CurrentStrain, currentSectionPeak);
currentSectionPeak = Math.Max(StrainValueAt(current), currentSectionPeak);
}
/// <summary>
@ -88,9 +74,9 @@ namespace osu.Game.Rulesets.Difficulty.Skills
/// <param name="time">The beginning of the new section in milliseconds.</param>
private void startNewSectionFrom(double time)
{
// The maximum strain of the new section is not zero by default, strain decays as usual regardless of section boundaries.
// The maximum strain of the new section is not zero by default
// This means we need to capture the strain level at the beginning of the new section, and use that as the initial peak level.
currentSectionPeak = GetPeakStrain(time);
currentSectionPeak = CalculateInitialStrain(time);
}
/// <summary>
@ -98,7 +84,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills
/// </summary>
/// <param name="time">The time to retrieve the peak strain at.</param>
/// <returns>The peak strain.</returns>
protected virtual double GetPeakStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime);
protected abstract double CalculateInitialStrain(double time);
/// <summary>
/// Returns a live enumerable of the peak strains for each <see cref="SectionLength"/> section of the beatmap,
@ -124,12 +110,5 @@ namespace osu.Game.Rulesets.Difficulty.Skills
return difficulty;
}
/// <summary>
/// Calculates the strain value of a <see cref="DifficultyHitObject"/>. This value is affected by previously processed objects.
/// </summary>
protected abstract double StrainValueOf(DifficultyHitObject current);
private double strainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000);
}
}

View File

@ -41,11 +41,13 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
protected override void PopIn()
{
base.PopIn();
Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint);
}
protected override void PopOut()
{
base.PopOut();
Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine);
}

View File

@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// <param name="score">The score containing the player's replay.</param>
/// <param name="spectatorPlayerClock">The clock controlling the gameplay running state.</param>
public MultiSpectatorPlayer([NotNull] Score score, [NotNull] ISpectatorPlayerClock spectatorPlayerClock)
: base(score)
: base(score, new PlayerConfiguration { AllowUserInteraction = false })
{
this.spectatorPlayerClock = spectatorPlayerClock;
}
@ -34,6 +34,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
private void load()
{
spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames);
HUDOverlay.PlayerSettingsOverlay.Expire();
HUDOverlay.HoldToQuit.Expire();
}
protected override void UpdateAfterChildren()

View File

@ -3,6 +3,7 @@
using System;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Game.Scoring;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
@ -19,6 +20,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
{
}
[BackgroundDependencyLoader]
private void load()
{
PlayerSettings.Expire();
}
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
}

View File

@ -20,6 +20,11 @@ namespace osu.Game.Screens.Play
/// </summary>
public bool AllowRestart { get; set; } = true;
/// <summary>
/// Whether the player should be able to interact with this player instance.
/// </summary>
public bool AllowUserInteraction { get; set; } = true;
/// <summary>
/// Whether the player should be allowed to skip intros/outros, advancing to the start of gameplay or the end of a storyboard.
/// </summary>

View File

@ -46,9 +46,14 @@ namespace osu.Game.Screens.Play
protected override bool PlayResumeSound => false;
protected BeatmapMetadataDisplay MetadataInfo;
protected BeatmapMetadataDisplay MetadataInfo { get; private set; }
protected VisualSettings VisualSettings;
/// <summary>
/// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader.
/// </summary>
protected FillFlowContainer<PlayerSettingsGroup> PlayerSettings { get; private set; }
protected VisualSettings VisualSettings { get; private set; }
protected Task LoadTask { get; private set; }
@ -140,7 +145,7 @@ namespace osu.Game.Screens.Play
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
new FillFlowContainer<PlayerSettingsGroup>
PlayerSettings = new FillFlowContainer<PlayerSettingsGroup>
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,

View File

@ -119,7 +119,8 @@ namespace osu.Game.Screens.Play
if (drawableRuleset != null)
{
AllowSeeking.BindTo(drawableRuleset.HasReplayLoaded);
if (player?.Configuration.AllowUserInteraction == true)
((IBindable<bool>)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded);
referenceClock = drawableRuleset.FrameStableClock;
Objects = drawableRuleset.Objects;

View File

@ -23,7 +23,8 @@ namespace osu.Game.Screens.Play
protected override bool CheckModsAllowFailure() => false; // todo: better support starting mid-way through beatmap
public SpectatorPlayer(Score score)
public SpectatorPlayer(Score score, PlayerConfiguration configuration = null)
: base(configuration)
{
this.score = score;
}