Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Zekins3366
2025-09-07 21:56:10 +03:00
1618 changed files with 205213 additions and 191837 deletions

View File

@@ -1,9 +1,11 @@
using System.Numerics;
using Content.Client.Cooldown;
using Content.Client.UserInterface.Systems.Inventory.Controls;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.Controls
{
@@ -20,6 +22,7 @@ namespace Content.Client.UserInterface.Controls
public CooldownGraphic CooldownDisplay { get; }
private SpriteView SpriteView { get; }
private EntityPrototypeView ProtoView { get; }
public EntityUid? Entity => SpriteView.Entity;
@@ -141,6 +144,13 @@ namespace Content.Client.UserInterface.Controls
SetSize = new Vector2(DefaultButtonSize, DefaultButtonSize),
OverrideDirection = Direction.South
});
AddChild(ProtoView = new EntityPrototypeView
{
Visible = false,
Scale = new Vector2(2, 2),
SetSize = new Vector2(DefaultButtonSize, DefaultButtonSize),
OverrideDirection = Direction.South
});
AddChild(HoverSpriteView = new SpriteView
{
@@ -209,12 +219,35 @@ namespace Content.Client.UserInterface.Controls
HoverSpriteView.SetEntity(null);
}
/// <summary>
/// Causes the control to display a placeholder prototype, optionally faded
/// </summary>
public void SetEntity(EntityUid? ent)
{
SpriteView.SetEntity(ent);
SpriteView.Visible = true;
ProtoView.Visible = false;
UpdateButtonTexture();
}
/// <summary>
/// Causes the control to display a placeholder prototype, optionally faded
/// </summary>
public void SetPrototype(EntProtoId? proto, bool fade)
{
ProtoView.SetPrototype(proto);
SpriteView.Visible = false;
ProtoView.Visible = true;
UpdateButtonTexture();
if (ProtoView.Entity is not { } ent || !fade)
return;
var sprites = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>();
sprites.SetColor((ent.Owner, ent.Comp1), Color.DarkGray.WithAlpha(0.65f));
}
private void UpdateButtonTexture()
{
var fullTexture = Theme.ResolveTextureOrNull(_fullButtonTexturePath);

View File

@@ -5,7 +5,7 @@
<ScrollContainer HorizontalExpand="True"
VerticalExpand="True"
SizeFlagsStretchRatio="6">
<GridContainer Name="Values"/>
<GridContainer Name="Values" HSeparationOverride="0" VSeparationOverride="15"/>
</ScrollContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -3,12 +3,12 @@ using Content.Client.Actions;
using Content.Client.Actions.UI;
using Content.Client.Cooldown;
using Content.Client.Stylesheets;
using Content.Shared.Actions;
using Content.Shared.Actions.Components;
using Content.Shared.Charges.Components;
using Content.Shared.Charges.Systems;
using Content.Shared.Examine;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
@@ -23,9 +23,9 @@ namespace Content.Client.UserInterface.Systems.Actions.Controls;
public sealed class ActionButton : Control, IEntityControl
{
private IEntityManager _entities;
private IPlayerManager _player;
private SpriteSystem? _spriteSys;
private ActionUIController? _controller;
private SharedChargesSystem _sharedChargesSys;
private bool _beingHovered;
private bool _depressed;
private bool _toggled;
@@ -67,8 +67,8 @@ public sealed class ActionButton : Control, IEntityControl
// TODO why is this constructor so slooooow. The rest of the code is fine
_entities = entities;
_player = IoCManager.Resolve<IPlayerManager>();
_spriteSys = spriteSys;
_sharedChargesSys = _entities.System<SharedChargesSystem>();
_controller = controller;
MouseFilter = MouseFilterMode.Pass;
@@ -197,23 +197,17 @@ public sealed class ActionButton : Control, IEntityControl
return null;
var name = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityName));
var decr = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityDescription));
FormattedMessage? chargesText = null;
var desc = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityDescription));
// 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(Action, out LimitedChargesComponent? actionCharges))
{
var charges = _sharedChargesSys.GetCurrentCharges((Action.Value, actionCharges, null));
chargesText = FormattedMessage.FromMarkupPermissive(Loc.GetString($"Charges: {charges.ToString()}/{actionCharges.MaxCharges}"));
if (_player.LocalEntity is null)
return null;
if (_entities.TryGetComponent(Action, out AutoRechargeComponent? autoRecharge))
{
var chargeTimeRemaining = _sharedChargesSys.GetNextRechargeTime((Action.Value, actionCharges, autoRecharge));
chargesText.AddText(Loc.GetString($"{Environment.NewLine}Time Til Recharge: {chargeTimeRemaining}"));
}
}
var ev = new ExaminedEvent(desc, Action.Value, _player.LocalEntity.Value, true, !desc.IsEmpty);
_entities.EventBus.RaiseLocalEvent(Action.Value.Owner, ev);
return new ActionAlertTooltip(name, decr, charges: chargesText);
var newDesc = ev.GetTotalMessage();
return new ActionAlertTooltip(name, newDesc);
}
protected override void ControlFocusExited()

View File

@@ -21,17 +21,20 @@ public sealed class EmotesUIController : UIController, IOnStateChanged<GameplayS
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
private MenuButton? EmotesButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.EmotesButton;
private SimpleRadialMenu? _menu;
private static readonly Dictionary<EmoteCategory, (string Tooltip, SpriteSpecifier Sprite)> EmoteGroupingInfo
= new Dictionary<EmoteCategory, (string Tooltip, SpriteSpecifier Sprite)>
{
[EmoteCategory.General] = ("emote-menu-category-general", new SpriteSpecifier.Texture(new ResPath("/Textures/Clothing/Head/Soft/mimesoft.rsi/icon.png"))),
[EmoteCategory.Hands] = ("emote-menu-category-hands", new SpriteSpecifier.Texture(new ResPath("/Textures/Clothing/Hands/Gloves/latex.rsi/icon.png"))),
[EmoteCategory.Vocal] = ("emote-menu-category-vocal", new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Emotes/vocal.png"))),
};
private static readonly Dictionary<EmoteCategory, (string Tooltip, SpriteSpecifier Sprite)> EmoteGroupingInfo =
new()
{
[EmoteCategory.General] = ("emote-menu-category-general",
new SpriteSpecifier.Rsi(new ResPath("/Textures/Clothing/Head/Soft/mimesoft.rsi"), "icon")),
[EmoteCategory.Hands] = ("emote-menu-category-hands",
new SpriteSpecifier.Rsi(new ResPath("/Textures/Clothing/Hands/Gloves/latex.rsi"), "icon")),
[EmoteCategory.Vocal] = ("emote-menu-category-vocal",
new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Emotes/vocal.png"))),
};
public void OnStateEntered(GameplayState state)
{
@@ -135,7 +138,7 @@ public sealed class EmotesUIController : UIController, IOnStateChanged<GameplayS
var whitelistSystem = EntitySystemManager.GetEntitySystem<EntityWhitelistSystem>();
var player = _playerManager.LocalSession?.AttachedEntity;
Dictionary<EmoteCategory, List<RadialMenuOption>> emotesByCategory = new();
Dictionary<EmoteCategory, List<RadialMenuOption>> emotesByCategory = new();
foreach (var emote in emotePrototypes)
{
if(emote.Category == EmoteCategory.Invalid)

View File

@@ -12,6 +12,7 @@ using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Shared.Input;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -73,7 +74,8 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
{
if (entity.Owner != _player.LocalEntity)
return;
AddHand(name, location);
if (_handsSystem.TryGetHand((entity.Owner, entity.Comp), name, out var hand))
AddHand(name, hand.Value);
}
private void OnRemoveHand(Entity<HandsComponent> entity, string name)
@@ -139,7 +141,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
_playerHandsComponent = handsComp;
foreach (var (name, hand) in handsComp.Comp.Hands)
{
var handButton = AddHand(name, hand.Location);
var handButton = AddHand(name, hand);
if (_handsSystem.TryGetHeldItem(handsComp.AsNullable(), name, out var held) &&
_entities.TryGetComponent(held, out VirtualItemComponent? virt))
@@ -147,11 +149,25 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
handButton.SetEntity(virt.BlockingEntity);
handButton.Blocked = true;
}
else
else if (held != null)
{
handButton.SetEntity(held);
handButton.Blocked = false;
}
else
{
if (hand.EmptyRepresentative is { } representative)
{
// placeholder, view it
SetRepresentative(handButton, representative);
}
else
{
// otherwise empty
handButton.SetEntity(null);
}
handButton.Blocked = false;
}
}
if (handsComp.Comp.ActiveHandId == null)
@@ -159,6 +175,11 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
SetActiveHand(handsComp.Comp.ActiveHandId);
}
private void SetRepresentative(HandButton handButton, EntProtoId prototype)
{
handButton.SetPrototype(prototype, true);
}
private void HandBlocked(string handName)
{
if (!_handLookup.TryGetValue(handName, out var hand))
@@ -203,7 +224,12 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
hand.Blocked = false;
}
UpdateHandStatus(hand, entity);
if (_playerHandsComponent != null &&
_player.LocalSession?.AttachedEntity is { } playerEntity &&
_handsSystem.TryGetHand((playerEntity, _playerHandsComponent), name, out var handData))
{
UpdateHandStatus(hand, entity, handData);
}
}
private void OnItemRemoved(string name, EntityUid entity)
@@ -212,8 +238,19 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
if (hand == null)
return;
if (_playerHandsComponent != null &&
_player.LocalSession?.AttachedEntity is { } playerEntity &&
_handsSystem.TryGetHand((playerEntity, _playerHandsComponent), name, out var handData))
{
UpdateHandStatus(hand, null, handData);
if (handData?.EmptyRepresentative is { } representative)
{
SetRepresentative(hand, representative);
return;
}
}
hand.SetEntity(null);
UpdateHandStatus(hand, null);
}
private HandsContainer GetFirstAvailableContainer()
@@ -276,13 +313,13 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
if (foldedLocation == HandUILocation.Left)
{
_statusHandLeft = handControl;
HandsGui.UpdatePanelEntityLeft(heldEnt);
HandsGui.UpdatePanelEntityLeft(heldEnt, hand.Value);
}
else
{
// Middle or right
_statusHandRight = handControl;
HandsGui.UpdatePanelEntityRight(heldEnt);
HandsGui.UpdatePanelEntityRight(heldEnt, hand.Value);
}
HandsGui.SetHighlightHand(foldedLocation);
@@ -295,9 +332,9 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
return handControl;
}
private HandButton AddHand(string handName, HandLocation location)
private HandButton AddHand(string handName, Hand hand)
{
var button = new HandButton(handName, location);
var button = new HandButton(handName, hand.Location);
button.StoragePressed += StorageActivate;
button.Pressed += HandPressed;
@@ -313,10 +350,16 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
GetFirstAvailableContainer().AddButton(button);
}
if (hand.EmptyRepresentative is { } representative)
{
SetRepresentative(button, representative);
}
UpdateHandStatus(button, null, hand);
// If we don't have a status for this hand type yet, set it.
// This means we have status filled by default in most scenarios,
// otherwise the user'd need to switch hands to "activate" the hands the first time.
if (location.GetUILocation() == HandUILocation.Left)
if (hand.Location.GetUILocation() == HandUILocation.Left)
_statusHandLeft ??= button;
else
_statusHandRight ??= button;
@@ -480,12 +523,12 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
}
}
private void UpdateHandStatus(HandButton hand, EntityUid? entity)
private void UpdateHandStatus(HandButton hand, EntityUid? entity, Hand? handData)
{
if (hand == _statusHandLeft)
HandsGui?.UpdatePanelEntityLeft(entity);
HandsGui?.UpdatePanelEntityLeft(entity, handData);
if (hand == _statusHandRight)
HandsGui?.UpdatePanelEntityRight(entity);
HandsGui?.UpdatePanelEntityRight(entity, handData);
}
}

View File

@@ -19,14 +19,14 @@ public sealed partial class HotbarGui : UIWidget
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.Begin);
}
public void UpdatePanelEntityLeft(EntityUid? entity)
public void UpdatePanelEntityLeft(EntityUid? entity, Hand? hand)
{
StatusPanelLeft.Update(entity);
StatusPanelLeft.Update(entity, hand);
}
public void UpdatePanelEntityRight(EntityUid? entity)
public void UpdatePanelEntityRight(EntityUid? entity, Hand? hand)
{
StatusPanelRight.Update(entity);
StatusPanelRight.Update(entity, hand);
}
public void SetHighlightHand(HandUILocation? hand)

View File

@@ -17,6 +17,7 @@ public sealed partial class ItemStatusPanel : Control
[Dependency] private readonly IEntityManager _entityManager = default!;
[ViewVariables] private EntityUid? _entity;
[ViewVariables] private Hand? _hand;
// Tracked so we can re-run SetSide() if the theme changes.
private HandUILocation _side;
@@ -101,29 +102,45 @@ public sealed partial class ItemStatusPanel : Control
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateItemName();
UpdateItemName(_hand);
}
public void Update(EntityUid? entity)
public void Update(EntityUid? entity, Hand? hand)
{
ItemNameLabel.Visible = entity != null;
NoItemLabel.Visible = entity == null;
if (entity == _entity && hand == _hand)
return;
_hand = hand;
if (entity == null)
{
ItemNameLabel.Text = "";
ClearOldStatus();
_entity = null;
if (hand?.EmptyLabel is { } label)
{
ItemNameLabel.Visible = true;
NoItemLabel.Visible = false;
ItemNameLabel.Text = Loc.GetString(label);
}
else
{
ItemNameLabel.Visible = false;
NoItemLabel.Visible = true;
ItemNameLabel.Text = "";
}
return;
}
if (entity != _entity)
{
_entity = entity.Value;
BuildNewEntityStatus();
ItemNameLabel.Visible = true;
NoItemLabel.Visible = false;
UpdateItemName();
}
_entity = entity.Value;
BuildNewEntityStatus();
UpdateItemName(hand);
}
public void UpdateHighlight(bool highlight)
@@ -131,14 +148,14 @@ public sealed partial class ItemStatusPanel : Control
HighlightPanel.Visible = highlight;
}
private void UpdateItemName()
private void UpdateItemName(Hand? hand)
{
if (_entity == null)
return;
if (!_entityManager.TryGetComponent<MetaDataComponent>(_entity, out var meta) || meta.Deleted)
{
Update(null);
Update(null, hand);
return;
}

View File

@@ -194,8 +194,6 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
}
}
return;
int GetIndex(Vector2i position)
{
return position.Y * maxWidth + position.X;

View File

@@ -185,12 +185,7 @@ public sealed class ItemGridPiece : Control, IEntityControl
handle.SetTransform(pos, iconRotation);
var box = new UIBox2(root, root + sprite.Size * scale);
var ev = new BeforeRenderInGridEvent(new Color(255, 255, 255));
_entityManager.EventBus.RaiseLocalEvent(Entity, ev);
handle.DrawTextureRect(sprite, box, ev.Color);
handle.DrawTextureRect(sprite, box);
handle.SetTransform(GlobalPixelPosition, Angle.Zero);
}
else
@@ -303,19 +298,6 @@ public sealed class ItemGridPiece : Control, IEntityControl
public EntityUid? UiEntity => Entity;
}
/// <summary>
/// This event gets raised before a sprite gets drawn in a grid and lets to change the sprite color for several gameobjects that have special sprites to render in containers.
/// </summary>
public sealed class BeforeRenderInGridEvent : EntityEventArgs
{
public Color Color { get; set; }
public BeforeRenderInGridEvent(Color color)
{
Color = color;
}
}
public enum ItemGridPieceMarks
{
First,