Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Matchmaking.Events;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
using osu.Game.Online.Rooms;
Expand Down Expand Up @@ -158,5 +160,64 @@ public void ChangeRankings()
MultiplayerClient.ChangeMatchRoomState(state).WaitSafely();
});
}

[Test]
public void InteractionSpam()
{
AddStep("join users", () =>
{
for (int i = 0; i < 7; i++)
{
MultiplayerClient.AddUser(new MultiplayerRoomUser(i)
{
User = new APIUser
{
Username = $"User {i}"
}
});
}
});
AddStep("change to grid mode", () => list.DisplayStyle = PanelDisplayStyle.Grid);
AddStep("player jump", () => { MultiplayerClient.SendUserMatchRequest(1001, new MatchmakingAvatarActionRequest { Action = MatchmakingAvatarAction.Jump }).WaitSafely(); });
AddStep("local jumping", () => jumpSpam(false));
AddWaitStep("wait", 25);
AddStep("group jumping spam", () => jumpSpam(true));
AddWaitStep("wait", 25);

AddStep("change to split mode", () => list.DisplayStyle = PanelDisplayStyle.Split);
AddStep("local jumping", () => jumpSpam(false));
AddWaitStep("wait", 25);
AddStep("group jumping spam", () => jumpSpam(true));
AddWaitStep("wait", 25);

AddStep("change to hidden mode", () => list.DisplayStyle = PanelDisplayStyle.Hidden);
AddStep("local jumping", () => jumpSpam(false));
AddWaitStep("wait", 25);
AddStep("group jumping spam", () => jumpSpam(true));
AddWaitStep("wait", 25);
}

private void jumpSpam(bool everyone)
{
for (int i = 0; i < 30; i++)
{
Scheduler.AddDelayed(() =>
{
MultiplayerClient.SendUserMatchRequest(1001, new MatchmakingAvatarActionRequest { Action = MatchmakingAvatarAction.Jump }).WaitSafely();
}, i * 150 + RNG.NextDouble(0, 140));

if (!everyone)
continue;

for (int ii = 0; ii < 7; ii++)
{
int iii = ii;
Scheduler.AddDelayed(() =>
{
MultiplayerClient.SendUserMatchRequest(iii, new MatchmakingAvatarActionRequest { Action = MatchmakingAvatarAction.Jump }).WaitSafely();
}, i * 150 + RNG.NextDouble(0, 140));
}
}
}
}
}
70 changes: 69 additions & 1 deletion osu.Game/Screens/OnlinePlay/Matchmaking/Match/PlayerPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Linq;
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
Expand All @@ -15,6 +17,7 @@
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Screens;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
Expand Down Expand Up @@ -114,6 +117,18 @@ public partial class PlayerPanel : OsuClickableContainer, IHasContextMenu
private PlayerPanelDisplayMode displayMode = PlayerPanelDisplayMode.Horizontal;
private bool hasQuit;

private enum InteractionSampleType
{
PlayerJump,
PlayerReJump,
OtherPlayerJump,
}

private Dictionary<InteractionSampleType, Sample?> interactionSamples = new Dictionary<InteractionSampleType, Sample?>();
private readonly Dictionary<InteractionSampleType, SampleChannel?> interactionSampleChannels = new Dictionary<InteractionSampleType, SampleChannel?>();
private double samplePitch;
private double? lastSamplePlayback;

public PlayerPanel(MultiplayerRoomUser user)
: base(HoverSampleSet.Button)
{
Expand All @@ -130,7 +145,7 @@ public PlayerPanel(MultiplayerRoomUser user)
}

[BackgroundDependencyLoader]
private void load()
private void load(AudioManager audio)
{
Content.Masking = true;
Content.CornerRadius = 10;
Expand Down Expand Up @@ -255,6 +270,13 @@ private void load()

// Allow avatar to exist outside of masking for when it jumps around and stuff.
AddInternal(avatar.CreateProxy());

interactionSamples = new Dictionary<InteractionSampleType, Sample?>
{
{ InteractionSampleType.PlayerJump, audio.Samples.Get(@"Multiplayer/Matchmaking/player-jump") },
{ InteractionSampleType.PlayerReJump, audio.Samples.Get(@"Multiplayer/Matchmaking/player-rejump") },
{ InteractionSampleType.OtherPlayerJump, audio.Samples.Get(@"Multiplayer/Matchmaking/player-jump-other") }
};
}

protected override void LoadComplete()
Expand All @@ -272,6 +294,9 @@ protected override void LoadComplete()
avatar.ScaleTo(0)
.ScaleTo(1, 500, Easing.OutElasticHalf)
.FadeIn(200);

// pick a random pitch to be used by the player for duration of this session
samplePitch = 0.75f + RNG.NextDouble(0f, 0.75f);
}

public PlayerPanelDisplayMode DisplayMode
Expand Down Expand Up @@ -481,6 +506,11 @@ private void onMatchEvent(MatchServerEvent e)
scale.Then().ScaleTo(new Vector2(1, 1.05f), 200, Easing.Out)
.Then().ScaleTo(new Vector2(1, 0.95f), 200, Easing.In)
.Then().ScaleTo(Vector2.One, 800, Easing.OutElastic);

// only play jump sample if panel is visible
if (Alpha > 0)
playJumpSample(isConsecutive);

break;
}

Expand All @@ -498,6 +528,44 @@ private void onBeatmapAvailabilityChanged(MultiplayerRoomUser user, BeatmapAvail
downloadProgressBar.ResizeWidthTo(availability.DownloadProgress ?? 0, 200, Easing.OutPow10);
});

private void playJumpSample(bool rejumping)
{
bool isLocalUser = User.OnlineID == client.LocalUser?.UserID;

if (isLocalUser)
playInteractionSample(rejumping ? InteractionSampleType.PlayerReJump : InteractionSampleType.PlayerJump);
else
playInteractionSample(InteractionSampleType.OtherPlayerJump);
}

private void playInteractionSample(InteractionSampleType sampleType)
{
bool enoughTimePassedSinceLastPlayback = lastSamplePlayback == null || Time.Current - lastSamplePlayback.Value >= OsuGameBase.SAMPLE_DEBOUNCE_TIME;
if (!enoughTimePassedSinceLastPlayback)
return;

Sample? targetSample = interactionSamples[sampleType];
SampleChannel? targetChannel = interactionSampleChannels.GetValueOrDefault(sampleType);

targetChannel?.Stop();
targetChannel = targetSample?.GetChannel();

if (targetChannel == null)
return;

float horizontalPos = BoundingBox.Centre.X / Parent!.ToLocalSpace(Parent!.ScreenSpaceDrawQuad).Width;
// rescale balance from 0..1 to -1..1
float balance = -1f + horizontalPos * 2f;

targetChannel.Frequency.Value = samplePitch;
targetChannel.Balance.Value = balance * OsuGameBase.SFX_STEREO_STRENGTH;
targetChannel.Play();

interactionSampleChannels[sampleType] = targetChannel;

lastSamplePlayback = Time.Current;
}

protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Expand Down