Merge remote-tracking branch 'upstream/stable' into ed-30-04-2025-upstream-sync
# Conflicts: # Content.Client/Parallax/ParallaxControl.cs # Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs # Content.IntegrationTests/Tests/PostMapInitTest.cs # Content.Server/Chat/Managers/ChatManager.cs # Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs # Content.Server/Labels/Label/LabelSystem.cs # Content.Shared/Actions/SharedActionsSystem.cs # Content.Shared/Fluids/Components/EvaporationComponent.cs # Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs # README.md # Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml # Resources/Prototypes/Maps/Pools/deathmatch.yml # Resources/Prototypes/Maps/arenas.yml
This commit is contained in:
@@ -12,6 +12,7 @@ using Content.Client.UserInterface.Systems.Actions.Widgets;
|
||||
using Content.Client.UserInterface.Systems.Actions.Windows;
|
||||
using Content.Client.UserInterface.Systems.Gameplay;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Charges.Systems;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -42,7 +43,6 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
[Dependency] private readonly IOverlayManager _overlays = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IInputManager _input = default!;
|
||||
|
||||
[UISystemDependency] private readonly ActionsSystem? _actionsSystem = default;
|
||||
@@ -173,7 +173,6 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
|
||||
// Is the action currently valid?
|
||||
if (!action.Enabled
|
||||
|| action is { Charges: 0, RenewCharges: false }
|
||||
|| action.Cooldown.HasValue && action.Cooldown.Value.End > _timing.CurTime)
|
||||
{
|
||||
// The user is targeting with this action, but it is not valid. Maybe mark this click as
|
||||
@@ -483,7 +482,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
continue;
|
||||
}
|
||||
|
||||
var button = new ActionButton(_entMan, _spriteSystem, this) {Locked = true};
|
||||
var button = new ActionButton(EntityManager, _spriteSystem, this) {Locked = true};
|
||||
button.ActionPressed += OnWindowActionPressed;
|
||||
button.ActionUnpressed += OnWindowActionUnPressed;
|
||||
button.ActionFocusExited += OnWindowActionFocusExisted;
|
||||
@@ -632,8 +631,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
if (args.Function != EngineKeyFunctions.UIClick && args.Function != EngineKeyFunctions.Use)
|
||||
return;
|
||||
|
||||
_menuDragHelper.MouseDown(action);
|
||||
args.Handle();
|
||||
HandleActionPressed(args, action);
|
||||
}
|
||||
|
||||
private void OnWindowActionUnPressed(GUIBoundKeyEventArgs args, ActionButton dragged)
|
||||
@@ -641,8 +639,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
if (args.Function != EngineKeyFunctions.UIClick && args.Function != EngineKeyFunctions.Use)
|
||||
return;
|
||||
|
||||
DragAction();
|
||||
args.Handle();
|
||||
HandleActionUnpressed(args, dragged);
|
||||
}
|
||||
|
||||
private void OnWindowActionFocusExisted(ActionButton button)
|
||||
@@ -662,6 +659,11 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
HandleActionPressed(args, button);
|
||||
}
|
||||
|
||||
private void HandleActionPressed(GUIBoundKeyEventArgs args, ActionButton button)
|
||||
{
|
||||
args.Handle();
|
||||
if (button.ActionId != null)
|
||||
{
|
||||
@@ -677,7 +679,15 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
||||
|
||||
private void OnActionUnpressed(GUIBoundKeyEventArgs args, ActionButton button)
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick || _actionsSystem == null)
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
HandleActionUnpressed(args, button);
|
||||
}
|
||||
|
||||
private void HandleActionUnpressed(GUIBoundKeyEventArgs args, ActionButton button)
|
||||
{
|
||||
if (_actionsSystem == null)
|
||||
return;
|
||||
|
||||
args.Handle();
|
||||
|
||||
@@ -4,6 +4,8 @@ using Content.Client.Actions.UI;
|
||||
using Content.Client.Cooldown;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Charges.Components;
|
||||
using Content.Shared.Charges.Systems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
@@ -22,6 +24,7 @@ public sealed class ActionButton : Control, IEntityControl
|
||||
private IEntityManager _entities;
|
||||
private SpriteSystem? _spriteSys;
|
||||
private ActionUIController? _controller;
|
||||
private SharedChargesSystem _sharedChargesSys;
|
||||
private bool _beingHovered;
|
||||
private bool _depressed;
|
||||
private bool _toggled;
|
||||
@@ -65,6 +68,7 @@ public sealed class ActionButton : Control, IEntityControl
|
||||
|
||||
_entities = entities;
|
||||
_spriteSys = spriteSys;
|
||||
_sharedChargesSys = _entities.System<SharedChargesSystem>();
|
||||
_controller = controller;
|
||||
|
||||
MouseFilter = MouseFilterMode.Pass;
|
||||
@@ -194,14 +198,22 @@ public sealed class ActionButton : Control, IEntityControl
|
||||
|
||||
var name = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityName));
|
||||
var decr = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityDescription));
|
||||
FormattedMessage? chargesText = null;
|
||||
|
||||
if (_action is { Charges: not null })
|
||||
// TODO: Don't touch this use an event make callers able to add their own shit for actions or I kill you.
|
||||
if (_entities.TryGetComponent(ActionId, out LimitedChargesComponent? actionCharges))
|
||||
{
|
||||
var charges = FormattedMessage.FromMarkupPermissive(Loc.GetString($"Charges: {_action.Charges.Value.ToString()}/{_action.MaxCharges.ToString()}"));
|
||||
return new ActionAlertTooltip(name, decr, charges: charges);
|
||||
var charges = _sharedChargesSys.GetCurrentCharges((ActionId.Value, actionCharges, null));
|
||||
chargesText = FormattedMessage.FromMarkupPermissive(Loc.GetString($"Charges: {charges.ToString()}/{actionCharges.MaxCharges}"));
|
||||
|
||||
if (_entities.TryGetComponent(ActionId, out AutoRechargeComponent? autoRecharge))
|
||||
{
|
||||
var chargeTimeRemaining = _sharedChargesSys.GetNextRechargeTime((ActionId.Value, actionCharges, autoRecharge));
|
||||
chargesText.AddText(Loc.GetString($"{Environment.NewLine}Time Til Recharge: {chargeTimeRemaining}"));
|
||||
}
|
||||
}
|
||||
|
||||
return new ActionAlertTooltip(name, decr);
|
||||
return new ActionAlertTooltip(name, decr, charges: chargesText);
|
||||
}
|
||||
|
||||
protected override void ControlFocusExited()
|
||||
|
||||
@@ -221,18 +221,11 @@ public sealed class CharacterUIController : UIController, IOnStateEntered<Gamepl
|
||||
if (!_ent.TryGetComponent<MindComponent>(container.Mind.Value, out var mind))
|
||||
return;
|
||||
|
||||
var roleText = Loc.GetString("role-type-crew-aligned-name");
|
||||
var color = Color.White;
|
||||
if (_prototypeManager.TryIndex(mind.RoleType, out var proto))
|
||||
{
|
||||
roleText = Loc.GetString(proto.Name);
|
||||
color = proto.Color;
|
||||
}
|
||||
else
|
||||
_sawmill.Error($"{_player.LocalEntity} has invalid Role Type '{mind.RoleType}'. Displaying '{roleText}' instead");
|
||||
if (!_prototypeManager.TryIndex(mind.RoleType, out var proto))
|
||||
_sawmill.Error($"Player '{_player.LocalSession}' has invalid Role Type '{mind.RoleType}'. Displaying default instead");
|
||||
|
||||
_window.RoleType.Text = roleText;
|
||||
_window.RoleType.FontColorOverride = color;
|
||||
_window.RoleType.Text = Loc.GetString(proto?.Name ?? "role-type-crew-aligned-name");
|
||||
_window.RoleType.FontColorOverride = proto?.Color ?? Color.White;
|
||||
}
|
||||
|
||||
private void CharacterDetached(EntityUid uid)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:widgets="clr-namespace:Content.Client.UserInterface.Systems.Chat.Widgets"
|
||||
Title="{Loc chat-window-title}"
|
||||
MinSize="465 265">
|
||||
<widgets:ChatBox Name="Chatbox"/>
|
||||
</controls:FancyWindow>
|
||||
44
Content.Client/UserInterface/Systems/Chat/ChatWindow.xaml.cs
Normal file
44
Content.Client/UserInterface/Systems/Chat/ChatWindow.xaml.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// Window which only holds a single chatbox, useful for monitoring multiple chats simultaneously.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ChatWindow : FancyWindow
|
||||
{
|
||||
public ChatWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
// These are necessary for the controls inside the chatbox to initialize correctly:
|
||||
Chatbox.Repopulate();
|
||||
var controller = UserInterfaceManager.GetUIController<ChatUIController>();
|
||||
controller.UpdateSelectedChannel(Chatbox);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to configure this window to be useful for admins.
|
||||
/// Sets incoming filters to only admin chats and output to admin channel
|
||||
/// </summary>
|
||||
public void ConfigureForAdminChat()
|
||||
{
|
||||
Chatbox.ChatInput.ChannelSelector.Select(ChatSelectChannel.Admin);
|
||||
|
||||
var filter = Chatbox.ChatInput.FilterButton.Popup;
|
||||
foreach (var c in Enum.GetValues(typeof(ChatChannel)))
|
||||
{
|
||||
var channel = (ChatChannel)c;
|
||||
var isAdminInterest = channel == ChatChannel.Admin
|
||||
|| channel == ChatChannel.AdminChat
|
||||
|| channel == ChatChannel.AdminAlert
|
||||
|| channel == ChatChannel.AdminRelated;
|
||||
filter.SetActive(channel, isAdminInterest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Chat;
|
||||
|
||||
/// <summary>
|
||||
/// Command which creates a window containing a chatbox
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed class ChatWindowCommand : LocalizedCommands
|
||||
{
|
||||
public override string Command => "chatwindow";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var window = new ChatWindow();
|
||||
window.OpenCentered();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command which creates a window containing a chatbox configured for admin use
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed class AdminChatWindowCommand : LocalizedCommands
|
||||
{
|
||||
public override string Command => "achatwindow";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var window = new ChatWindow();
|
||||
window.ConfigureForAdminChat();
|
||||
window.OpenCentered();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
@@ -40,6 +40,15 @@ public sealed partial class ChannelFilterPopup : Popup
|
||||
return _filterStates.TryGetValue(channel, out var checkbox) && checkbox.Pressed;
|
||||
}
|
||||
|
||||
public void SetActive(ChatChannel channel, bool isActive)
|
||||
{
|
||||
if (_filterStates.TryGetValue(channel, out var checkbox) && checkbox.Pressed != isActive)
|
||||
{
|
||||
checkbox.Pressed = isActive;
|
||||
OnChannelFilter?.Invoke(checkbox.Channel, checkbox.Pressed);
|
||||
}
|
||||
}
|
||||
|
||||
public ChatChannel GetActive()
|
||||
{
|
||||
ChatChannel active = 0;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<PanelContainer Name="ChatWindowPanel" Access="Public" HorizontalExpand="True" VerticalExpand="True"
|
||||
StyleClasses="StyleNano.StyleClassChatPanel">
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="4" HorizontalExpand="True" VerticalExpand="True">
|
||||
<OutputPanel Name="Contents" HorizontalExpand="True" VerticalExpand="True" Margin="8 8 8 4" />
|
||||
<OutputPanel Name="Contents" HorizontalExpand="True" VerticalExpand="True" Margin="8 8 8 4" ShowScrollDownButton="True" />
|
||||
<controls:ChatInputBox HorizontalExpand="True" Name="ChatInput" Access="Public" Margin="2"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
|
||||
@@ -9,12 +9,32 @@
|
||||
Orientation="Vertical"
|
||||
HorizontalAlignment="Center">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Name="StorageContainer"
|
||||
<BoxContainer Name="SingleStorageContainer"
|
||||
Access="Public"
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalExpand="True"
|
||||
Margin="10">
|
||||
</BoxContainer>
|
||||
<BoxContainer Name="DoubleStorageContainer"
|
||||
Access="Public"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalExpand="True"
|
||||
Margin="10">
|
||||
<BoxContainer Name="LeftStorageContainer"
|
||||
Access="Public"
|
||||
HorizontalAlignment="Left"
|
||||
HorizontalExpand="True"
|
||||
VerticalAlignment="Bottom"
|
||||
Margin="10">
|
||||
</BoxContainer>
|
||||
<BoxContainer Name="RightStorageContainer"
|
||||
Access="Public"
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalExpand="True"
|
||||
VerticalAlignment="Bottom"
|
||||
Margin="10">
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" Name="Hotbar" HorizontalAlignment="Center">
|
||||
<inventory:ItemSlotButtonContainer
|
||||
Name="SecondHotbar"
|
||||
|
||||
@@ -38,6 +38,7 @@ public sealed partial class ItemStatusPanel : Control
|
||||
StyleBox.Margin cutOut;
|
||||
StyleBox.Margin flat;
|
||||
Thickness contentMargin;
|
||||
Thickness patchMargin;
|
||||
|
||||
switch (location)
|
||||
{
|
||||
@@ -61,15 +62,23 @@ public sealed partial class ItemStatusPanel : Control
|
||||
|
||||
Contents.Margin = contentMargin;
|
||||
|
||||
//Important to note for patchMargin!
|
||||
//Because of hand ui flipping, left and right instead correspond to outside and inside respectively.
|
||||
patchMargin = MarginFromThemeColor("_itemstatus_patch_margin");
|
||||
|
||||
var panel = (StyleBoxTexture) Panel.PanelOverride!;
|
||||
panel.Texture = texture;
|
||||
panel.SetPatchMargin(flat, 4);
|
||||
panel.SetPatchMargin(cutOut, 7);
|
||||
panel.SetPatchMargin(cutOut, patchMargin.Left);
|
||||
panel.SetPatchMargin(flat, patchMargin.Right);
|
||||
panel.SetPatchMargin(StyleBox.Margin.Top, patchMargin.Top);
|
||||
panel.SetPatchMargin(StyleBox.Margin.Bottom, patchMargin.Bottom);
|
||||
|
||||
var panelHighlight = (StyleBoxTexture) HighlightPanel.PanelOverride!;
|
||||
panelHighlight.Texture = textureHighlight;
|
||||
panelHighlight.SetPatchMargin(flat, 4);
|
||||
panelHighlight.SetPatchMargin(cutOut, 7);
|
||||
panelHighlight.SetPatchMargin(cutOut, patchMargin.Left);
|
||||
panelHighlight.SetPatchMargin(flat, patchMargin.Right);
|
||||
panelHighlight.SetPatchMargin(StyleBox.Margin.Top, patchMargin.Top);
|
||||
panelHighlight.SetPatchMargin(StyleBox.Margin.Bottom, patchMargin.Bottom);
|
||||
|
||||
_side = location;
|
||||
}
|
||||
|
||||
@@ -163,22 +163,25 @@ public sealed class ItemGridPiece : Control, IEntityControl
|
||||
}
|
||||
|
||||
// typically you'd divide by two, but since the textures are half a tile, this is done implicitly
|
||||
var iconOffset = Location.Rotation.RotateVec(itemComponent.StoredOffset) * 2 * UIScale;
|
||||
var iconPosition = new Vector2(
|
||||
(boundingGrid.Width + 1) * size.X + Location.Rotation.RotateVec(itemComponent.StoredOffset).X * 2,
|
||||
(boundingGrid.Height + 1) * size.Y + Location.Rotation.RotateVec(itemComponent.StoredOffset).Y * 2);
|
||||
(boundingGrid.Width + 1) * size.X + iconOffset.X,
|
||||
(boundingGrid.Height + 1) * size.Y + iconOffset.Y);
|
||||
var iconRotation = Location.Rotation + Angle.FromDegrees(itemComponent.StoredRotation);
|
||||
|
||||
if (itemComponent.StoredSprite is { } storageSprite)
|
||||
{
|
||||
var scale = 2 * UIScale;
|
||||
var offset = (((Box2) boundingGrid).Size - Vector2.One) * size;
|
||||
var sprite = _entityManager.System<SpriteSystem>().Frame0(storageSprite);
|
||||
|
||||
var sizeDifference = ((boundingGrid.Size + Vector2i.One) * _centerTexture.Size * 2 - sprite.Size) * UIScale;
|
||||
|
||||
var spriteBox = new Box2Rotated(new Box2(0f, sprite.Height * scale, sprite.Width * scale, 0f), -iconRotation, Vector2.Zero);
|
||||
var root = spriteBox.CalcBoundingBox().BottomLeft;
|
||||
var pos = PixelPosition * 2
|
||||
+ (Parent?.GlobalPixelPosition ?? Vector2.Zero)
|
||||
+ offset;
|
||||
+ sizeDifference
|
||||
+ iconOffset;
|
||||
|
||||
handle.SetTransform(pos, iconRotation);
|
||||
var box = new UIBox2(root, root + sprite.Size * scale);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Examine;
|
||||
using Content.Client.Hands.Systems;
|
||||
@@ -48,6 +49,7 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
public Angle DraggingRotation = Angle.Zero;
|
||||
public bool StaticStorageUIEnabled;
|
||||
public bool OpaqueStorageWindow;
|
||||
private int _openStorageLimit = -1;
|
||||
|
||||
public bool IsDragging => _menuDragHelper.IsDragging;
|
||||
public ItemGridPiece? CurrentlyDragging => _menuDragHelper.Dragged;
|
||||
@@ -66,6 +68,12 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
_configuration.OnValueChanged(CCVars.StaticStorageUI, OnStaticStorageChanged, true);
|
||||
_configuration.OnValueChanged(CCVars.OpaqueStorageWindow, OnOpaqueWindowChanged, true);
|
||||
_configuration.OnValueChanged(CCVars.StorageWindowTitle, OnStorageWindowTitle, true);
|
||||
_configuration.OnValueChanged(CCVars.StorageLimit, OnStorageLimitChanged, true);
|
||||
}
|
||||
|
||||
private void OnStorageLimitChanged(int obj)
|
||||
{
|
||||
_openStorageLimit = obj;
|
||||
}
|
||||
|
||||
private void OnStorageWindowTitle(bool obj)
|
||||
@@ -99,7 +107,49 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
|
||||
if (StaticStorageUIEnabled)
|
||||
{
|
||||
UIManager.GetActiveUIWidgetOrNull<HotbarGui>()?.StorageContainer.AddChild(window);
|
||||
var hotbar = UIManager.GetActiveUIWidgetOrNull<HotbarGui>();
|
||||
// this lambda handles the nested storage case
|
||||
// during nested storage, a parent window hides and a child window is
|
||||
// immediately inserted to the end of the list
|
||||
// we can reorder the newly inserted to the same index as the invisible
|
||||
// window in order to prevent an invisible window from being replaced
|
||||
// with a visible one in a different position
|
||||
Action<Control?, Control> reorder = (parent, child) =>
|
||||
{
|
||||
if (parent is null)
|
||||
return;
|
||||
|
||||
var parentChildren = parent.Children.ToList();
|
||||
var invisibleIndex = parentChildren.FindIndex(c => c.Visible == false);
|
||||
if (invisibleIndex == -1)
|
||||
return;
|
||||
child.SetPositionInParent(invisibleIndex);
|
||||
};
|
||||
|
||||
if (hotbar != null)
|
||||
{
|
||||
hotbar.DoubleStorageContainer.Visible = _openStorageLimit == 2;
|
||||
hotbar.SingleStorageContainer.Visible = _openStorageLimit != 2;
|
||||
}
|
||||
|
||||
if (_openStorageLimit == 2)
|
||||
{
|
||||
if (hotbar?.LeftStorageContainer.Children.Any(c => c.Visible) == false) // we're comparing booleans because it's bool? and not bool from the optional chaining
|
||||
{
|
||||
hotbar?.LeftStorageContainer.AddChild(window);
|
||||
reorder(hotbar?.LeftStorageContainer, window);
|
||||
}
|
||||
else
|
||||
{
|
||||
hotbar?.RightStorageContainer.AddChild(window);
|
||||
reorder(hotbar?.RightStorageContainer, window);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hotbar?.SingleStorageContainer.AddChild(window);
|
||||
reorder(hotbar?.SingleStorageContainer, window);
|
||||
}
|
||||
_closeRecentWindowUIController.SetMostRecentlyInteractedWindow(window);
|
||||
}
|
||||
else
|
||||
@@ -269,12 +319,19 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
var position = targetStorage.GetMouseGridPieceLocation(dragEnt, dragLoc);
|
||||
var newLocation = new ItemStorageLocation(DraggingRotation, position);
|
||||
|
||||
EntityManager.RaisePredictiveEvent(new StorageSetItemLocationEvent(
|
||||
EntityManager.GetNetEntity(draggingGhost.Entity),
|
||||
EntityManager.GetNetEntity(sourceStorage),
|
||||
newLocation));
|
||||
if (!_storage.ItemFitsInGridLocation(dragEnt, sourceStorage, newLocation))
|
||||
{
|
||||
window.Reclaim(control.Location, control);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityManager.RaisePredictiveEvent(new StorageSetItemLocationEvent(
|
||||
EntityManager.GetNetEntity(draggingGhost.Entity),
|
||||
EntityManager.GetNetEntity(sourceStorage),
|
||||
newLocation));
|
||||
|
||||
window.Reclaim(newLocation, control);
|
||||
window.Reclaim(newLocation, control);
|
||||
}
|
||||
}
|
||||
// Dragging to new storage
|
||||
else if (targetStorage?.StorageEntity != null && targetStorage != window)
|
||||
@@ -336,6 +393,17 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
|
||||
if (DraggingGhost == null)
|
||||
return false;
|
||||
|
||||
var player = _player.LocalEntity;
|
||||
|
||||
// If the attached storage is closed then stop dragging
|
||||
if (player == null ||
|
||||
!_storage.TryGetStorageLocation(DraggingGhost.Entity, out var container, out _, out _) ||
|
||||
!_ui.IsUiOpen(container.Owner, StorageComponent.StorageUiKey.Key, player.Value))
|
||||
{
|
||||
DraggingGhost.Orphan();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetDraggingRotation();
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user