mirror of
https://github.com/osukey/osukey.git
synced 2025-05-29 17:37:23 +09:00
Merge branch 'master' into change-default-hover-click-sample
This commit is contained in:
commit
9c6c1dd237
@ -33,13 +33,13 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
|
|
||||||
private class MouseInputHelper : Drawable, IKeyBindingHandler<CatchAction>, IRequireHighFrequencyMousePosition
|
private class MouseInputHelper : Drawable, IKeyBindingHandler<CatchAction>, IRequireHighFrequencyMousePosition
|
||||||
{
|
{
|
||||||
private readonly Catcher catcher;
|
private readonly CatcherArea catcherArea;
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
public MouseInputHelper(CatchPlayfield playfield)
|
public MouseInputHelper(CatchPlayfield playfield)
|
||||||
{
|
{
|
||||||
catcher = playfield.CatcherArea.MovableCatcher;
|
catcherArea = playfield.CatcherArea;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
{
|
{
|
||||||
catcher.UpdatePosition(e.MousePosition.X / DrawSize.X * CatchPlayfield.WIDTH);
|
catcherArea.SetCatcherPosition(e.MousePosition.X / DrawSize.X * CatchPlayfield.WIDTH);
|
||||||
return base.OnMouseMove(e);
|
return base.OnMouseMove(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Pooling;
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -26,7 +25,7 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class Catcher : SkinReloadableDrawable, IKeyBindingHandler<CatchAction>
|
public class Catcher : SkinReloadableDrawable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail
|
/// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail
|
||||||
@ -54,6 +53,11 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const double BASE_SPEED = 1.0;
|
public const double BASE_SPEED = 1.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current speed of the catcher.
|
||||||
|
/// </summary>
|
||||||
|
public double Speed => (Dashing ? 1 : 0.5) * BASE_SPEED * hyperDashModifier;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount by which caught fruit should be offset from the plate surface to make them look visually "caught".
|
/// The amount by which caught fruit should be offset from the plate surface to make them look visually "caught".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -96,7 +100,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
public bool Dashing
|
public bool Dashing
|
||||||
{
|
{
|
||||||
get => dashing;
|
get => dashing;
|
||||||
protected set
|
set
|
||||||
{
|
{
|
||||||
if (value == dashing) return;
|
if (value == dashing) return;
|
||||||
|
|
||||||
@ -106,6 +110,12 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Direction VisualDirection
|
||||||
|
{
|
||||||
|
get => Scale.X > 0 ? Direction.Right : Direction.Left;
|
||||||
|
set => Scale = new Vector2((value == Direction.Right ? 1 : -1) * Math.Abs(Scale.X), Scale.Y);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the area that can be used to attempt catches during gameplay.
|
/// Width of the area that can be used to attempt catches during gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -116,8 +126,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
|
private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||||
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
|
private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR;
|
||||||
|
|
||||||
private int currentDirection;
|
|
||||||
|
|
||||||
private double hyperDashModifier = 1;
|
private double hyperDashModifier = 1;
|
||||||
private int hyperDashDirection;
|
private int hyperDashDirection;
|
||||||
private float hyperDashTargetPosition;
|
private float hyperDashTargetPosition;
|
||||||
@ -315,55 +323,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdatePosition(float position)
|
|
||||||
{
|
|
||||||
position = Math.Clamp(position, 0, CatchPlayfield.WIDTH);
|
|
||||||
|
|
||||||
if (position == X)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y);
|
|
||||||
X = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnPressed(CatchAction action)
|
|
||||||
{
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case CatchAction.MoveLeft:
|
|
||||||
currentDirection--;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case CatchAction.MoveRight:
|
|
||||||
currentDirection++;
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case CatchAction.Dash:
|
|
||||||
Dashing = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnReleased(CatchAction action)
|
|
||||||
{
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case CatchAction.MoveLeft:
|
|
||||||
currentDirection++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CatchAction.MoveRight:
|
|
||||||
currentDirection--;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CatchAction.Dash:
|
|
||||||
Dashing = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Drop any fruit off the plate.
|
/// Drop any fruit off the plate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -405,15 +364,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (currentDirection == 0) return;
|
|
||||||
|
|
||||||
var direction = Math.Sign(currentDirection);
|
|
||||||
|
|
||||||
var dashModifier = Dashing ? 1 : 0.5;
|
|
||||||
var speed = BASE_SPEED * dashModifier * hyperDashModifier;
|
|
||||||
|
|
||||||
UpdatePosition((float)(X + direction * Clock.ElapsedFrameTime * speed));
|
|
||||||
|
|
||||||
// Correct overshooting.
|
// Correct overshooting.
|
||||||
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
|
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
|
||||||
(hyperDashDirection < 0 && hyperDashTargetPosition > X))
|
(hyperDashDirection < 0 && hyperDashTargetPosition > X))
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
@ -14,13 +16,20 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class CatcherArea : Container
|
public class CatcherArea : Container, IKeyBindingHandler<CatchAction>
|
||||||
{
|
{
|
||||||
public const float CATCHER_SIZE = 106.75f;
|
public const float CATCHER_SIZE = 106.75f;
|
||||||
|
|
||||||
public readonly Catcher MovableCatcher;
|
public readonly Catcher MovableCatcher;
|
||||||
private readonly CatchComboDisplay comboDisplay;
|
private readonly CatchComboDisplay comboDisplay;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <c>-1</c> when only left button is pressed.
|
||||||
|
/// <c>1</c> when only right button is pressed.
|
||||||
|
/// <c>0</c> when none or both left and right buttons are pressed.
|
||||||
|
/// </summary>
|
||||||
|
private int currentDirection;
|
||||||
|
|
||||||
public CatcherArea(Container<CaughtObject> droppedObjectContainer, BeatmapDifficulty difficulty = null)
|
public CatcherArea(Container<CaughtObject> droppedObjectContainer, BeatmapDifficulty difficulty = null)
|
||||||
{
|
{
|
||||||
Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE);
|
Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE);
|
||||||
@ -63,16 +72,73 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
MovableCatcher.OnRevertResult(hitObject, result);
|
MovableCatcher.OnRevertResult(hitObject, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
var replayState = (GetContainingInputManager().CurrentState as RulesetInputManagerInputState<CatchAction>)?.LastReplayState as CatchFramedReplayInputHandler.CatchReplayState;
|
||||||
|
|
||||||
|
SetCatcherPosition(
|
||||||
|
replayState?.CatcherX ??
|
||||||
|
(float)(MovableCatcher.X + MovableCatcher.Speed * currentDirection * Clock.ElapsedFrameTime));
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
var state = (GetContainingInputManager().CurrentState as RulesetInputManagerInputState<CatchAction>)?.LastReplayState as CatchFramedReplayInputHandler.CatchReplayState;
|
|
||||||
|
|
||||||
if (state?.CatcherX != null)
|
|
||||||
MovableCatcher.X = state.CatcherX.Value;
|
|
||||||
|
|
||||||
comboDisplay.X = MovableCatcher.X;
|
comboDisplay.X = MovableCatcher.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetCatcherPosition(float X)
|
||||||
|
{
|
||||||
|
float lastPosition = MovableCatcher.X;
|
||||||
|
float newPosition = Math.Clamp(X, 0, CatchPlayfield.WIDTH);
|
||||||
|
|
||||||
|
MovableCatcher.X = newPosition;
|
||||||
|
|
||||||
|
if (lastPosition < newPosition)
|
||||||
|
MovableCatcher.VisualDirection = Direction.Right;
|
||||||
|
else if (lastPosition > newPosition)
|
||||||
|
MovableCatcher.VisualDirection = Direction.Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(CatchAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case CatchAction.MoveLeft:
|
||||||
|
currentDirection--;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case CatchAction.MoveRight:
|
||||||
|
currentDirection++;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case CatchAction.Dash:
|
||||||
|
MovableCatcher.Dashing = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(CatchAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case CatchAction.MoveLeft:
|
||||||
|
currentDirection++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CatchAction.MoveRight:
|
||||||
|
currentDirection--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CatchAction.Dash:
|
||||||
|
MovableCatcher.Dashing = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
osu.Game.Rulesets.Catch/UI/Direction.cs
Normal file
11
osu.Game.Rulesets.Catch/UI/Direction.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
|
{
|
||||||
|
public enum Direction
|
||||||
|
{
|
||||||
|
Right = 1,
|
||||||
|
Left = -1
|
||||||
|
}
|
||||||
|
}
|
BIN
osu.Game.Tests/Resources/special-skin/scorebar-bg.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 250 B |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-0.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-1.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-2.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-3.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-colour-3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
osu.Game.Tests/Resources/special-skin/scorebar-marker.png
Normal file
BIN
osu.Game.Tests/Resources/special-skin/scorebar-marker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 126 B |
240
osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs
Normal file
240
osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public class TestSceneMessageNotifier : OsuManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
private User friend;
|
||||||
|
private Channel publicChannel;
|
||||||
|
private Channel privateMessageChannel;
|
||||||
|
private TestContainer testContainer;
|
||||||
|
|
||||||
|
private int messageIdCounter;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
if (API is DummyAPIAccess daa)
|
||||||
|
{
|
||||||
|
daa.HandleRequest = dummyAPIHandleRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend = new User { Id = 0, Username = "Friend" };
|
||||||
|
publicChannel = new Channel { Id = 1, Name = "osu" };
|
||||||
|
privateMessageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM };
|
||||||
|
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
Child = testContainer = new TestContainer(new[] { publicChannel, privateMessageChannel })
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
};
|
||||||
|
|
||||||
|
testContainer.ChatOverlay.Show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool dummyAPIHandleRequest(APIRequest request)
|
||||||
|
{
|
||||||
|
switch (request)
|
||||||
|
{
|
||||||
|
case GetMessagesRequest messagesRequest:
|
||||||
|
messagesRequest.TriggerSuccess(new List<Message>(0));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case CreateChannelRequest createChannelRequest:
|
||||||
|
var apiChatChannel = new APIChatChannel
|
||||||
|
{
|
||||||
|
RecentMessages = new List<Message>(0),
|
||||||
|
ChannelID = (int)createChannelRequest.Channel.Id
|
||||||
|
};
|
||||||
|
createChannelRequest.TriggerSuccess(apiChatChannel);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ListChannelsRequest listChannelsRequest:
|
||||||
|
listChannelsRequest.TriggerSuccess(new List<Channel>(1) { publicChannel });
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GetUpdatesRequest updatesRequest:
|
||||||
|
updatesRequest.TriggerSuccess(new GetUpdatesResponse
|
||||||
|
{
|
||||||
|
Messages = new List<Message>(0),
|
||||||
|
Presence = new List<Channel>(0)
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case JoinChannelRequest joinChannelRequest:
|
||||||
|
joinChannelRequest.TriggerSuccess();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPublicChannelMention()
|
||||||
|
{
|
||||||
|
AddStep("switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel);
|
||||||
|
|
||||||
|
AddStep("receive public message", () => receiveMessage(friend, publicChannel, "Hello everyone"));
|
||||||
|
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
|
||||||
|
|
||||||
|
AddStep("receive message containing mention", () => receiveMessage(friend, publicChannel, $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!"));
|
||||||
|
AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1);
|
||||||
|
|
||||||
|
AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show());
|
||||||
|
AddStep("click notification", clickNotification<MessageNotifier.MentionNotification>);
|
||||||
|
|
||||||
|
AddAssert("chat overlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible);
|
||||||
|
AddAssert("public channel is selected", () => testContainer.ChannelManager.CurrentChannel.Value == publicChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPrivateMessageNotification()
|
||||||
|
{
|
||||||
|
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
|
||||||
|
|
||||||
|
AddStep("receive PM", () => receiveMessage(friend, privateMessageChannel, $"Hello {API.LocalUser.Value.Username}"));
|
||||||
|
AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1);
|
||||||
|
|
||||||
|
AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show());
|
||||||
|
AddStep("click notification", clickNotification<MessageNotifier.PrivateMessageNotification>);
|
||||||
|
|
||||||
|
AddAssert("chat overlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible);
|
||||||
|
AddAssert("PM channel is selected", () => testContainer.ChannelManager.CurrentChannel.Value == privateMessageChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoNotificationWhenPMChannelOpen()
|
||||||
|
{
|
||||||
|
AddStep("switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel);
|
||||||
|
|
||||||
|
AddStep("receive PM", () => receiveMessage(friend, privateMessageChannel, "you're reading this, right?"));
|
||||||
|
|
||||||
|
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoNotificationWhenMentionedInOpenPublicChannel()
|
||||||
|
{
|
||||||
|
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
|
||||||
|
|
||||||
|
AddStep("receive mention", () => receiveMessage(friend, publicChannel, $"{API.LocalUser.Value.Username.ToUpperInvariant()} has been reading this"));
|
||||||
|
|
||||||
|
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoNotificationOnSelfMention()
|
||||||
|
{
|
||||||
|
AddStep("switch to PM channel", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel);
|
||||||
|
|
||||||
|
AddStep("receive self-mention", () => receiveMessage(API.LocalUser.Value, publicChannel, $"my name is {API.LocalUser.Value.Username}"));
|
||||||
|
|
||||||
|
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNoNotificationOnPMFromSelf()
|
||||||
|
{
|
||||||
|
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
|
||||||
|
|
||||||
|
AddStep("receive PM from self", () => receiveMessage(API.LocalUser.Value, privateMessageChannel, "hey hey"));
|
||||||
|
|
||||||
|
AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNotificationsNotFiredTwice()
|
||||||
|
{
|
||||||
|
AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel);
|
||||||
|
|
||||||
|
AddStep("receive same PM twice", () =>
|
||||||
|
{
|
||||||
|
var message = createMessage(friend, privateMessageChannel, "hey hey");
|
||||||
|
privateMessageChannel.AddNewMessages(message, message);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show());
|
||||||
|
AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveMessage(User sender, Channel channel, string content) => channel.AddNewMessages(createMessage(sender, channel, content));
|
||||||
|
|
||||||
|
private Message createMessage(User sender, Channel channel, string content) => new Message(messageIdCounter++)
|
||||||
|
{
|
||||||
|
Content = content,
|
||||||
|
Sender = sender,
|
||||||
|
ChannelId = channel.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
private void clickNotification<T>() where T : Notification
|
||||||
|
{
|
||||||
|
var notification = testContainer.NotificationOverlay.ChildrenOfType<T>().Single();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(notification);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestContainer : Container
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
public ChannelManager ChannelManager { get; } = new ChannelManager();
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
};
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
public ChatOverlay ChatOverlay { get; } = new ChatOverlay();
|
||||||
|
|
||||||
|
private readonly MessageNotifier messageNotifier = new MessageNotifier();
|
||||||
|
|
||||||
|
private readonly Channel[] channels;
|
||||||
|
|
||||||
|
public TestContainer(Channel[] channels)
|
||||||
|
{
|
||||||
|
this.channels = channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
ChannelManager,
|
||||||
|
ChatOverlay,
|
||||||
|
NotificationOverlay,
|
||||||
|
messageNotifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
((BindableList<Channel>)ChannelManager.AvailableChannels).AddRange(channels);
|
||||||
|
|
||||||
|
foreach (var channel in channels)
|
||||||
|
ChannelManager.JoinChannel(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -61,6 +61,9 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
SetDefault(OsuSetting.ShowOnlineExplicitContent, false);
|
SetDefault(OsuSetting.ShowOnlineExplicitContent, false);
|
||||||
|
|
||||||
|
SetDefault(OsuSetting.NotifyOnUsernameMentioned, true);
|
||||||
|
SetDefault(OsuSetting.NotifyOnPrivateMessage, true);
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
||||||
|
|
||||||
@ -259,6 +262,8 @@ namespace osu.Game.Configuration
|
|||||||
ScalingSizeY,
|
ScalingSizeY,
|
||||||
UIScale,
|
UIScale,
|
||||||
IntroSequence,
|
IntroSequence,
|
||||||
|
NotifyOnUsernameMentioned,
|
||||||
|
NotifyOnPrivateMessage,
|
||||||
UIHoldActivationDelay,
|
UIHoldActivationDelay,
|
||||||
HitLighting,
|
HitLighting,
|
||||||
MenuBackgroundSource,
|
MenuBackgroundSource,
|
||||||
|
@ -11,11 +11,11 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
public class CreateChannelRequest : APIRequest<APIChatChannel>
|
public class CreateChannelRequest : APIRequest<APIChatChannel>
|
||||||
{
|
{
|
||||||
private readonly Channel channel;
|
public readonly Channel Channel;
|
||||||
|
|
||||||
public CreateChannelRequest(Channel channel)
|
public CreateChannelRequest(Channel channel)
|
||||||
{
|
{
|
||||||
this.channel = channel;
|
Channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
@ -24,7 +24,7 @@ namespace osu.Game.Online.API.Requests
|
|||||||
req.Method = HttpMethod.Post;
|
req.Method = HttpMethod.Post;
|
||||||
|
|
||||||
req.AddParameter("type", $"{ChannelType.PM}");
|
req.AddParameter("type", $"{ChannelType.PM}");
|
||||||
req.AddParameter("target_id", $"{channel.Users.First().Id}");
|
req.AddParameter("target_id", $"{Channel.Users.First().Id}");
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
@ -63,5 +63,7 @@ namespace osu.Game.Online.Chat
|
|||||||
|
|
||||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||||
public override int GetHashCode() => Id.GetHashCode();
|
public override int GetHashCode() => Id.GetHashCode();
|
||||||
|
|
||||||
|
public override string ToString() => $"[{ChannelId}] ({Id}) {Sender}: {Content}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
181
osu.Game/Online/Chat/MessageNotifier.cs
Normal file
181
osu.Game/Online/Chat/MessageNotifier.cs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.Chat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Component that handles creating and posting notifications for incoming messages.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageNotifier : Component
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private NotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ChatOverlay chatOverlay { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ChannelManager channelManager { get; set; }
|
||||||
|
|
||||||
|
private Bindable<bool> notifyOnUsername;
|
||||||
|
private Bindable<bool> notifyOnPrivateMessage;
|
||||||
|
|
||||||
|
private readonly IBindable<User> localUser = new Bindable<User>();
|
||||||
|
private readonly IBindableList<Channel> joinedChannels = new BindableList<Channel>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config, IAPIProvider api)
|
||||||
|
{
|
||||||
|
notifyOnUsername = config.GetBindable<bool>(OsuSetting.NotifyOnUsernameMentioned);
|
||||||
|
notifyOnPrivateMessage = config.GetBindable<bool>(OsuSetting.NotifyOnPrivateMessage);
|
||||||
|
|
||||||
|
localUser.BindTo(api.LocalUser);
|
||||||
|
joinedChannels.BindTo(channelManager.JoinedChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
joinedChannels.BindCollectionChanged(channelsChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void channelsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
foreach (var channel in e.NewItems.Cast<Channel>())
|
||||||
|
channel.NewMessagesArrived += checkNewMessages;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
foreach (var channel in e.OldItems.Cast<Channel>())
|
||||||
|
channel.NewMessagesArrived -= checkNewMessages;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNewMessages(IEnumerable<Message> messages)
|
||||||
|
{
|
||||||
|
if (!messages.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == messages.First().ChannelId);
|
||||||
|
|
||||||
|
if (channel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Only send notifications, if ChatOverlay and the target channel aren't visible.
|
||||||
|
if (chatOverlay.IsPresent && channelManager.CurrentChannel.Value == channel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var message in messages.OrderByDescending(m => m.Id))
|
||||||
|
{
|
||||||
|
// ignore messages that already have been read
|
||||||
|
if (message.Id <= channel.LastReadId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (message.Sender.Id == localUser.Value.Id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check for private messages first to avoid both posting two notifications about the same message
|
||||||
|
if (checkForPMs(channel, message))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
checkForMentions(channel, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the user enabled private message notifications and whether specified <paramref name="message"/> is a direct message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">The channel associated to the <paramref name="message"/></param>
|
||||||
|
/// <param name="message">The message to be checked</param>
|
||||||
|
/// <returns>Whether a notification was fired.</returns>
|
||||||
|
private bool checkForPMs(Channel channel, Message message)
|
||||||
|
{
|
||||||
|
if (!notifyOnPrivateMessage.Value || channel.Type != ChannelType.PM)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
notifications.Post(new PrivateMessageNotification(message.Sender.Username, channel));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkForMentions(Channel channel, Message message)
|
||||||
|
{
|
||||||
|
if (!notifyOnUsername.Value || !checkContainsUsername(message.Content, localUser.Value.Username)) return;
|
||||||
|
|
||||||
|
notifications.Post(new MentionNotification(message.Sender.Username, channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if <paramref name="message"/> contains <paramref name="username"/>.
|
||||||
|
/// This will match against the case where underscores are used instead of spaces (which is how osu-stable handles usernames with spaces).
|
||||||
|
/// </summary>
|
||||||
|
private static bool checkContainsUsername(string message, string username) => message.Contains(username, StringComparison.OrdinalIgnoreCase) || message.Contains(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public class PrivateMessageNotification : OpenChannelNotification
|
||||||
|
{
|
||||||
|
public PrivateMessageNotification(string username, Channel channel)
|
||||||
|
: base(channel)
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.Envelope;
|
||||||
|
Text = $"You received a private message from '{username}'. Click to read it!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MentionNotification : OpenChannelNotification
|
||||||
|
{
|
||||||
|
public MentionNotification(string username, Channel channel)
|
||||||
|
: base(channel)
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.At;
|
||||||
|
Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class OpenChannelNotification : SimpleNotification
|
||||||
|
{
|
||||||
|
protected OpenChannelNotification(Channel channel)
|
||||||
|
{
|
||||||
|
this.channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Channel channel;
|
||||||
|
|
||||||
|
public override bool IsImportant => false;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager)
|
||||||
|
{
|
||||||
|
IconBackgound.Colour = colours.PurpleDark;
|
||||||
|
|
||||||
|
Activated = delegate
|
||||||
|
{
|
||||||
|
notificationOverlay.Hide();
|
||||||
|
chatOverlay.Show();
|
||||||
|
channelManager.CurrentChannel.Value = channel;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -728,6 +728,7 @@ namespace osu.Game
|
|||||||
var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
|
var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
|
||||||
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
|
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
|
||||||
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
|
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
|
||||||
|
loadComponentSingleFile(new MessageNotifier(), AddInternal, true);
|
||||||
loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true);
|
loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true);
|
||||||
var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true);
|
var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true);
|
||||||
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);
|
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);
|
||||||
|
@ -6,18 +6,18 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osuTK.Graphics;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics.Cursor;
|
|
||||||
using osu.Game.Online.Chat;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Chat
|
namespace osu.Game.Overlays.Chat
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Settings.Sections.Online
|
||||||
|
{
|
||||||
|
public class AlertsAndPrivacySettings : SettingsSubsection
|
||||||
|
{
|
||||||
|
protected override string Header => "Alerts and Privacy";
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SettingsCheckbox
|
||||||
|
{
|
||||||
|
LabelText = "Show a notification when someone mentions your name",
|
||||||
|
Current = config.GetBindable<bool>(OsuSetting.NotifyOnUsernameMentioned)
|
||||||
|
},
|
||||||
|
new SettingsCheckbox
|
||||||
|
{
|
||||||
|
LabelText = "Show a notification when you receive a private message",
|
||||||
|
Current = config.GetBindable<bool>(OsuSetting.NotifyOnPrivateMessage)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new WebSettings(),
|
new WebSettings(),
|
||||||
|
new AlertsAndPrivacySettings(),
|
||||||
new IntegrationSettings()
|
new IntegrationSettings()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -148,9 +148,9 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class LegacyOldStyleFill : LegacyHealthPiece
|
internal abstract class LegacyFill : LegacyHealthPiece
|
||||||
{
|
{
|
||||||
public LegacyOldStyleFill(ISkin skin)
|
protected LegacyFill(ISkin skin)
|
||||||
{
|
{
|
||||||
// required for sizing correctly..
|
// required for sizing correctly..
|
||||||
var firstFrame = getTexture(skin, "colour-0");
|
var firstFrame = getTexture(skin, "colour-0");
|
||||||
@ -162,27 +162,29 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InternalChild = skin.GetAnimation("scorebar-colour", true, true, startAtCurrentTime: false, applyConfigFrameRate: true) ?? Drawable.Empty();
|
InternalChild = skin.GetAnimation("scorebar-colour", true, true, startAtCurrentTime: false, applyConfigFrameRate: true) ?? Empty();
|
||||||
Size = new Vector2(firstFrame.DisplayWidth, firstFrame.DisplayHeight);
|
Size = new Vector2(firstFrame.DisplayWidth, firstFrame.DisplayHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
Position = new Vector2(3, 10) * 1.6f;
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class LegacyNewStyleFill : LegacyHealthPiece
|
internal class LegacyOldStyleFill : LegacyFill
|
||||||
|
{
|
||||||
|
public LegacyOldStyleFill(ISkin skin)
|
||||||
|
: base(skin)
|
||||||
|
{
|
||||||
|
Position = new Vector2(3, 10) * 1.6f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LegacyNewStyleFill : LegacyFill
|
||||||
{
|
{
|
||||||
public LegacyNewStyleFill(ISkin skin)
|
public LegacyNewStyleFill(ISkin skin)
|
||||||
|
: base(skin)
|
||||||
{
|
{
|
||||||
InternalChild = new Sprite
|
|
||||||
{
|
|
||||||
Texture = getTexture(skin, "colour"),
|
|
||||||
};
|
|
||||||
|
|
||||||
Size = InternalChild.Size;
|
|
||||||
Position = new Vector2(7.5f, 7.8f) * 1.6f;
|
Position = new Vector2(7.5f, 7.8f) * 1.6f;
|
||||||
Masking = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user