Hotbar Improvements + Item Action Integration Test (#2749)
* my IDE keeps wanting to change this so.... * Add item actions integration test, fix bug where empty item action dict was left in SharedActionsComponent state * bigger hotbar arrows * nice wide hotbar pagination hitboxes * add ability to switch hotbar loadout via keybinds * always highlight on drag over of actions hotbar * dont rely on content entity for integration test
This commit is contained in:
@@ -27,7 +27,7 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
[ComponentReference(typeof(SharedActionsComponent))]
|
||||
public sealed class ClientActionsComponent : SharedActionsComponent
|
||||
{
|
||||
public const byte Hotbars = 10;
|
||||
public const byte Hotbars = 9;
|
||||
public const byte Slots = 10;
|
||||
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
@@ -106,6 +106,11 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
_ui?.HandleHotbarKeybind(slot, args);
|
||||
}
|
||||
|
||||
public void HandleChangeHotbarKeybind(byte hotbar, in PointerInputCmdHandler.PointerInputCmdArgs args)
|
||||
{
|
||||
_ui?.HandleChangeHotbarKeybind(hotbar, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the displayed hotbar (and menu) based on current state of actions.
|
||||
/// </summary>
|
||||
|
||||
@@ -42,6 +42,24 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
HandleHotbarKeybind(8))
|
||||
.Bind(ContentKeyFunctions.Hotbar0,
|
||||
HandleHotbarKeybind(9))
|
||||
.Bind(ContentKeyFunctions.Loadout1,
|
||||
HandleChangeHotbarKeybind(0))
|
||||
.Bind(ContentKeyFunctions.Loadout2,
|
||||
HandleChangeHotbarKeybind(1))
|
||||
.Bind(ContentKeyFunctions.Loadout3,
|
||||
HandleChangeHotbarKeybind(2))
|
||||
.Bind(ContentKeyFunctions.Loadout4,
|
||||
HandleChangeHotbarKeybind(3))
|
||||
.Bind(ContentKeyFunctions.Loadout5,
|
||||
HandleChangeHotbarKeybind(4))
|
||||
.Bind(ContentKeyFunctions.Loadout6,
|
||||
HandleChangeHotbarKeybind(5))
|
||||
.Bind(ContentKeyFunctions.Loadout7,
|
||||
HandleChangeHotbarKeybind(6))
|
||||
.Bind(ContentKeyFunctions.Loadout8,
|
||||
HandleChangeHotbarKeybind(7))
|
||||
.Bind(ContentKeyFunctions.Loadout9,
|
||||
HandleChangeHotbarKeybind(8))
|
||||
// when selecting a target, we intercept clicks in the game world, treating them as our target selection. We want to
|
||||
// take priority before any other systems handle the click.
|
||||
.BindBefore(EngineKeyFunctions.Use, new PointerInputCmdHandler(TargetingOnUse),
|
||||
@@ -66,6 +84,20 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
actionsComponent.HandleHotbarKeybind(slot, args);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private PointerInputCmdHandler HandleChangeHotbarKeybind(byte hotbar)
|
||||
{
|
||||
// delegate to the ActionsUI, simulating a click on it
|
||||
return new((in PointerInputCmdHandler.PointerInputCmdArgs args) =>
|
||||
{
|
||||
var playerEntity = _playerManager.LocalPlayer.ControlledEntity;
|
||||
if (playerEntity == null ||
|
||||
!playerEntity.TryGetComponent<ClientActionsComponent>( out var actionsComponent)) return false;
|
||||
|
||||
actionsComponent.HandleChangeHotbarKeybind(hotbar, args);
|
||||
return true;
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,15 @@ namespace Content.Client.Input
|
||||
human.AddFunction(ContentKeyFunctions.Hotbar7);
|
||||
human.AddFunction(ContentKeyFunctions.Hotbar8);
|
||||
human.AddFunction(ContentKeyFunctions.Hotbar9);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout1);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout2);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout3);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout4);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout5);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout6);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout7);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout8);
|
||||
human.AddFunction(ContentKeyFunctions.Loadout9);
|
||||
|
||||
var ghost = contexts.New("ghost", "common");
|
||||
ghost.AddFunction(EngineKeyFunctions.MoveUp);
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace Content.Client.UserInterface
|
||||
private static readonly Regex Whitespace = new Regex(@"\s+", RegexOptions.Compiled);
|
||||
private static readonly BaseActionPrototype[] EmptyActionList = Array.Empty<BaseActionPrototype>();
|
||||
|
||||
/// <summary>
|
||||
/// Is an action currently being dragged from this window?
|
||||
/// </summary>
|
||||
public bool IsDragging => _dragDropHelper.IsDragging;
|
||||
|
||||
// parallel list of actions currently selectable in itemList
|
||||
private BaseActionPrototype[] _actionList;
|
||||
|
||||
@@ -158,6 +163,7 @@ namespace Content.Client.UserInterface
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
base.ExitedTree();
|
||||
_dragDropHelper.EndDrag();
|
||||
_clearButton.OnPressed -= OnClearButtonPressed;
|
||||
_searchBar.OnTextChanged -= OnSearchTextChanged;
|
||||
_filterButton.OnItemSelected -= OnFilterItemSelected;
|
||||
|
||||
@@ -39,11 +39,10 @@ namespace Content.Client.UserInterface
|
||||
|
||||
private readonly TextureButton _lockButton;
|
||||
private readonly TextureButton _settingsButton;
|
||||
private readonly TextureButton _previousHotbarButton;
|
||||
private readonly Label _loadoutNumber;
|
||||
private readonly TextureButton _nextHotbarButton;
|
||||
private readonly Texture _lockTexture;
|
||||
private readonly Texture _unlockTexture;
|
||||
private readonly HBoxContainer _loadoutContainer;
|
||||
|
||||
private readonly TextureRect _dragShadow;
|
||||
|
||||
@@ -148,38 +147,39 @@ namespace Content.Client.UserInterface
|
||||
};
|
||||
hotbarContainer.AddChild(_slotContainer);
|
||||
|
||||
var loadoutContainer = new HBoxContainer
|
||||
_loadoutContainer = new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
MouseFilter = MouseFilterMode.Stop
|
||||
};
|
||||
hotbarContainer.AddChild(loadoutContainer);
|
||||
hotbarContainer.AddChild(_loadoutContainer);
|
||||
|
||||
loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 });
|
||||
_previousHotbarButton = new TextureButton
|
||||
_loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 });
|
||||
var previousHotbarIcon = new TextureRect()
|
||||
{
|
||||
TextureNormal = resourceCache.GetTexture("/Textures/Interface/Nano/left_arrow.svg.png"),
|
||||
Texture = resourceCache.GetTexture("/Textures/Interface/Nano/left_arrow.svg.png"),
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsStretchRatio = 1
|
||||
};
|
||||
loadoutContainer.AddChild(_previousHotbarButton);
|
||||
loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 });
|
||||
_loadoutContainer.AddChild(previousHotbarIcon);
|
||||
_loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 });
|
||||
_loadoutNumber = new Label
|
||||
{
|
||||
Text = "1",
|
||||
SizeFlagsStretchRatio = 1
|
||||
};
|
||||
loadoutContainer.AddChild(_loadoutNumber);
|
||||
loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 });
|
||||
_nextHotbarButton = new TextureButton
|
||||
_loadoutContainer.AddChild(_loadoutNumber);
|
||||
_loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 });
|
||||
var nextHotbarIcon = new TextureRect
|
||||
{
|
||||
TextureNormal = resourceCache.GetTexture("/Textures/Interface/Nano/right_arrow.svg.png"),
|
||||
Texture = resourceCache.GetTexture("/Textures/Interface/Nano/right_arrow.svg.png"),
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsStretchRatio = 1
|
||||
};
|
||||
loadoutContainer.AddChild(_nextHotbarButton);
|
||||
loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 });
|
||||
_loadoutContainer.AddChild(nextHotbarIcon);
|
||||
_loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 });
|
||||
|
||||
_slots = new ActionSlot[ClientActionsComponent.Slots];
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace Content.Client.UserInterface
|
||||
|
||||
for (byte i = 0; i < ClientActionsComponent.Slots; i++)
|
||||
{
|
||||
var slot = new ActionSlot(this, actionsComponent, i);
|
||||
var slot = new ActionSlot(this, _menu, actionsComponent, i);
|
||||
_slotContainer.AddChild(slot);
|
||||
_slots[i] = slot;
|
||||
}
|
||||
@@ -206,9 +206,8 @@ namespace Content.Client.UserInterface
|
||||
{
|
||||
base.EnteredTree();
|
||||
_lockButton.OnPressed += OnLockPressed;
|
||||
_nextHotbarButton.OnPressed += NextHotbar;
|
||||
_previousHotbarButton.OnPressed += PreviousHotbar;
|
||||
_settingsButton.OnPressed += OnToggleActionsMenu;
|
||||
_loadoutContainer.OnKeyBindDown += OnHotbarPaginate;
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
@@ -217,9 +216,8 @@ namespace Content.Client.UserInterface
|
||||
StopTargeting();
|
||||
_menu.Close();
|
||||
_lockButton.OnPressed -= OnLockPressed;
|
||||
_nextHotbarButton.OnPressed -= NextHotbar;
|
||||
_previousHotbarButton.OnPressed -= PreviousHotbar;
|
||||
_settingsButton.OnPressed -= OnToggleActionsMenu;
|
||||
_loadoutContainer.OnKeyBindDown -= OnHotbarPaginate;
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
@@ -420,17 +418,24 @@ namespace Content.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
private void NextHotbar(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
ChangeHotbar((byte) ((SelectedHotbar + 1) % ClientActionsComponent.Hotbars));
|
||||
}
|
||||
|
||||
private void PreviousHotbar(BaseButton.ButtonEventArgs args)
|
||||
private void OnHotbarPaginate(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
var newBar = SelectedHotbar == 0 ? ClientActionsComponent.Hotbars - 1 : SelectedHotbar - 1;
|
||||
ChangeHotbar((byte) newBar);
|
||||
}
|
||||
// rather than clicking the arrows themselves, the user can click the hbox so it's more
|
||||
// "forgiving" for misclicks, and we simply check which side they are closer to
|
||||
if (args.Function != EngineKeyFunctions.UIClick) return;
|
||||
|
||||
var rightness = args.RelativePosition.X / _loadoutContainer.Width;
|
||||
if (rightness > 0.5)
|
||||
{
|
||||
ChangeHotbar((byte) ((SelectedHotbar + 1) % ClientActionsComponent.Hotbars));
|
||||
}
|
||||
else
|
||||
{
|
||||
var newBar = SelectedHotbar == 0 ? ClientActionsComponent.Hotbars - 1 : SelectedHotbar - 1;
|
||||
ChangeHotbar((byte) newBar);
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeHotbar(byte hotbar)
|
||||
{
|
||||
@@ -547,6 +552,15 @@ namespace Content.Client.UserInterface
|
||||
actionSlot.Depress(args.State == BoundKeyState.Down);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle hotbar change.
|
||||
/// </summary>
|
||||
/// <param name="hotbar">hotbar index to switch to</param>
|
||||
public void HandleChangeHotbarKeybind(byte hotbar, PointerInputCmdHandler.PointerInputCmdArgs args)
|
||||
{
|
||||
ChangeHotbar(hotbar);
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.Update(args);
|
||||
|
||||
@@ -110,6 +110,7 @@ namespace Content.Client.UserInterface.Controls
|
||||
private readonly SpriteView _bigItemSpriteView;
|
||||
private readonly CooldownGraphic _cooldownGraphic;
|
||||
private readonly ActionsUI _actionsUI;
|
||||
private readonly ActionMenu _actionMenu;
|
||||
private readonly ClientActionsComponent _actionsComponent;
|
||||
private bool _toggledOn;
|
||||
// whether button is currently pressed down by mouse or keybind down.
|
||||
@@ -120,10 +121,11 @@ namespace Content.Client.UserInterface.Controls
|
||||
/// Creates an action slot for the specified number
|
||||
/// </summary>
|
||||
/// <param name="slotIndex">slot index this corresponds to, 0-9 (0 labeled as 1, 8, labeled "9", 9 labeled as "0".</param>
|
||||
public ActionSlot(ActionsUI actionsUI, ClientActionsComponent actionsComponent, byte slotIndex)
|
||||
public ActionSlot(ActionsUI actionsUI, ActionMenu actionMenu, ClientActionsComponent actionsComponent, byte slotIndex)
|
||||
{
|
||||
_actionsComponent = actionsComponent;
|
||||
_actionsUI = actionsUI;
|
||||
_actionMenu = actionMenu;
|
||||
_gameTiming = IoCManager.Resolve<IGameTiming>();
|
||||
SlotIndex = slotIndex;
|
||||
MouseFilter = MouseFilterMode.Stop;
|
||||
@@ -259,7 +261,7 @@ namespace Content.Client.UserInterface.Controls
|
||||
|
||||
if (args.Function == EngineKeyFunctions.UIRightClick)
|
||||
{
|
||||
if (!_actionsUI.Locked && !_actionsUI.DragDropHelper.IsDragging)
|
||||
if (!_actionsUI.Locked && !_actionsUI.DragDropHelper.IsDragging && !_actionMenu.IsDragging)
|
||||
{
|
||||
_actionsComponent.Assignments.ClearSlot(_actionsUI.SelectedHotbar, SlotIndex, true);
|
||||
_actionsUI.StopTargeting();
|
||||
@@ -582,6 +584,18 @@ namespace Content.Client.UserInterface.Controls
|
||||
|
||||
private void DrawModeChanged()
|
||||
{
|
||||
|
||||
// show a hover only if the action is usable or another action is being dragged on top of this
|
||||
if (_beingHovered)
|
||||
{
|
||||
if (_actionsUI.DragDropHelper.IsDragging || _actionMenu.IsDragging ||
|
||||
(HasAssignment && ActionEnabled && !IsOnCooldown))
|
||||
{
|
||||
SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassHover);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// always show the normal empty button style if no action in this slot
|
||||
if (!HasAssignment)
|
||||
{
|
||||
@@ -597,15 +611,6 @@ namespace Content.Client.UserInterface.Controls
|
||||
return;
|
||||
}
|
||||
|
||||
// show a hover only if the action is usable
|
||||
if (_beingHovered)
|
||||
{
|
||||
if (ActionEnabled && !IsOnCooldown)
|
||||
{
|
||||
SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassHover);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's toggled on, always show the toggled on style (currently same as depressed style)
|
||||
if (ToggledOn)
|
||||
|
||||
@@ -180,6 +180,15 @@ namespace Content.Client.UserInterface
|
||||
AddButton(ContentKeyFunctions.Hotbar8, "Hotbar slot 8");
|
||||
AddButton(ContentKeyFunctions.Hotbar9, "Hotbar slot 9");
|
||||
AddButton(ContentKeyFunctions.Hotbar0, "Hotbar slot 0");
|
||||
AddButton(ContentKeyFunctions.Loadout1, "Hotbar Loadout 1");
|
||||
AddButton(ContentKeyFunctions.Loadout2, "Hotbar Loadout 2");
|
||||
AddButton(ContentKeyFunctions.Loadout3, "Hotbar Loadout 3");
|
||||
AddButton(ContentKeyFunctions.Loadout4, "Hotbar Loadout 4");
|
||||
AddButton(ContentKeyFunctions.Loadout5, "Hotbar Loadout 5");
|
||||
AddButton(ContentKeyFunctions.Loadout6, "Hotbar Loadout 6");
|
||||
AddButton(ContentKeyFunctions.Loadout7, "Hotbar Loadout 7");
|
||||
AddButton(ContentKeyFunctions.Loadout8, "Hotbar Loadout 8");
|
||||
AddButton(ContentKeyFunctions.Loadout9, "Hotbar Loadout 9");
|
||||
|
||||
AddHeader("Map Editor");
|
||||
AddButton(EngineKeyFunctions.EditorPlaceObject, "Place object");
|
||||
|
||||
@@ -106,6 +106,15 @@ Hotbar slot 7: [color=#a4885c]{40}[/color]
|
||||
Hotbar slot 8: [color=#a4885c]{41}[/color]
|
||||
Hotbar slot 9: [color=#a4885c]{42}[/color]
|
||||
Hotbar slot 0: [color=#a4885c]{43}[/color]
|
||||
Hotbar Loadout 1: [color=#a4885c]{44}[/color]
|
||||
Hotbar Loadout 2: [color=#a4885c]{45}[/color]
|
||||
Hotbar Loadout 3: [color=#a4885c]{46}[/color]
|
||||
Hotbar Loadout 4: [color=#a4885c]{47}[/color]
|
||||
Hotbar Loadout 5: [color=#a4885c]{48}[/color]
|
||||
Hotbar Loadout 6: [color=#a4885c]{49}[/color]
|
||||
Hotbar Loadout 7: [color=#a4885c]{50}[/color]
|
||||
Hotbar Loadout 8: [color=#a4885c]{51}[/color]
|
||||
Hotbar Loadout 9: [color=#a4885c]{52}[/color]
|
||||
",
|
||||
Key(MoveUp), Key(MoveLeft), Key(MoveDown), Key(MoveRight),
|
||||
Key(SwapHands),
|
||||
@@ -147,7 +156,16 @@ Hotbar slot 0: [color=#a4885c]{43}[/color]
|
||||
Key(Hotbar7),
|
||||
Key(Hotbar8),
|
||||
Key(Hotbar9),
|
||||
Key(Hotbar0)));
|
||||
Key(Hotbar0),
|
||||
Key(Loadout1),
|
||||
Key(Loadout2),
|
||||
Key(Loadout3),
|
||||
Key(Loadout4),
|
||||
Key(Loadout5),
|
||||
Key(Loadout6),
|
||||
Key(Loadout7),
|
||||
Key(Loadout8),
|
||||
Key(Loadout9)));
|
||||
|
||||
//Gameplay
|
||||
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" });
|
||||
|
||||
Reference in New Issue
Block a user