Revert "Upstream sync (#1509)" (#1510)

This reverts commit a35c718734.
This commit is contained in:
Red
2025-07-08 11:59:51 +03:00
committed by GitHub
parent a35c718734
commit ae077c3971
935 changed files with 9384 additions and 19938 deletions

View File

@@ -211,7 +211,7 @@ namespace Content.Client.Actions
else
{
var request = new RequestPerformActionEvent(GetNetEntity(action));
RaisePredictiveEvent(request);
EntityManager.RaisePredictiveEvent(request);
}
}

View File

@@ -1,4 +1,3 @@
using System.Collections.Frozen;
using System.Linq;
using System.Numerics;
using Content.Client.Administration.Systems;
@@ -25,7 +24,6 @@ internal sealed class AdminNameOverlay : Overlay
private readonly EntityLookupSystem _entityLookup;
private readonly IUserInterfaceManager _userInterfaceManager;
private readonly SharedRoleSystem _roles;
private readonly IPrototypeManager _prototypeManager;
private readonly Font _font;
private readonly Font _fontBold;
private AdminOverlayAntagFormat _overlayFormat;
@@ -38,9 +36,8 @@ internal sealed class AdminNameOverlay : Overlay
private float _overlayMergeDistance;
//TODO make this adjustable via GUI?
private static readonly FrozenSet<ProtoId<RoleTypePrototype>> Filter =
new ProtoId<RoleTypePrototype>[] {"SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"}
.ToFrozenSet();
private readonly ProtoId<RoleTypePrototype>[] _filter =
["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"];
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
@@ -52,8 +49,7 @@ internal sealed class AdminNameOverlay : Overlay
EntityLookupSystem entityLookup,
IUserInterfaceManager userInterfaceManager,
IConfigurationManager config,
SharedRoleSystem roles,
IPrototypeManager prototypeManager)
SharedRoleSystem roles)
{
_system = system;
_entityManager = entityManager;
@@ -61,7 +57,6 @@ internal sealed class AdminNameOverlay : Overlay
_entityLookup = entityLookup;
_userInterfaceManager = userInterfaceManager;
_roles = roles;
_prototypeManager = prototypeManager;
ZIndex = 200;
// Setting these to a specific ttf would break the antag symbols
_font = resourceCache.NotoStack();
@@ -130,14 +125,6 @@ internal sealed class AdminNameOverlay : Overlay
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
{
var playerInfo = info.Item1;
var rolePrototype = playerInfo.RoleProto == null
? null
: _prototypeManager.Index(playerInfo.RoleProto.Value);
var roleName = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
var roleColor = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
var roleSymbol = rolePrototype?.Symbol ?? RoleTypePrototype.FallbackSymbol;
var aabb = info.Item2;
var entity = info.Item3;
var screenCoordinatesCenter = info.Item4;
@@ -222,7 +209,7 @@ internal sealed class AdminNameOverlay : Overlay
switch (_overlaySymbolStyle)
{
case AdminOverlayAntagSymbolStyle.Specific:
symbol = roleSymbol;
symbol = playerInfo.RoleProto.Symbol;
break;
case AdminOverlayAntagSymbolStyle.Basic:
symbol = Loc.GetString("player-tab-antag-prefix");
@@ -238,17 +225,17 @@ internal sealed class AdminNameOverlay : Overlay
switch (_overlayFormat)
{
case AdminOverlayAntagFormat.Roletype:
color = roleColor;
symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
text = IsFiltered(playerInfo.RoleProto)
? roleName.ToUpper()
color = playerInfo.RoleProto.Color;
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty;
text = _filter.Contains(playerInfo.RoleProto)
? Loc.GetString(playerInfo.RoleProto.Name).ToUpper()
: string.Empty;
break;
case AdminOverlayAntagFormat.Subtype:
color = roleColor;
symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
text = IsFiltered(playerInfo.RoleProto)
? _roles.GetRoleSubtypeLabel(roleName, playerInfo.Subtype).ToUpper()
color = playerInfo.RoleProto.Color;
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty;
text = _filter.Contains(playerInfo.RoleProto)
? _roles.GetRoleSubtypeLabel(playerInfo.RoleProto.Name, playerInfo.Subtype).ToUpper()
: string.Empty;
break;
default:
@@ -271,12 +258,4 @@ internal sealed class AdminNameOverlay : Overlay
drawnOverlays.Add((screenCoordinatesCenter, currentOffset));
}
}
private static bool IsFiltered(ProtoId<RoleTypePrototype>? roleProtoId)
{
if (roleProtoId == null)
return false;
return Filter.Contains(roleProtoId.Value);
}
}

View File

@@ -4,7 +4,6 @@ using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.Systems
{
@@ -18,7 +17,6 @@ namespace Content.Client.Administration.Systems
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly SharedRoleSystem _roles = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
private AdminNameOverlay _adminNameOverlay = default!;
@@ -35,8 +33,7 @@ namespace Content.Client.Administration.Systems
_entityLookup,
_userInterfaceManager,
_configurationManager,
_roles,
_proto);
_roles);
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
}

View File

@@ -1,7 +1,7 @@
<DefaultWindow
xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
Title="{Loc ban-panel-title}" MinSize="410 500">
Title="{Loc ban-panel-title}" MinSize="350 500">
<BoxContainer Orientation="Vertical">
<TabContainer Name="Tabs" VerticalExpand="True">
<!-- Basic info -->

View File

@@ -1,14 +1,12 @@
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using Content.Client.Administration.UI.CustomControls;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.Database;
using Content.Shared.Roles;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -33,21 +31,14 @@ public sealed partial class BanPanel : DefaultWindow
private uint Multiplier { get; set; }
private bool HasBanFlag { get; set; }
private TimeSpan? ButtonResetOn { get; set; }
// This is less efficient than just holding a reference to the root control and enumerating children, but you
// have to know how the controls are nested, which makes the code more complicated.
// Role group name -> the role buttons themselves.
private readonly Dictionary<string, List<Button>> _roleCheckboxes = new();
private readonly List<CheckBox> _roleCheckboxes = new();
private readonly ISawmill _banpanelSawmill;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
private const string ExpandedArrow = "▼";
private const string ContractedArrow = "▶";
private enum TabNumbers
{
@@ -153,90 +144,47 @@ public sealed partial class BanPanel : DefaultWindow
ReasonTextEdit.Placeholder = new Rope.Leaf(Loc.GetString("ban-panel-reason"));
var departmentJobs = _protoMan.EnumeratePrototypes<DepartmentPrototype>()
.OrderBy(x => x.Weight);
foreach (var proto in departmentJobs)
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
foreach (var proto in prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
{
var roles = proto.Roles.Select(x => _protoMan.Index(x))
.OrderBy(x => x.ID);
CreateRoleGroup(proto.ID, proto.Color, roles);
CreateRoleGroup(proto.ID, proto.Roles.Select(p => p.Id), proto.Color);
}
var antagRoles = _protoMan.EnumeratePrototypes<AntagPrototype>()
.OrderBy(x => x.ID);
CreateRoleGroup("Antagonist", Color.Red, antagRoles);
CreateRoleGroup("Antagonist", prototypeManager.EnumeratePrototypes<AntagPrototype>().Select(p => p.ID), Color.Red);
}
/// <summary>
/// Creates a "Role group" which stores information and logic for one "group" of roll bans.
/// For example, all antags are one group, logi is a group, medical is a group, etc...
/// </summary>
private void CreateRoleGroup<T>(string groupName, Color color, IEnumerable<T> roles) where T : class, IPrototype
private void CreateRoleGroup(string roleName, IEnumerable<string> roleList, Color color)
{
var outerContainer = new BoxContainer
{
Name = $"{groupName}GroupOuterBox",
Name = $"{roleName}GroupOuterBox",
HorizontalExpand = true,
VerticalExpand = true,
Orientation = BoxContainer.LayoutOrientation.Vertical,
Margin = new Thickness(4),
Margin = new Thickness(4)
};
// Stores stuff like ban all and expand buttons.
var roleGroupHeader = new BoxContainer
var departmentCheckbox = new CheckBox
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
Name = $"{roleName}GroupCheckbox",
Text = roleName,
Modulate = color,
HorizontalAlignment = HAlignment.Left
};
// Stores the role checkboxes themselves.
var innerContainer = new GridContainer
outerContainer.AddChild(departmentCheckbox);
var innerContainer = new BoxContainer
{
Name = $"{groupName}GroupInnerBox",
Name = $"{roleName}GroupInnerBox",
HorizontalExpand = true,
Columns = 2,
Visible = false,
Margin = new Thickness(15, 5, 0, 5),
Orientation = BoxContainer.LayoutOrientation.Horizontal
};
var roleGroupCheckbox = CreateRoleGroupHeader(groupName, roleGroupHeader, color, innerContainer);
outerContainer.AddChild(roleGroupHeader);
// Add the roles themselves
foreach (var role in roles)
departmentCheckbox.OnToggled += args =>
{
AddRoleCheckbox(groupName, role.ID, innerContainer, roleGroupCheckbox);
}
outerContainer.AddChild(innerContainer);
RolesContainer.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat
foreach (var child in innerContainer.Children)
{
BackgroundColor = color
}
});
RolesContainer.AddChild(outerContainer);
RolesContainer.AddChild(new HSeparator());
}
private Button CreateRoleGroupHeader(string groupName, BoxContainer header, Color color, GridContainer innerContainer)
{
var roleGroupCheckbox = new Button
{
Name = $"{groupName}GroupCheckbox",
Text = "Ban all",
Margin = new Thickness(0, 0, 5, 0),
ToggleMode = true,
};
// When this is toggled, toggle all buttons in this group so they match.
roleGroupCheckbox.OnToggled += args =>
{
foreach (var role in _roleCheckboxes[groupName])
{
role.Pressed = args.Pressed;
if (child is CheckBox c)
{
c.Pressed = args.Pressed;
}
}
if (args.Pressed)
@@ -251,12 +199,15 @@ public sealed partial class BanPanel : DefaultWindow
}
else
{
foreach (var roleButtons in _roleCheckboxes.Values)
foreach (var childContainer in RolesContainer.Children)
{
foreach (var button in roleButtons)
if (childContainer is Container)
{
if (button.Pressed)
return;
foreach (var child in childContainer.Children)
{
if (child is CheckBox { Pressed: true })
return;
}
}
}
@@ -269,72 +220,38 @@ public sealed partial class BanPanel : DefaultWindow
SeverityOption.SelectId((int) newSeverity);
}
};
var hideButton = new Button
outerContainer.AddChild(innerContainer);
foreach (var role in roleList)
{
Text = Loc.GetString("role-bans-expand-roles") + " " + ContractedArrow,
ToggleMode = true,
};
hideButton.OnPressed += args =>
AddRoleCheckbox(role, innerContainer, departmentCheckbox);
}
RolesContainer.AddChild(new PanelContainer
{
innerContainer.Visible = args.Button.Pressed;
((Button)args.Button).Text = args.Button.Pressed
? Loc.GetString("role-bans-contract-roles") + " " + ExpandedArrow
: Loc.GetString("role-bans-expand-roles") + " " + ContractedArrow;
};
header.AddChild(new Label
{
Text = groupName,
Modulate = color,
Margin = new Thickness(0, 0, 5, 0),
PanelOverride = new StyleBoxFlat
{
BackgroundColor = color
}
});
header.AddChild(roleGroupCheckbox);
header.AddChild(hideButton);
return roleGroupCheckbox;
RolesContainer.AddChild(outerContainer);
RolesContainer.AddChild(new HSeparator());
}
/// <summary>
/// Adds a checkbutton specifically for one "role" in a "group"
/// E.g. it would add the Chief Medical Officer "role" into the "Medical" group.
/// </summary>
private void AddRoleCheckbox(string group, string role, GridContainer roleGroupInnerContainer, Button roleGroupCheckbox)
private void AddRoleCheckbox(string role, Control container, CheckBox header)
{
var roleCheckboxContainer = new BoxContainer();
var roleCheckButton = new Button
var roleCheckbox = new CheckBox
{
Name = $"{role}RoleCheckbox",
Text = role,
ToggleMode = true,
Text = role
};
roleCheckButton.OnToggled += args =>
roleCheckbox.OnToggled += args =>
{
// Checks the role group checkbox if all the children are pressed
if (args.Pressed && _roleCheckboxes[group].All(e => e.Pressed))
roleGroupCheckbox.Pressed = args.Pressed;
if (args is { Pressed: true, Button.Parent: { } } && args.Button.Parent.Children.Where(e => e is CheckBox).All(e => ((CheckBox) e).Pressed))
header.Pressed = args.Pressed;
else
roleGroupCheckbox.Pressed = false;
header.Pressed = false;
};
// This is adding the icon before the role name
// Yeah, this is sus, but having to split the functions up and stuff is worse imo.
if (_protoMan.TryIndex<JobPrototype>(role, out var jobPrototype) && _protoMan.TryIndex(jobPrototype.Icon, out var iconProto))
{
var jobIconTexture = new TextureRect
{
Texture = _entMan.System<SpriteSystem>().Frame0(iconProto.Icon),
TextureScale = new Vector2(2.5f, 2.5f),
Stretch = TextureRect.StretchMode.KeepCentered,
Margin = new Thickness(5, 0, 0, 0),
};
roleCheckboxContainer.AddChild(jobIconTexture);
}
roleCheckboxContainer.AddChild(roleCheckButton);
roleGroupInnerContainer.AddChild(roleCheckboxContainer);
_roleCheckboxes.TryAdd(group, []);
_roleCheckboxes[group].Add(roleCheckButton);
container.AddChild(roleCheckbox);
_roleCheckboxes.Add(roleCheckbox);
}
public void UpdateBanFlag(bool newFlag)
@@ -552,13 +469,7 @@ public sealed partial class BanPanel : DefaultWindow
if (_roleCheckboxes.Count == 0)
throw new DebugAssertException("RoleCheckboxes was empty");
foreach (var button in _roleCheckboxes.Values.SelectMany(departmentButtons => departmentButtons))
{
if (button is { Pressed: true, Text: not null })
{
rolesList.Add(button.Text);
}
}
rolesList.AddRange(_roleCheckboxes.Where(c => c is { Pressed: true, Text: { } }).Select(c => c.Text!));
if (rolesList.Count == 0)
{

View File

@@ -49,7 +49,6 @@
<Control HorizontalExpand="True"/>
<Label Name="Count" Access="Public"/>
<Control HorizontalExpand="True"/>
<Button Name="ExportLogs" Access="Public" Text="{Loc admin-logs-export}"/>
<Button Name="PopOutButton" Access="Public" Text="{Loc admin-logs-pop-out}"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal">

View File

@@ -1,6 +1,4 @@
using System.IO;
using System.Linq;
using Content.Client.Administration.UI.CustomControls;
using System.Linq;
using Content.Client.Eui;
using Content.Shared.Administration.Logs;
using Content.Shared.Eui;
@@ -17,16 +15,6 @@ public sealed class AdminLogsEui : BaseEui
{
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
[Dependency] private readonly IFileDialogManager _dialogManager = default!;
[Dependency] private readonly ILogManager _log = default!;
private const char CsvSeparator = ',';
private const string CsvQuote = "\"";
private const string CsvHeader = "Date,ID,PlayerID,Severity,Type,Message";
private ISawmill _sawmill;
private bool _currentlyExportingLogs = false;
public AdminLogsEui()
{
@@ -38,9 +26,6 @@ public sealed class AdminLogsEui : BaseEui
LogsControl.RefreshButton.OnPressed += _ => RequestLogs();
LogsControl.NextButton.OnPressed += _ => NextLogs();
LogsControl.PopOutButton.OnPressed += _ => PopOut();
LogsControl.ExportLogs.OnPressed += _ => ExportLogs();
_sawmill = _log.GetSawmill("admin.logs.ui");
}
private WindowRoot? Root { get; set; }
@@ -89,71 +74,6 @@ public sealed class AdminLogsEui : BaseEui
SendMessage(request);
}
private async void ExportLogs()
{
if (_currentlyExportingLogs)
return;
_currentlyExportingLogs = true;
LogsControl.ExportLogs.Disabled = true;
var file = await _dialogManager.SaveFile(new FileDialogFilters(new FileDialogFilters.Group("csv")));
if (file == null)
return;
try
{
// Buffer is set to 4KB for performance reasons. As the average export of 1000 logs is ~200KB
await using var writer = new StreamWriter(file.Value.fileStream, bufferSize: 4096);
await writer.WriteLineAsync(CsvHeader);
foreach (var child in LogsControl.LogsContainer.Children)
{
if (child is not AdminLogLabel logLabel || !child.Visible)
continue;
var log = logLabel.Log;
// Date
// I swear to god if someone adds ,s or "s to the other fields...
await writer.WriteAsync(log.Date.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
await writer.WriteAsync(CsvSeparator);
// ID
await writer.WriteAsync(log.Id.ToString());
await writer.WriteAsync(CsvSeparator);
// PlayerID
var players = log.Players;
for (var i = 0; i < players.Length; i++)
{
await writer.WriteAsync(players[i] + (i == players.Length - 1 ? "" : " "));
}
await writer.WriteAsync(CsvSeparator);
// Severity
await writer.WriteAsync(log.Impact.ToString());
await writer.WriteAsync(CsvSeparator);
// Type
await writer.WriteAsync(log.Type.ToString());
await writer.WriteAsync(CsvSeparator);
// Message
await writer.WriteAsync(CsvQuote);
await writer.WriteAsync(log.Message.Replace(CsvQuote, CsvQuote + CsvQuote));
await writer.WriteAsync(CsvQuote);
await writer.WriteLineAsync();
}
}
catch (Exception exc)
{
_sawmill.Error($"Error when exporting admin log:\n{exc.StackTrace}");
}
finally
{
await file.Value.fileStream.DisposeAsync();
_currentlyExportingLogs = false;
LogsControl.ExportLogs.Disabled = false;
}
}
private void PopOut()
{
if (LogsWindow == null)

View File

@@ -132,8 +132,8 @@ public sealed partial class ObjectsTab : Control
entry.OnTeleport += TeleportTo;
entry.OnDelete += Delete;
button.ToolTip = $"{info.Name}, {info.Entity}";
button.AddChild(entry);
button.StyleClasses.Clear();
}
private bool DataFilterCondition(string filter, ListData listData)

View File

@@ -172,7 +172,6 @@ public sealed partial class PlayerTab : Control
_playerTabSymbolSetting);
button.AddChild(entry);
button.ToolTip = $"{player.Username}, {player.CharacterName}, {player.IdentityName}, {player.StartingJob}";
button.StyleClasses.Clear();
}
/// <summary>

View File

@@ -1,11 +1,9 @@
using Content.Shared.Administration;
using Content.Shared.Mind;
using Content.Shared.Roles;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.UI.Tabs.PlayerTab;
@@ -13,7 +11,6 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab;
public sealed partial class PlayerTabEntry : PanelContainer
{
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public PlayerTabEntry(
PlayerInfo player,
@@ -26,8 +23,6 @@ public sealed partial class PlayerTabEntry : PanelContainer
RobustXamlLoader.Load(this);
var roles = _entMan.System<SharedRoleSystem>();
var rolePrototype = player.RoleProto == null ? null : _prototype.Index(player.RoleProto.Value);
UsernameLabel.Text = player.Username;
if (!player.Connected)
UsernameLabel.StyleClasses.Add("Disabled");
@@ -62,19 +57,19 @@ public sealed partial class PlayerTabEntry : PanelContainer
break;
default:
case AdminPlayerTabSymbolOption.Specific:
symbol = player.Antag ? rolePrototype?.Symbol ?? RoleTypePrototype.FallbackSymbol : string.Empty;
symbol = player.Antag ? player.RoleProto.Symbol : string.Empty;
break;
}
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
if (player.Antag && colorAntags)
CharacterLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
CharacterLabel.FontColorOverride = player.RoleProto.Color;
if (player.IdentityName != player.CharacterName)
CharacterLabel.Text += $" [{player.IdentityName}]";
var roletype = RoleTypeLabel.Text = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
var subtype = roles.GetRoleSubtypeLabel(rolePrototype?.Name ?? RoleTypePrototype.FallbackName, player.Subtype);
var roletype = RoleTypeLabel.Text = Loc.GetString(player.RoleProto.Name);
var subtype = roles.GetRoleSubtypeLabel(player.RoleProto.Name, player.Subtype);
switch (roleSetting)
{
case AdminPlayerTabRoleTypeOption.RoleTypeSubtype:
@@ -97,7 +92,7 @@ public sealed partial class PlayerTabEntry : PanelContainer
}
if (colorRoles)
RoleTypeLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
BackgroundColorPanel.PanelOverride = styleBoxFlat;
OverallPlaytimeLabel.Text = player.PlaytimeString;
}

View File

@@ -1,90 +0,0 @@
using System.Numerics;
using Content.Shared.Alert.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
namespace Content.Client.Alerts;
/// <summary>
/// This handles <see cref="GenericCounterAlertComponent"/>
/// </summary>
public sealed class GenericCounterAlertSystem : EntitySystem
{
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<GenericCounterAlertComponent, UpdateAlertSpriteEvent>(OnUpdateAlertSprite);
}
private void OnUpdateAlertSprite(Entity<GenericCounterAlertComponent> ent, ref UpdateAlertSpriteEvent args)
{
var sprite = args.SpriteViewEnt.Comp;
var ev = new GetGenericAlertCounterAmountEvent(args.Alert);
RaiseLocalEvent(args.ViewerEnt, ref ev);
if (!ev.Handled)
return;
// It cannot be null if its handled, but good to check to avoid ugly null ignores.
if (ev.Amount == null)
return;
// How many digits can we display
var maxDigitCount = GetMaxDigitCount((ent, ent, sprite));
// Clamp it to a positive number that we can actually display in full (no rollover to 0)
var amount = (int) Math.Clamp(ev.Amount.Value, 0, Math.Pow(10, maxDigitCount) - 1);
// This is super wack but ig it works?
var digitCount = ent.Comp.HideLeadingZeroes
? amount.ToString().Length
: maxDigitCount;
if (ent.Comp.HideLeadingZeroes)
{
for (var i = 0; i < ent.Comp.DigitKeys.Count; i++)
{
if (!_sprite.LayerMapTryGet(ent.Owner, ent.Comp.DigitKeys[i], out var layer, false))
continue;
_sprite.LayerSetVisible(ent.Owner, layer, i <= digitCount - 1);
}
}
// ReSharper disable once PossibleLossOfFraction
var baseOffset = (ent.Comp.AlertSize.X - digitCount * ent.Comp.GlyphWidth) / 2 * (1f / EyeManager.PixelsPerMeter);
for (var i = 0; i < ent.Comp.DigitKeys.Count; i++)
{
if (!_sprite.LayerMapTryGet(ent.Owner, ent.Comp.DigitKeys[i], out var layer, false))
continue;
var result = amount / (int) Math.Pow(10, i) % 10;
_sprite.LayerSetRsiState(ent.Owner, layer, result.ToString());
if (ent.Comp.CenterGlyph)
{
var offset = baseOffset + (digitCount - 1 - i) * ent.Comp.GlyphWidth * (1f / EyeManager.PixelsPerMeter);
_sprite.LayerSetOffset(ent.Owner, layer, new Vector2(offset, 0));
}
}
}
/// <summary>
/// Gets the number of digits that we can display.
/// </summary>
/// <returns>The number of digits.</returns>
private int GetMaxDigitCount(Entity<GenericCounterAlertComponent, SpriteComponent> ent)
{
for (var i = ent.Comp1.DigitKeys.Count - 1; i >= 0; i--)
{
if (_sprite.LayerExists((ent.Owner, ent.Comp2), ent.Comp1.DigitKeys[i]))
return i + 1;
}
return 0;
}
}

View File

@@ -11,14 +11,11 @@ public record struct UpdateAlertSpriteEvent
{
public Entity<SpriteComponent> SpriteViewEnt;
public EntityUid ViewerEnt;
public AlertPrototype Alert;
public UpdateAlertSpriteEvent(Entity<SpriteComponent> spriteViewEnt, EntityUid viewerEnt, AlertPrototype alert)
public UpdateAlertSpriteEvent(Entity<SpriteComponent> spriteViewEnt, AlertPrototype alert)
{
SpriteViewEnt = spriteViewEnt;
ViewerEnt = viewerEnt;
Alert = alert;
}
}

View File

@@ -1,31 +0,0 @@
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Atmos.Piping.Binary.Components;
namespace Content.Client.Atmos.EntitySystems;
/// <summary>
/// Represents the client system responsible for managing and updating the gas pressure regulator interface.
/// Inherits from the shared system <see cref="SharedGasPressureRegulatorSystem"/>.
/// </summary>
public sealed partial class GasPressureRegulatorSystem : SharedGasPressureRegulatorSystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasPressureRegulatorComponent, AfterAutoHandleStateEvent>(OnValveUpdate);
}
private void OnValveUpdate(Entity<GasPressureRegulatorComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateUi(ent);
}
protected override void UpdateUi(Entity<GasPressureRegulatorComponent> ent)
{
if (UserInterfaceSystem.TryGetOpenUi(ent.Owner, GasPressureRegulatorUiKey.Key, out var bui))
{
bui.Update();
}
}
}

View File

@@ -1,58 +0,0 @@
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Localizations;
using Robust.Client.UserInterface;
namespace Content.Client.Atmos.UI;
public sealed class GasPressureRegulatorBoundUserInterface(EntityUid owner, Enum uiKey)
: BoundUserInterface(owner, uiKey)
{
private GasPressureRegulatorWindow? _window;
protected override void Open()
{
base.Open();
_window = this.CreateWindow<GasPressureRegulatorWindow>();
_window.SetEntity(Owner);
_window.ThresholdPressureChanged += OnThresholdChanged;
if (EntMan.TryGetComponent(Owner, out GasPressureRegulatorComponent? comp))
_window.SetThresholdPressureInput(comp.Threshold);
Update();
}
public override void Update()
{
if (_window == null)
return;
_window.Title = Identity.Name(Owner, EntMan);
if (!EntMan.TryGetComponent(Owner, out GasPressureRegulatorComponent? comp))
return;
_window.SetThresholdPressureLabel(comp.Threshold);
_window.UpdateInfo(comp.InletPressure, comp.OutletPressure, comp.FlowRate);
}
private void OnThresholdChanged(string newThreshold)
{
var sentThreshold = 0f;
if (UserInputParser.TryFloat(newThreshold, out var parsedNewThreshold) && parsedNewThreshold >= 0 &&
!float.IsInfinity(parsedNewThreshold))
{
sentThreshold = parsedNewThreshold;
}
// Autofill to zero if the user inputs an invalid value.
_window?.SetThresholdPressureInput(sentThreshold);
SendPredictedMessage(new GasPressureRegulatorChangeThresholdMessage(sentThreshold));
}
}

View File

@@ -1,96 +0,0 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
SetSize="345 380"
MinSize="345 380"
Title="{Loc gas-pressure-regulator-ui-title}"
Resizable="False">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Vertical" Margin="0 10 0 10">
<BoxContainer Orientation="Vertical" Align="Center">
<Label Text="{Loc gas-pressure-regulator-ui-outlet}" Align="Center" StyleClasses="LabelKeyText" />
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
<Label Name="OutletPressureLabel" Text="N/A" Margin="0 0 4 0" />
<Label Text="{Loc gas-pressure-regulator-ui-pressure-unit}" />
</BoxContainer>
</BoxContainer>
<BoxContainer Orientation="Horizontal" Align="Center">
<BoxContainer Orientation="Vertical" Align="Center" HorizontalExpand="True">
<Label Text="{Loc gas-pressure-regulator-ui-target}" Align="Right" StyleClasses="LabelKeyText" />
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Right">
<Label Name="TargetPressureLabel" Margin="0 0 4 0" />
<Label Text="{Loc gas-pressure-regulator-ui-pressure-unit}" />
</BoxContainer>
</BoxContainer>
<ProgressBar Name="ToTargetBar" MaxValue="1" SetSize="5 75" Margin="10" Vertical="True" />
<SpriteView Name="EntityView" SetSize="64 64" Scale="3 3" OverrideDirection="North" Margin="0" />
<ProgressBar Name="FlowRateBar" MaxValue="1" SetSize="5 75" Margin="10" Vertical="True" />
<BoxContainer Orientation="Vertical" Align="Center" HorizontalExpand="True">
<Label Text="{Loc gas-pressure-regulator-ui-flow}" StyleClasses="LabelKeyText" />
<BoxContainer Orientation="Horizontal">
<Label Name="CurrentFlowLabel" Text="N/A" Margin="0 0 4 0" />
<Label Text="{Loc gas-pressure-regulator-ui-flow-rate-unit}" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
<BoxContainer Orientation="Vertical" Align="Center" Margin="1">
<Label Text="{Loc gas-pressure-regulator-ui-inlet}" Align="Center" StyleClasses="LabelKeyText" />
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
<Label Name="InletPressureLabel" Text="N/A" Margin="0 0 4 0" />
<Label Text="{Loc gas-pressure-regulator-ui-pressure-unit}" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
<!-- Controls to Set Pressure -->
<controls:StripeBack Name="SetPressureStripeBack" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="10 10 10 10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<LineEdit Name="ThresholdInput" HorizontalExpand="True" MinSize="70 0" />
<Button Name="SetThresholdButton" Text="{Loc gas-pressure-regulator-ui-set-threshold}"
Disabled="True" Margin="5 0 0 0" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 5 0 0">
<Button Name="Subtract1000Button" Text="{Loc gas-pressure-regulator-ui-subtract-1000}"
HorizontalExpand="True" Margin="0 2 2 0"
StyleClasses="OpenBoth" />
<Button Name="Subtract100Button" Text="{Loc gas-pressure-regulator-ui-subtract-100}"
HorizontalExpand="True" Margin="0 2 2 0"
StyleClasses="OpenBoth" />
<Button Name="Subtract10Button" Text="{Loc gas-pressure-regulator-ui-subtract-10}"
HorizontalExpand="True" Margin="0 2 2 0"
StyleClasses="OpenBoth" />
<Button Name="Add10Button" Text="{Loc gas-pressure-regulator-ui-add-10}" HorizontalExpand="True"
Margin="0 2 2 0"
StyleClasses="OpenBoth" />
<Button Name="Add100Button" Text="{Loc gas-pressure-regulator-ui-add-100}"
HorizontalExpand="True" Margin="0 2 2 0"
StyleClasses="OpenBoth" />
<Button Name="Add1000Button" Text="{Loc gas-pressure-regulator-ui-add-1000}"
HorizontalExpand="True" Margin="0 2 2 0"
StyleClasses="OpenBoth" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 5 0 0">
<Button Name="ZeroThresholdButton" Text="{Loc gas-pressure-regulator-ui-zero-threshold}"
HorizontalExpand="True" Margin="0 0 5 0" />
<Button Name="SetToCurrentPressureButton"
Text="{Loc gas-pressure-regulator-ui-set-to-current-pressure}" HorizontalExpand="True" />
</BoxContainer>
</BoxContainer>
</controls:StripeBack>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -1,129 +0,0 @@
using System.Globalization;
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.Atmos.UI;
/// <summary>
/// Client-side UI for controlling a pressure regulator.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class GasPressureRegulatorWindow : FancyWindow
{
private float _flowRate;
public GasPressureRegulatorWindow()
{
RobustXamlLoader.Load(this);
ThresholdInput.OnTextChanged += _ => SetThresholdButton.Disabled = false;
SetThresholdButton.OnPressed += _ =>
{
ThresholdPressureChanged?.Invoke(ThresholdInput.Text ??= "");
SetThresholdButton.Disabled = true;
};
SetToCurrentPressureButton.OnPressed += _ =>
{
if (InletPressureLabel.Text != null)
{
ThresholdInput.Text = InletPressureLabel.Text;
}
SetThresholdButton.Disabled = false;
};
ZeroThresholdButton.OnPressed += _ =>
{
ThresholdInput.Text = "0";
SetThresholdButton.Disabled = false;
};
Add1000Button.OnPressed += _ => AdjustThreshold(1000);
Add100Button.OnPressed += _ => AdjustThreshold(100);
Add10Button.OnPressed += _ => AdjustThreshold(10);
Subtract10Button.OnPressed += _ => AdjustThreshold(-10);
Subtract100Button.OnPressed += _ => AdjustThreshold(-100);
Subtract1000Button.OnPressed += _ => AdjustThreshold(-1000);
return;
void AdjustThreshold(float adjustment)
{
if (float.TryParse(ThresholdInput.Text, out var currentValue))
{
ThresholdInput.Text = (currentValue + adjustment).ToString(CultureInfo.CurrentCulture);
SetThresholdButton.Disabled = false;
}
}
}
public event Action<string>? ThresholdPressureChanged;
/// <summary>
/// Sets the current threshold pressure label. This is not setting the threshold input box.
/// </summary>
/// <param name="threshold"> Threshold to set.</param>
public void SetThresholdPressureLabel(float threshold)
{
TargetPressureLabel.Text = threshold.ToString(CultureInfo.CurrentCulture);
}
/// <summary>
/// Sets the threshold pressure input field with the given value.
/// When the client opens the UI the field will be autofilled with the current threshold pressure.
/// </summary>
/// <param name="input">The threshold pressure value to autofill into the input field.</param>
public void SetThresholdPressureInput(float input)
{
ThresholdInput.Text = input.ToString(CultureInfo.CurrentCulture);
}
/// <summary>
/// Sets the entity to be visible in the UI.
/// </summary>
/// <param name="entity"></param>
public void SetEntity(EntityUid entity)
{
EntityView.SetEntity(entity);
}
/// <summary>
/// Updates the UI for the labels.
/// </summary>
/// <param name="inletPressure">The current pressure at the valve's inlet.</param>
/// <param name="outletPressure">The current pressure at the valve's outlet.</param>
/// <param name="flowRate">The current flow rate through the valve.</param>
public void UpdateInfo(float inletPressure, float outletPressure, float flowRate)
{
if (float.TryParse(TargetPressureLabel.Text, out var parsedfloat))
ToTargetBar.Value = inletPressure / parsedfloat;
InletPressureLabel.Text = float.Round(inletPressure).ToString(CultureInfo.CurrentCulture);
OutletPressureLabel.Text = float.Round(outletPressure).ToString(CultureInfo.CurrentCulture);
CurrentFlowLabel.Text = float.IsNaN(flowRate) ? "0" : flowRate.ToString(CultureInfo.CurrentCulture);
_flowRate = flowRate;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
// Defines the flow rate at which the progress bar fills in one second.
// If the flow rate is >50 L/s, the bar will take <1 second to fill.
// If the flow rate is <50 L/s, the bar will take >1 second to fill.
const int barFillPerSecond = 50;
var maxValue = FlowRateBar.MaxValue;
// Increment the progress bar value based on elapsed time
FlowRateBar.Value += (_flowRate / barFillPerSecond) * args.DeltaSeconds;
// Reset the progress bar when it is fully filled
if (FlowRateBar.Value >= maxValue)
{
FlowRateBar.Value = 0f;
}
}
}

View File

@@ -168,7 +168,7 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
_targetTime = _gameTiming.CurTime + TimeSpan.FromSeconds(_cooldown);
var player = _playerManager.LocalEntity;
if (!TryComp(player, out TransformComponent? xform))
if (!EntityManager.TryGetComponent(player, out TransformComponent? xform))
{
ClearSounds();
return;

View File

@@ -1,5 +0,0 @@
using Content.Shared.Body.Systems;
namespace Content.Client.Body.Systems;
public sealed class BloodstreamSystem : SharedBloodstreamSystem;

View File

@@ -5,27 +5,32 @@ using Robust.Shared.Containers;
namespace Content.Client.Commands;
public sealed class HideMechanismsCommand : LocalizedEntityCommands
public sealed class HideMechanismsCommand : LocalizedCommands
{
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SpriteSystem _spriteSystem = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public override string Command => "hidemechanisms";
public override string Description => LocalizationManager.GetString($"cmd-{Command}-desc", ("showMechanismsCommand", ShowMechanismsCommand.CommandName));
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var query = EntityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
var containerSys = _entityManager.System<SharedContainerSystem>();
var spriteSys = _entityManager.System<SpriteSystem>();
var query = _entityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
while (query.MoveNext(out var uid, out _, out var sprite))
{
_spriteSystem.SetContainerOccluded((uid, sprite), false);
spriteSys.SetContainerOccluded((uid, sprite), false);
var tempParent = uid;
while (_containerSystem.TryGetContainingContainer((tempParent, null, null), out var container))
while (containerSys.TryGetContainingContainer((tempParent, null, null), out var container))
{
if (!container.ShowContents)
{
_spriteSystem.SetContainerOccluded((uid, sprite), true);
spriteSys.SetContainerOccluded((uid, sprite), true);
break;
}

View File

@@ -1,46 +1,57 @@
using Content.Shared.Damage.Prototypes;
using Content.Shared.Overlays;
using Robust.Client.Player;
using Robust.Shared.Console;
using Robust.Shared.Prototypes;
using System.Linq;
namespace Content.Client.Commands;
public sealed class ShowHealthBarsCommand : LocalizedEntityCommands
public sealed class ShowHealthBarsCommand : LocalizedCommands
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public override string Command => "showhealthbars";
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = shell.Player;
var player = _playerManager.LocalSession;
if (player == null)
{
shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command"));
shell.WriteError(LocalizationManager.GetString($"cmd-{Command}-error-not-player"));
return;
}
if (player.AttachedEntity is not { } playerEntity)
var playerEntity = player?.AttachedEntity;
if (!playerEntity.HasValue)
{
shell.WriteError(Loc.GetString("shell-must-be-attached-to-entity"));
shell.WriteError(LocalizationManager.GetString($"cmd-{Command}-error-no-entity"));
return;
}
if (!EntityManager.HasComponent<ShowHealthBarsComponent>(playerEntity))
if (!_entityManager.HasComponent<ShowHealthBarsComponent>(playerEntity))
{
var showHealthBarsComponent = new ShowHealthBarsComponent
{
DamageContainers = args.Select(arg => new ProtoId<DamageContainerPrototype>(arg)).ToList(),
HealthStatusIcon = null,
NetSyncEnabled = false,
NetSyncEnabled = false
};
EntityManager.AddComponent(playerEntity, showHealthBarsComponent, true);
_entityManager.AddComponent(playerEntity.Value, showHealthBarsComponent, true);
shell.WriteLine(Loc.GetString("cmd-showhealthbars-notify-enabled", ("args", string.Join(", ", args))));
shell.WriteLine(LocalizationManager.GetString($"cmd-{Command}-notify-enabled", ("args", string.Join(", ", args))));
return;
}
else
{
_entityManager.RemoveComponentDeferred<ShowHealthBarsComponent>(playerEntity.Value);
shell.WriteLine(LocalizationManager.GetString($"cmd-{Command}-notify-disabled"));
}
EntityManager.RemoveComponentDeferred<ShowHealthBarsComponent>(playerEntity);
shell.WriteLine(Loc.GetString("cmd-showhealthbars-notify-disabled"));
return;
}
}

View File

@@ -4,19 +4,24 @@ using Robust.Shared.Console;
namespace Content.Client.Commands;
public sealed class ShowMechanismsCommand : LocalizedEntityCommands
public sealed class ShowMechanismsCommand : LocalizedCommands
{
[Dependency] private readonly SpriteSystem _spriteSystem = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
public override string Command => "showmechanisms";
public const string CommandName = "showmechanisms";
public override string Command => CommandName;
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var query = EntityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
var spriteSys = _entManager.System<SpriteSystem>();
var query = _entManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
while (query.MoveNext(out var uid, out _, out var sprite))
{
_spriteSystem.SetContainerOccluded((uid, sprite), false);
spriteSys.SetContainerOccluded((uid, sprite), false);
}
}
}

View File

@@ -286,14 +286,14 @@ namespace Content.Client.Construction
if (!CheckConstructionConditions(prototype, loc, dir, user, showPopup: true))
return false;
ghost = Spawn("constructionghost", loc);
var comp = Comp<ConstructionGhostComponent>(ghost.Value);
ghost = EntityManager.SpawnEntity("constructionghost", loc);
var comp = EntityManager.GetComponent<ConstructionGhostComponent>(ghost.Value);
comp.Prototype = prototype;
comp.GhostId = ghost.GetHashCode();
Comp<TransformComponent>(ghost.Value).LocalRotation = dir.ToAngle();
EntityManager.GetComponent<TransformComponent>(ghost.Value).LocalRotation = dir.ToAngle();
_ghosts.Add(comp.GhostId, ghost.Value);
var sprite = Comp<SpriteComponent>(ghost.Value);
var sprite = EntityManager.GetComponent<SpriteComponent>(ghost.Value);
_sprite.SetColor((ghost.Value, sprite), new Color(48, 255, 48, 128));
if (targetProto.TryGetComponent(out IconComponent? icon, EntityManager.ComponentFactory))
@@ -306,7 +306,7 @@ namespace Content.Client.Construction
else if (targetProto.Components.TryGetValue("Sprite", out _))
{
var dummy = EntityManager.SpawnEntity(targetProtoId, MapCoordinates.Nullspace);
var targetSprite = EnsureComp<SpriteComponent>(dummy);
var targetSprite = EntityManager.EnsureComponent<SpriteComponent>(dummy);
EntityManager.System<AppearanceSystem>().OnChangeData(dummy, targetSprite);
for (var i = 0; i < targetSprite.AllLayers.Count(); i++)
@@ -325,7 +325,7 @@ namespace Content.Client.Construction
_sprite.LayerSetVisible((ghost.Value, sprite), i, true);
}
Del(dummy);
EntityManager.DeleteEntity(dummy);
}
else
return false;
@@ -367,7 +367,7 @@ namespace Content.Client.Construction
{
foreach (var ghost in _ghosts)
{
if (Comp<TransformComponent>(ghost.Value).Coordinates.Equals(loc))
if (EntityManager.GetComponent<TransformComponent>(ghost.Value).Coordinates.Equals(loc))
return true;
}
@@ -384,7 +384,7 @@ namespace Content.Client.Construction
throw new ArgumentException($"Can't start construction for a ghost with no prototype. Ghost id: {ghostId}");
}
var transform = Comp<TransformComponent>(ghostId);
var transform = EntityManager.GetComponent<TransformComponent>(ghostId);
var msg = new TryStartStructureConstructionMessage(GetNetCoordinates(transform.Coordinates), ghostComp.Prototype.ID, transform.LocalRotation, ghostId.GetHashCode());
RaiseNetworkEvent(msg);
}
@@ -405,7 +405,7 @@ namespace Content.Client.Construction
if (!_ghosts.TryGetValue(ghostId, out var ghost))
return;
QueueDel(ghost);
EntityManager.QueueDeleteEntity(ghost);
_ghosts.Remove(ghostId);
}
@@ -416,7 +416,7 @@ namespace Content.Client.Construction
{
foreach (var ghost in _ghosts.Values)
{
QueueDel(ghost);
EntityManager.QueueDeleteEntity(ghost);
}
_ghosts.Clear();

View File

@@ -7,7 +7,7 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<OutputPath>..\bin\Content.Client\</OutputPath>
<OutputType Condition="'$(FullRelease)' != 'True'">Exe</OutputType>
<WarningsAsErrors>RA0032;nullable</WarningsAsErrors>
<WarningsAsErrors>nullable</WarningsAsErrors>
<Nullable>enable</Nullable>
<Configurations>Debug;Release;Tools;DebugOpt</Configurations>
<Platforms>AnyCPU</Platforms>

View File

@@ -1,5 +1,5 @@
using Content.Shared.Drowsiness;
using Content.Shared.StatusEffectNew;
using Content.Shared.StatusEffect;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
@@ -15,7 +15,6 @@ public sealed class DrowsinessOverlay : Overlay
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private readonly SharedStatusEffectsSystem _statusEffects = default!;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public override bool RequestScreenTexture => true;
@@ -30,9 +29,6 @@ public sealed class DrowsinessOverlay : Overlay
public DrowsinessOverlay()
{
IoCManager.InjectDependencies(this);
_statusEffects = _sysMan.GetEntitySystem<SharedStatusEffectsSystem>();
_drowsinessShader = _prototypeManager.Index<ShaderPrototype>("Drowsiness").InstanceUnique();
}
@@ -43,11 +39,17 @@ public sealed class DrowsinessOverlay : Overlay
if (playerEntity == null)
return;
if (!_statusEffects.TryGetEffectsEndTimeWithComp<DrowsinessStatusEffectComponent>(playerEntity, out var endTime))
if (!_entityManager.HasComponent<DrowsinessComponent>(playerEntity)
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
return;
endTime ??= TimeSpan.MaxValue;
var timeLeft = (float)(endTime - _timing.CurTime).Value.TotalSeconds;
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
if (!statusSys.TryGetTime(playerEntity.Value, SharedDrowsinessSystem.DrowsinessKey, out var time, status))
return;
var curTime = _timing.CurTime;
var timeLeft = (float)(time.Value.Item2 - curTime).TotalSeconds;
CurrentPower += 8f * (0.5f * timeLeft - CurrentPower) * args.DeltaSeconds / (timeLeft + 1);
}

View File

@@ -1,5 +1,4 @@
using Content.Shared.Drowsiness;
using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Player;
@@ -10,7 +9,6 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly SharedStatusEffectsSystem _statusEffects = default!;
private DrowsinessOverlay _overlay = default!;
@@ -18,44 +16,35 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
{
base.Initialize();
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectAppliedEvent>(OnDrowsinessApply);
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectRemovedEvent>(OnDrowsinessShutdown);
SubscribeLocalEvent<DrowsinessComponent, ComponentInit>(OnDrowsinessInit);
SubscribeLocalEvent<DrowsinessComponent, ComponentShutdown>(OnDrowsinessShutdown);
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnStatusEffectPlayerAttached);
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnStatusEffectPlayerDetached);
SubscribeLocalEvent<DrowsinessComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<DrowsinessComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
_overlay = new();
}
private void OnDrowsinessApply(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
{
if (_player.LocalEntity == args.Target)
_overlayMan.AddOverlay(_overlay);
}
private void OnDrowsinessShutdown(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
{
if (_player.LocalEntity != args.Target)
return;
if (!_statusEffects.HasEffectComp<DrowsinessStatusEffectComponent>(_player.LocalEntity.Value))
{
_overlay.CurrentPower = 0;
_overlayMan.RemoveOverlay(_overlay);
}
}
private void OnStatusEffectPlayerAttached(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
private void OnPlayerAttached(EntityUid uid, DrowsinessComponent component, LocalPlayerAttachedEvent args)
{
_overlayMan.AddOverlay(_overlay);
}
private void OnStatusEffectPlayerDetached(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
private void OnPlayerDetached(EntityUid uid, DrowsinessComponent component, LocalPlayerDetachedEvent args)
{
if (_player.LocalEntity is null)
return;
_overlay.CurrentPower = 0;
_overlayMan.RemoveOverlay(_overlay);
}
if (!_statusEffects.HasEffectComp<DrowsinessStatusEffectComponent>(_player.LocalEntity.Value))
private void OnDrowsinessInit(EntityUid uid, DrowsinessComponent component, ComponentInit args)
{
if (_player.LocalEntity == uid)
_overlayMan.AddOverlay(_overlay);
}
private void OnDrowsinessShutdown(EntityUid uid, DrowsinessComponent component, ComponentShutdown args)
{
if (_player.LocalEntity == uid)
{
_overlay.CurrentPower = 0;
_overlayMan.RemoveOverlay(_overlay);

View File

@@ -1,5 +1,4 @@
using Content.Shared.Drugs;
using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Player;
@@ -18,47 +17,49 @@ public sealed class DrugOverlaySystem : EntitySystem
private RainbowOverlay _overlay = default!;
public static string RainbowKey = "SeeingRainbows";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectAppliedEvent>(OnApplied);
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRemovedEvent>(OnRemoved);
SubscribeLocalEvent<SeeingRainbowsComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<SeeingRainbowsComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnPlayerAttached);
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnPlayerDetached);
SubscribeLocalEvent<SeeingRainbowsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<SeeingRainbowsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
_overlay = new();
}
private void OnRemoved(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
private void OnPlayerAttached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerAttachedEvent args)
{
if (_player.LocalEntity != args.Target)
return;
_overlayMan.AddOverlay(_overlay);
}
private void OnPlayerDetached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerDetachedEvent args)
{
_overlay.Intoxication = 0;
_overlay.TimeTicker = 0;
_overlayMan.RemoveOverlay(_overlay);
}
private void OnApplied(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
private void OnInit(EntityUid uid, SeeingRainbowsComponent component, ComponentInit args)
{
if (_player.LocalEntity != args.Target)
return;
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
_overlayMan.AddOverlay(_overlay);
if (_player.LocalEntity == uid)
{
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
_overlayMan.AddOverlay(_overlay);
}
}
private void OnPlayerAttached(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
private void OnShutdown(EntityUid uid, SeeingRainbowsComponent component, ComponentShutdown args)
{
_overlayMan.AddOverlay(_overlay);
}
private void OnPlayerDetached(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
{
_overlay.Intoxication = 0;
_overlay.TimeTicker = 0;
_overlayMan.RemoveOverlay(_overlay);
if (_player.LocalEntity == uid)
{
_overlay.Intoxication = 0;
_overlay.TimeTicker = 0;
_overlayMan.RemoveOverlay(_overlay);
}
}
}

View File

@@ -1,6 +1,6 @@
using Content.Shared.CCVar;
using Content.Shared.Drugs;
using Content.Shared.StatusEffectNew;
using Content.Shared.StatusEffect;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Configuration;
@@ -17,8 +17,6 @@ public sealed class RainbowOverlay : Overlay
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private readonly SharedStatusEffectsSystem _statusEffects = default!;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public override bool RequestScreenTexture => true;
@@ -39,8 +37,6 @@ public sealed class RainbowOverlay : Overlay
{
IoCManager.InjectDependencies(this);
_statusEffects = _sysMan.GetEntitySystem<SharedStatusEffectsSystem>();
_rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique();
_config.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
}
@@ -58,13 +54,18 @@ public sealed class RainbowOverlay : Overlay
if (playerEntity == null)
return;
if (!_statusEffects.TryGetEffectsEndTimeWithComp<SeeingRainbowsStatusEffectComponent>(playerEntity, out var endTime))
if (!_entityManager.HasComponent<SeeingRainbowsComponent>(playerEntity)
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
return;
endTime ??= TimeSpan.MaxValue;
var timeLeft = (float)(endTime - _timing.CurTime).Value.TotalSeconds;
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status))
return;
var timeLeft = (float)(time.Value.Item2 - time.Value.Item1).TotalSeconds;
TimeTicker += args.DeltaSeconds;
if (timeLeft - TimeTicker > timeLeft / 16f)
{
Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;

View File

@@ -110,7 +110,7 @@ namespace Content.Client.Examine
{
var entity = args.EntityUid;
if (!args.EntityUid.IsValid() || !Exists(entity))
if (!args.EntityUid.IsValid() || !EntityManager.EntityExists(entity))
{
return false;
}
@@ -225,7 +225,7 @@ namespace Content.Client.Examine
vBox.AddChild(hBox);
if (HasComp<SpriteComponent>(target))
if (EntityManager.HasComponent<SpriteComponent>(target))
{
var spriteView = new SpriteView
{

View File

@@ -61,7 +61,7 @@ public sealed partial class TriggerSystem
private void OnProximityInit(EntityUid uid, TriggerOnProximityComponent component, ComponentInit args)
{
EnsureComp<AnimationPlayerComponent>(uid);
EntityManager.EnsureComponent<AnimationPlayerComponent>(uid);
}
private void OnProxAppChange(EntityUid uid, TriggerOnProximityComponent component, ref AppearanceChangeEvent args)

View File

@@ -1,5 +1,6 @@
using Content.Shared.Flash;
using Content.Shared.Flash.Components;
using Content.Shared.StatusEffect;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Player;

View File

@@ -6,7 +6,7 @@ using Robust.Shared.Utility;
namespace Content.Client.Guidebook.Richtext;
[UsedImplicitly]
public sealed class KeyBindTag : IMarkupTagHandler
public sealed class KeyBindTag : IMarkupTag
{
[Dependency] private readonly IInputManager _inputManager = default!;

View File

@@ -9,7 +9,7 @@ namespace Content.Client.Guidebook.RichText;
/// In order to be accessed by this tag, the desired field/property must
/// be tagged with <see cref="Shared.Guidebook.GuidebookDataAttribute"/>.
/// </summary>
public sealed class ProtodataTag : IMarkupTagHandler
public sealed class ProtodataTag : IMarkupTag
{
[Dependency] private readonly ILogManager _logMan = default!;
[Dependency] private readonly IEntityManager _entMan = default!;

View File

@@ -10,14 +10,16 @@ using Content.Client.UserInterface.ControlExtensions;
namespace Content.Client.Guidebook.RichText;
[UsedImplicitly]
public sealed class TextLinkTag : IMarkupTagHandler
public sealed class TextLinkTag : IMarkupTag
{
public static Color LinkColor => Color.CornflowerBlue;
public string Name => "textlink";
public Control? Control;
/// <inheritdoc/>
public bool TryCreateControl(MarkupNode node, [NotNullWhen(true)] out Control? control)
public bool TryGetControl(MarkupNode node, [NotNullWhen(true)] out Control? control)
{
if (!node.Value.TryGetString(out var text)
|| !node.Attributes.TryGetValue("link", out var linkParameter)
@@ -36,21 +38,22 @@ public sealed class TextLinkTag : IMarkupTagHandler
label.OnMouseEntered += _ => label.FontColorOverride = Color.LightSkyBlue;
label.OnMouseExited += _ => label.FontColorOverride = Color.CornflowerBlue;
label.OnKeyBindDown += args => OnKeybindDown(args, link, label);
label.OnKeyBindDown += args => OnKeybindDown(args, link);
control = label;
Control = label;
return true;
}
private void OnKeybindDown(GUIBoundKeyEventArgs args, string link, Control? control)
private void OnKeybindDown(GUIBoundKeyEventArgs args, string link)
{
if (args.Function != EngineKeyFunctions.UIClick)
return;
if (control == null)
if (Control == null)
return;
if (control.TryGetParentHandler<ILinkClickHandler>(out var handler))
if (Control.TryGetParentHandler<ILinkClickHandler>(out var handler))
handler.HandleClick(link);
else
Logger.Warning("Warning! No valid ILinkClickHandler found.");

View File

@@ -16,6 +16,7 @@ using Robust.Client.UserInterface;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Hands.Systems
@@ -26,13 +27,16 @@ namespace Content.Client.Hands.Systems
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly StrippableSystem _stripSys = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly ExamineSystem _examine = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
public event Action<string, HandLocation>? OnPlayerAddHand;
public event Action<string>? OnPlayerRemoveHand;
public event Action<string?>? OnPlayerSetActiveHand;
public event Action<Entity<HandsComponent>>? OnPlayerHandsAdded;
public event Action<HandsComponent>? OnPlayerHandsAdded;
public event Action? OnPlayerHandsRemoved;
public event Action<string, EntityUid>? OnPlayerItemAdded;
public event Action<string, EntityUid>? OnPlayerItemRemoved;
@@ -54,28 +58,67 @@ namespace Content.Client.Hands.Systems
}
#region StateHandling
private void HandleComponentState(Entity<HandsComponent> ent, ref ComponentHandleState args)
private void HandleComponentState(EntityUid uid, HandsComponent component, ref ComponentHandleState args)
{
if (args.Current is not HandsComponentState state)
return;
var newHands = state.Hands.Keys.Except(ent.Comp.Hands.Keys); // hands that were added between states
var oldHands = ent.Comp.Hands.Keys.Except(state.Hands.Keys); // hands that were removed between states
foreach (var handId in oldHands)
var handsModified = component.Hands.Count != state.Hands.Count;
// we need to check that, even if we have the same amount, that the individual hands didn't change.
if (!handsModified)
{
RemoveHand(ent.AsNullable(), handId);
foreach (var hand in component.Hands.Values)
{
if (state.Hands.Contains(hand))
continue;
handsModified = true;
break;
}
}
foreach (var handId in state.SortedHands.Intersect(newHands))
var manager = EnsureComp<ContainerManagerComponent>(uid);
if (handsModified)
{
AddHand(ent.AsNullable(), handId, state.Hands[handId]);
List<Hand> addedHands = new();
foreach (var hand in state.Hands)
{
if (component.Hands.ContainsKey(hand.Name))
continue;
var container = _containerSystem.EnsureContainer<ContainerSlot>(uid, hand.Name, manager);
var newHand = new Hand(hand.Name, hand.Location, container);
component.Hands.Add(hand.Name, newHand);
addedHands.Add(newHand);
}
foreach (var name in component.Hands.Keys)
{
if (!state.HandNames.Contains(name))
{
RemoveHand(uid, name, component);
}
}
component.SortedHands.Clear();
component.SortedHands.AddRange(state.HandNames);
var sorted = addedHands.OrderBy(hand => component.SortedHands.IndexOf(hand.Name));
foreach (var hand in sorted)
{
AddHand(uid, hand, component);
}
}
ent.Comp.SortedHands = new (state.SortedHands);
SetActiveHand(ent.AsNullable(), state.ActiveHandId);
_stripSys.UpdateUi(uid);
_stripSys.UpdateUi(ent);
if (component.ActiveHand == null && state.ActiveHand == null)
return; //edge case
if (component.ActiveHand != null && state.ActiveHand != component.ActiveHand.Name)
{
SetActiveHand(uid, component.Hands[state.ActiveHand!], component);
}
}
#endregion
@@ -86,77 +129,72 @@ namespace Content.Client.Hands.Systems
return;
}
OnPlayerHandsAdded?.Invoke(hands.Value);
OnPlayerHandsAdded?.Invoke(hands);
}
public override void DoDrop(Entity<HandsComponent?> ent,
string handId,
bool doDropInteraction = true,
bool log = true)
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null, bool log = true)
{
base.DoDrop(ent, handId, doDropInteraction, log);
base.DoDrop(uid, hand, doDropInteraction, hands, log);
if (TryGetHeldItem(ent, handId, out var held) && TryComp(held, out SpriteComponent? sprite))
if (TryComp(hand.HeldEntity, out SpriteComponent? sprite))
sprite.RenderOrder = EntityManager.CurrentTick.Value;
}
public EntityUid? GetActiveHandEntity()
{
return TryGetPlayerHands(out var hands) ? GetActiveItem(hands.Value.AsNullable()) : null;
return TryGetPlayerHands(out var hands) ? hands.ActiveHandEntity : null;
}
/// <summary>
/// Get the hands component of the local player
/// </summary>
public bool TryGetPlayerHands([NotNullWhen(true)] out Entity<HandsComponent>? hands)
public bool TryGetPlayerHands([NotNullWhen(true)] out HandsComponent? hands)
{
var player = _playerManager.LocalEntity;
hands = null;
if (player == null || !TryComp<HandsComponent>(player.Value, out var handsComp))
return false;
hands = (player.Value, handsComp);
return true;
return player != null && TryComp(player.Value, out hands);
}
/// <summary>
/// Called when a user clicked on their hands GUI
/// </summary>
public void UIHandClick(Entity<HandsComponent> ent, string handName)
public void UIHandClick(HandsComponent hands, string handName)
{
var hands = ent.Comp;
if (hands.ActiveHandId == null)
if (!hands.Hands.TryGetValue(handName, out var pressedHand))
return;
var pressedEntity = GetHeldItem(ent.AsNullable(), handName);
var activeEntity = GetActiveItem(ent.AsNullable());
if (hands.ActiveHand == null)
return;
if (handName == hands.ActiveHandId && activeEntity != null)
var pressedEntity = pressedHand.HeldEntity;
var activeEntity = hands.ActiveHand.HeldEntity;
if (pressedHand == hands.ActiveHand && activeEntity != null)
{
// use item in hand
// it will always be attack_self() in my heart.
RaisePredictiveEvent(new RequestUseInHandEvent());
EntityManager.RaisePredictiveEvent(new RequestUseInHandEvent());
return;
}
if (handName != hands.ActiveHandId && pressedEntity == null)
if (pressedHand != hands.ActiveHand && pressedEntity == null)
{
// change active hand
RaisePredictiveEvent(new RequestSetHandEvent(handName));
EntityManager.RaisePredictiveEvent(new RequestSetHandEvent(handName));
return;
}
if (handName != hands.ActiveHandId && pressedEntity != null && activeEntity != null)
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity != null)
{
// use active item on held item
RaisePredictiveEvent(new RequestHandInteractUsingEvent(handName));
EntityManager.RaisePredictiveEvent(new RequestHandInteractUsingEvent(pressedHand.Name));
return;
}
if (handName != hands.ActiveHandId && pressedEntity != null && activeEntity == null)
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity == null)
{
// move the item to the active hand
RaisePredictiveEvent(new RequestMoveHandItemEvent(handName));
EntityManager.RaisePredictiveEvent(new RequestMoveHandItemEvent(pressedHand.Name));
}
}
@@ -166,18 +204,19 @@ namespace Content.Client.Hands.Systems
/// </summary>
public void UIHandActivate(string handName)
{
RaisePredictiveEvent(new RequestActivateInHandEvent(handName));
EntityManager.RaisePredictiveEvent(new RequestActivateInHandEvent(handName));
}
public void UIInventoryExamine(string handName)
{
if (!TryGetPlayerHands(out var hands) ||
!TryGetHeldItem(hands.Value.AsNullable(), handName, out var heldEntity))
!hands.Hands.TryGetValue(handName, out var hand) ||
hand.HeldEntity is not { Valid: true } entity)
{
return;
}
_examine.DoExamine(heldEntity.Value);
_examine.DoExamine(entity);
}
/// <summary>
@@ -187,12 +226,13 @@ namespace Content.Client.Hands.Systems
public void UIHandOpenContextMenu(string handName)
{
if (!TryGetPlayerHands(out var hands) ||
!TryGetHeldItem(hands.Value.AsNullable(), handName, out var heldEntity))
!hands.Hands.TryGetValue(handName, out var hand) ||
hand.HeldEntity is not { Valid: true } entity)
{
return;
}
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(heldEntity.Value);
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(entity);
}
public void UIHandAltActivateItem(string handName)
@@ -206,67 +246,60 @@ namespace Content.Client.Hands.Systems
{
base.HandleEntityInserted(uid, hands, args);
if (!hands.Hands.ContainsKey(args.Container.ID))
if (!hands.Hands.TryGetValue(args.Container.ID, out var hand))
return;
UpdateHandVisuals(uid, args.Entity, args.Container.ID);
UpdateHandVisuals(uid, args.Entity, hand);
_stripSys.UpdateUi(uid);
if (uid != _playerManager.LocalEntity)
return;
OnPlayerItemAdded?.Invoke(args.Container.ID, args.Entity);
OnPlayerItemAdded?.Invoke(hand.Name, args.Entity);
if (HasComp<VirtualItemComponent>(args.Entity))
OnPlayerHandBlocked?.Invoke(args.Container.ID);
OnPlayerHandBlocked?.Invoke(hand.Name);
}
protected override void HandleEntityRemoved(EntityUid uid, HandsComponent hands, EntRemovedFromContainerMessage args)
{
base.HandleEntityRemoved(uid, hands, args);
if (!hands.Hands.ContainsKey(args.Container.ID))
if (!hands.Hands.TryGetValue(args.Container.ID, out var hand))
return;
UpdateHandVisuals(uid, args.Entity, args.Container.ID);
UpdateHandVisuals(uid, args.Entity, hand);
_stripSys.UpdateUi(uid);
if (uid != _playerManager.LocalEntity)
return;
OnPlayerItemRemoved?.Invoke(args.Container.ID, args.Entity);
OnPlayerItemRemoved?.Invoke(hand.Name, args.Entity);
if (HasComp<VirtualItemComponent>(args.Entity))
OnPlayerHandUnblocked?.Invoke(args.Container.ID);
OnPlayerHandUnblocked?.Invoke(hand.Name);
}
/// <summary>
/// Update the players sprite with new in-hand visuals.
/// </summary>
private void UpdateHandVisuals(Entity<HandsComponent?, SpriteComponent?> ent, EntityUid held, string handId)
private void UpdateHandVisuals(EntityUid uid, EntityUid held, Hand hand, HandsComponent? handComp = null, SpriteComponent? sprite = null)
{
if (!Resolve(ent, ref ent.Comp1, ref ent.Comp2, false))
return;
var handComp = ent.Comp1;
var sprite = ent.Comp2;
if (!TryGetHand((ent, handComp), handId, out var hand))
if (!Resolve(uid, ref handComp, ref sprite, false))
return;
// visual update might involve changes to the entity's effective sprite -> need to update hands GUI.
if (ent == _playerManager.LocalEntity)
OnPlayerItemAdded?.Invoke(handId, held);
if (uid == _playerManager.LocalEntity)
OnPlayerItemAdded?.Invoke(hand.Name, held);
if (!handComp.ShowInHands)
return;
// Remove old layers. We could also just set them to invisible, but as items may add arbitrary layers, this
// may eventually bloat the player with lots of layers.
if (handComp.RevealedLayers.TryGetValue(hand.Value.Location, out var revealedLayers))
if (handComp.RevealedLayers.TryGetValue(hand.Location, out var revealedLayers))
{
foreach (var key in revealedLayers)
{
_sprite.RemoveLayer((ent, sprite), key);
_sprite.RemoveLayer((uid, sprite), key);
}
revealedLayers.Clear();
@@ -274,22 +307,22 @@ namespace Content.Client.Hands.Systems
else
{
revealedLayers = new();
handComp.RevealedLayers[hand.Value.Location] = revealedLayers;
handComp.RevealedLayers[hand.Location] = revealedLayers;
}
if (HandIsEmpty((ent, handComp), handId))
if (hand.HeldEntity == null)
{
// the held item was removed.
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(ent, revealedLayers), true);
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
return;
}
var ev = new GetInhandVisualsEvent(ent, hand.Value.Location);
var ev = new GetInhandVisualsEvent(uid, hand.Location);
RaiseLocalEvent(held, ev);
if (ev.Layers.Count == 0)
{
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(ent, revealedLayers), true);
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
return;
}
@@ -302,7 +335,7 @@ namespace Content.Client.Hands.Systems
continue;
}
var index = _sprite.LayerMapReserve((ent, sprite), key);
var index = _sprite.LayerMapReserve((uid, sprite), key);
// In case no RSI is given, use the item's base RSI as a default. This cuts down on a lot of unnecessary yaml entries.
if (layerData.RsiPath == null
@@ -310,34 +343,35 @@ namespace Content.Client.Hands.Systems
&& sprite[index].Rsi == null)
{
if (TryComp<ItemComponent>(held, out var itemComponent) && itemComponent.RsiPath != null)
_sprite.LayerSetRsi((ent, sprite), index, new ResPath(itemComponent.RsiPath));
_sprite.LayerSetRsi((uid, sprite), index, new ResPath(itemComponent.RsiPath));
else if (TryComp(held, out SpriteComponent? clothingSprite))
_sprite.LayerSetRsi((ent, sprite), index, clothingSprite.BaseRSI);
_sprite.LayerSetRsi((uid, sprite), index, clothingSprite.BaseRSI);
}
_sprite.LayerSetData((ent, sprite), index, layerData);
_sprite.LayerSetData((uid, sprite), index, layerData);
// Add displacement maps
var displacement = hand.Value.Location switch
var displacement = hand.Location switch
{
HandLocation.Left => handComp.LeftHandDisplacement,
HandLocation.Right => handComp.RightHandDisplacement,
_ => handComp.HandDisplacement
};
if (displacement is not null && _displacement.TryAddDisplacement(displacement, (ent, sprite), index, key, out var displacementKey))
if (displacement is not null && _displacement.TryAddDisplacement(displacement, (uid, sprite), index, key, out var displacementKey))
revealedLayers.Add(displacementKey);
}
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(ent, revealedLayers), true);
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
}
private void OnVisualsChanged(EntityUid uid, HandsComponent component, VisualsChangedEvent args)
{
// update hands visuals if this item is in a hand (rather then inventory or other container).
if (!component.Hands.ContainsKey(args.ContainerId))
return;
UpdateHandVisuals((uid, component), GetEntity(args.Item), args.ContainerId);
if (component.Hands.TryGetValue(args.ContainerId, out var hand))
{
UpdateHandVisuals(uid, GetEntity(args.Item), hand, component);
}
}
#endregion
@@ -345,7 +379,7 @@ namespace Content.Client.Hands.Systems
private void HandlePlayerAttached(EntityUid uid, HandsComponent component, LocalPlayerAttachedEvent args)
{
OnPlayerHandsAdded?.Invoke((uid, component));
OnPlayerHandsAdded?.Invoke(component);
}
private void HandlePlayerDetached(EntityUid uid, HandsComponent component, LocalPlayerDetachedEvent args)
@@ -356,7 +390,7 @@ namespace Content.Client.Hands.Systems
private void OnHandsStartup(EntityUid uid, HandsComponent component, ComponentStartup args)
{
if (_playerManager.LocalEntity == uid)
OnPlayerHandsAdded?.Invoke((uid, component));
OnPlayerHandsAdded?.Invoke(component);
}
private void OnHandsShutdown(EntityUid uid, HandsComponent component, ComponentShutdown args)
@@ -366,6 +400,36 @@ namespace Content.Client.Hands.Systems
}
#endregion
private void AddHand(EntityUid uid, Hand newHand, HandsComponent? handsComp = null)
{
AddHand(uid, newHand.Name, newHand.Location, handsComp);
}
public override void AddHand(EntityUid uid, string handName, HandLocation handLocation, HandsComponent? handsComp = null)
{
base.AddHand(uid, handName, handLocation, handsComp);
if (uid == _playerManager.LocalEntity)
OnPlayerAddHand?.Invoke(handName, handLocation);
if (handsComp == null)
return;
if (handsComp.ActiveHand == null)
SetActiveHand(uid, handsComp.Hands[handName], handsComp);
}
public override void RemoveHand(EntityUid uid, string handName, HandsComponent? handsComp = null)
{
if (uid == _playerManager.LocalEntity && handsComp != null &&
handsComp.Hands.ContainsKey(handName) && uid ==
_playerManager.LocalEntity)
{
OnPlayerRemoveHand?.Invoke(handName);
}
base.RemoveHand(uid, handName, handsComp);
}
private void OnHandActivated(Entity<HandsComponent>? ent)
{
if (ent is not { } hand)
@@ -374,7 +438,13 @@ namespace Content.Client.Hands.Systems
if (_playerManager.LocalEntity != hand.Owner)
return;
OnPlayerSetActiveHand?.Invoke(hand.Comp.ActiveHandId);
if (hand.Comp.ActiveHand == null)
{
OnPlayerSetActiveHand?.Invoke(null);
return;
}
OnPlayerSetActiveHand?.Invoke(hand.Comp.ActiveHand.Name);
}
}
}

View File

@@ -107,7 +107,7 @@ public sealed class HolopadSystem : SharedHolopadSystem
// Remove shading from all layers (except displacement maps)
for (var i = 0; i < hologramSprite.AllLayers.Count(); i++)
{
if (_sprite.TryGetLayer((hologram, hologramSprite), i, out var layer, false) && layer.ShaderPrototype != "DisplacedDraw")
if (_sprite.TryGetLayer((hologram, hologramSprite), i, out var layer, false) && layer.ShaderPrototype != "DisplacedStencilDraw")
hologramSprite.LayerSetShader(i, "unshaded");
}

View File

@@ -27,7 +27,6 @@ public sealed class EyeColorPicker : Control
AddChild(vBox);
vBox.AddChild(_colorSelectors = new ColorSelectorSliders());
_colorSelectors.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
_colorSelectors.OnColorChanged += ColorValueChanged;
}

View File

@@ -36,7 +36,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
private void OnCvarChanged(bool value)
{
var humanoidQuery = AllEntityQuery<HumanoidAppearanceComponent, SpriteComponent>();
var humanoidQuery = EntityManager.AllEntityQueryEnumerator<HumanoidAppearanceComponent, SpriteComponent>();
while (humanoidQuery.MoveNext(out var uid, out var humanoidComp, out var spriteComp))
{
UpdateSprite((uid, humanoidComp, spriteComp));

View File

@@ -416,7 +416,6 @@ public sealed partial class MarkingPicker : Control
CMarkingColors.AddChild(colorContainer);
ColorSelectorSliders colorSelector = new ColorSelectorSliders();
colorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
colorSliders.Add(colorSelector);
colorContainer.AddChild(new Label { Text = $"{stateNames[i]} color:" });

View File

@@ -15,7 +15,7 @@ public sealed partial class SingleMarkingPicker : BoxContainer
[Dependency] private readonly IEntityManager _entityManager = default!;
private readonly SpriteSystem _sprite;
/// <summary>
/// What happens if a marking is selected.
/// It will send the 'slot' (marking index)
@@ -231,7 +231,6 @@ public sealed partial class SingleMarkingPicker : BoxContainer
HorizontalExpand = true
};
selector.Color = marking.MarkingColors[i];
selector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
var colorIndex = i;
selector.OnColorChanged += color =>

View File

@@ -102,8 +102,6 @@ public static class MidiParser
// 0x03 is TrackName,
// 0x04 is InstrumentName
// This string can potentially contain control characters, including 0x00 which can cause problems if it ends up in database entries via admin logs
// we sanitize TrackName and InstrumentName after they have been send to the server
var text = Encoding.ASCII.GetString(metaData, 0, (int)metaLength);
switch (metaType)
{

View File

@@ -194,12 +194,12 @@ namespace Content.Client.Inventory
public void UIInventoryActivate(string slot)
{
RaisePredictiveEvent(new UseSlotNetworkMessage(slot));
EntityManager.RaisePredictiveEvent(new UseSlotNetworkMessage(slot));
}
public void UIInventoryStorageActivate(string slot)
{
RaisePredictiveEvent(new OpenSlotStorageNetworkMessage(slot));
EntityManager.RaisePredictiveEvent(new OpenSlotStorageNetworkMessage(slot));
}
public void UIInventoryExamine(string slot, EntityUid uid)
@@ -223,7 +223,7 @@ namespace Content.Client.Inventory
if (!TryGetSlotEntity(uid, slot, out var item))
return;
RaisePredictiveEvent(
EntityManager.RaisePredictiveEvent(
new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: false));
}
@@ -232,7 +232,7 @@ namespace Content.Client.Inventory
if (!TryGetSlotEntity(uid, slot, out var item))
return;
RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
}
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)

View File

@@ -1,7 +1,6 @@
using System.Linq;
using System.Numerics;
using Content.Client.Examine;
using Content.Client.Hands.Systems;
using Content.Client.Strip;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
@@ -35,7 +34,6 @@ namespace Content.Client.Inventory
[Dependency] private readonly IUserInterfaceManager _ui = default!;
private readonly ExamineSystem _examine;
private readonly HandsSystem _hands;
private readonly InventorySystem _inv;
private readonly SharedCuffableSystem _cuffable;
private readonly StrippableSystem _strippable;
@@ -67,7 +65,6 @@ namespace Content.Client.Inventory
public StrippableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
_examine = EntMan.System<ExamineSystem>();
_hands = EntMan.System<HandsSystem>();
_inv = EntMan.System<InventorySystem>();
_cuffable = EntMan.System<SharedCuffableSystem>();
_strippable = EntMan.System<StrippableSystem>();
@@ -123,28 +120,28 @@ namespace Content.Client.Inventory
{
// good ol hands shit code. there is a GuiHands comparer that does the same thing... but these are hands
// and not gui hands... which are different...
foreach (var (id, hand) in handsComp.Hands)
foreach (var hand in handsComp.Hands.Values)
{
if (hand.Location != HandLocation.Right)
continue;
AddHandButton((Owner, handsComp), id, hand);
AddHandButton(hand);
}
foreach (var (id, hand) in handsComp.Hands)
foreach (var hand in handsComp.Hands.Values)
{
if (hand.Location != HandLocation.Middle)
continue;
AddHandButton((Owner, handsComp), id, hand);
AddHandButton(hand);
}
foreach (var (id, hand) in handsComp.Hands)
foreach (var hand in handsComp.Hands.Values)
{
if (hand.Location != HandLocation.Left)
continue;
AddHandButton((Owner, handsComp), id, hand);
AddHandButton(hand);
}
}
@@ -180,21 +177,20 @@ namespace Content.Client.Inventory
_strippingMenu.SetSize = new Vector2(horizontalMenuSize, verticalMenuSize);
}
private void AddHandButton(Entity<HandsComponent> ent, string handId, Hand hand)
private void AddHandButton(Hand hand)
{
var button = new HandButton(handId, hand.Location);
var button = new HandButton(hand.Name, hand.Location);
button.Pressed += SlotPressed;
var heldEntity = _hands.GetHeldItem(ent.AsNullable(), handId);
if (EntMan.TryGetComponent<VirtualItemComponent>(heldEntity, out var virt))
if (EntMan.TryGetComponent<VirtualItemComponent>(hand.HeldEntity, out var virt))
{
button.Blocked = true;
if (EntMan.TryGetComponent<CuffableComponent>(Owner, out var cuff) && _cuffable.GetAllCuffs(cuff).Contains(virt.BlockingEntity))
button.BlockedRect.MouseFilter = MouseFilterMode.Ignore;
}
UpdateEntityIcon(button, heldEntity);
UpdateEntityIcon(button, hand.HeldEntity);
_strippingMenu!.HandsContainer.AddChild(button);
LayoutContainer.SetPosition(button, new Vector2i(_handCount, 0) * (SlotControl.DefaultButtonSize + ButtonSeparation));
_handCount++;

View File

@@ -223,14 +223,13 @@ public sealed partial class LatheMenu : DefaultWindow
/// Populates the build queue list with all queued items
/// </summary>
/// <param name="queue"></param>
public void PopulateQueueList(IReadOnlyCollection<ProtoId<LatheRecipePrototype>> queue)
public void PopulateQueueList(List<LatheRecipePrototype> queue)
{
QueueList.DisposeAllChildren();
var idx = 1;
foreach (var recipeProto in queue)
foreach (var recipe in queue)
{
var recipe = _prototypeManager.Index(recipeProto);
var queuedRecipeBox = new BoxContainer();
queuedRecipeBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
@@ -244,14 +243,12 @@ public sealed partial class LatheMenu : DefaultWindow
}
}
public void SetQueueInfo(ProtoId<LatheRecipePrototype>? recipeProto)
public void SetQueueInfo(LatheRecipePrototype? recipe)
{
FabricatingContainer.Visible = recipeProto != null;
if (recipeProto == null)
FabricatingContainer.Visible = recipe != null;
if (recipe == null)
return;
var recipe = _prototypeManager.Index(recipeProto.Value);
FabricatingDisplayContainer.Children.Clear();
FabricatingDisplayContainer.AddChild(GetRecipeDisplayControl(recipe));

View File

@@ -1,144 +0,0 @@
using System.Numerics;
using Content.Shared.CCVar;
using Content.Shared.Maps;
using Robust.Client.Graphics;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.Light;
/// <summary>
/// Applies ambient-occlusion to the viewport.
/// </summary>
public sealed class AmbientOcclusionOverlay : Overlay
{
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities;
private IRenderTexture? _aoTarget;
private IRenderTexture? _aoBlurBuffer;
// Couldn't figure out a way to avoid this so if you can then please do.
private IRenderTexture? _aoStencilTarget;
public AmbientOcclusionOverlay()
{
IoCManager.InjectDependencies(this);
ZIndex = AfterLightTargetOverlay.ContentZIndex + 1;
}
protected override void Draw(in OverlayDrawArgs args)
{
/*
* tl;dr
* - we draw a black square on each "ambient occlusion" entity.
* - we blur this.
* - We apply it to the viewport.
*
* We do this while ignoring lighting because it will wash out the actual effect.
* In 3D ambient occlusion is more complicated due top having to calculate normals but in 2D
* we don't have a concept of depth / corners necessarily.
*/
var viewport = args.Viewport;
var mapId = args.MapId;
var worldBounds = args.WorldBounds;
var worldHandle = args.WorldHandle;
var color = Color.FromHex(_cfgManager.GetCVar(CCVars.AmbientOcclusionColor));
var distance = _cfgManager.GetCVar(CCVars.AmbientOcclusionDistance);
//var color = Color.Red;
var target = viewport.RenderTarget;
var lightScale = target.Size / (Vector2) viewport.Size;
var scale = viewport.RenderScale / (Vector2.One / lightScale);
var maps = _entManager.System<SharedMapSystem>();
var lookups = _entManager.System<EntityLookupSystem>();
var query = _entManager.System<OccluderSystem>();
var xformSystem = _entManager.System<SharedTransformSystem>();
var turfSystem = _entManager.System<TurfSystem>();
var invMatrix = args.Viewport.GetWorldToLocalMatrix();
if (_aoTarget?.Texture.Size != target.Size)
{
_aoTarget?.Dispose();
_aoTarget = _clyde.CreateRenderTarget(target.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "ambient-occlusion-target");
}
if (_aoBlurBuffer?.Texture.Size != target.Size)
{
_aoBlurBuffer?.Dispose();
_aoBlurBuffer = _clyde.CreateRenderTarget(target.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "ambient-occlusion-blur-target");
}
if (_aoStencilTarget?.Texture.Size != target.Size)
{
_aoStencilTarget?.Dispose();
_aoStencilTarget = _clyde.CreateRenderTarget(target.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "ambient-occlusion-stencil-target");
}
// Draw the texture data to the texture.
args.WorldHandle.RenderInRenderTarget(_aoTarget,
() =>
{
worldHandle.UseShader(_proto.Index<ShaderPrototype>("unshaded").Instance());
var invMatrix = _aoTarget.GetWorldToLocalMatrix(viewport.Eye!, scale);
foreach (var entry in query.QueryAabb(mapId, worldBounds))
{
DebugTools.Assert(entry.Component.Enabled);
var matrix = xformSystem.GetWorldMatrix(entry.Transform);
var localMatrix = Matrix3x2.Multiply(matrix, invMatrix);
worldHandle.SetTransform(localMatrix);
// 4 pixels
worldHandle.DrawRect(Box2.UnitCentered.Enlarged(distance / EyeManager.PixelsPerMeter), Color.White);
}
}, Color.Transparent);
_clyde.BlurRenderTarget(viewport, _aoTarget, _aoBlurBuffer, viewport.Eye!, 14f);
// Need to do stencilling after blur as it will nuke it.
// Draw stencil for the grid so we don't draw in space.
args.WorldHandle.RenderInRenderTarget(_aoStencilTarget,
() =>
{
// Don't want lighting affecting it.
worldHandle.UseShader(_proto.Index<ShaderPrototype>("unshaded").Instance());
foreach (var grid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
{
var transform = xformSystem.GetWorldMatrix(grid.Owner);
var worldToTextureMatrix = Matrix3x2.Multiply(transform, invMatrix);
var tiles = maps.GetTilesEnumerator(grid.Owner, grid, worldBounds);
worldHandle.SetTransform(worldToTextureMatrix);
while (tiles.MoveNext(out var tileRef))
{
if (turfSystem.IsSpace(tileRef))
continue;
var bounds = lookups.GetLocalBounds(tileRef, grid.TileSize);
worldHandle.DrawRect(bounds, Color.White);
}
}
}, Color.Transparent);
// Draw the stencil texture to depth buffer.
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilMask").Instance());
worldHandle.DrawTextureRect(_aoStencilTarget!.Texture, worldBounds);
// Draw the Blurred AO texture finally.
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilEqualDraw").Instance());
worldHandle.DrawTextureRect(_aoTarget!.Texture, worldBounds, color);
args.WorldHandle.SetTransform(Matrix3x2.Identity);
args.WorldHandle.UseShader(null);
}
}

View File

@@ -63,7 +63,7 @@ public sealed class LightBehaviorSystem : EntitySystem
/// </summary>
private void CopyLightSettings(Entity<LightBehaviourComponent> entity, string property)
{
if (TryComp(entity, out PointLightComponent? light))
if (EntityManager.TryGetComponent(entity, out PointLightComponent? light))
{
var propertyValue = AnimationHelper.GetAnimatableProperty(light, property);
if (propertyValue != null)
@@ -73,7 +73,7 @@ public sealed class LightBehaviorSystem : EntitySystem
}
else
{
Log.Warning($"{Comp<MetaDataComponent>(entity).EntityName} has a {nameof(LightBehaviourComponent)} but it has no {nameof(PointLightComponent)}! Check the prototype!");
Log.Warning($"{EntityManager.GetComponent<MetaDataComponent>(entity).EntityName} has a {nameof(LightBehaviourComponent)} but it has no {nameof(PointLightComponent)}! Check the prototype!");
}
}
@@ -84,7 +84,7 @@ public sealed class LightBehaviorSystem : EntitySystem
/// </summary>
public void StartLightBehaviour(Entity<LightBehaviourComponent> entity, string id = "")
{
if (!TryComp(entity, out AnimationPlayerComponent? animation))
if (!EntityManager.TryGetComponent(entity, out AnimationPlayerComponent? animation))
{
return;
}
@@ -113,7 +113,7 @@ public sealed class LightBehaviorSystem : EntitySystem
/// <param name="resetToOriginalSettings">Should the light have its original settings applied?</param>
public void StopLightBehaviour(Entity<LightBehaviourComponent> entity, string id = "", bool removeBehaviour = false, bool resetToOriginalSettings = false)
{
if (!TryComp(entity, out AnimationPlayerComponent? animation))
if (!EntityManager.TryGetComponent(entity, out AnimationPlayerComponent? animation))
{
return;
}
@@ -143,7 +143,7 @@ public sealed class LightBehaviorSystem : EntitySystem
comp.Animations.Remove(container);
}
if (resetToOriginalSettings && TryComp(entity, out PointLightComponent? light))
if (resetToOriginalSettings && EntityManager.TryGetComponent(entity, out PointLightComponent? light))
{
foreach (var (property, value) in comp.OriginalPropertyValues)
{
@@ -161,7 +161,7 @@ public sealed class LightBehaviorSystem : EntitySystem
public bool HasRunningBehaviours(Entity<LightBehaviourComponent> entity)
{
//var uid = Owner;
if (!TryComp(entity, out AnimationPlayerComponent? animation))
if (!EntityManager.TryGetComponent(entity, out AnimationPlayerComponent? animation))
{
return false;
}

View File

@@ -1,51 +1,17 @@
using Content.Shared.CCVar;
using Robust.Client.Graphics;
using Robust.Shared.Configuration;
namespace Content.Client.Light.EntitySystems;
public sealed class PlanetLightSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
/// <summary>
/// Enables / disables the ambient occlusion overlay.
/// </summary>
public bool AmbientOcclusion
{
get => _ambientOcclusion;
set
{
if (_ambientOcclusion == value)
return;
_ambientOcclusion = value;
if (value)
{
_overlayMan.AddOverlay(new AmbientOcclusionOverlay());
}
else
{
_overlayMan.RemoveOverlay<AmbientOcclusionOverlay>();
}
}
}
private bool _ambientOcclusion;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GetClearColorEvent>(OnClearColor);
_cfgManager.OnValueChanged(CCVars.AmbientOcclusion, val =>
{
AmbientOcclusion = val;
}, true);
_overlayMan.AddOverlay(new BeforeLightTargetOverlay());
_overlayMan.AddOverlay(new RoofOverlay(EntityManager));
_overlayMan.AddOverlay(new TileEmissionOverlay(EntityManager));

View File

@@ -62,8 +62,6 @@ public sealed class RoofOverlay : Overlay
worldHandle.RenderInRenderTarget(target,
() =>
{
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
for (var i = 0; i < _grids.Count; i++)
{
var grid = _grids[i];
@@ -71,6 +69,8 @@ public sealed class RoofOverlay : Overlay
if (!_entManager.TryGetComponent(grid.Owner, out ImplicitRoofComponent? roof))
continue;
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);
@@ -94,13 +94,13 @@ public sealed class RoofOverlay : Overlay
worldHandle.RenderInRenderTarget(target,
() =>
{
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
foreach (var grid in _grids)
{
if (!_entManager.TryGetComponent(grid.Owner, out RoofComponent? roof))
continue;
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);

View File

@@ -241,7 +241,6 @@ namespace Content.Client.Lobby.UI
};
RgbSkinColorContainer.AddChild(_rgbSkinColorSelector = new ColorSelectorSliders());
_rgbSkinColorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
_rgbSkinColorSelector.OnColorChanged += _ =>
{
OnSkinColorOnValueChanged();

View File

@@ -144,8 +144,8 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
{
subList.AddChild(proto);
}
var itemName = firstElement.Text ?? "";
UpdateSubGroupSelectedInfo(firstElement, itemName, subList);
UpdateToggleColor(toggle, subList);
}
else
{
@@ -164,14 +164,12 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
};
toggle.Text = subContainer.Visible ? OpenedGroupMark : ClosedGroupMark;
toggle.Pressed = subContainer.Visible;
toggle.OnPressed += _ =>
{
var willOpen = !subContainer.Visible;
subContainer.Visible = willOpen;
toggle.Text = willOpen ? OpenedGroupMark : ClosedGroupMark;
toggle.Pressed = willOpen;
_openedGroups[kvp.Key] = willOpen;
};
@@ -180,16 +178,15 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
return toggle;
}
private void UpdateSubGroupSelectedInfo(LoadoutContainer loadout, string itemName, BoxContainer subList)
private void UpdateToggleColor(Button toggle, BoxContainer subList)
{
var countSubSelected = subList.Children
var anyActive = subList.Children
.OfType<LoadoutContainer>()
.Count(c => c.Select.Pressed);
.Any(c => c.Select.Pressed);
if (countSubSelected > 0)
{
loadout.Text = Loc.GetString("loadouts-count-items-in-group", ("item", itemName), ("count", countSubSelected));
}
toggle.Modulate = anyActive
? Color.Green
: Color.White;
}
/// <summary>

View File

@@ -793,7 +793,7 @@ public sealed class MappingState : GameplayStateBase
if (_mapMan.TryFindGridAt(mapPos, out var gridUid, out var grid) &&
_entityManager.System<SharedMapSystem>().TryGetTileRef(gridUid, grid, coords, out var tileRef) &&
_allPrototypesDict.TryGetValue(_entityManager.System<TurfSystem>().GetContentTileDefinition(tileRef), out button))
_allPrototypesDict.TryGetValue(tileRef.GetContentTileDefinition(), out button))
{
OnSelected(button);
return true;

View File

@@ -33,7 +33,7 @@ public sealed class MarkerSystem : EntitySystem
private void UpdateVisibility(EntityUid uid)
{
if (TryComp(uid, out SpriteComponent? sprite))
if (EntityManager.TryGetComponent(uid, out SpriteComponent? sprite))
{
_sprite.SetVisible((uid, sprite), MarkersVisible);
}

View File

@@ -1,5 +1,4 @@
using System.Linq;
using System.Numerics;
using System.Numerics;
using Content.Client.UserInterface.Controls;
using Content.Shared.DeviceLinking;
using Content.Shared.DeviceNetwork;
@@ -15,8 +14,6 @@ namespace Content.Client.NetworkConfigurator;
[GenerateTypedNameReferences]
public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private const string PanelBgColor = "#202023";
private readonly LinksRender _links;
@@ -36,7 +33,6 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
public NetworkConfiguratorLinkMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var footerStyleBox = new StyleBoxFlat()
{
@@ -65,7 +61,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
ButtonContainerRight.RemoveAllChildren();
_sources.Clear();
_sources.AddRange(linkState.Sources.Select(s => _prototypeManager.Index(s)));
_sources.AddRange(linkState.Sources);
_links.SourceButtons.Clear();
var i = 0;
foreach (var source in _sources)
@@ -77,7 +73,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
}
_sinks.Clear();
_sinks.AddRange(linkState.Sinks.Select(s => _prototypeManager.Index(s)));
_sinks.AddRange(linkState.Sinks);
_links.SinkButtons.Clear();
i = 0;
foreach (var sink in _sinks)

View File

@@ -14,7 +14,6 @@
<ui:OptionDropDown Name="DropDownLightingQuality" Title="{Loc 'ui-options-lighting-label'}" />
<CheckBox Name="ViewportLowResCheckBox" Text="{Loc 'ui-options-vp-low-res'}" />
<CheckBox Name="ParallaxLowQualityCheckBox" Text="{Loc 'ui-options-parallax-low-quality'}" />
<CheckBox Name="AmbientOcclusionCheckBox" Text="{Loc 'ui-options-ambient-occlusion'}" />
<!-- Interface -->
<Label Text="{Loc 'ui-options-interface-label'}" StyleClasses="LabelKeyText"/>

View File

@@ -20,7 +20,6 @@ public sealed partial class GraphicsTab : Control
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CVars.DisplayVSync, VSyncCheckBox);
Control.AddOptionCheckBox(CCVars.AmbientOcclusion, AmbientOcclusionCheckBox);
Control.AddOption(new OptionFullscreen(Control, _cfg, FullscreenCheckBox));
Control.AddOption(new OptionLightingQuality(Control, _cfg, DropDownLightingQuality));

View File

@@ -64,7 +64,7 @@ public sealed class OrbitVisualsSystem : EntitySystem
{
base.FrameUpdate(frameTime);
var query = EntityQueryEnumerator<OrbitVisualsComponent, SpriteComponent>();
var query = EntityManager.EntityQueryEnumerator<OrbitVisualsComponent, SpriteComponent>();
while (query.MoveNext(out var uid, out var orbit, out var sprite))
{
var progress = (float)(_timing.CurTime.TotalSeconds / orbit.OrbitLength) % 1;

View File

@@ -48,14 +48,17 @@ public sealed class PowerCellSystem : SharedPowerCellSystem
if (!_sprite.LayerExists((uid, args.Sprite), PowerCellVisualLayers.Unshaded))
return;
if (!_appearance.TryGetData<byte>(uid, PowerCellVisuals.ChargeLevel, out var level, args.Component))
level = 0;
if (_appearance.TryGetData<byte>(uid, PowerCellVisuals.ChargeLevel, out var level, args.Component))
{
if (level == 0)
{
_sprite.LayerSetVisible((uid, args.Sprite), PowerCellVisualLayers.Unshaded, false);
return;
}
var positiveCharge = level > 0;
_sprite.LayerSetVisible((uid, args.Sprite), PowerCellVisualLayers.Unshaded, positiveCharge);
if (positiveCharge)
_sprite.LayerSetVisible((uid, args.Sprite), PowerCellVisualLayers.Unshaded, false);
_sprite.LayerSetRsiState((uid, args.Sprite), PowerCellVisualLayers.Unshaded, $"o{level}");
}
}
private enum PowerCellVisualLayers : byte

View File

@@ -1,6 +1,5 @@
using System.Numerics;
using Content.Client.Gameplay;
using Content.Client.Hands.Systems;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.RCD.Components;
@@ -18,7 +17,6 @@ public sealed class AlignRCDConstruction : PlacementMode
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
private readonly SharedMapSystem _mapSystem;
private readonly HandsSystem _handsSystem;
private readonly RCDSystem _rcdSystem;
private readonly SharedTransformSystem _transformSystem;
[Dependency] private readonly IPlayerManager _playerManager = default!;
@@ -36,7 +34,6 @@ public sealed class AlignRCDConstruction : PlacementMode
{
IoCManager.InjectDependencies(this);
_mapSystem = _entityManager.System<SharedMapSystem>();
_handsSystem = _entityManager.System<HandsSystem>();
_rcdSystem = _entityManager.System<RCDSystem>();
_transformSystem = _entityManager.System<SharedTransformSystem>();
@@ -91,9 +88,11 @@ public sealed class AlignRCDConstruction : PlacementMode
}
// Determine if player is carrying an RCD in their active hand
if (!_handsSystem.TryGetActiveItem(player.Value, out var heldEntity))
if (!_entityManager.TryGetComponent<HandsComponent>(player, out var hands))
return false;
var heldEntity = hands.ActiveHand?.HeldEntity;
if (!_entityManager.TryGetComponent<RCDComponent>(heldEntity, out var rcd))
return false;

View File

@@ -1,7 +1,8 @@
using Content.Client.Hands.Systems;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.RCD;
using Content.Shared.RCD.Components;
using Content.Shared.RCD.Systems;
using Robust.Client.Placement;
using Robust.Client.Player;
using Robust.Shared.Enums;
@@ -9,18 +10,13 @@ using Robust.Shared.Prototypes;
namespace Content.Client.RCD;
/// <summary>
/// System for handling structure ghost placement in places where RCD can create objects.
/// </summary>
public sealed class RCDConstructionGhostSystem : EntitySystem
{
private const string PlacementMode = nameof(AlignRCDConstruction);
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPlacementManager _placementManager = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly HandsSystem _hands = default!;
private string _placementMode = typeof(AlignRCDConstruction).Name;
private Direction _placementDirection = default;
public override void Update(float frameTime)
@@ -37,10 +33,12 @@ public sealed class RCDConstructionGhostSystem : EntitySystem
return;
// Determine if player is carrying an RCD in their active hand
if (_playerManager.LocalSession?.AttachedEntity is not { } player)
var player = _playerManager.LocalSession?.AttachedEntity;
if (!TryComp<HandsComponent>(player, out var hands))
return;
var heldEntity = _hands.GetActiveItem(player);
var heldEntity = hands.ActiveHand?.HeldEntity;
if (!TryComp<RCDComponent>(heldEntity, out var rcd))
{
@@ -67,7 +65,7 @@ public sealed class RCDConstructionGhostSystem : EntitySystem
var newObjInfo = new PlacementInformation
{
MobUid = heldEntity.Value,
PlacementOption = PlacementMode,
PlacementOption = _placementMode,
EntityType = prototype.Prototype,
Range = (int) Math.Ceiling(SharedInteractionSystem.InteractionRange),
IsTile = (prototype.Mode == RcdMode.ConstructTile),

View File

@@ -1,6 +1,4 @@
using Content.Client.Alerts;
using Content.Shared.Alert;
using Content.Shared.Alert.Components;
using Content.Shared.Revenant;
using Content.Shared.Revenant.Components;
using Robust.Client.GameObjects;
@@ -17,7 +15,7 @@ public sealed class RevenantSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<RevenantComponent, AppearanceChangeEvent>(OnAppearanceChange);
SubscribeLocalEvent<RevenantComponent, GetGenericAlertCounterAmountEvent>(OnGetCounterAmount);
SubscribeLocalEvent<RevenantComponent, UpdateAlertSpriteEvent>(OnUpdateAlert);
}
private void OnAppearanceChange(EntityUid uid, RevenantComponent component, ref AppearanceChangeEvent args)
@@ -42,14 +40,14 @@ public sealed class RevenantSystem : EntitySystem
}
}
private void OnGetCounterAmount(Entity<RevenantComponent> ent, ref GetGenericAlertCounterAmountEvent args)
private void OnUpdateAlert(Entity<RevenantComponent> ent, ref UpdateAlertSpriteEvent args)
{
if (args.Handled)
if (args.Alert.ID != ent.Comp.EssenceAlert)
return;
if (ent.Comp.EssenceAlert != args.Alert)
return;
args.Amount = ent.Comp.Essence.Int();
var essence = Math.Clamp(ent.Comp.Essence.Int(), 0, 999);
_sprite.LayerSetRsiState(args.SpriteViewEnt.AsNullable(), RevenantVisualLayers.Digit1, $"{(essence / 100) % 10}");
_sprite.LayerSetRsiState(args.SpriteViewEnt.AsNullable(), RevenantVisualLayers.Digit2, $"{(essence / 10) % 10}");
_sprite.LayerSetRsiState(args.SpriteViewEnt.AsNullable(), RevenantVisualLayers.Digit3, $"{essence % 10}");
}
}

View File

@@ -90,7 +90,7 @@ namespace Content.Client.Sandbox
// Try copy entity.
if (uid.IsValid()
&& TryComp(uid, out MetaDataComponent? comp)
&& EntityManager.TryGetComponent(uid, out MetaDataComponent? comp)
&& !comp.EntityDeleted)
{
if (comp.EntityPrototype == null || comp.EntityPrototype.HideSpawnMenu || comp.EntityPrototype.Abstract)

View File

@@ -25,29 +25,6 @@ public sealed partial class SensorMonitoringWindow : FancyWindow, IComputerWindo
private TimeSpan _retentionTime;
private readonly Dictionary<int, SensorData> _sensorData = new();
/// <summary>
/// <para>A shared array used to store vertices for drawing graphs in <see cref="GraphView"/>.
/// Prevents excessive allocations by reusing the same array across multiple graph views.</para>
/// <para>This effectively makes it so that each <see cref="SensorMonitoringWindow"/> has its own pooled array.</para>
/// </summary>
private Vector2[] _sharedVertices = [];
/// <summary>
/// Retrieves a shared array of vertices, ensuring that it has at least the requested size.
/// Assigns a new array of the requested size if the current shared array is smaller than the requested size.
/// </summary>
/// <param name="requestedSize">The minimum number of vertices required in the shared array.</param>
/// <returns>An array of <see cref="System.Numerics.Vector2"/> representing the shared vertices.</returns>
/// <remarks>This does not prevent other threads from accessing the same shared pool.</remarks>
public Vector2[] GetSharedVertices(int requestedSize)
{
if (_sharedVertices.Length < requestedSize)
{
_sharedVertices = new Vector2[requestedSize];
}
return _sharedVertices;
}
public SensorMonitoringWindow()
{
RobustXamlLoader.Load(this);
@@ -168,7 +145,7 @@ public sealed partial class SensorMonitoringWindow : FancyWindow, IComputerWindo
}
});
Asdf.AddChild(new GraphView(stream.Samples, startTime, curTime, maxValue * 1.1f, this) { MinHeight = 150 });
Asdf.AddChild(new GraphView(stream.Samples, startTime, curTime, maxValue * 1.1f) { MinHeight = 150 });
Asdf.AddChild(new PanelContainer { StyleClasses = { StyleBase.ClassLowDivider } });
}
}
@@ -220,37 +197,31 @@ public sealed partial class SensorMonitoringWindow : FancyWindow, IComputerWindo
private readonly TimeSpan _startTime;
private readonly TimeSpan _curTime;
private readonly float _maxY;
private readonly SensorMonitoringWindow _parentWindow;
public GraphView(Queue<SensorSample> samples,
TimeSpan startTime,
TimeSpan curTime,
float maxY,
SensorMonitoringWindow parentWindow)
public GraphView(Queue<SensorSample> samples, TimeSpan startTime, TimeSpan curTime, float maxY)
{
_samples = samples;
_startTime = startTime;
_curTime = curTime;
_maxY = maxY;
RectClipContent = true;
_parentWindow = parentWindow;
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
var window = (float)(_curTime - _startTime).TotalSeconds;
var window = (float) (_curTime - _startTime).TotalSeconds;
// TODO: omg this is terrible don't fucking hardcode this size to something uncached huge omfg.
var vertices = new Vector2[25000];
var countVtx = 0;
var lastPoint = new Vector2(float.NaN, float.NaN);
var requiredVertices = 6 * (_samples.Count - 1);
var vertices = _parentWindow.GetSharedVertices(requiredVertices);
foreach (var (time, sample) in _samples)
{
var relTime = (float)(time - _startTime).TotalSeconds;
var relTime = (float) (time - _startTime).TotalSeconds;
var posY = PixelHeight - (sample / _maxY) * PixelHeight;
var posX = (relTime / window) * PixelWidth;
@@ -271,9 +242,8 @@ public sealed partial class SensorMonitoringWindow : FancyWindow, IComputerWindo
lastPoint = newPoint;
}
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList,
vertices.AsSpan(0, countVtx),
Color.White.WithAlpha(0.1f));
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, vertices.AsSpan(0, countVtx), Color.White.WithAlpha(0.1f));
}
}
}

View File

@@ -1,50 +0,0 @@
using Content.Shared.StatusEffectNew;
using Content.Shared.StatusEffectNew.Components;
using Robust.Shared.Collections;
using Robust.Shared.GameStates;
namespace Content.Client.StatusEffectNew;
/// <inheritdoc/>
public sealed partial class ClientStatusEffectsSystem : SharedStatusEffectsSystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StatusEffectContainerComponent, ComponentHandleState>(OnHandleState);
}
private void OnHandleState(Entity<StatusEffectContainerComponent> ent, ref ComponentHandleState args)
{
if (args.Current is not StatusEffectContainerComponentState state)
return;
var toRemove = new ValueList<EntityUid>();
foreach (var effect in ent.Comp.ActiveStatusEffects)
{
if (state.ActiveStatusEffects.Contains(GetNetEntity(effect)))
continue;
toRemove.Add(effect);
}
foreach (var effect in toRemove)
{
ent.Comp.ActiveStatusEffects.Remove(effect);
var ev = new StatusEffectRemovedEvent(ent);
RaiseLocalEvent(effect, ref ev);
}
foreach (var effect in state.ActiveStatusEffects)
{
var effectUid = GetEntity(effect);
if (ent.Comp.ActiveStatusEffects.Contains(effectUid))
continue;
ent.Comp.ActiveStatusEffects.Add(effectUid);
var ev = new StatusEffectAppliedEvent(ent);
RaiseLocalEvent(effectUid, ref ev);
}
}
}

View File

@@ -68,15 +68,11 @@ public sealed class TrayScannerSystem : SharedTrayScannerSystem
foreach (var hand in _hands.EnumerateHands(player.Value))
{
if (!_hands.TryGetHeldItem(player.Value, hand, out var heldEntity))
continue;
if (!scannerQuery.TryGetComponent(heldEntity, out var heldScanner) || !heldScanner.Enabled)
if (!scannerQuery.TryGetComponent(hand.HeldEntity, out var heldScanner) || !heldScanner.Enabled)
continue;
range = MathF.Max(heldScanner.Range, range);
canSee = true;
break;
}
inRange = new HashSet<Entity<SubFloorHideComponent>>();

View File

@@ -131,7 +131,7 @@ namespace Content.Client.Tabletop
// Get the camera entity that the server has created for us
var camera = GetEntity(msg.CameraUid);
if (!TryComp<EyeComponent>(camera, out var eyeComponent))
if (!EntityManager.TryGetComponent<EyeComponent>(camera, out var eyeComponent))
{
// If there is no eye, print error and do not open any window
Log.Error("Camera entity does not have eye component!");
@@ -258,7 +258,7 @@ namespace Content.Client.Tabletop
private void StopDragging(bool broadcast = true)
{
// Set the dragging player on the component to noone
if (broadcast && _draggedEntity != null && HasComp<TabletopDraggableComponent>(_draggedEntity.Value))
if (broadcast && _draggedEntity != null && EntityManager.HasComponent<TabletopDraggableComponent>(_draggedEntity.Value))
{
RaisePredictiveEvent(new TabletopMoveEvent(GetNetEntity(_draggedEntity.Value), Transforms.GetMapCoordinates(_draggedEntity.Value), GetNetEntity(_table!.Value)));
RaisePredictiveEvent(new TabletopDraggingPlayerChangedEvent(GetNetEntity(_draggedEntity.Value), false));

View File

@@ -98,8 +98,7 @@ public sealed class AlertsUIController : UIController, IOnStateEntered<GameplayS
if (!EntityManager.TryGetComponent<SpriteComponent>(spriteViewEnt, out var sprite))
return;
var ev = new UpdateAlertSpriteEvent((spriteViewEnt, sprite), player, alert);
var ev = new UpdateAlertSpriteEvent((spriteViewEnt, sprite), alert);
EntityManager.EventBus.RaiseLocalEvent(player, ref ev);
EntityManager.EventBus.RaiseLocalEvent(spriteViewEnt, ref ev);
}
}

View File

@@ -57,15 +57,10 @@ namespace Content.Client.UserInterface.Systems.Alerts.Controls
_sprite = _entityManager.System<SpriteSystem>();
TooltipSupplier = SupplyTooltip;
Alert = alert;
HorizontalAlignment = HAlignment.Left;
_severity = severity;
_icon = new SpriteView
{
Scale = new Vector2(2, 2),
MaxSize = new Vector2(64, 64),
Stretch = SpriteView.StretchMode.None,
HorizontalAlignment = HAlignment.Left
Scale = new Vector2(2, 2)
};
SetupIcon();

View File

@@ -207,9 +207,7 @@ public sealed class GasTankWindow
_btnInternals.Disabled = !canConnectInternals;
_lblInternals.SetMarkup(Loc.GetString("gas-tank-window-internal-text",
("status", Loc.GetString(internalsConnected ? "gas-tank-window-internal-connected" : "gas-tank-window-internal-disconnected"))));
if (!_spbPressure.HasKeyboardFocus())
// Don't update release pressure if we're currently editing it
_spbPressure.Value = outputPressure;
_spbPressure.Value = outputPressure;
}
protected override void FrameUpdate(FrameEventArgs args)

View File

@@ -7,7 +7,6 @@ using Content.Shared.Hands.Components;
using Content.Shared.Input;
using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Timing;
using JetBrains.Annotations;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
@@ -29,7 +28,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
private readonly Dictionary<string, int> _handContainerIndices = new();
private readonly Dictionary<string, HandButton> _handLookup = new();
private HandsComponent? _playerHandsComponent;
private HandButton? _activeHand;
private HandButton? _activeHand = null;
// We only have two item status controls (left and right hand),
// but we may have more than two hands.
@@ -39,7 +38,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
private HandButton? _statusHandLeft;
private HandButton? _statusHandRight;
private int _backupSuffix; //this is used when autogenerating container names if they don't have names
private int _backupSuffix = 0; //this is used when autogenerating container names if they don't have names
private HotbarGui? HandsGui => UIManager.GetActiveUIWidgetOrNull<HotbarGui>();
@@ -49,7 +48,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
_handsSystem.OnPlayerItemAdded += OnItemAdded;
_handsSystem.OnPlayerItemRemoved += OnItemRemoved;
_handsSystem.OnPlayerSetActiveHand += SetActiveHand;
_handsSystem.OnPlayerRemoveHand += OnRemoveHand;
_handsSystem.OnPlayerRemoveHand += RemoveHand;
_handsSystem.OnPlayerHandsAdded += LoadPlayerHands;
_handsSystem.OnPlayerHandsRemoved += UnloadPlayerHands;
_handsSystem.OnPlayerHandBlocked += HandBlocked;
@@ -62,35 +61,28 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
_handsSystem.OnPlayerItemAdded -= OnItemAdded;
_handsSystem.OnPlayerItemRemoved -= OnItemRemoved;
_handsSystem.OnPlayerSetActiveHand -= SetActiveHand;
_handsSystem.OnPlayerRemoveHand -= OnRemoveHand;
_handsSystem.OnPlayerRemoveHand -= RemoveHand;
_handsSystem.OnPlayerHandsAdded -= LoadPlayerHands;
_handsSystem.OnPlayerHandsRemoved -= UnloadPlayerHands;
_handsSystem.OnPlayerHandBlocked -= HandBlocked;
_handsSystem.OnPlayerHandUnblocked -= HandUnblocked;
}
private void OnAddHand(Entity<HandsComponent> entity, string name, HandLocation location)
private void OnAddHand(string name, HandLocation location)
{
if (entity.Owner != _player.LocalEntity)
return;
AddHand(name, location);
}
private void OnRemoveHand(Entity<HandsComponent> entity, string name)
{
if (entity.Owner != _player.LocalEntity)
return;
RemoveHand(name);
}
private void HandPressed(GUIBoundKeyEventArgs args, SlotControl hand)
{
if (!_handsSystem.TryGetPlayerHands(out var hands))
if (_playerHandsComponent == null)
{
return;
}
if (args.Function == EngineKeyFunctions.UIClick)
{
_handsSystem.UIHandClick(hands.Value, hand.SlotName);
_handsSystem.UIHandClick(_playerHandsComponent, hand.SlotName);
args.Handle();
}
else if (args.Function == EngineKeyFunctions.UseSecondary)
@@ -130,33 +122,33 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
}
}
private void LoadPlayerHands(Entity<HandsComponent> handsComp)
private void LoadPlayerHands(HandsComponent handsComp)
{
DebugTools.Assert(_playerHandsComponent == null);
if (HandsGui != null)
HandsGui.Visible = true;
_playerHandsComponent = handsComp;
foreach (var (name, hand) in handsComp.Comp.Hands)
foreach (var (name, hand) in handsComp.Hands)
{
var handButton = AddHand(name, hand.Location);
if (_handsSystem.TryGetHeldItem(handsComp.AsNullable(), name, out var held) &&
_entities.TryGetComponent(held, out VirtualItemComponent? virt))
if (_entities.TryGetComponent(hand.HeldEntity, out VirtualItemComponent? virt))
{
handButton.SetEntity(virt.BlockingEntity);
handButton.Blocked = true;
}
else
{
handButton.SetEntity(held);
handButton.SetEntity(hand.HeldEntity);
handButton.Blocked = false;
}
}
if (handsComp.Comp.ActiveHandId == null)
var activeHand = handsComp.ActiveHand;
if (activeHand == null)
return;
SetActiveHand(handsComp.Comp.ActiveHandId);
SetActiveHand(activeHand.Name);
}
private void HandBlocked(string handName)
@@ -268,21 +260,19 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
if (HandsGui != null &&
_playerHandsComponent != null &&
_player.LocalSession?.AttachedEntity is { } playerEntity &&
_handsSystem.TryGetHand((playerEntity, _playerHandsComponent), handName, out var hand))
_handsSystem.TryGetHand(playerEntity, handName, out var hand, _playerHandsComponent))
{
var heldEnt = _handsSystem.GetHeldItem((playerEntity, _playerHandsComponent), handName);
var foldedLocation = hand.Value.Location.GetUILocation();
var foldedLocation = hand.Location.GetUILocation();
if (foldedLocation == HandUILocation.Left)
{
_statusHandLeft = handControl;
HandsGui.UpdatePanelEntityLeft(heldEnt);
HandsGui.UpdatePanelEntityLeft(hand.HeldEntity);
}
else
{
// Middle or right
_statusHandRight = handControl;
HandsGui.UpdatePanelEntityRight(heldEnt);
HandsGui.UpdatePanelEntityRight(hand.HeldEntity);
}
HandsGui.SetHighlightHand(foldedLocation);
@@ -302,7 +292,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
button.Pressed += HandPressed;
if (!_handLookup.TryAdd(handName, button))
return _handLookup[handName];
throw new Exception("Tried to add hand with duplicate name to UI. Name:" + handName);
if (HandsGui != null)
{
@@ -372,7 +362,6 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
RemoveHand(handName, out _);
}
[PublicAPI]
private bool RemoveHand(string handName, out HandButton? handButton)
{
if (!_handLookup.TryGetValue(handName, out handButton))
@@ -388,7 +377,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
_statusHandRight = null;
_handLookup.Remove(handName);
handButton.Orphan();
handButton.Dispose();
UpdateVisibleStatusPanels();
return true;
}

View File

@@ -329,8 +329,9 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
var player = _playerUid;
if (!control.MouseIsHovering ||
player == null ||
!_handsSystem.TryGetActiveItem(player.Value, out var held) ||
_playerInventory == null ||
!_entities.TryGetComponent<HandsComponent>(player, out var hands) ||
hands.ActiveHandEntity is not { } held ||
!_entities.TryGetComponent(held, out SpriteComponent? sprite) ||
!_inventorySystem.TryGetSlotContainer(player.Value, control.SlotName, out var container, out var slotDef))
{
@@ -341,12 +342,12 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
// Set green / red overlay at 50% transparency
var hoverEntity = _entities.SpawnEntity("hoverentity", MapCoordinates.Nullspace);
var hoverSprite = _entities.GetComponent<SpriteComponent>(hoverEntity);
var fits = _inventorySystem.CanEquip(player.Value, held.Value, control.SlotName, out _, slotDef) &&
_container.CanInsert(held.Value, container);
var fits = _inventorySystem.CanEquip(player.Value, held, control.SlotName, out _, slotDef) &&
_container.CanInsert(held, container);
if (!fits && _entities.TryGetComponent<StorageComponent>(container.ContainedEntity, out var storage))
{
fits = _entities.System<StorageSystem>().CanInsert(container.ContainedEntity.Value, held.Value, out _, storage);
fits = _entities.System<StorageSystem>().CanInsert(container.ContainedEntity.Value, held, out _, storage);
}
else if (!fits && _entities.TryGetComponent<ItemSlotsComponent>(container.ContainedEntity, out var itemSlots))
{
@@ -356,14 +357,14 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
if (!slot.InsertOnInteract)
continue;
if (!itemSlotsSys.CanInsert(container.ContainedEntity.Value, held.Value, null, slot))
if (!itemSlotsSys.CanInsert(container.ContainedEntity.Value, held, null, slot))
continue;
fits = true;
break;
}
}
_sprite.CopySprite((held.Value, sprite), (hoverEntity, hoverSprite));
_sprite.CopySprite((held, sprite), (hoverEntity, hoverSprite));
_sprite.SetColor((hoverEntity, hoverSprite), fits ? new Color(0, 255, 0, 127) : new Color(255, 0, 0, 127));
control.HoverSpriteView.SetEntity(hoverEntity);

View File

@@ -225,7 +225,7 @@ namespace Content.Client.Verbs
// is this a client exclusive (gui) verb?
ExecuteVerb(verb, user, GetEntity(target));
else
RaisePredictiveEvent(new ExecuteVerbEvent(target, verb));
EntityManager.RaisePredictiveEvent(new ExecuteVerbEvent(target, verb));
}
private void HandleVerbResponse(VerbsResponseEvent msg)

View File

@@ -178,7 +178,7 @@ public sealed partial class GunSystem : SharedGunSystem
if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down && !gun.BurstActivated)
{
if (gun.ShotCounter != 0)
RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
EntityManager.RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
return;
}
@@ -190,7 +190,7 @@ public sealed partial class GunSystem : SharedGunSystem
if (mousePos.MapId == MapId.Nullspace)
{
if (gun.ShotCounter != 0)
RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
EntityManager.RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });
return;
}
@@ -204,7 +204,7 @@ public sealed partial class GunSystem : SharedGunSystem
Log.Debug($"Sending shoot request tick {Timing.CurTick} / {Timing.CurTime}");
RaisePredictiveEvent(new RequestShootEvent
EntityManager.RaisePredictiveEvent(new RequestShootEvent
{
Target = target,
Coordinates = GetNetCoordinates(coordinates),