merge remote wizden/master

This commit is contained in:
Dmitry
2026-05-21 15:29:28 +07:00
233 changed files with 5391 additions and 3113 deletions
+6
View File
@@ -9,6 +9,11 @@
## Технические детали ## Технические детали
<!-- Краткое описание изменений в коде для облегчения проверки. --> <!-- Краткое описание изменений в коде для облегчения проверки. -->
## Test plan
<!--
Describe how you tested the pull request, and how someone reviewing this PR can test it themselves.
-->
## Медиа ## Медиа
<!-- Прикрепите медиафайлы, если PR вносит изменения в игру (одежда, предметы, механики и т.д.). <!-- Прикрепите медиафайлы, если PR вносит изменения в игру (одежда, предметы, механики и т.д.).
Небольшие исправления/рефакторинг освобождаются от этого требования. --> Небольшие исправления/рефакторинг освобождаются от этого требования. -->
@@ -16,6 +21,7 @@
## Требования ## Требования
<!-- Подтвердите следующее, поставив X в скобках без пробелов [X]: --> <!-- Подтвердите следующее, поставив X в скобках без пробелов [X]: -->
- [ ] Я прочитал(а) и следую [Рекомендациям по оформлению Pull Request и Changelog](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html). - [ ] Я прочитал(а) и следую [Рекомендациям по оформлению Pull Request и Changelog](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html).
- [ ] I have tested this pull request and written instructions on how to test it
- [ ] Я добавил(а) медиафайлы к этому PR или он не требует демонстрации в игре. - [ ] Я добавил(а) медиафайлы к этому PR или он не требует демонстрации в игре.
<!-- Вы должны понимать, что несоблюдение вышеуказанного может привести к закрытию вашего PR по усмотрению сопровождающего --> <!-- Вы должны понимать, что несоблюдение вышеуказанного может привести к закрытию вашего PR по усмотрению сопровождающего -->
+3
View File
@@ -317,3 +317,6 @@ Resources/MapImages
# Direnv stuff # Direnv stuff
.direnv/ .direnv/
# C# Dev Kit cache file
*.lscache
+1 -1
View File
@@ -262,7 +262,7 @@ namespace Content.Client.Actions
SetIcon(actionId, new SpriteSpecifier.EntityPrototype(id)); SetIcon(actionId, new SpriteSpecifier.EntityPrototype(id));
SetEvent(actionId, new StartPlacementActionEvent() SetEvent(actionId, new StartPlacementActionEvent()
{ {
PlacementOption = "SnapgridCenter", PlacementOption = proto.PlacementMode,
EntityType = id EntityType = id
}); });
_metaData.SetEntityName(actionId, proto.Name); _metaData.SetEntityName(actionId, proto.Name);
@@ -1,5 +1,5 @@
using Content.Shared.Cargo;
using Content.Client.Cargo.UI; using Content.Client.Cargo.UI;
using Content.Shared.Cargo;
using Content.Shared.Cargo.BUI; using Content.Shared.Cargo.BUI;
using Content.Shared.Cargo.Components; using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Events; using Content.Shared.Cargo.Events;
@@ -7,15 +7,15 @@ using Content.Shared.Cargo.Prototypes;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Utility;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using static Robust.Client.UserInterface.Controls.BaseButton; using Robust.Shared.Utility;
namespace Content.Client.Cargo.BUI namespace Content.Client.Cargo.BUI
{ {
public sealed class CargoOrderConsoleBoundUserInterface : BoundUserInterface public sealed partial class CargoOrderConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
{ {
private readonly SharedCargoSystem _cargoSystem; [Dependency] private SharedCargoSystem _cargoSystem = default!;
[Dependency] private IdentitySystem _identity = default!;
[ViewVariables] [ViewVariables]
private CargoConsoleMenu? _menu; private CargoConsoleMenu? _menu;
@@ -44,11 +44,6 @@ namespace Content.Client.Cargo.BUI
[ViewVariables] [ViewVariables]
private CargoProductPrototype? _product; private CargoProductPrototype? _product;
public CargoOrderConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
_cargoSystem = EntMan.System<SharedCargoSystem>();
}
protected override void Open() protected override void Open()
{ {
base.Open(); base.Open();
@@ -59,12 +54,9 @@ namespace Content.Client.Cargo.BUI
var localPlayer = dependencies.Resolve<IPlayerManager>().LocalEntity; var localPlayer = dependencies.Resolve<IPlayerManager>().LocalEntity;
var description = new FormattedMessage(); var description = new FormattedMessage();
string orderRequester; var orderRequester = Loc.GetString("cargo-console-paper-approver-default");
if (EntMan.EntityExists(localPlayer)) if (EntMan.EntityExists(localPlayer))
orderRequester = Identity.Name(localPlayer.Value, EntMan); orderRequester = _identity.GetIdentityShortInfo(localPlayer.Value, Owner) ?? orderRequester;
else
orderRequester = string.Empty;
_orderMenu = new CargoConsoleOrderMenu(); _orderMenu = new CargoConsoleOrderMenu();
@@ -142,6 +134,11 @@ namespace Content.Client.Cargo.BUI
return; return;
_menu.ProductCatalogue = cState.Products; _menu.ProductCatalogue = cState.Products;
_menu.ShuttleCapacityLabel.Text = Loc.GetString(
"cargo-console-menu-order-capacity-number",
("count", OrderCount),
("capacity", OrderCapacity)
);
_menu?.UpdateStation(station); _menu?.UpdateStation(station);
Populate(cState.Orders); Populate(cState.Orders);
@@ -52,7 +52,8 @@
<PanelContainer StyleClasses="LowDivider" Margin="0 -2 0 -1"/> <PanelContainer StyleClasses="LowDivider" Margin="0 -2 0 -1"/>
<Label Name="ShuttleCapacityLabel" <Label Name="ShuttleCapacityLabel"
Text="0/20" Text="0/0"
Access="Public"
Margin="4 0"/> Margin="4 0"/>
</GridContainer> </GridContainer>
+3 -4
View File
@@ -1,6 +1,5 @@
<controls:FancyWindow xmlns="https://spacestation14.io" <controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls" xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Resizable="False" Resizable="False"
MaxSize="400 800" MaxSize="400 800"
MinSize="400 150"> MinSize="400 150">
@@ -10,7 +9,7 @@
<!-- Header text --> <!-- Header text -->
<controls:StripeBack> <controls:StripeBack>
<PanelContainer> <PanelContainer>
<RichTextLabel Name="EmergencyBroadcastText" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10 10 10 10" ReservesSpace="False"/> <RichTextLabel Text="{Loc 'holopad-window-emergency-broadcast-in-progress'}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10 10 10 10" ReservesSpace="False"/>
</PanelContainer> </PanelContainer>
</controls:StripeBack> </controls:StripeBack>
@@ -52,8 +51,8 @@
<controls:StripeBack> <controls:StripeBack>
<PanelContainer> <PanelContainer>
<BoxContainer Orientation="Vertical"> <BoxContainer Orientation="Vertical">
<RichTextLabel Name="SubtitleText" HorizontalAlignment="Center" Margin="0 5 0 0"/> <RichTextLabel Text="{Loc 'holopad-window-subtitle'}" HorizontalAlignment="Center" Margin="0 5 0 0"/>
<RichTextLabel Name="OptionsText" HorizontalAlignment="Center" Margin="0 0 0 5"/> <RichTextLabel Text="{Loc 'holopad-window-options'}" HorizontalAlignment="Center" Margin="0 0 0 5"/>
</BoxContainer> </BoxContainer>
</PanelContainer> </PanelContainer>
</controls:StripeBack> </controls:StripeBack>
+75 -68
View File
@@ -10,7 +10,6 @@ using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using System.Linq;
namespace Content.Client.Holopad; namespace Content.Client.Holopad;
@@ -19,22 +18,18 @@ public sealed partial class HolopadWindow : FancyWindow
{ {
[Dependency] private IEntityManager _entManager = default!; [Dependency] private IEntityManager _entManager = default!;
[Dependency] private IPlayerManager _playerManager = default!; [Dependency] private IPlayerManager _playerManager = default!;
[Dependency] private ILogManager _logManager = default!;
[Dependency] private IGameTiming _timing = default!; [Dependency] private IGameTiming _timing = default!;
private readonly SharedHolopadSystem _holopadSystem = default!; private readonly SharedHolopadSystem _holopadSystem = default!;
private readonly SharedTelephoneSystem _telephoneSystem = default!; private readonly SharedTelephoneSystem _telephoneSystem = default!;
private readonly AccessReaderSystem _accessReaderSystem = default!; private readonly AccessReaderSystem _accessReaderSystem = default!;
private readonly PopupSystem _popupSystem = default!; private readonly PopupSystem _popupSystem = default!;
private readonly ISawmill _sawmill = default!;
private EntityUid? _owner = null; private EntityUid? _owner = null;
private HolopadUiKey _currentUiKey; private HolopadUiKey _currentUiKey;
private TelephoneState _currentState; private string _currentSearch = string.Empty;
private TelephoneState _previousState;
private TimeSpan _buttonUnlockTime;
private float _updateTimer = 0.25f;
private const float UpdateTime = 0.25f;
private TimeSpan _buttonUnlockDelay = TimeSpan.FromSeconds(0.5f);
public event Action<NetEntity>? SendHolopadStartNewCallMessageAction; public event Action<NetEntity>? SendHolopadStartNewCallMessageAction;
public event Action? SendHolopadAnswerCallMessageAction; public event Action? SendHolopadAnswerCallMessageAction;
@@ -43,6 +38,9 @@ public sealed partial class HolopadWindow : FancyWindow
public event Action? SendHolopadActivateProjectorMessageAction; public event Action? SendHolopadActivateProjectorMessageAction;
public event Action? SendHolopadRequestStationAiMessageAction; public event Action? SendHolopadRequestStationAiMessageAction;
private TimeSpan _updateDelay = TimeSpan.FromSeconds(0.25f);
private TimeSpan _nextUpdate;
public HolopadWindow() public HolopadWindow()
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
@@ -52,8 +50,7 @@ public sealed partial class HolopadWindow : FancyWindow
_telephoneSystem = _entManager.System<SharedTelephoneSystem>(); _telephoneSystem = _entManager.System<SharedTelephoneSystem>();
_accessReaderSystem = _entManager.System<AccessReaderSystem>(); _accessReaderSystem = _entManager.System<AccessReaderSystem>();
_popupSystem = _entManager.System<PopupSystem>(); _popupSystem = _entManager.System<PopupSystem>();
_sawmill = _logManager.GetSawmill("Holopad");
_buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay;
// Assign button actions // Assign button actions
AnswerCallButton.OnPressed += args => { OnHolopadAnswerCallMessage(); }; AnswerCallButton.OnPressed += args => { OnHolopadAnswerCallMessage(); };
@@ -78,10 +75,6 @@ public sealed partial class HolopadWindow : FancyWindow
{ {
BackgroundColor = new Color(82, 82, 82), BackgroundColor = new Color(82, 82, 82),
}; };
EmergencyBroadcastText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-emergency-broadcast-in-progress")));
SubtitleText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-subtitle")));
OptionsText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-options")));
} }
#region: Button actions #region: Button actions
@@ -166,16 +159,28 @@ public sealed partial class HolopadWindow : FancyWindow
public void UpdateState(Dictionary<NetEntity, string> holopads) public void UpdateState(Dictionary<NetEntity, string> holopads)
{ {
if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone)) if (!_entManager.TryGetComponent<TelephoneComponent>(_owner, out var telephone))
return; return;
// Caller ID text // Caller and holopad ID text
var callerId = _telephoneSystem.GetFormattedCallerIdForEntity(telephone.LastCallerId.Item1, telephone.LastCallerId.Item2, Color.LightGray, "Default", 11); var callerId = _telephoneSystem.GetFormattedCallerIdForEntity(telephone.LastCallerId?.CallerId, telephone.LastCallerId?.CallerJob, Color.LightGray, "Default", 11);
var holoapdId = _telephoneSystem.GetFormattedDeviceIdForEntity(telephone.LastCallerId.Item3, Color.LightGray, "Default", 11); var holopadId = _telephoneSystem.GetFormattedDeviceIdForEntity(telephone.LastCallerId?.DeviceId, Color.LightGray, "Default", 11);
CallerIdText.SetMessage(FormattedMessage.FromMarkupPermissive(callerId)); if (!FormattedMessage.TryFromMarkup(callerId, out var callerIdMsg))
HolopadIdText.SetMessage(FormattedMessage.FromMarkupPermissive(holoapdId)); {
LockOutIdText.SetMessage(FormattedMessage.FromMarkupPermissive(callerId)); callerIdMsg = FormattedMessage.FromMarkupPermissive(callerId);
_sawmill.Error($"CallerId markup text was incorrectly formatted: {callerIdMsg}");
}
if (!FormattedMessage.TryFromMarkup(holopadId, out var holopadIdMsg))
{
holopadIdMsg = FormattedMessage.FromMarkupPermissive(holopadId);
_sawmill.Error($"HolopadId markup text was incorrectly formatted: {holopadIdMsg}");
}
CallerIdText.SetMessage(callerIdMsg);
LockOutIdText.SetMessage(callerIdMsg);
HolopadIdText.SetMessage(holopadIdMsg);
// Sort holopads alphabetically // Sort holopads alphabetically
var holopadArray = holopads.ToArray(); var holopadArray = holopads.ToArray();
@@ -183,7 +188,9 @@ public sealed partial class HolopadWindow : FancyWindow
// Clear excess children from the contact list // Clear excess children from the contact list
while (ContactsList.ChildCount > holopadArray.Length) while (ContactsList.ChildCount > holopadArray.Length)
{
ContactsList.RemoveChild(ContactsList.GetChild(ContactsList.ChildCount - 1)); ContactsList.RemoveChild(ContactsList.GetChild(ContactsList.ChildCount - 1));
}
// Make / update required children // Make / update required children
for (int i = 0; i < holopadArray.Length; i++) for (int i = 0; i < holopadArray.Length; i++)
@@ -213,55 +220,57 @@ public sealed partial class HolopadWindow : FancyWindow
private void UpdateAppearance() private void UpdateAppearance()
{ {
if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone)) if (!_entManager.TryGetComponent<TelephoneComponent>(_owner, out var telephone))
return; return;
if (_owner == null || !_entManager.TryGetComponent<HolopadComponent>(_owner.Value, out var holopad)) if (!_entManager.TryGetComponent<HolopadComponent>(_owner, out var holopad))
return; return;
var hasBroadcastAccess = !_holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad)); var broadcastOnCooldown = _holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad));
var localPlayer = _playerManager.LocalSession?.AttachedEntity; var localPlayer = _playerManager.LocalSession?.AttachedEntity;
// Update container visibility
ControlsLockOutContainer.Visible = _holopadSystem.IsHolopadControlLocked((_owner.Value, holopad), localPlayer); ControlsLockOutContainer.Visible = _holopadSystem.IsHolopadControlLocked((_owner.Value, holopad), localPlayer);
ControlsContainer.Visible = !ControlsLockOutContainer.Visible; ControlsContainer.Visible = !ControlsLockOutContainer.Visible;
// Temporarily disable the interface buttons when the call state changes to prevent any misclicks // Update contact button visibility
if (_currentState != telephone.CurrentState) if (SearchLineEdit.Text != _currentSearch)
{ {
_previousState = _currentState; _currentSearch = SearchLineEdit.Text;
_currentState = telephone.CurrentState;
_buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay; foreach (var child in ContactsList.Children)
{
if (child is not HolopadContactButton contactButton)
continue;
var passesFilter = string.IsNullOrEmpty(SearchLineEdit.Text) ||
contactButton.Text?.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase) == true;
contactButton.Visible = passesFilter;
}
} }
var lockButtons = _timing.CurTime < _buttonUnlockTime; // Update timers
if (ControlsContainer.Visible)
// Make / update required children
foreach (var child in ContactsList.Children)
{ {
if (child is not HolopadContactButton contactButton) var cooldown = _holopadSystem.GetHolopadBroadcastCoolDown((_owner.Value, holopad));
continue; var cooldownString = $"{cooldown.Minutes:00}:{cooldown.Seconds:00}";
var passesFilter = string.IsNullOrEmpty(SearchLineEdit.Text) || StartBroadcastButton.Text = broadcastOnCooldown
contactButton.Text?.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase) == true; ? Loc.GetString("holopad-window-emergency-broadcast-with-countdown", ("countdown", cooldownString))
: Loc.GetString("holopad-window-emergency-broadcast");
contactButton.Visible = passesFilter;
contactButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
} }
// Update control text if (ControlsLockOutContainer.Visible)
var cooldown = _holopadSystem.GetHolopadBroadcastCoolDown((_owner.Value, holopad)); {
var cooldownString = $"{cooldown.Minutes:00}:{cooldown.Seconds:00}"; var lockout = _holopadSystem.GetHolopadControlLockedPeriod((_owner.Value, holopad));
var lockoutString = $"{lockout.Minutes:00}:{lockout.Seconds:00}";
StartBroadcastButton.Text = _holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad)) ? LockOutCountDownText.Text = Loc.GetString("holopad-window-controls-unlock-countdown", ("countdown", lockoutString));
Loc.GetString("holopad-window-emergency-broadcast-with-countdown", ("countdown", cooldownString)) : }
Loc.GetString("holopad-window-emergency-broadcast");
var lockout = _holopadSystem.GetHolopadControlLockedPeriod((_owner.Value, holopad)); // Update call status text
var lockoutString = $"{lockout.Minutes:00}:{lockout.Seconds:00}"; switch (telephone.CurrentState)
LockOutCountDownText.Text = Loc.GetString("holopad-window-controls-unlock-countdown", ("countdown", lockoutString));
switch (_currentState)
{ {
case TelephoneState.Idle: case TelephoneState.Idle:
CallStatusText.Text = Loc.GetString("holopad-window-no-calls-in-progress"); break; CallStatusText.Text = Loc.GetString("holopad-window-no-calls-in-progress"); break;
@@ -277,7 +286,7 @@ public sealed partial class HolopadWindow : FancyWindow
CallStatusText.Text = Loc.GetString("holopad-window-call-in-progress"); break; CallStatusText.Text = Loc.GetString("holopad-window-call-in-progress"); break;
case TelephoneState.EndingCall: case TelephoneState.EndingCall:
if (_previousState == TelephoneState.Calling || _previousState == TelephoneState.Idle) if (telephone.PreviousState == TelephoneState.Calling || telephone.PreviousState == TelephoneState.Idle)
CallStatusText.Text = Loc.GetString("holopad-window-call-rejected"); CallStatusText.Text = Loc.GetString("holopad-window-call-rejected");
else else
CallStatusText.Text = Loc.GetString("holopad-window-call-ending"); CallStatusText.Text = Loc.GetString("holopad-window-call-ending");
@@ -285,31 +294,29 @@ public sealed partial class HolopadWindow : FancyWindow
} }
// Update control disability // Update control disability
AnswerCallButton.Disabled = (_currentState != TelephoneState.Ringing || lockButtons); AnswerCallButton.Disabled = telephone.CurrentState is not TelephoneState.Ringing;
EndCallButton.Disabled = (_currentState == TelephoneState.Idle || _currentState == TelephoneState.EndingCall || lockButtons); EndCallButton.Disabled = telephone.CurrentState is TelephoneState.Idle or TelephoneState.EndingCall;
StartBroadcastButton.Disabled = (_currentState != TelephoneState.Idle || !hasBroadcastAccess || lockButtons); StartBroadcastButton.Disabled = telephone.CurrentState is not TelephoneState.Idle || broadcastOnCooldown;
RequestStationAiButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons); RequestStationAiButton.Disabled = telephone.CurrentState is not TelephoneState.Idle;
ActivateProjectorButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons); ActivateProjectorButton.Disabled = telephone.CurrentState is not TelephoneState.Idle;
// Update control visibility // Update control visibility
FetchingAvailableHolopadsContainer.Visible = (ContactsList.ChildCount == 0); FetchingAvailableHolopadsContainer.Visible = ContactsList.ChildCount == 0;
ActiveCallControlsContainer.Visible = (_currentState != TelephoneState.Idle || _currentUiKey == HolopadUiKey.AiRequestWindow); ActiveCallControlsContainer.Visible = telephone.CurrentState is not TelephoneState.Idle || _currentUiKey is HolopadUiKey.AiRequestWindow;
CallPlacementControlsContainer.Visible = !ActiveCallControlsContainer.Visible; CallPlacementControlsContainer.Visible = !ActiveCallControlsContainer.Visible;
CallerIdContainer.Visible = (_currentState == TelephoneState.Ringing); CallerIdContainer.Visible = telephone.CurrentState is TelephoneState.Ringing;
AnswerCallButton.Visible = (_currentState == TelephoneState.Ringing); AnswerCallButton.Visible = telephone.CurrentState is TelephoneState.Ringing;
} }
protected override void FrameUpdate(FrameEventArgs args) protected override void FrameUpdate(FrameEventArgs args)
{ {
base.FrameUpdate(args); base.FrameUpdate(args);
_updateTimer += args.DeltaSeconds; if (_timing.CurTime < _nextUpdate)
return;
if (_updateTimer >= UpdateTime) _nextUpdate = _timing.CurTime + _updateDelay;
{ UpdateAppearance();
_updateTimer -= UpdateTime;
UpdateAppearance();
}
} }
private sealed class HolopadContactButton : Button private sealed class HolopadContactButton : Button
+57 -39
View File
@@ -1,52 +1,70 @@
<Control xmlns="https://spacestation14.io" <Control xmlns="https://spacestation14.io"
xmlns:pllax="clr-namespace:Content.Client.Parallax" xmlns:pllax="clr-namespace:Content.Client.Parallax"
xmlns:clog="clr-namespace:Content.Client.Changelog"> xmlns:clog="clr-namespace:Content.Client.Changelog"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<pllax:ParallaxControl <pllax:ParallaxControl
ParallaxPrototype="TrainStation" Name="BackgroundParallax"
SpeedX="5" SpeedX="5"
SpeedY="20" SpeedY="20"
ScaleX="3" ScaleX="3"
ScaleY="3"/> ScaleY="3" />
<BoxContainer Name="VBox" <BoxContainer Name="VBox"
Orientation="Vertical" Orientation="Vertical"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
HorizontalExpand="True" HorizontalExpand="True"
VerticalExpand="True" VerticalExpand="True">
StyleIdentifier="mainMenuVBox" <PanelContainer StyleClasses="BackgroundPanel">
SeparationOverride="3"> <BoxContainer Orientation="Vertical"
<TextureRect Name="Logo" HorizontalAlignment="Center"
Stretch="KeepCentered"/> VerticalAlignment="Center"
<GridContainer Columns="2"> HorizontalExpand="True"
<Label Text="{Loc 'main-menu-username-label'}" /> VerticalExpand="True"
<LineEdit Name="UsernameBox" StyleIdentifier="mainMenuVBox"
Access="Public" Margin="4 16">
PlaceHolder="{Loc 'main-menu-username-text'}" <TextureRect Name="Logo"
HorizontalExpand="True" /> Stretch="KeepCentered" />
<Label Text="{Loc 'main-menu-address-label'}"/> <GridContainer Columns="2" Margin="0 4">
<LineEdit Name="AddressBox" <Label Text="{Loc 'main-menu-username-label'}" />
Access="Public" <LineEdit Name="UsernameBox"
Text="localhost" Access="Public"
PlaceHolder="server address:port" PlaceHolder="{Loc 'main-menu-username-text'}"
HorizontalExpand="True" /> HorizontalExpand="True" />
</GridContainer> <Label Text="{Loc 'main-menu-address-label'}" />
<Button Name="DirectConnectButton" <LineEdit Name="AddressBox"
Access="Public" Access="Public"
Text="{Loc 'main-menu-direct-connect-button'}" Text="localhost"
TextAlign="Center" PlaceHolder="server address:port"
StyleIdentifier="mainMenu"/> HorizontalExpand="True" />
<Button Name="OptionsButton" </GridContainer>
Access="Public" <Button Name="DirectConnectButton"
Text="{Loc 'main-menu-options-button'}" Access="Public"
TextAlign="Center" Text="{Loc 'main-menu-direct-connect-button'}"
StyleIdentifier="mainMenu"/> TextAlign="Center"
<Button Name="QuitButton" StyleClasses="OpenLeft"
Access="Public" StyleIdentifier="mainMenu" />
Text="{Loc 'main-menu-quit-button'}" <clog:ChangelogButton
TextAlign="Center" Name="ChangelogButton"
StyleIdentifier="mainMenu"/> StyleIdentifier="mainMenu"
<clog:ChangelogButton StyleClasses="OpenBoth"
Name="ChangelogButton" Access="Public" />
Access="Public"/> <Button Name="OptionsButton"
Access="Public"
Text="{Loc 'main-menu-options-button'}"
TextAlign="Center"
StyleClasses="OpenBoth"
StyleIdentifier="mainMenu" />
<Button Name="QuitButton"
Access="Public"
Text="{Loc 'main-menu-quit-button'}"
TextAlign="Center"
StyleIdentifier="mainMenu">
<Control.StyleClasses>
<system:String>negative</system:String>
<system:String>OpenRight</system:String>
</Control.StyleClasses>
</Button>
</BoxContainer>
</PanelContainer>
</BoxContainer> </BoxContainer>
</Control> </Control>
@@ -1,21 +1,43 @@
using Robust.Client.AutoGenerated; using Content.Client.Parallax.Data;
using Robust.Client.AutoGenerated;
using Robust.Client.ResourceManagement; using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared; using Robust.Shared;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Client.MainMenu.UI; namespace Content.Client.MainMenu.UI;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class MainMenuControl : Control public sealed partial class MainMenuControl : Control
{ {
[Dependency] private IRobustRandom _random = default!;
public const string StyleIdentifierMainMenu = "mainMenu"; public const string StyleIdentifierMainMenu = "mainMenu";
public const string StyleIdentifierMainMenuVBox = "mainMenuVBox"; public const string StyleIdentifierMainMenuVBox = "mainMenuVBox";
private static readonly ProtoId<ParallaxPrototype>[] Parallaxes =
[
"Wizard",
"TrainStation",
"PlasmaStation",
"AmberStation",
"FastSpace",
"AspidParallax",
"OriginStation",
"Default",
"Sky",
"KettleStation",
"BagelStation",
"ExoStation",
];
public MainMenuControl(IResourceCache resCache, IConfigurationManager configMan) public MainMenuControl(IResourceCache resCache, IConfigurationManager configMan)
{ {
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
LayoutContainer.SetAnchorPreset(this, LayoutContainer.LayoutPreset.Wide); LayoutContainer.SetAnchorPreset(this, LayoutContainer.LayoutPreset.Wide);
@@ -25,6 +47,10 @@ public sealed partial class MainMenuControl : Control
LayoutContainer.SetMarginTop(VBox, 30); LayoutContainer.SetMarginTop(VBox, 30);
LayoutContainer.SetGrowHorizontal(VBox, LayoutContainer.GrowDirection.Begin); LayoutContainer.SetGrowHorizontal(VBox, LayoutContainer.GrowDirection.Begin);
// I don't just enumerate them all as there's some hideous parallaxes, and it's easier
// to update an allowlist than to randomly get an ugly one to fix a blocklist.
BackgroundParallax.ParallaxPrototype = _random.Pick(Parallaxes).Id;
var logoTexture = resCache.GetResource<TextureResource>("/Textures/Logo/logo.png"); var logoTexture = resCache.GetResource<TextureResource>("/Textures/Logo/logo.png");
Logo.Texture = logoTexture; Logo.Texture = logoTexture;
@@ -1,9 +1,7 @@
using System.Numerics; using System.Numerics;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Physics.Components;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Client.Movement.Systems; namespace Content.Client.Movement.Systems;
+23 -12
View File
@@ -1,22 +1,33 @@
<ui1:EscapeMenu xmlns="https://spacestation14.io" <ui1:EscapeMenu xmlns="https://spacestation14.io"
xmlns:changelog="clr-namespace:Content.Client.Changelog" xmlns:changelog="clr-namespace:Content.Client.Changelog"
xmlns:ui="clr-namespace:Content.Client.Voting.UI" xmlns:ui="clr-namespace:Content.Client.Voting.UI"
xmlns:ui1="clr-namespace:Content.Client.Options.UI" xmlns:ui1="clr-namespace:Content.Client.Options.UI"
Title="{Loc 'ui-escape-title'}" xmlns:system="clr-namespace:System;assembly=System.Runtime"
Resizable="False"> Title="{Loc 'ui-escape-title'}"
Resizable="False">
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150"> <BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150">
<ui:VoteCallMenuButton /> <ui:VoteCallMenuButton />
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" /> <PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
<Button Access="Public" Name="RulesButton" Text="{Loc 'ui-escape-rules'}" /> <Button Access="Public" Name="RulesButton" Text="{Loc 'ui-escape-rules'}" StyleClasses="OpenLeft" />
<Button Access="Public" Name="GuidebookButton" Text="{Loc 'ui-escape-guidebook'}" /> <Button Access="Public" Name="GuidebookButton" Text="{Loc 'ui-escape-guidebook'}" StyleClasses="OpenBoth" />
<Button Access="Public" Name="WikiButton" Text="{Loc 'ui-escape-wiki'}" /> <Button Access="Public" Name="WikiButton" Text="{Loc 'ui-escape-wiki'}" StyleClasses="OpenBoth" />
<changelog:ChangelogButton Access="Public" Name="ChangelogButton" /> <changelog:ChangelogButton Access="Public" Name="ChangelogButton" StyleClasses="OpenBoth"/>
<Button Access="Public" Name="FeedbackButton" Text="{Loc 'ui-escape-feedback'}"/> <Button Access="Public" Name="FeedbackButton" Text="{Loc 'ui-escape-feedback'}" StyleClasses="OpenRight"/>
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" /> <PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
<Button Access="Public" Name="OptionsButton" Text="{Loc 'ui-escape-options'}" /> <Button Access="Public" Name="OptionsButton" Text="{Loc 'ui-escape-options'}" />
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" /> <PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
<Button Access="Public" Name="DisconnectButton" Text="{Loc 'ui-escape-disconnect'}" /> <Button Access="Public" Name="DisconnectButton" Text="{Loc 'ui-escape-disconnect'}">
<Button Access="Public" Name="QuitButton" Text="{Loc 'ui-escape-quit'}" StyleClasses="ButtonColorRed" /> <Control.StyleClasses>
<system:String>negative</system:String>
<system:String>OpenLeft</system:String>
</Control.StyleClasses>
</Button>
<Button Access="Public" Name="QuitButton" Text="{Loc 'ui-escape-quit'}">
<Control.StyleClasses>
<system:String>negative</system:String>
<system:String>OpenRight</system:String>
</Control.StyleClasses>
</Button>
</BoxContainer> </BoxContainer>
</ui1:EscapeMenu> </ui1:EscapeMenu>
@@ -7,6 +7,7 @@
<Label Text="{Loc 'ui-options-accessability-header-visuals'}" <Label Text="{Loc 'ui-options-accessability-header-visuals'}"
StyleClasses="LabelKeyText"/> StyleClasses="LabelKeyText"/>
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" /> <CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="DisableAiStaticCheckBox" Text="{Loc 'ui-options-disable-ai-static'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" /> <CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" /> <CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
<ui:OptionSlider Name="ScreenShakeIntensitySlider" Title="{Loc 'ui-options-screen-shake-intensity'}" /> <ui:OptionSlider Name="ScreenShakeIntensitySlider" Title="{Loc 'ui-options-screen-shake-intensity'}" />
@@ -15,6 +15,7 @@ public sealed partial class AccessibilityTab : Control
Control.AddOptionCheckBox(CCVars.ChatEnableColorName, EnableColorNameCheckBox); Control.AddOptionCheckBox(CCVars.ChatEnableColorName, EnableColorNameCheckBox);
Control.AddOptionCheckBox(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox); Control.AddOptionCheckBox(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox);
Control.AddOptionCheckBox(CCVars.ReducedMotion, ReducedMotionCheckBox); Control.AddOptionCheckBox(CCVars.ReducedMotion, ReducedMotionCheckBox);
Control.AddOptionCheckBox(CCVars.DisableAiStatic, DisableAiStaticCheckBox);
Control.AddOptionPercentSlider(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider); Control.AddOptionPercentSlider(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider);
Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider); Control.AddOptionPercentSlider(CCVars.ChatWindowOpacity, ChatWindowOpacitySlider);
Control.AddOptionPercentSlider(CCVars.SpeechBubbleTextOpacity, SpeechBubbleTextOpacitySlider); Control.AddOptionPercentSlider(CCVars.SpeechBubbleTextOpacity, SpeechBubbleTextOpacitySlider);
@@ -1,8 +1,10 @@
using System.Numerics; using System.Numerics;
using Content.Client.Graphics; using Content.Client.Graphics;
using Content.Shared.CCVar;
using Content.Shared.Silicons.StationAi; using Content.Shared.Silicons.StationAi;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics; using Robust.Shared.Physics;
@@ -14,10 +16,12 @@ namespace Content.Client.Silicons.StationAi;
public sealed partial class StationAiOverlay : Overlay public sealed partial class StationAiOverlay : Overlay
{ {
private static readonly ProtoId<ShaderPrototype> CameraStaticShader = "CameraStatic"; private static readonly ProtoId<ShaderPrototype> CameraStaticShader = "CameraStatic";
private static readonly ProtoId<ShaderPrototype> CameraStaticAccessibleShader = "CameraStaticAccessible";
private static readonly ProtoId<ShaderPrototype> StencilMaskShader = "StencilMask"; private static readonly ProtoId<ShaderPrototype> StencilMaskShader = "StencilMask";
private static readonly ProtoId<ShaderPrototype> StencilDrawShader = "StencilDraw"; private static readonly ProtoId<ShaderPrototype> StencilDrawShader = "StencilDraw";
[Dependency] private IClyde _clyde = default!; [Dependency] private IClyde _clyde = default!;
[Dependency] private IConfigurationManager _cfg = default!;
[Dependency] private IEntityManager _entManager = default!; [Dependency] private IEntityManager _entManager = default!;
[Dependency] private IGameTiming _timing = default!; [Dependency] private IGameTiming _timing = default!;
[Dependency] private IPlayerManager _player = default!; [Dependency] private IPlayerManager _player = default!;
@@ -29,12 +33,20 @@ public sealed partial class StationAiOverlay : Overlay
private readonly OverlayResourceCache<CachedResources> _resources = new(); private readonly OverlayResourceCache<CachedResources> _resources = new();
private ProtoId<ShaderPrototype> _activeShader = CameraStaticShader;
private float _updateRate = 1f / 30f; private float _updateRate = 1f / 30f;
private float _accumulator; private float _accumulator;
public StationAiOverlay() public StationAiOverlay()
{ {
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
_cfg.OnValueChanged(CCVars.DisableAiStatic, OnAiStaticChanged, invokeImmediately: true);
}
private void OnAiStaticChanged(bool toggle)
{
_activeShader = toggle ? CameraStaticAccessibleShader : CameraStaticShader;
} }
protected override void Draw(in OverlayDrawArgs args) protected override void Draw(in OverlayDrawArgs args)
@@ -97,7 +109,7 @@ public sealed partial class StationAiOverlay : Overlay
() => () =>
{ {
worldHandle.SetTransform(invMatrix); worldHandle.SetTransform(invMatrix);
var shader = _proto.Index(CameraStaticShader).Instance(); var shader = _proto.Index(_activeShader).Instance();
worldHandle.UseShader(shader); worldHandle.UseShader(shader);
worldHandle.DrawRect(worldBounds, Color.White); worldHandle.DrawRect(worldBounds, Color.White);
}, },
@@ -239,11 +239,15 @@ public abstract class RadialMenuButtonBase : BaseButton
/// <inheritdoc /> /// <inheritdoc />
protected override void KeyBindUp(GUIBoundKeyEventArgs args) protected override void KeyBindUp(GUIBoundKeyEventArgs args)
{ {
if (args.Function == EngineKeyFunctions.UIClick if (args.Function.IsClickOrAltClick())
|| args.Function == ContentKeyFunctions.AltActivateItemInWorld)
{
base.KeyBindUp(args); base.KeyBindUp(args);
} }
/// <inheritdoc />
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
if (args.Function.IsClickOrAltClick())
base.KeyBindDown(args);
} }
} }
@@ -285,11 +289,15 @@ public sealed class RadialMenuContextualCentralTextureButton : TextureButton
/// <inheritdoc /> /// <inheritdoc />
protected override void KeyBindUp(GUIBoundKeyEventArgs args) protected override void KeyBindUp(GUIBoundKeyEventArgs args)
{ {
if (args.Function == EngineKeyFunctions.UIClick if (args.Function.IsClickOrAltClick())
|| args.Function == ContentKeyFunctions.AltActivateItemInWorld)
{
base.KeyBindUp(args); base.KeyBindUp(args);
} }
/// <inheritdoc />
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
if (args.Function.IsClickOrAltClick())
base.KeyBindDown(args);
} }
} }
@@ -684,3 +692,12 @@ public class RadialMenuButtonWithSector : RadialMenuButton, IRadialMenuItemWithS
return new Angle(angleSectorFrom).EqualsApprox(new Angle(angleSectorTo)); return new Angle(angleSectorFrom).EqualsApprox(new Angle(angleSectorTo));
} }
} }
static file class RadialMenuButtonsHelpers
{
public static bool IsClickOrAltClick(this BoundKeyFunction function)
{
return function == EngineKeyFunctions.UIClick
|| function == ContentKeyFunctions.AltActivateItemInWorld;
}
}
@@ -250,6 +250,7 @@ public abstract partial class GameTest
catch (Exception) catch (Exception)
{ {
_pairDestroyed = true; _pairDestroyed = true;
Assert.Fail();
throw; throw;
} }
finally finally
@@ -20,12 +20,14 @@ public static class CompConstraintExtensions
{ {
extension(Has) extension(Has)
{ {
/// <inheritdoc cref="extension(ConstraintExpression).Comp{T}"/>
public static ResolvableConstraintExpression Comp<T>(IIntegrationInstance instance) public static ResolvableConstraintExpression Comp<T>(IIntegrationInstance instance)
where T : IComponent where T : IComponent
{ {
return new ConstraintExpression().Comp<T>(instance); return new ConstraintExpression().Comp<T>(instance);
} }
/// <inheritdoc cref="extension(ConstraintExpression).Comp(Type, IIntegrationInstance)"/>
public static ResolvableConstraintExpression Comp(Type t, IIntegrationInstance instance) public static ResolvableConstraintExpression Comp(Type t, IIntegrationInstance instance)
{ {
return new ConstraintExpression().Comp(t, instance); return new ConstraintExpression().Comp(t, instance);
@@ -34,12 +36,52 @@ public static class CompConstraintExtensions
extension(ConstraintExpression expr) extension(ConstraintExpression expr)
{ {
/// <summary>
/// Returns a new constraint which will either test for the existence of a <typeparamref name="T"/>
/// on the entity being tested or apply any following constraint to that component.
/// </summary>
/// <typeparam name="T">The component Type to check for.</typeparam>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity has an ItemComponent on the server.
/// Assert.That(myEntity, Has.Comp&lt;ItemComponent&gt;(Server));
///
/// // Assert that the server-sided entity myEntity has an ItemComponent with a Size field equal to "Small"
/// Assert.That(myEntity,
/// Has
/// .Comp&lt;ItemComponent&gt;(Server)
/// .Property(nameof(ItemComponent.Size))
/// .EqualTo("Small")
/// );
/// </code>
/// </example>
public ResolvableConstraintExpression Comp<T>(IIntegrationInstance instance) public ResolvableConstraintExpression Comp<T>(IIntegrationInstance instance)
where T : IComponent where T : IComponent
{ {
return expr.Append(new CompOperator(typeof(T), instance)); return expr.Append(new CompOperator(typeof(T), instance));
} }
/// <summary>
/// Returns a new constraint which will either test for the existence of a component of the specified type
/// on the entity being tested or apply any following constraint to that component.
/// </summary>
/// <param name="t">The Type of the component to check for.</param>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity has an ItemComponent on the server.
/// Assert.That(myEntity, Has.Comp(typeof(ItemComponent), Server));
///
/// // Assert that the server-sided entity myEntity has an ItemComponent with a Size field equal to "Small"
/// Assert.That(myEntity,
/// Has
/// .Comp(typeof(ItemComponent), Server)
/// .Property(nameof(ItemComponent.Size))
/// .EqualTo("Small")
/// );
/// </code>
/// </example>
public ResolvableConstraintExpression Comp(Type t, IIntegrationInstance instance) public ResolvableConstraintExpression Comp(Type t, IIntegrationInstance instance)
{ {
return expr.Append(new CompOperator(t, instance)); return expr.Append(new CompOperator(t, instance));
@@ -56,36 +56,43 @@ public static class LifeStageConstraintExtensions
{ {
extension(Is) extension(Is)
{ {
/// <inheritdoc cref="extension(ConstraintExpression).LifeStage"/>
public static LifeStageConstraint LifeStage(EntityLifeStage stage, IIntegrationInstance instance) public static LifeStageConstraint LifeStage(EntityLifeStage stage, IIntegrationInstance instance)
{ {
return new LifeStageConstraint(stage, instance); return new LifeStageConstraint(stage, instance);
} }
/// <inheritdoc cref="extension(ConstraintExpression).PreInit"/>
public static LifeStageConstraint PreInit(IIntegrationInstance instance) public static LifeStageConstraint PreInit(IIntegrationInstance instance)
{ {
return Is.LifeStage(EntityLifeStage.PreInit, instance); return Is.LifeStage(EntityLifeStage.PreInit, instance);
} }
/// <inheritdoc cref="extension(ConstraintExpression).Initializing"/>
public static LifeStageConstraint Initializing(IIntegrationInstance instance) public static LifeStageConstraint Initializing(IIntegrationInstance instance)
{ {
return Is.LifeStage(EntityLifeStage.Initializing, instance); return Is.LifeStage(EntityLifeStage.Initializing, instance);
} }
/// <inheritdoc cref="extension(ConstraintExpression).Initialized"/>
public static LifeStageConstraint Initialized(IIntegrationInstance instance) public static LifeStageConstraint Initialized(IIntegrationInstance instance)
{ {
return Is.LifeStage(EntityLifeStage.Initialized, instance); return Is.LifeStage(EntityLifeStage.Initialized, instance);
} }
/// <inheritdoc cref="extension(ConstraintExpression).MapInitialized"/>
public static LifeStageConstraint MapInitialized(IIntegrationInstance instance) public static LifeStageConstraint MapInitialized(IIntegrationInstance instance)
{ {
return Is.LifeStage(EntityLifeStage.MapInitialized, instance); return Is.LifeStage(EntityLifeStage.MapInitialized, instance);
} }
/// <inheritdoc cref="extension(ConstraintExpression).Terminating"/>
public static LifeStageConstraint Terminating(IIntegrationInstance instance) public static LifeStageConstraint Terminating(IIntegrationInstance instance)
{ {
return Is.LifeStage(EntityLifeStage.Terminating, instance); return Is.LifeStage(EntityLifeStage.Terminating, instance);
} }
/// <inheritdoc cref="extension(ConstraintExpression).Deleted"/>
public static LifeStageConstraint Deleted(IIntegrationInstance instance) public static LifeStageConstraint Deleted(IIntegrationInstance instance)
{ {
return Is.LifeStage(EntityLifeStage.Deleted, instance); return Is.LifeStage(EntityLifeStage.Deleted, instance);
@@ -94,6 +101,17 @@ public static class LifeStageConstraintExtensions
extension(ConstraintExpression expr) extension(ConstraintExpression expr)
{ {
/// <summary>
/// Returns a new constraint that checks if the entity is in the given lifestage.
/// </summary>
/// <param name="stage">The <see cref="EntityLifeStage"/> to check for.</param>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity is MapInitialized.
/// Assert.That(myEntity, Is.LifeStage(EntityLifeStage.MapInitialized, Server));
/// </code>
/// </example>
public LifeStageConstraint LifeStage(EntityLifeStage stage, IIntegrationInstance instance) public LifeStageConstraint LifeStage(EntityLifeStage stage, IIntegrationInstance instance)
{ {
var c = new LifeStageConstraint(stage, instance); var c = new LifeStageConstraint(stage, instance);
@@ -103,31 +121,91 @@ public static class LifeStageConstraintExtensions
return c; return c;
} }
/// <summary>
/// Returns a new constraint that checks if the entity is in the PreInit lifestage.
/// </summary>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity has not yet been initialized.
/// Assert.That(myEntity, Is.PreInit(Server));
/// </code>
/// </example>
public LifeStageConstraint PreInit(IIntegrationInstance instance) public LifeStageConstraint PreInit(IIntegrationInstance instance)
{ {
return expr.LifeStage(EntityLifeStage.PreInit, instance); return expr.LifeStage(EntityLifeStage.PreInit, instance);
} }
/// <summary>
/// Returns a new constraint that checks if the entity is in the Intializing lifestage.
/// </summary>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity is Initializing.
/// Assert.That(myEntity, Is.Initializing(Server));
/// </code>
/// </example>
public LifeStageConstraint Initializing(IIntegrationInstance instance) public LifeStageConstraint Initializing(IIntegrationInstance instance)
{ {
return expr.LifeStage(EntityLifeStage.Initializing, instance); return expr.LifeStage(EntityLifeStage.Initializing, instance);
} }
/// <summary>
/// Returns a new constraint that checks if the entity is in the Initialized lifestage.
/// </summary>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity is Initialized.
/// Assert.That(myEntity, Is.Initialized(Server));
/// </code>
/// </example>
public LifeStageConstraint Initialized(IIntegrationInstance instance) public LifeStageConstraint Initialized(IIntegrationInstance instance)
{ {
return expr.LifeStage(EntityLifeStage.Initialized, instance); return expr.LifeStage(EntityLifeStage.Initialized, instance);
} }
/// <summary>
/// Returns a new constraint that checks if the entity is in the MapInitialized lifestage.
/// </summary>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity is MapInitialized.
/// Assert.That(myEntity, Is.MapInitialized(Server));
/// </code>
/// </example>
public LifeStageConstraint MapInitialized(IIntegrationInstance instance) public LifeStageConstraint MapInitialized(IIntegrationInstance instance)
{ {
return expr.LifeStage(EntityLifeStage.MapInitialized, instance); return expr.LifeStage(EntityLifeStage.MapInitialized, instance);
} }
/// <summary>
/// Returns a new constraint that checks if the entity is in the Terminating lifestage.
/// </summary>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity is Terminating.
/// Assert.That(myEntity, Is.Terminating(Server));
/// </code>
/// </example>
public LifeStageConstraint Terminating(IIntegrationInstance instance) public LifeStageConstraint Terminating(IIntegrationInstance instance)
{ {
return expr.LifeStage(EntityLifeStage.Terminating, instance); return expr.LifeStage(EntityLifeStage.Terminating, instance);
} }
/// <summary>
/// Returns a new constraint that checks if the entity is in the Deleted lifestage.
/// </summary>
/// <param name="instance">The <see cref="IIntegrationInstance"/> (i.e. Server or Client) on which to perform the test.</param>
/// <example>
/// <code>
/// // Assert that the server-sided entity myEntity is Deleted.
/// Assert.That(myEntity, Is.Deleted(Server));
/// </code>
/// </example>
public LifeStageConstraint Deleted(IIntegrationInstance instance) public LifeStageConstraint Deleted(IIntegrationInstance instance)
{ {
return expr.LifeStage(EntityLifeStage.Deleted, instance); return expr.LifeStage(EntityLifeStage.Deleted, instance);
@@ -2,13 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.IntegrationTests.Fixtures; using Content.IntegrationTests.Fixtures;
using Content.IntegrationTests.Fixtures.Attributes;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Database; using Content.Server.Database;
using Content.Server.GameTicking; using Content.Server.GameTicking;
using Content.Shared.Administration.Logs; using Content.Shared.Administration.Logs;
using Content.Shared.Database; using Content.Shared.Database;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.GameObjects;
namespace Content.IntegrationTests.Tests.Administration.Logs; namespace Content.IntegrationTests.Tests.Administration.Logs;
@@ -23,29 +23,28 @@ public sealed class AddTests : GameTest
Connected = true Connected = true
}; };
[SidedDependency(Side.Server)] private readonly IAdminLogManager _sAdminLogManager = null!;
[SidedDependency(Side.Server)] private readonly IServerDbManager _sDbManager = null!;
[SidedDependency(Side.Server)] private readonly GameTicker _sGameTicker = null!;
[SidedDependency(Side.Server)] private readonly IPlayerManager _sPlayerManager = null!;
[Test] [Test]
public async Task AddAndGetSingleLog() public async Task AddAndGetSingleLog()
{ {
var pair = Pair;
var server = pair.Server;
var sEntities = server.ResolveDependency<IEntityManager>();
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
var guid = Guid.NewGuid(); var guid = Guid.NewGuid();
await pair.CreateTestMap(); await Pair.CreateTestMap();
var coordinates = pair.TestMap!.GridCoords; var coordinates = Pair.TestMap!.GridCoords;
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
var entity = sEntities.SpawnEntity(null, coordinates); var entity = SSpawnAtPosition(null, coordinates);
sAdminLogSystem.Add(LogType.Unknown, $"{entity:Entity} test log: {guid}"); _sAdminLogManager.Add(LogType.Unknown, $"{entity:Entity} test log: {guid}");
}); });
await PoolManager.WaitUntil(server, async () => await PoolManager.WaitUntil(Server, async () =>
{ {
var logs = sAdminLogSystem.CurrentRoundJson(new LogFilter var logs = _sAdminLogManager.CurrentRoundJson(new LogFilter
{ {
Search = guid.ToString() Search = guid.ToString()
}); });
@@ -69,32 +68,22 @@ public sealed class AddTests : GameTest
[Test] [Test]
public async Task AddAndGetUnformattedLog() public async Task AddAndGetUnformattedLog()
{ {
var pair = Pair;
var server = pair.Server;
var sDatabase = server.ResolveDependency<IServerDbManager>();
var sEntities = server.ResolveDependency<IEntityManager>();
var sSystems = server.ResolveDependency<IEntitySystemManager>();
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
var sGamerTicker = sSystems.GetEntitySystem<GameTicker>();
var guid = Guid.NewGuid(); var guid = Guid.NewGuid();
var testMap = await pair.CreateTestMap(); var testMap = await Pair.CreateTestMap();
var coordinates = testMap.GridCoords; var coordinates = testMap.GridCoords;
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
var entity = sEntities.SpawnEntity(null, coordinates); var entity = SSpawnAtPosition(null, coordinates);
sAdminLogSystem.Add(LogType.Unknown, $"{entity} test log: {guid}"); _sAdminLogManager.Add(LogType.Unknown, $"{entity} test log: {guid}");
}); });
SharedAdminLog log = default; SharedAdminLog log = default;
await PoolManager.WaitUntil(server, async () => await PoolManager.WaitUntil(Server, async () =>
{ {
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter var logs = await _sAdminLogManager.CurrentRoundLogs(new LogFilter
{ {
Search = guid.ToString() Search = guid.ToString()
}); });
@@ -110,12 +99,12 @@ public sealed class AddTests : GameTest
var filter = new LogFilter var filter = new LogFilter
{ {
Round = sGamerTicker.RoundId, Round = _sGameTicker.RoundId,
Search = log.Message, Search = log.Message,
Types = new HashSet<LogType> { log.Type }, Types = new HashSet<LogType> { log.Type },
}; };
await foreach (var json in sDatabase.GetAdminLogsJson(filter)) await foreach (var json in _sDbManager.GetAdminLogsJson(filter))
{ {
var root = json.RootElement; var root = json.RootElement;
@@ -133,27 +122,21 @@ public sealed class AddTests : GameTest
[TestCase(500)] [TestCase(500)]
public async Task BulkAddLogs(int amount) public async Task BulkAddLogs(int amount)
{ {
var pair = Pair; var testMap = await Pair.CreateTestMap();
var server = pair.Server;
var sEntities = server.ResolveDependency<IEntityManager>();
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
var testMap = await pair.CreateTestMap();
var coordinates = testMap.GridCoords; var coordinates = testMap.GridCoords;
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
var entity = sEntities.SpawnEntity(null, coordinates); var entity = SSpawnAtPosition(null, coordinates);
for (var i = 0; i < amount; i++) for (var i = 0; i < amount; i++)
{ {
sAdminLogSystem.Add(LogType.Unknown, $"{entity:Entity} test log."); _sAdminLogManager.Add(LogType.Unknown, $"{entity:Entity} test log.");
} }
}); });
await PoolManager.WaitUntil(server, async () => await PoolManager.WaitUntil(Server, async () =>
{ {
var messages = await sAdminLogSystem.CurrentRoundLogs(); var messages = await _sAdminLogManager.CurrentRoundLogs();
return messages.Count >= amount; return messages.Count >= amount;
}); });
} }
@@ -161,28 +144,22 @@ public sealed class AddTests : GameTest
[Test] [Test]
public async Task AddPlayerSessionLog() public async Task AddPlayerSessionLog()
{ {
var pair = Pair;
var server = pair.Server;
var sPlayers = server.ResolveDependency<IPlayerManager>();
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
Guid playerGuid = default; Guid playerGuid = default;
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
var player = sPlayers.Sessions.First(); var player = _sPlayerManager.Sessions.First();
playerGuid = player.UserId; playerGuid = player.UserId;
Assert.DoesNotThrow(() => Assert.DoesNotThrow(() =>
{ {
sAdminLogSystem.Add(LogType.Unknown, $"{player:Player} test log."); _sAdminLogManager.Add(LogType.Unknown, $"{player:Player} test log.");
}); });
}); });
await PoolManager.WaitUntil(server, async () => await PoolManager.WaitUntil(Server, async () =>
{ {
var logs = await sAdminLogSystem.CurrentRoundLogs(); var logs = await _sAdminLogManager.CurrentRoundLogs();
if (logs.Count == 0) if (logs.Count == 0)
{ {
return false; return false;
@@ -196,24 +173,18 @@ public sealed class AddTests : GameTest
[Test] [Test]
public async Task DuplicatePlayerDoesNotThrowTest() public async Task DuplicatePlayerDoesNotThrowTest()
{ {
var pair = Pair;
var server = pair.Server;
var sPlayers = server.ResolveDependency<IPlayerManager>();
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
var guid = Guid.NewGuid(); var guid = Guid.NewGuid();
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
var player = sPlayers.Sessions.Single(); var player = _sPlayerManager.Sessions.Single();
sAdminLogSystem.Add(LogType.Unknown, $"{player} {player} test log: {guid}"); _sAdminLogManager.Add(LogType.Unknown, $"{player} {player} test log: {guid}");
}); });
await PoolManager.WaitUntil(server, async () => await PoolManager.WaitUntil(Server, async () =>
{ {
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter var logs = await _sAdminLogManager.CurrentRoundLogs(new LogFilter
{ {
Search = guid.ToString() Search = guid.ToString()
}); });
@@ -230,25 +201,18 @@ public sealed class AddTests : GameTest
[Test] [Test]
public async Task DuplicatePlayerIdDoesNotThrowTest() public async Task DuplicatePlayerIdDoesNotThrowTest()
{ {
var pair = Pair;
var server = pair.Server;
var sPlayers = server.ResolveDependency<IPlayerManager>();
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
var guid = Guid.NewGuid(); var guid = Guid.NewGuid();
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
var player = sPlayers.Sessions.Single(); var player = _sPlayerManager.Sessions.Single();
sAdminLogSystem.Add(LogType.Unknown, $"{player:first} {player:second} test log: {guid}"); _sAdminLogManager.Add(LogType.Unknown, $"{player:first} {player:second} test log: {guid}");
}); });
await PoolManager.WaitUntil(server, async () => await PoolManager.WaitUntil(Server, async () =>
{ {
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter var logs = await _sAdminLogManager.CurrentRoundLogs(new LogFilter
{ {
Search = guid.ToString() Search = guid.ToString()
}); });
@@ -272,35 +236,30 @@ public sealed class PreRoundAddTests : GameTest
AdminLogsEnabled = true AdminLogsEnabled = true
}; };
[SidedDependency(Side.Server)] private readonly IAdminLogManager _sAdminLogManager = null!;
[SidedDependency(Side.Server)] private readonly IServerDbManager _sDbManager = null!;
[SidedDependency(Side.Server)] private readonly GameTicker _sGameTicker = null!;
[Test] [Test]
public async Task PreRoundAddAndGetSingle() public async Task PreRoundAddAndGetSingle()
{ {
var pair = Pair;
var server = pair.Server;
var sDatabase = server.ResolveDependency<IServerDbManager>();
var sSystems = server.ResolveDependency<IEntitySystemManager>();
var sAdminLogSystem = server.ResolveDependency<IAdminLogManager>();
var sGamerTicker = sSystems.GetEntitySystem<GameTicker>();
var guid = Guid.NewGuid(); var guid = Guid.NewGuid();
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
sAdminLogSystem.Add(LogType.Unknown, $"test log: {guid}"); _sAdminLogManager.Add(LogType.Unknown, $"test log: {guid}");
}); });
await server.WaitPost(() => await Server.WaitPost(() =>
{ {
sGamerTicker.StartRound(true); _sGameTicker.StartRound(true);
}); });
SharedAdminLog log = default; SharedAdminLog log = default;
await PoolManager.WaitUntil(server, async () => await PoolManager.WaitUntil(Server, async () =>
{ {
var logs = await sAdminLogSystem.CurrentRoundLogs(new LogFilter var logs = await _sAdminLogManager.CurrentRoundLogs(new LogFilter
{ {
Search = guid.ToString() Search = guid.ToString()
}); });
@@ -316,12 +275,12 @@ public sealed class PreRoundAddTests : GameTest
var filter = new LogFilter var filter = new LogFilter
{ {
Round = sGamerTicker.RoundId, Round = _sGameTicker.RoundId,
Search = log.Message, Search = log.Message,
Types = new HashSet<LogType> { log.Type }, Types = new HashSet<LogType> { log.Type },
}; };
await foreach (var json in sDatabase.GetAdminLogsJson(filter)) await foreach (var json in _sDbManager.GetAdminLogsJson(filter))
{ {
var root = json.RootElement; var root = json.RootElement;
@@ -0,0 +1,86 @@
using Content.Server.Atmos.Piping.Trinary.Components;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.Piping.Binary.Components;
using Robust.Shared.Utility;
namespace Content.IntegrationTests.Tests.Atmos;
/// <summary>
/// Test for ensuring that atmospherics components deserialize and spawn with settings applied.
/// </summary>
[TestFixture]
public sealed class AtmosMapLoadSettingsTest : AtmosTest
{
// These values correspond to settings in the test map.
private const float PumpSetting = 180f;
private const float MixerMainSetting = 0.1f;
private const float MixerSideSetting = 0.9f;
/// <summary>
/// Test map containing saved atmos components.
/// </summary>
protected override ResPath? TestMapPath => new("Maps/Test/Atmospherics/load_atmos_test_room.yml");
/// <summary>
/// Test to verify that the settings have been properly applied.
/// </summary>
[Test]
public async Task TestMapLoading()
{
await Server.WaitAssertion(() =>
{
var volumePumpQuery = SEntMan.EntityQueryEnumerator<GasVolumePumpComponent>();
while (volumePumpQuery.MoveNext(out var volumePump))
{
using (Assert.EnterMultipleScope())
{
Assert.That(volumePump.Enabled, Is.True, "Volume pump did not load enabled!");
Assert.That(
volumePump.TransferRate,
Is.EqualTo(PumpSetting),
"Volume pump did not load correct setting!"
);
}
}
var pressurePumpQuery = SEntMan.EntityQueryEnumerator<GasPressurePumpComponent>();
while (pressurePumpQuery.MoveNext(out var pressurePump))
{
using (Assert.EnterMultipleScope())
{
Assert.That(pressurePump.Enabled, Is.True, "Pressure pump did not load enabled!");
Assert.That(
pressurePump.TargetPressure,
Is.EqualTo(PumpSetting),
"Pressure pump did not load correct setting!"
);
}
}
var mixerQuery = SEntMan.EntityQueryEnumerator<GasMixerComponent>();
while (mixerQuery.MoveNext(out var mixer))
{
using (Assert.EnterMultipleScope())
{
Assert.That(mixer.Enabled, Is.True, "Mixer did not load enabled!");
Assert.That(
mixer.TargetPressure,
Is.EqualTo(PumpSetting),
"Mixer pump did not load correct setting!"
);
Assert.That(
mixer.InletOneConcentration,
Is.EqualTo(MixerMainSetting),
"Mixer split did not load correct setting!"
);
Assert.That(
mixer.InletTwoConcentration,
Is.EqualTo(MixerSideSetting),
"Mixer split did not load correct setting!"
);
}
}
});
}
}
@@ -44,6 +44,9 @@ public sealed class SharedGasSpecificHeatsTest
_sAtmos = _sEntMan.System<Content.Server.Atmos.EntitySystems.AtmosphereSystem>(); _sAtmos = _sEntMan.System<Content.Server.Atmos.EntitySystems.AtmosphereSystem>();
_cAtmos = _cEntMan.System<AtmosphereSystem>(); _cAtmos = _cEntMan.System<AtmosphereSystem>();
// ensure that client and server atmos are fully inited otherwise arrays might not agree
await _pair.ReallyBeIdle(1);
} }
[TearDown] [TearDown]
@@ -0,0 +1,495 @@
using Content.IntegrationTests.Tests.Interaction;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Item;
using Content.Shared.Wieldable;
using Content.Shared.Wieldable.Components;
namespace Content.IntegrationTests.Tests.Hands;
[TestOf(typeof(MultiHandedItemComponent))]
[TestOf(typeof(WieldableComponent))]
public abstract class BaseMultiHandedItemTest : InteractionTest
{
protected SharedHandsSystem CHands = default!;
protected SharedHandsSystem SHands = default!;
protected SharedWieldableSystem SWieldable = default!;
protected const string Dummy1 = "DummyOneHanded";
protected const string Dummy2 = "DummyTwoHanded";
protected const string Dummy3 = "DummyThreeHanded";
protected const string Dummy4 = "DummyFourHanded";
protected const string Crowbar1 = "CrowbarOneHanded";
protected const string Crowbar2 = "CrowbarTwoHanded";
protected const string Crowbar3 = "CrowbarThreeHanded";
protected const string CrowbarWield1 = "CrowbarWieldableOneHanded";
protected const string CrowbarWield2 = "CrowbarWieldableTwoHanded";
protected const string CrowbarWield3 = "CrowbarWieldableThreeHanded";
[TestPrototypes]
private const string TestPrototypes = @$"
- type: entity
id: {Dummy1}
name: Urist McOneHand
components:
- type: DoAfter
- type: Hands
hands:
hand_right:
location: Right
sortedHands:
- hand_right
- type: ComplexInteraction
- type: MindContainer
- type: Puller
- type: entity
parent: {Dummy1}
id: {Dummy2}
name: Urist McTwoHands
components:
- type: Hands
hands:
hand_right:
location: Right
hand_left:
location: Left
sortedHands:
- hand_right
- hand_left
- type: entity
parent: {Dummy1}
id: {Dummy3}
name: Urist McThreeHands
components:
- type: Hands
hands:
hand_right:
location: Right
hand_middle:
location: Middle
hand_left:
location: Left
sortedHands:
- hand_right
- hand_middle
- hand_left
- type: entity
parent: {Dummy1}
id: {Dummy4}
name: Urist McFourHands
components:
- type: Hands
hands:
hand_right1:
location: Right
hand_right2:
location: Right
hand_left1:
location: Left
hand_left2:
location: Left
sortedHands:
- hand_right1
- hand_right2
- hand_left1
- hand_left2
- type: entity
parent: BaseItem
id: {Crowbar1}
components:
- type: Sprite
sprite: Objects/Tools/crowbar.rsi
state: icon
- type: entity
parent: {Crowbar1}
id: {Crowbar2}
components:
- type: MultiHandedItem
handsNeeded: 2
- type: entity
parent: {Crowbar1}
id: {Crowbar3}
components:
- type: MultiHandedItem
handsNeeded: 3
- type: entity
parent: {Crowbar1}
id: {CrowbarWield1}
components:
- type: Wieldable
freeHandsRequired: 0
- type: entity
parent: {Crowbar1}
id: {CrowbarWield2}
components:
- type: Wieldable
freeHandsRequired: 1
- type: entity
parent: {Crowbar1}
id: {CrowbarWield3}
components:
- type: Wieldable
freeHandsRequired: 2
";
[SetUp]
public override async Task Setup()
{
await base.Setup();
CHands = CEntMan.System<SharedHandsSystem>();
SHands = SEntMan.System<SharedHandsSystem>();
SWieldable = SEntMan.System<SharedWieldableSystem>();
}
protected async Task AssertHandItems(int hands, int freeHands, int items, int virtualItems)
{
await RunTicks(3);
await Server.WaitAssertion(() =>
{
var itemCount = 0;
var virtualItemCount = 0;
foreach (var item in SHands.EnumerateHeld(SPlayer))
{
itemCount++;
if (SEntMan.HasComponent<VirtualItemComponent>(item))
virtualItemCount++;
}
Assert.Multiple(() =>
{
Assert.That(SHands.GetHandCount(SPlayer), Is.EqualTo(hands));
Assert.That(SHands.CountFreeHands(SPlayer), Is.EqualTo(freeHands));
Assert.That(itemCount, Is.EqualTo(items));
Assert.That(virtualItemCount, Is.EqualTo(virtualItems));
});
});
await Client.WaitAssertion(() =>
{
var itemCount = 0;
var virtualItemCount = 0;
foreach (var item in CHands.EnumerateHeld(CPlayer))
{
itemCount++;
if (CEntMan.HasComponent<VirtualItemComponent>(item))
virtualItemCount++;
}
Assert.Multiple(() =>
{
Assert.That(CHands.GetHandCount(CPlayer), Is.EqualTo(hands));
Assert.That(CHands.CountFreeHands(CPlayer), Is.EqualTo(freeHands));
Assert.That(itemCount, Is.EqualTo(items));
Assert.That(virtualItemCount, Is.EqualTo(virtualItems));
});
});
}
}
// we need a separate fixture for each hand amount so that we can override the PlayerPrototype
public sealed class OneHandedItemTestFixture : BaseMultiHandedItemTest
{
protected override string PlayerPrototype => Dummy1;
/// <summary>
/// Tries out a few possible combinations for using multi-handed and wieldable items while having one hand.
/// This does not cover all possible scenarios, so if something breaks at some point then add it here as well.
/// </summary>
[Test]
public async Task OneHandedItemTest()
{
// Start with one empty hand
await AssertHandItems(1, 1, 0, 0);
// We can pick up a one-handed item with one hand
await SpawnTarget(Crowbar1);
await Pickup();
await SwapHands(); // does nothing but we try anyways
await AssertHandItems(1, 0, 1, 0);
// We cannot pick up a second item
await SpawnTarget(Crowbar1);
await Server.WaitAssertion(() =>
{
Assert.That(SHands.TryPickupAnyHand(SPlayer, STarget.Value), Is.False);
});
await AssertHandItems(1, 0, 1, 0);
// We can drop our current item to free up the hand
await Drop();
await AssertHandItems(1, 1, 0, 0);
// We cannot pick up a multi-handed item
await SpawnTarget(Crowbar2);
await Server.WaitAssertion(() =>
{
Assert.That(SHands.TryPickupAnyHand(SPlayer, STarget.Value), Is.False);
});
await AssertHandItems(1, 1, 0, 0);
// Spawn a wieldable Crowbar that does not need extra hands, pick it up, wield it
await SpawnTarget(CrowbarWield1);
await Pickup();
await AssertHandItems(1, 0, 1, 0);
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.True);
});
await AssertHandItems(1, 0, 1, 0);
// Drop the wielded item
await Drop();
await AssertHandItems(1, 1, 0, 0);
// Spawn a wieldable Crowbar that needs extra hands, pick it up, fail to wield it
await SpawnTarget(CrowbarWield2);
await Pickup();
await AssertHandItems(1, 0, 1, 0);
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.False);
});
await AssertHandItems(1, 0, 1, 0);
// Drop the unwielded item
await Drop();
await AssertHandItems(1, 1, 0, 0);
}
}
public sealed class TwoHandedItemTestFixture : BaseMultiHandedItemTest
{
protected override string PlayerPrototype => Dummy2;
/// <summary>
/// Tries out a few possible combinations for using multi-handed and wieldable items while having two hands.
/// This does not cover all possible scenarios, so if something breaks at some point then add it here as well.
/// </summary>
[Test]
public async Task TwoHandedItemTest()
{
// Start with two empty hands
await AssertHandItems(2, 2, 0, 0);
// We can pick up a one-handed item with one hand
await SpawnTarget(Crowbar1);
await Pickup();
await SwapHands();
await AssertHandItems(2, 1, 1, 0);
// We can pick up another one-handed item with the second hand
await SpawnTarget(Crowbar1);
await Pickup();
await SwapHands();
await AssertHandItems(2, 0, 2, 0);
// We cannot pick up a third item
await SpawnTarget(Crowbar1);
await Server.WaitAssertion(() =>
{
Assert.That(SHands.TryPickupAnyHand(SPlayer, STarget.Value), Is.False);
});
await AssertHandItems(2, 0, 2, 0);
// Drop all items
await DropAll();
await AssertHandItems(2, 2, 0, 0);
// We can pick up a two-handed item with two hands
await SpawnTarget(Crowbar2);
await Pickup();
await SwapHands();
await AssertHandItems(2, 0, 2, 1);
// We cannot pick up a second item
await SpawnTarget(Crowbar1);
await Server.WaitAssertion(() =>
{
Assert.That(SHands.TryPickupAnyHand(SPlayer, STarget.Value), Is.False);
});
await AssertHandItems(2, 0, 2, 1);
// Drop all items
await DropAll();
await AssertHandItems(2, 2, 0, 0);
// We can pick up a one-handed item with one hand
var handOneItem = await SpawnTarget(Crowbar1);
await Pickup();
await SwapHands();
await AssertHandItems(2, 1, 1, 0);
// We cannot pick up a two-handed item with only one free hand
await SpawnTarget(Crowbar2);
await Server.WaitAssertion(() =>
{
Assert.That(SHands.TryPickupAnyHand(SPlayer, STarget.Value), Is.False);
});
await AssertHandItems(2, 1, 1, 0);
// We can pick up a one handed wieldable item
await SpawnTarget(CrowbarWield1);
await Pickup();
await AssertHandItems(2, 0, 2, 0);
// We can wield the one-handed wieldable item without dropping other items
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.True);
});
Assert.That(SHands.IsHolding(SPlayer, ToServer(handOneItem)), Is.True);
await AssertHandItems(2, 0, 2, 0);
// Drop it and pick up a two-handed wieldable item
await Drop();
await AssertHandItems(2, 1, 1, 0);
await SpawnTarget(CrowbarWield2);
await Pickup();
await AssertHandItems(2, 0, 2, 0);
// We can wield the two-handed wieldable item, but drop the item in the other hand while doing so
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.True);
});
Assert.That(SHands.IsHolding(SPlayer, ToServer(handOneItem)), Is.False);
await AssertHandItems(2, 0, 2, 1);
// Drop the wielded item
await Drop();
await AssertHandItems(2, 2, 0, 0);
// We cannot pick up a three-handed item
await SpawnTarget(Crowbar3);
await Server.WaitAssertion(() =>
{
Assert.That(SHands.TryPickupAnyHand(SPlayer, STarget.Value), Is.False);
});
await AssertHandItems(2, 2, 0, 0);
// We can pick up a three-handed wieldable item
await SpawnTarget(CrowbarWield3);
await Server.WaitAssertion(() =>
{
Assert.That(SHands.TryPickupAnyHand(SPlayer, STarget.Value), Is.True);
});
await AssertHandItems(2, 1, 1, 0);
// But we cannot wield it
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.False);
});
await AssertHandItems(2, 1, 1, 0);
}
}
public sealed class ThreeHandedItemTestFixture : BaseMultiHandedItemTest
{
protected override string PlayerPrototype => Dummy3;
/// <summary>
/// Tries out a few possible combinations for using multi-handed and wieldable items while having three hands.
/// This does not cover all possible scenarios, so if something breaks at some point then add it here as well.
/// </summary>
[Test]
public async Task ThreeHandedItemTest()
{
// Start with three empty hands
await AssertHandItems(3, 3, 0, 0);
// We can pick up a three-handed item
await SpawnTarget(Crowbar3);
await Pickup();
await AssertHandItems(3, 0, 3, 2);
// Drop it
await Drop();
await AssertHandItems(3, 3, 0, 0);
// We can pick up a two-handed wieldable item
var handOneItem = await SpawnTarget(CrowbarWield2);
await Pickup();
await AssertHandItems(3, 2, 1, 0);
// And we can wield it
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.True);
});
await AssertHandItems(3, 1, 2, 1);
// We can pick up a second two-handed wieldable item
await SwapHands();
await SwapHands();
await SpawnTarget(CrowbarWield2);
await Pickup();
await AssertHandItems(3, 0, 3, 1);
// And wielding it drops the first item
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.True);
});
Assert.That(SHands.IsHolding(SPlayer, ToServer(handOneItem)), Is.False);
await AssertHandItems(3, 1, 2, 1);
}
}
public sealed class FourHandedItemTestFixture : BaseMultiHandedItemTest
{
protected override string PlayerPrototype => Dummy4;
/// <summary>
/// Tries out a few possible combinations for using multi-handed and wieldable items while having four hands.
/// This does not cover all possible scenarios, so if something breaks at some point then add it here as well.
/// </summary>
[Test]
public async Task FourHandedItemTest()
{
// Start with four empty hands
await AssertHandItems(4, 4, 0, 0);
// We can wield two two-handed wieldable items at the same time
await SpawnTarget(CrowbarWield2);
await Pickup();
await AssertHandItems(4, 3, 1, 0);
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.True);
});
await AssertHandItems(4, 2, 2, 1);
await SwapHands();
await SwapHands();
await SpawnTarget(CrowbarWield2);
await Pickup();
await AssertHandItems(4, 1, 3, 1);
await Server.WaitAssertion(() =>
{
Assert.That(SWieldable.TryWield(STarget.Value, SPlayer), Is.True);
});
await AssertHandItems(4, 0, 4, 2);
// Drop the first item
await Drop();
await AssertHandItems(4, 2, 2, 1);
// Drop the second item
await SwapHands();
await SwapHands();
await Drop();
await AssertHandItems(4, 4, 0, 0);
}
}
@@ -1,5 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Content.IntegrationTests.Fixtures; using Content.IntegrationTests.Fixtures;
using Content.IntegrationTests.Fixtures.Attributes;
using Content.IntegrationTests.Utility; using Content.IntegrationTests.Utility;
using Content.Shared.Body; using Content.Shared.Body;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
@@ -21,10 +23,10 @@ public sealed class HumanoidProfileTests : GameTest
private static readonly ProtoId<SpeciesPrototype> Vox = "Vox"; private static readonly ProtoId<SpeciesPrototype> Vox = "Vox";
private static string[] _species = GameDataScrounger.PrototypesOfKind<SpeciesPrototype>(); private static string[] _species = GameDataScrounger.PrototypesOfKind<SpeciesPrototype>();
private BodySystem _bodySystem; [SidedDependency(Side.Server)] private BodySystem _bodySystem = default!;
private HumanoidProfileSystem _humanoidProfile; [SidedDependency(Side.Server)] private HumanoidProfileSystem _humanoidProfile = default!;
private MarkingManager _markingManager; [SidedDependency(Side.Server)] private MarkingManager _markingManager = default!;
private SharedVisualBodySystem _visualBody; [SidedDependency(Side.Server)] private SharedVisualBodySystem _visualBody = default!;
[Test] [Test]
public async Task EnsureValidLoading() public async Task EnsureValidLoading()
@@ -36,17 +38,15 @@ public sealed class HumanoidProfileTests : GameTest
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
var entityManager = server.ResolveDependency<IEntityManager>(); LoadDependencies(out var body, out var humanoidComponent);
var humanoidProfile = entityManager.System<HumanoidProfileSystem>();
var human = entityManager.Spawn(BaseSpecies); _humanoidProfile.ApplyProfileTo(body,
humanoidProfile.ApplyProfileTo(human,
new HumanoidCharacterProfile() new HumanoidCharacterProfile()
.WithSex(Sex.Female) .WithSex(Sex.Female)
.WithAge(67) .WithAge(67)
.WithGender(Gender.Neuter) .WithGender(Gender.Neuter)
.WithSpecies(Vox)); .WithSpecies(Vox));
var humanoidComponent = entityManager.GetComponent<HumanoidProfileComponent>(human); var voiceComponent = SEntMan.GetComponent<VocalComponent>(body);
var voiceComponent = entityManager.GetComponent<VocalComponent>(human);
Assert.That(humanoidComponent.Age, Is.EqualTo(67)); Assert.That(humanoidComponent.Age, Is.EqualTo(67));
Assert.That(humanoidComponent.Sex, Is.EqualTo(Sex.Female)); Assert.That(humanoidComponent.Sex, Is.EqualTo(Sex.Female));
@@ -71,6 +71,7 @@ public sealed class HumanoidProfileTests : GameTest
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
LoadDependencies(out var body, out var humanoidComponent); LoadDependencies(out var body, out var humanoidComponent);
var profile = HumanoidCharacterProfile.Random(); var profile = HumanoidCharacterProfile.Random();
_humanoidProfile.ApplyProfileTo(body, profile); _humanoidProfile.ApplyProfileTo(body, profile);
_visualBody.ApplyProfileTo(body, profile); _visualBody.ApplyProfileTo(body, profile);
@@ -91,17 +92,17 @@ public sealed class HumanoidProfileTests : GameTest
{ {
LoadDependencies(out var body, out var humanoidComponent); LoadDependencies(out var body, out var humanoidComponent);
var proto = Server.ProtoMan.Index<SpeciesPrototype>(species); var proto = SProtoMan.Index<SpeciesPrototype>(species);
var profile = HumanoidCharacterProfile.RandomWithSpecies(species); var profile = HumanoidCharacterProfile.RandomWithSpecies(species);
_humanoidProfile.ApplyProfileTo(body, profile); _humanoidProfile.ApplyProfileTo(body, profile);
_visualBody.ApplyProfileTo(body, profile); _visualBody.ApplyProfileTo(body, profile);
Assert.That(humanoidComponent.Age, Is.LessThanOrEqualTo(proto.MaxAge)); Assert.That(humanoidComponent.Age, Is.LessThanOrEqualTo(proto.MaxAge), $"Expected age is above the maximum age limit! Current: {humanoidComponent.Age} Max: {proto.MaxAge}");
Assert.That(humanoidComponent.Age, Is.GreaterThanOrEqualTo(proto.MinAge)); Assert.That(humanoidComponent.Age, Is.GreaterThanOrEqualTo(proto.MinAge), $"Expected age is below the minimum age limit! Current: {humanoidComponent.Age} Min: {proto.MinAge}");
Assert.That(proto.Sexes.Contains(humanoidComponent.Sex), Is.True); Assert.That(proto.Sexes.Contains(humanoidComponent.Sex), Is.True, $"Character has sex not found in the species prototype! Current: {humanoidComponent.Sex}");
Assert.That(humanoidComponent.Species, Is.EqualTo(species)); Assert.That(humanoidComponent.Species, Is.EqualTo(species), $"Species does not match! Expected: {species} Current: {humanoidComponent.Species}");
var strategy = Server.ProtoMan.Index(proto.SkinColoration).Strategy; var strategy = Server.ProtoMan.Index(proto.SkinColoration).Strategy;
Assert.That(strategy.VerifySkinColor(profile.Appearance.SkinColor), Is.True); Assert.That(strategy.VerifySkinColor(profile.Appearance.SkinColor, out var reason), Is.True, $"Failed to verify the skin color from strategy {strategy}. Reason: {reason}");
AssertValidProfile((body, humanoidComponent), profile); AssertValidProfile((body, humanoidComponent), profile);
}); });
@@ -109,29 +110,24 @@ public sealed class HumanoidProfileTests : GameTest
private void LoadDependencies(out EntityUid body, out HumanoidProfileComponent humanoidComponent) private void LoadDependencies(out EntityUid body, out HumanoidProfileComponent humanoidComponent)
{ {
var entityManager = Server.ResolveDependency<IEntityManager>(); body = SEntMan.Spawn(BaseSpecies);
_humanoidProfile = entityManager.System<HumanoidProfileSystem>(); humanoidComponent = SEntMan.GetComponent<HumanoidProfileComponent>(body);
_markingManager = Server.ResolveDependency<MarkingManager>();
_visualBody = entityManager.System<SharedVisualBodySystem>();
_bodySystem = entityManager.System<BodySystem>();
body = entityManager.Spawn(BaseSpecies);
humanoidComponent = entityManager.GetComponent<HumanoidProfileComponent>(body);
} }
private void AssertValidProfile(Entity<HumanoidProfileComponent> body, HumanoidCharacterProfile profile) private void AssertValidProfile(Entity<HumanoidProfileComponent> body, HumanoidCharacterProfile profile)
{ {
_bodySystem.TryGetOrgansWithComponent<VisualOrganComponent>(body.Owner, out var organs); _bodySystem.TryGetOrgansWithComponent<VisualOrganComponent>(body.Owner, out var organs);
foreach (var (_, visualOrgan) in organs) foreach (var (uid, visualOrgan) in organs)
{ {
Assert.That(visualOrgan.Profile.Sex, Is.EqualTo(profile.Sex)); Assert.That(visualOrgan.Profile.Sex, Is.EqualTo(profile.Sex), $"Organ {uid} has invalid sex appearance! Expected: {profile.Sex} Current: {visualOrgan.Profile.Sex}");
Assert.That(visualOrgan.Profile.EyeColor, Is.EqualTo(profile.Appearance.EyeColor)); Assert.That(visualOrgan.Profile.EyeColor, Is.EqualTo(profile.Appearance.EyeColor), $"Organ {uid} has invalid eye color! Expected: {profile.Appearance.EyeColor} Current: {visualOrgan.Profile.EyeColor}");
Assert.That(visualOrgan.Profile.SkinColor, Is.EqualTo(profile.Appearance.SkinColor)); Assert.That(visualOrgan.Profile.SkinColor, Is.EqualTo(profile.Appearance.SkinColor), $"Organ {uid} has invalid skin color! Expected: {profile.Appearance.SkinColor} Current: {visualOrgan.Profile.SkinColor}");
} }
_bodySystem.TryGetOrgansWithComponent<VisualOrganMarkingsComponent>(body.Owner, out var markings); _bodySystem.TryGetOrgansWithComponent<VisualOrganMarkingsComponent>(body.Owner, out var markings);
foreach (var (_, markingOrgan) in markings) foreach (var (uid, markingOrgan) in markings)
{ {
// Needed to avoid access restrictions // Needed to avoid access restrictions
var data = markingOrgan.MarkingData; var data = markingOrgan.MarkingData;
@@ -143,9 +139,9 @@ public sealed class HumanoidProfileTests : GameTest
{ {
var markingProto = Server.ProtoMan.Index(marking.MarkingId); var markingProto = Server.ProtoMan.Index(marking.MarkingId);
Assert.That(markingProto.Sprites.Count, Is.EqualTo(marking.MarkingColors.Count)); Assert.That(markingProto.Sprites.Count, Is.EqualTo(marking.MarkingColors.Count), $"Organ {uid} has invald amount of marking sprites! Expected: {marking.MarkingColors.Count} Current: {markingProto.Sprites.Count}");
Assert.That(_markingManager.CanBeApplied(data.Group, profile.Sex, markingProto), Is.True); Assert.That(_markingManager.CanBeApplied(data.Group, profile.Sex, markingProto), Is.True, $"Marking {markingProto.ID} cannot be applied to group {data.Group.Id} with sex {profile.Sex}");
Assert.That(data.Layers.Contains(markingProto.BodyPart), Is.True); Assert.That(data.Layers.Contains(markingProto.BodyPart), Is.True, $"Organ {uid} marking visual layers do not contain an entry for {markingProto.BodyPart}");
if (!markingProto.ForcedColoring && groupProto.Appearances.GetValueOrDefault(markingProto.BodyPart)?.MatchSkin != true) if (!markingProto.ForcedColoring && groupProto.Appearances.GetValueOrDefault(markingProto.BodyPart)?.MatchSkin != true)
freeMarkings.Add(marking); freeMarkings.Add(marking);
@@ -172,7 +168,7 @@ public sealed class HumanoidProfileTests : GameTest
Is.EqualTo(MarkingColoring.GetMarkingLayerColors(markingProto, profile.Appearance.SkinColor, profile.Appearance.EyeColor, markingOrgan.AppliedMarkings))); Is.EqualTo(MarkingColoring.GetMarkingLayerColors(markingProto, profile.Appearance.SkinColor, profile.Appearance.EyeColor, markingOrgan.AppliedMarkings)));
if (markingProto.SexRestriction != null) if (markingProto.SexRestriction != null)
Assert.That(markingProto.SexRestriction, Is.EqualTo(profile.Sex)); Assert.That(markingProto.SexRestriction, Is.EqualTo(profile.Sex), $"Marking {markingProto.ID} has invalid sex restriction! Expected: {profile.Sex} Current: {markingProto.SexRestriction}");
} }
} }
} }
@@ -259,6 +259,7 @@ public abstract partial class InteractionTest
/// <summary> /// <summary>
/// Drops the currently held entity. /// Drops the currently held entity.
/// Causes an error if no entity was held.
/// </summary> /// </summary>
protected async Task Drop() protected async Task Drop()
{ {
@@ -277,6 +278,36 @@ public abstract partial class InteractionTest
Assert.That(HandSys.GetActiveItem((ToServer(Player), Hands)), Is.Null); Assert.That(HandSys.GetActiveItem((ToServer(Player), Hands)), Is.Null);
} }
/// <summary>
/// Drops all currently held entities.
/// Does nothing if no entity was held.
/// </summary>
protected async Task DropAll()
{
await Server.WaitPost(() =>
{
HandSys.DropAll((ToServer(Player), Hands));
});
await RunTicks(1);
// make sure that all hands are empty
Assert.That(HandSys.GetEmptyHandCount((ToServer(Player), Hands)), Is.EqualTo(HandSys.GetHandCount((ToServer(Player), Hands))));
}
/// <summary>
/// Swaps the current hand.
/// </summary>
protected async Task SwapHands(bool reverse = false)
{
await Server.WaitPost(() =>
{
HandSys.SwapHands((ToServer(Player), Hands), reverse: reverse);
});
await RunTicks(1);
}
#region Interact #region Interact
/// <summary> /// <summary>
@@ -2,55 +2,61 @@ using System.Linq;
using Content.IntegrationTests.Fixtures; using Content.IntegrationTests.Fixtures;
using Content.Shared.Containers.ItemSlots; using Content.Shared.Containers.ItemSlots;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Shared.GameObjects; using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.Utility namespace Content.IntegrationTests.Tests.Utility
{ {
[TestFixture]
[TestOf(typeof(EntityWhitelist))] [TestOf(typeof(EntityWhitelist))]
public sealed class EntityWhitelistTest : GameTest public sealed class EntityWhitelistTest : GameTest
{ {
private const string InvalidComponent = "Sprite"; private const string InvalidComponent = "Sprite";
private const string ValidComponent = "Physics"; private const string ValidComponent = "Physics";
private const string WhitelistProtoId = "WhitelistDummy";
private const string ValidComponentProtoId = "ValidComponentDummy";
private const string WhitelistTestValidTagProtoId = "WhitelistTestValidTagDummy";
private const string InvalidComponentProtoId = "InvalidComponentDummy";
private const string WhitelistTestInvalidTagProtoId = "WhitelistTestInvalidTagDummy";
[TestPrototypes] [TestPrototypes]
private const string Prototypes = $@" private const string Prototypes = $@"
- type: Tag - type: Tag
id: WhitelistTestValidTag id: WhitelistTestValidTag
- type: Tag - type: Tag
id: WhitelistTestInvalidTag id: WhitelistTestInvalidTag
- type: entity - type: entity
id: WhitelistDummy id: {WhitelistProtoId}
components: components:
- type: ItemSlots - type: ItemSlots
slots: slots:
slotName: slotName:
whitelist: whitelist:
prototypes:
- ValidPrototypeDummy
components: components:
- {ValidComponent} - {ValidComponent}
tags: tags:
- WhitelistTestValidTag - WhitelistTestValidTag
- type: entity - type: entity
id: InvalidComponentDummy id: {InvalidComponentProtoId}
components: components:
- type: {InvalidComponent} - type: {InvalidComponent}
- type: entity - type: entity
id: WhitelistTestInvalidTagDummy id: {WhitelistTestInvalidTagProtoId}
components: components:
- type: Tag - type: Tag
tags: tags:
- WhitelistTestInvalidTag - WhitelistTestInvalidTag
- type: entity - type: entity
id: ValidComponentDummy id: {ValidComponentProtoId}
components: components:
- type: {ValidComponent} - type: {ValidComponent}
- type: entity - type: entity
id: WhitelistTestValidTagDummy id: {WhitelistTestValidTagProtoId}
components: components:
- type: Tag - type: Tag
tags: tags:
@@ -70,11 +76,17 @@ namespace Content.IntegrationTests.Tests.Utility
await server.WaitAssertion(() => await server.WaitAssertion(() =>
{ {
var validComponent = sEntities.SpawnEntity("ValidComponentDummy", mapCoordinates); var prototypeManager = server.ResolveDependency<IPrototypeManager>();
var WhitelistTestValidTag = sEntities.SpawnEntity("WhitelistTestValidTagDummy", mapCoordinates);
var invalidComponent = sEntities.SpawnEntity("InvalidComponentDummy", mapCoordinates); var validComponentProto = prototypeManager.Index(ValidComponentProtoId);
var WhitelistTestInvalidTag = sEntities.SpawnEntity("WhitelistTestInvalidTagDummy", mapCoordinates); var whitelistTestValidTagProto = prototypeManager.Index(WhitelistTestValidTagProtoId);
var invalidComponentProto = prototypeManager.Index(InvalidComponentProtoId);
var whitelistTestInvalidTagProto = prototypeManager.Index(WhitelistTestInvalidTagProtoId);
var validComponentUid = sEntities.SpawnEntity(ValidComponentProtoId, mapCoordinates);
var whitelistTestValidTagUid = sEntities.SpawnEntity(WhitelistTestValidTagProtoId, mapCoordinates);
var invalidComponentUid = sEntities.SpawnEntity(InvalidComponentProtoId, mapCoordinates);
var whitelistTestInvalidTagUid = sEntities.SpawnEntity(WhitelistTestInvalidTagProtoId, mapCoordinates);
// Test instantiated on its own // Test instantiated on its own
var whitelistInst = new EntityWhitelist var whitelistInst = new EntityWhitelist
@@ -85,15 +97,25 @@ namespace Content.IntegrationTests.Tests.Utility
Assert.Multiple(() => Assert.Multiple(() =>
{ {
Assert.That(sys.IsValid(whitelistInst, validComponent), Is.True); Assert.That(sys.IsValid(whitelistInst, validComponentUid), Is.True);
Assert.That(sys.IsValid(whitelistInst, WhitelistTestValidTag), Is.True); Assert.That(sys.IsValid(whitelistInst, validComponentProto), Is.True);
Assert.That(sys.IsValid(whitelistInst, ValidComponentProtoId), Is.True);
Assert.That(sys.IsValid(whitelistInst, invalidComponent), Is.False); Assert.That(sys.IsValid(whitelistInst, whitelistTestValidTagUid), Is.True);
Assert.That(sys.IsValid(whitelistInst, WhitelistTestInvalidTag), Is.False); Assert.That(sys.IsValid(whitelistInst, whitelistTestValidTagProto), Is.True);
Assert.That(sys.IsValid(whitelistInst, WhitelistTestValidTagProtoId), Is.True);
Assert.That(sys.IsValid(whitelistInst, invalidComponentUid), Is.False);
Assert.That(sys.IsValid(whitelistInst, invalidComponentProto), Is.False);
Assert.That(sys.IsValid(whitelistInst, InvalidComponentProtoId), Is.False);
Assert.That(sys.IsValid(whitelistInst, whitelistTestInvalidTagUid), Is.False);
Assert.That(sys.IsValid(whitelistInst, whitelistTestInvalidTagProto), Is.False);
Assert.That(sys.IsValid(whitelistInst, WhitelistTestInvalidTagProtoId), Is.False);
}); });
// Test from serialized // Test from serialized
var dummy = sEntities.SpawnEntity("WhitelistDummy", mapCoordinates); var dummy = sEntities.SpawnEntity(WhitelistProtoId, mapCoordinates);
var whitelistSer = sEntities.GetComponent<ItemSlotsComponent>(dummy).Slots.Values.First().Whitelist; var whitelistSer = sEntities.GetComponent<ItemSlotsComponent>(dummy).Slots.Values.First().Whitelist;
Assert.That(whitelistSer, Is.Not.Null); Assert.That(whitelistSer, Is.Not.Null);
@@ -105,11 +127,21 @@ namespace Content.IntegrationTests.Tests.Utility
Assert.Multiple(() => Assert.Multiple(() =>
{ {
Assert.That(sys.IsValid(whitelistSer, validComponent), Is.True); Assert.That(sys.IsValid(whitelistSer, validComponentUid), Is.True);
Assert.That(sys.IsValid(whitelistSer, WhitelistTestValidTag), Is.True); Assert.That(sys.IsValid(whitelistSer, validComponentProto), Is.True);
Assert.That(sys.IsValid(whitelistSer, ValidComponentProtoId), Is.True);
Assert.That(sys.IsValid(whitelistSer, invalidComponent), Is.False); Assert.That(sys.IsValid(whitelistSer, whitelistTestValidTagUid), Is.True);
Assert.That(sys.IsValid(whitelistSer, WhitelistTestInvalidTag), Is.False); Assert.That(sys.IsValid(whitelistSer, whitelistTestValidTagProto), Is.True);
Assert.That(sys.IsValid(whitelistSer, WhitelistTestValidTagProtoId), Is.True);
Assert.That(sys.IsValid(whitelistSer, invalidComponentUid), Is.False);
Assert.That(sys.IsValid(whitelistSer, invalidComponentProto), Is.False);
Assert.That(sys.IsValid(whitelistSer, InvalidComponentProtoId), Is.False);
Assert.That(sys.IsValid(whitelistSer, whitelistTestInvalidTagUid), Is.False);
Assert.That(sys.IsValid(whitelistSer, whitelistTestInvalidTagProto), Is.False);
Assert.That(sys.IsValid(whitelistSer, WhitelistTestInvalidTagProtoId), Is.False);
}); });
}); });
} }
+199 -235
View File
@@ -1,5 +1,6 @@
using System.Linq; using System.Linq;
using Content.IntegrationTests.Fixtures; using Content.IntegrationTests.Fixtures;
using Content.IntegrationTests.Fixtures.Attributes;
using Content.Shared.Xenoarchaeology.Artifact; using Content.Shared.Xenoarchaeology.Artifact;
using Content.Shared.Xenoarchaeology.Artifact.Components; using Content.Shared.Xenoarchaeology.Artifact.Components;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -7,12 +8,21 @@ using Robust.Shared.GameObjects;
namespace Content.IntegrationTests.Tests; namespace Content.IntegrationTests.Tests;
[TestFixture] [TestFixture]
[TestOf(typeof(SharedXenoArtifactSystem))]
public sealed class XenoArtifactTest : GameTest public sealed class XenoArtifactTest : GameTest
{ {
private const string TestArtifact = "TestArtifact";
private const string TestArtifactNode = "TestArtifactNode";
private const string TestGenArtifactFlat = "TestGenArtifactFlat";
private const string TestGenArtifactTall = "TestGenArtifactTall";
private const string TestGenArtifactFull = "TestGenArtifactFull";
[SidedDependency(Side.Server)] private SharedXenoArtifactSystem _sArtifactSystem = null!;
[TestPrototypes] [TestPrototypes]
private const string Prototypes = @" private const string Prototypes = $@"
- type: entity - type: entity
id: TestArtifact id: {TestArtifact}
parent: BaseXenoArtifact parent: BaseXenoArtifact
name: artifact name: artifact
components: components:
@@ -22,7 +32,7 @@ public sealed class XenoArtifactTest : GameTest
tableId: XenoArtifactEffectsDefaultTable tableId: XenoArtifactEffectsDefaultTable
- type: entity - type: entity
id: TestGenArtifactFlat id: {TestGenArtifactFlat}
parent: BaseXenoArtifact parent: BaseXenoArtifact
name: artifact name: artifact
components: components:
@@ -41,7 +51,7 @@ public sealed class XenoArtifactTest : GameTest
tableId: XenoArtifactEffectsDefaultTable tableId: XenoArtifactEffectsDefaultTable
- type: entity - type: entity
id: TestGenArtifactTall id: {TestGenArtifactTall}
parent: BaseXenoArtifact parent: BaseXenoArtifact
name: artifact name: artifact
components: components:
@@ -60,7 +70,7 @@ public sealed class XenoArtifactTest : GameTest
tableId: XenoArtifactEffectsDefaultTable tableId: XenoArtifactEffectsDefaultTable
- type: entity - type: entity
id: TestGenArtifactFull id: {TestGenArtifactFull}
name: artifact name: artifact
components: components:
- type: XenoArtifact - type: XenoArtifact
@@ -78,7 +88,7 @@ public sealed class XenoArtifactTest : GameTest
tableId: XenoArtifactEffectsDefaultTable tableId: XenoArtifactEffectsDefaultTable
- type: entity - type: entity
id: TestArtifactNode id: {TestArtifactNode}
name: artifact node name: artifact node
components: components:
- type: XenoArtifactNode - type: XenoArtifactNode
@@ -89,314 +99,268 @@ public sealed class XenoArtifactTest : GameTest
/// Checks that adding nodes and edges properly adds them into the adjacency matrix /// Checks that adding nodes and edges properly adds them into the adjacency matrix
/// </summary> /// </summary>
[Test] [Test]
[Description("Checks that adding nodes and edges properly adds them into the adjacency matrix")]
[RunOnSide(Side.Server)]
public async Task XenoArtifactAddNodeTest() public async Task XenoArtifactAddNodeTest()
{ {
var pair = Pair; var artifactUid = SSpawn(TestArtifact);
var server = pair.Server; var artifactEnt = (artifactUid, comp: SComp<XenoArtifactComponent>(artifactUid));
var entManager = server.ResolveDependency<IEntityManager>(); // Create 3 nodes
var artifactSystem = entManager.System<SharedXenoArtifactSystem>(); Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node1, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node2, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node3, false));
await server.WaitPost(() => Assert.That(_sArtifactSystem.GetAllNodeIndices(artifactEnt).Count(), Is.EqualTo(3));
{
var artifactUid = entManager.Spawn("TestArtifact");
var artifactEnt = (artifactUid, comp: entManager.GetComponent<XenoArtifactComponent>(artifactUid));
// Create 3 nodes // Add connection from 1 -> 2 and 2-> 3
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node1, false)); _sArtifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node2, false)); _sArtifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node3, false));
Assert.That(artifactSystem.GetAllNodeIndices(artifactEnt).Count(), Is.EqualTo(3)); // Assert that successors and direct successors are counted correctly for node 1.
Assert.That(_sArtifactSystem.GetDirectSuccessorNodes(artifactEnt, node1!.Value), Has.Count.EqualTo(1));
Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node1!.Value), Has.Count.EqualTo(2));
// Assert that we didn't somehow get predecessors on node 1.
Assert.That(_sArtifactSystem.GetDirectPredecessorNodes(artifactEnt, node1!.Value), Is.Empty);
Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node1!.Value), Is.Empty);
// Add connection from 1 -> 2 and 2-> 3 // Assert that successors and direct successors are counted correctly for node 2.
artifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false); Assert.That(_sArtifactSystem.GetDirectSuccessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
artifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false); Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
// Assert that predecessors and direct predecessors are counted correctly for node 2.
Assert.That(_sArtifactSystem.GetDirectPredecessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
// Assert that successors and direct successors are counted correctly for node 1. // Assert that successors and direct successors are counted correctly for node 3.
Assert.That(artifactSystem.GetDirectSuccessorNodes(artifactEnt, node1!.Value).Count, Is.EqualTo(1)); Assert.That(_sArtifactSystem.GetDirectSuccessorNodes(artifactEnt, node3!.Value), Is.Empty);
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node1!.Value).Count, Is.EqualTo(2)); Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node3!.Value), Is.Empty);
// Assert that we didn't somehow get predecessors on node 1. // Assert that predecessors and direct predecessors are counted correctly for node 3.
Assert.That(artifactSystem.GetDirectPredecessorNodes(artifactEnt, node1!.Value), Is.Empty); Assert.That(_sArtifactSystem.GetDirectPredecessorNodes(artifactEnt, node3!.Value), Has.Count.EqualTo(1));
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node1!.Value), Is.Empty); Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node3!.Value), Has.Count.EqualTo(2));
// Assert that successors and direct successors are counted correctly for node 2.
Assert.That(artifactSystem.GetDirectSuccessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
// Assert that predecessors and direct predecessors are counted correctly for node 2.
Assert.That(artifactSystem.GetDirectPredecessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node2!.Value), Has.Count.EqualTo(1));
// Assert that successors and direct successors are counted correctly for node 3.
Assert.That(artifactSystem.GetDirectSuccessorNodes(artifactEnt, node3!.Value), Is.Empty);
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node3!.Value), Is.Empty);
// Assert that predecessors and direct predecessors are counted correctly for node 3.
Assert.That(artifactSystem.GetDirectPredecessorNodes(artifactEnt, node3!.Value), Has.Count.EqualTo(1));
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node3!.Value), Has.Count.EqualTo(2));
});
} }
/// <summary> /// <summary>
/// Checks to make sure that removing nodes properly cleans up all connections. /// Checks to make sure that removing nodes properly cleans up all connections.
/// </summary> /// </summary>
[Test] [Test]
[Description("Checks to make sure that removing nodes properly cleans up all connections.")]
[RunOnSide(Side.Server)]
public async Task XenoArtifactRemoveNodeTest() public async Task XenoArtifactRemoveNodeTest()
{ {
var pair = Pair; var artifactUid = SSpawn(TestArtifact);
var server = pair.Server; var artifactEnt = (artifactUid, comp: SComp<XenoArtifactComponent>(artifactUid));
var entManager = server.ResolveDependency<IEntityManager>(); // Create 3 nodes
var artifactSystem = entManager.System<SharedXenoArtifactSystem>(); Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node1, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node2, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node3, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node4, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node5, false));
await server.WaitPost(() => Assert.That(_sArtifactSystem.GetAllNodeIndices(artifactEnt).Count(), Is.EqualTo(5));
{
var artifactUid = entManager.Spawn("TestArtifact");
var artifactEnt = (artifactUid, comp: entManager.GetComponent<XenoArtifactComponent>(artifactUid));
// Create 3 nodes // Add connection: 1 -> 2 -> 3 -> 4 -> 5
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node1, false)); _sArtifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node2, false)); _sArtifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node3, false)); _sArtifactSystem.AddEdge(artifactEnt, node3!.Value, node4!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node4, false)); _sArtifactSystem.AddEdge(artifactEnt, node4!.Value, node5!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node5, false));
Assert.That(artifactSystem.GetAllNodeIndices(artifactEnt).Count(), Is.EqualTo(5)); // Make sure we have a continuous connection between the two ends of the graph.
Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node1.Value), Has.Count.EqualTo(4));
Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node5.Value), Has.Count.EqualTo(4));
// Add connection: 1 -> 2 -> 3 -> 4 -> 5 // Remove the node and make sure it's no longer in the artifact.
artifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false); Assert.That(_sArtifactSystem.RemoveNode(artifactEnt, node3!.Value, false));
artifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false); Assert.That(_sArtifactSystem.TryGetIndex(artifactEnt, node3!.Value, out _), Is.False, "Node 3 still present in artifact.");
artifactSystem.AddEdge(artifactEnt, node3!.Value, node4!.Value, false);
artifactSystem.AddEdge(artifactEnt, node4!.Value, node5!.Value, false);
// Make sure we have a continuous connection between the two ends of the graph. // Check to make sure that we got rid of all the connections.
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node1.Value), Has.Count.EqualTo(4)); Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node2!.Value), Is.Empty);
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node5.Value), Has.Count.EqualTo(4)); Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node4!.Value), Is.Empty);
// Remove the node and make sure it's no longer in the artifact.
Assert.That(artifactSystem.RemoveNode(artifactEnt, node3!.Value, false));
Assert.That(artifactSystem.TryGetIndex(artifactEnt, node3!.Value, out _), Is.False, "Node 3 still present in artifact.");
// Check to make sure that we got rid of all the connections.
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node2!.Value), Is.Empty);
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node4!.Value), Is.Empty);
});
} }
/// <summary> /// <summary>
/// Sets up series of linked nodes and ensures that resizing the adjacency matrix doesn't disturb the connections /// Sets up series of linked nodes and ensures that resizing the adjacency matrix doesn't disturb the connections
/// </summary> /// </summary>
[Test] [Test]
[Description("Sets up series of linked nodes and ensures that resizing the adjacency matrix doesn't disturb the connections")]
[RunOnSide(Side.Server)]
public async Task XenoArtifactResizeTest() public async Task XenoArtifactResizeTest()
{ {
var pair = Pair; var artifactUid = SSpawn(TestArtifact);
var server = pair.Server; var artifactEnt = (artifactUid, comp: SComp<XenoArtifactComponent>(artifactUid));
var entManager = server.ResolveDependency<IEntityManager>(); // Create 3 nodes
var artifactSystem = entManager.System<SharedXenoArtifactSystem>(); Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node1, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node2, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node3, false));
await server.WaitPost(() => // Add connection: 1 -> 2 -> 3
{ _sArtifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false);
var artifactUid = entManager.Spawn("TestArtifact"); _sArtifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false);
var artifactEnt = (artifactUid, comp: entManager.GetComponent<XenoArtifactComponent>(artifactUid));
// Create 3 nodes // Make sure our connection is set up
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node1, false)); Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node1.Value, node2.Value));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node2, false)); Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node2.Value, node3.Value));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node3, false)); Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node2.Value, node1.Value), Is.False);
Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node3.Value, node2.Value), Is.False);
Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node1.Value, node3.Value), Is.False);
Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node3.Value, node1.Value), Is.False);
// Add connection: 1 -> 2 -> 3 Assert.That(_sArtifactSystem.GetIndex(artifactEnt, node1!.Value), Is.Zero);
artifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false); Assert.That(_sArtifactSystem.GetIndex(artifactEnt, node2!.Value), Is.EqualTo(1));
artifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false); Assert.That(_sArtifactSystem.GetIndex(artifactEnt, node3!.Value), Is.EqualTo(2));
// Make sure our connection is set up // Add a new node, resizing the original adjacency matrix and array.
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node1.Value, node2.Value)); Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node4));
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node2.Value, node3.Value));
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node2.Value, node1.Value), Is.False);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node3.Value, node2.Value), Is.False);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node1.Value, node3.Value), Is.False);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node3.Value, node1.Value), Is.False);
Assert.That(artifactSystem.GetIndex(artifactEnt, node1!.Value), Is.EqualTo(0)); // Check that our connections haven't changed.
Assert.That(artifactSystem.GetIndex(artifactEnt, node2!.Value), Is.EqualTo(1)); Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node1.Value, node2.Value));
Assert.That(artifactSystem.GetIndex(artifactEnt, node3!.Value), Is.EqualTo(2)); Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node2.Value, node3.Value));
Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node2.Value, node1.Value), Is.False);
Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node3.Value, node2.Value), Is.False);
Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node1.Value, node3.Value), Is.False);
Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node3.Value, node1.Value), Is.False);
// Add a new node, resizing the original adjacency matrix and array. // Has our array shifted any when we resized?
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node4)); Assert.That(_sArtifactSystem.GetIndex(artifactEnt, node1!.Value), Is.Zero);
Assert.That(_sArtifactSystem.GetIndex(artifactEnt, node2!.Value), Is.EqualTo(1));
Assert.That(_sArtifactSystem.GetIndex(artifactEnt, node3!.Value), Is.EqualTo(2));
// Check that our connections haven't changed. // Check that 4 didn't somehow end up with connections
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node1.Value, node2.Value)); Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node4!.Value), Is.Empty);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node2.Value, node3.Value)); Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node4!.Value), Is.Empty);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node2.Value, node1.Value), Is.False);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node3.Value, node2.Value), Is.False);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node1.Value, node3.Value), Is.False);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node3.Value, node1.Value), Is.False);
// Has our array shifted any when we resized?
Assert.That(artifactSystem.GetIndex(artifactEnt, node1!.Value), Is.EqualTo(0));
Assert.That(artifactSystem.GetIndex(artifactEnt, node2!.Value), Is.EqualTo(1));
Assert.That(artifactSystem.GetIndex(artifactEnt, node3!.Value), Is.EqualTo(2));
// Check that 4 didn't somehow end up with connections
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node4!.Value), Is.Empty);
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node4!.Value), Is.Empty);
});
} }
/// <summary> /// <summary>
/// Checks if removing a node and adding a new node into its place in the adjacency matrix doesn't accidentally retain extra data. /// Checks if removing a node and adding a new node into its place in the adjacency matrix doesn't accidentally retain extra data.
/// </summary> /// </summary>
[Test] [Test]
[Description("Checks if removing a node and adding a new node into its place in the adjacency matrix doesn't accidentally retain extra data.")]
[RunOnSide(Side.Server)]
public async Task XenoArtifactReplaceTest() public async Task XenoArtifactReplaceTest()
{ {
var pair = Pair; var artifactUid = SSpawn(TestArtifact);
var server = pair.Server; var artifactEnt = (artifactUid, Comp: SComp<XenoArtifactComponent>(artifactUid));
var entManager = server.ResolveDependency<IEntityManager>(); // Create 3 nodes
var artifactSystem = entManager.System<SharedXenoArtifactSystem>(); Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node1, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node2, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node3, false));
await server.WaitPost(() => // Add connection: 1 -> 2 -> 3
{ _sArtifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false);
var artifactUid = entManager.Spawn("TestArtifact"); _sArtifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false);
var artifactEnt = (artifactUid, comp: entManager.GetComponent<XenoArtifactComponent>(artifactUid));
// Create 3 nodes // Make sure our connection is set up
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node1, false)); Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node1.Value, node2.Value));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node2, false)); Assert.That(_sArtifactSystem.NodeHasEdge(artifactEnt, node2.Value, node3.Value));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node3, false));
// Add connection: 1 -> 2 -> 3 // Remove middle node, severing connections
artifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false); _sArtifactSystem.RemoveNode(artifactEnt, node2!.Value, false);
artifactSystem.AddEdge(artifactEnt, node2!.Value, node3!.Value, false);
// Make sure our connection is set up // Make sure our connection are properly severed.
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node1.Value, node2.Value)); Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node1.Value), Is.Empty);
Assert.That(artifactSystem.NodeHasEdge(artifactEnt, node2.Value, node3.Value)); Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node3.Value), Is.Empty);
// Remove middle node, severing connections // Make sure our matrix is 3x3
artifactSystem.RemoveNode(artifactEnt, node2!.Value, false); Assert.That(artifactEnt.Comp.NodeAdjacencyMatrixRows, Is.EqualTo(3));
Assert.That(artifactEnt.Comp.NodeAdjacencyMatrixColumns, Is.EqualTo(3));
// Make sure our connection are properly severed. Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node4, false));
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node1.Value), Is.Empty);
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node3.Value), Is.Empty);
// Make sure our matrix is 3x3 // Make sure that adding in a new node didn't add a new slot but instead re-used the middle slot.
Assert.That(artifactEnt.Item2.NodeAdjacencyMatrixRows, Is.EqualTo(3)); Assert.That(artifactEnt.Comp.NodeAdjacencyMatrixRows, Is.EqualTo(3));
Assert.That(artifactEnt.Item2.NodeAdjacencyMatrixColumns, Is.EqualTo(3)); Assert.That(artifactEnt.Comp.NodeAdjacencyMatrixColumns, Is.EqualTo(3));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node4, false)); // Ensure that all connections are still severed
Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node1.Value), Is.Empty);
// Make sure that adding in a new node didn't add a new slot but instead re-used the middle slot. Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node3.Value), Is.Empty);
Assert.That(artifactEnt.Item2.NodeAdjacencyMatrixRows, Is.EqualTo(3)); Assert.That(_sArtifactSystem.GetSuccessorNodes(artifactEnt, node4!.Value), Is.Empty);
Assert.That(artifactEnt.Item2.NodeAdjacencyMatrixColumns, Is.EqualTo(3)); Assert.That(_sArtifactSystem.GetPredecessorNodes(artifactEnt, node4!.Value), Is.Empty);
// Ensure that all connections are still severed
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node1.Value), Is.Empty);
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node3.Value), Is.Empty);
Assert.That(artifactSystem.GetSuccessorNodes(artifactEnt, node4!.Value), Is.Empty);
Assert.That(artifactSystem.GetPredecessorNodes(artifactEnt, node4!.Value), Is.Empty);
});
} }
/// <summary> /// <summary>
/// Checks if the active nodes are properly detected. /// Checks if the active nodes are properly detected.
/// </summary> /// </summary>
[Test] [Test]
[Description("Checks if the active nodes are properly detected.")]
[RunOnSide(Side.Server)]
public async Task XenoArtifactBuildActiveNodesTest() public async Task XenoArtifactBuildActiveNodesTest()
{ {
var pair = Pair; var artifactUid = SSpawn(TestArtifact);
var server = pair.Server; Entity<XenoArtifactComponent> artifactEnt = (artifactUid, SComp<XenoArtifactComponent>(artifactUid));
var entManager = server.ResolveDependency<IEntityManager>(); Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node1, false));
var artifactSystem = entManager.System<SharedXenoArtifactSystem>(); Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node2, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node3, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node4, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node5, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node6, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node7, false));
Assert.That(_sArtifactSystem.AddNode(artifactEnt, TestArtifactNode, out var node8, false));
await server.WaitPost(() => // /----( 6 )
{ // /----[*3 ]-/----( 7 )----( 8 )
var artifactUid = entManager.Spawn("TestArtifact"); // /
Entity<XenoArtifactComponent> artifactEnt = (artifactUid, entManager.GetComponent<XenoArtifactComponent>(artifactUid)); // / /----[*5 ]
// [ 1 ]--/----[ 2 ]--/----( 4 )
// Diagram of the example generation. Nodes in [brackets] are unlocked, nodes in (braces) are locked
// and nodes with an *asterisk are supposed to be active.
_sArtifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false);
_sArtifactSystem.AddEdge(artifactEnt, node1!.Value, node3!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node1, false)); _sArtifactSystem.AddEdge(artifactEnt, node2!.Value, node4!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node2, false)); _sArtifactSystem.AddEdge(artifactEnt, node2!.Value, node5!.Value, false);
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node3, false));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node4, false));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node5, false));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node6, false));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node7, false));
Assert.That(artifactSystem.AddNode(artifactEnt, "TestArtifactNode", out var node8, false));
// /----( 6 ) _sArtifactSystem.AddEdge(artifactEnt, node3!.Value, node6!.Value, false);
// /----[*3 ]-/----( 7 )----( 8 ) _sArtifactSystem.AddEdge(artifactEnt, node3!.Value, node7!.Value, false);
// /
// / /----[*5 ]
// [ 1 ]--/----[ 2 ]--/----( 4 )
// Diagram of the example generation. Nodes in [brackets] are unlocked, nodes in (braces) are locked
// and nodes with an *asterisk are supposed to be active.
artifactSystem.AddEdge(artifactEnt, node1!.Value, node2!.Value, false);
artifactSystem.AddEdge(artifactEnt, node1!.Value, node3!.Value, false);
artifactSystem.AddEdge(artifactEnt, node2!.Value, node4!.Value, false); _sArtifactSystem.AddEdge(artifactEnt, node7!.Value, node8!.Value, false);
artifactSystem.AddEdge(artifactEnt, node2!.Value, node5!.Value, false);
artifactSystem.AddEdge(artifactEnt, node3!.Value, node6!.Value, false); _sArtifactSystem.SetNodeUnlocked(node1!.Value);
artifactSystem.AddEdge(artifactEnt, node3!.Value, node7!.Value, false); _sArtifactSystem.SetNodeUnlocked(node2!.Value);
_sArtifactSystem.SetNodeUnlocked(node3!.Value);
_sArtifactSystem.SetNodeUnlocked(node5!.Value);
artifactSystem.AddEdge(artifactEnt, node7!.Value, node8!.Value, false); NetEntity[] expectedActiveNodes =
[
artifactSystem.SetNodeUnlocked(node1!.Value); SEntMan.GetNetEntity(node3!.Value.Owner),
artifactSystem.SetNodeUnlocked(node2!.Value); SEntMan.GetNetEntity(node5!.Value.Owner)
artifactSystem.SetNodeUnlocked(node3!.Value); ];
artifactSystem.SetNodeUnlocked(node5!.Value); Assert.That(artifactEnt.Comp.CachedActiveNodes, Is.SupersetOf(expectedActiveNodes));
Assert.That(artifactEnt.Comp.CachedActiveNodes, Has.Count.EqualTo(expectedActiveNodes.Length));
NetEntity[] expectedActiveNodes =
[
entManager.GetNetEntity(node3!.Value.Owner),
entManager.GetNetEntity(node5!.Value.Owner)
];
Assert.That(artifactEnt.Comp.CachedActiveNodes, Is.SupersetOf(expectedActiveNodes));
Assert.That(artifactEnt.Comp.CachedActiveNodes, Has.Count.EqualTo(expectedActiveNodes.Length));
});
} }
[Test] [Test]
[RunOnSide(Side.Server)]
public async Task XenoArtifactGenerateSegmentsTest() public async Task XenoArtifactGenerateSegmentsTest()
{ {
var pair = Pair; var artifact1Uid = SSpawn(TestGenArtifactFlat);
var server = pair.Server; Entity<XenoArtifactComponent> artifact1Ent = (artifact1Uid, SComp<XenoArtifactComponent>(artifact1Uid));
var entManager = server.ResolveDependency<IEntityManager>(); var segments1 = _sArtifactSystem.GetSegments(artifact1Ent);
var artifactSystem = entManager.System<SharedXenoArtifactSystem>(); Assert.That(segments1, Has.Count.EqualTo(2));
Assert.That(segments1[0], Has.Count.EqualTo(1));
Assert.That(segments1[1], Has.Count.EqualTo(1));
await server.WaitPost(() => var artifact2Uid = SSpawn(TestGenArtifactTall);
{ Entity<XenoArtifactComponent> artifact2Ent = (artifact2Uid, SComp<XenoArtifactComponent>(artifact2Uid));
var artifact1Uid = entManager.Spawn("TestGenArtifactFlat");
Entity<XenoArtifactComponent> artifact1Ent = (artifact1Uid, entManager.GetComponent<XenoArtifactComponent>(artifact1Uid));
var segments1 = artifactSystem.GetSegments(artifact1Ent); var segments2 = _sArtifactSystem.GetSegments(artifact2Ent);
Assert.That(segments1.Count, Is.EqualTo(2)); Assert.That(segments2, Has.Count.EqualTo(1));
Assert.That(segments1[0].Count, Is.EqualTo(1)); Assert.That(segments2[0], Has.Count.EqualTo(2));
Assert.That(segments1[1].Count, Is.EqualTo(1));
var artifact2Uid = entManager.Spawn("TestGenArtifactTall"); var artifact3Uid = SSpawn(TestGenArtifactFull);
Entity<XenoArtifactComponent> artifact2Ent = (artifact2Uid, entManager.GetComponent<XenoArtifactComponent>(artifact2Uid)); Entity<XenoArtifactComponent> artifact3Ent = (artifact3Uid, SComp<XenoArtifactComponent>(artifact3Uid));
var segments2 = artifactSystem.GetSegments(artifact2Ent); var segments3 = _sArtifactSystem.GetSegments(artifact3Ent);
Assert.That(segments2.Count, Is.EqualTo(1)); Assert.That(segments3, Has.Count.EqualTo(1));
Assert.That(segments2[0].Count, Is.EqualTo(2)); Assert.That(segments3.Sum(x => x.Count), Is.EqualTo(6));
var nodesDepths = segments3[0].Select(x => x.Comp.Depth).ToArray();
var artifact3Uid = entManager.Spawn("TestGenArtifactFull"); Assert.That(nodesDepths.Distinct().Count(), Is.EqualTo(3));
Entity<XenoArtifactComponent> artifact3Ent = (artifact3Uid, entManager.GetComponent<XenoArtifactComponent>(artifact3Uid)); var grouped = nodesDepths.ToLookup(x => x);
Assert.That(grouped[0].Count(), Is.EqualTo(2));
var segments3 = artifactSystem.GetSegments(artifact3Ent); Assert.That(grouped[1].Count(), Is.GreaterThanOrEqualTo(2)); // tree is attempting sometimes to get wider (so it will look like a tree)
Assert.That(segments3.Count, Is.EqualTo(1)); Assert.That(grouped[2].Count(), Is.LessThanOrEqualTo(2)); // maintain same width or, if we used 3 nodes on previous layer - we only have 1 left!
Assert.That(segments3.Sum(x => x.Count), Is.EqualTo(6));
var nodesDepths = segments3[0].Select(x => x.Comp.Depth).ToArray();
Assert.That(nodesDepths.Distinct().Count(), Is.EqualTo(3));
var grouped = nodesDepths.ToLookup(x => x);
Assert.That(grouped[0].Count(), Is.EqualTo(2));
Assert.That(grouped[1].Count(), Is.GreaterThanOrEqualTo(2)); // tree is attempting sometimes to get wider (so it will look like a tree)
Assert.That(grouped[2].Count(), Is.LessThanOrEqualTo(2)); // maintain same width or, if we used 3 nodes on previous layer - we only have 1 left!
});
} }
} }
-1
View File
@@ -4,7 +4,6 @@ using Content.Server.Ame.EntitySystems;
using Content.Server.Chat.Managers; using Content.Server.Chat.Managers;
using Content.Server.Explosion.EntitySystems; using Content.Server.Explosion.EntitySystems;
using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes;
using Content.Shared.NodeContainer; using Content.Shared.NodeContainer;
using Content.Shared.NodeContainer.NodeGroups; using Content.Shared.NodeContainer.NodeGroups;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
@@ -22,6 +22,7 @@ public sealed partial class AnomalySystem
{ {
[Dependency] private SharedMapSystem _mapSystem = default!; [Dependency] private SharedMapSystem _mapSystem = default!;
[Dependency] private SharedTransformSystem _transform = default!; [Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private void InitializeGenerator() private void InitializeGenerator()
{ {
@@ -106,13 +107,12 @@ public sealed partial class AnomalySystem
} }
// don't spawn inside of solid objects // don't spawn inside of solid objects
var physQuery = GetEntityQuery<PhysicsComponent>();
var valid = true; var valid = true;
// TODO: This should be using static lookup. // TODO: This should be using static lookup.
foreach (var ent in _mapSystem.GetAnchoredEntities(grid, gridComp, tile)) foreach (var ent in _mapSystem.GetAnchoredEntities(grid, gridComp, tile))
{ {
if (!physQuery.TryGetComponent(ent, out var body)) if (!_physicsQuery.TryGetComponent(ent, out var body))
continue; continue;
if (body.BodyType != BodyType.Static || if (body.BodyType != BodyType.Static ||
!body.Hard || !body.Hard ||
@@ -30,8 +30,7 @@ public sealed partial class BluespaceAnomalySystem : EntitySystem
private void OnPulse(EntityUid uid, BluespaceAnomalyComponent component, ref AnomalyPulseEvent args) private void OnPulse(EntityUid uid, BluespaceAnomalyComponent component, ref AnomalyPulseEvent args)
{ {
var xformQuery = GetEntityQuery<TransformComponent>(); var xform = Transform(uid);
var xform = xformQuery.GetComponent(uid);
var range = component.MaxShuffleRadius * args.Severity * args.PowerModifier; var range = component.MaxShuffleRadius * args.Severity * args.PowerModifier;
// get a list of all entities in range with the MobStateComponent // get a list of all entities in range with the MobStateComponent
// we filter out those inside a container // we filter out those inside a container
@@ -42,7 +41,7 @@ public sealed partial class BluespaceAnomalySystem : EntitySystem
var coords = new ValueList<Vector2>(); var coords = new ValueList<Vector2>();
foreach (var ent in allEnts) foreach (var ent in allEnts)
{ {
if (xformQuery.TryGetComponent(ent, out var allXform)) if (TryComp(ent, out TransformComponent? allXform))
coords.Add(_xform.GetWorldPosition(allXform)); coords.Add(_xform.GetWorldPosition(allXform));
} }
@@ -3,7 +3,6 @@ using Content.Shared.Anomaly.Components;
using Content.Shared.Anomaly.Effects; using Content.Shared.Anomaly.Effects;
using Content.Shared.Anomaly.Effects.Components; using Content.Shared.Anomaly.Effects.Components;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random; using Robust.Shared.Random;
namespace Content.Server.Anomaly.Effects; namespace Content.Server.Anomaly.Effects;
@@ -14,13 +13,9 @@ public sealed partial class EntityAnomalySystem : SharedEntityAnomalySystem
[Dependency] private IRobustRandom _random = default!; [Dependency] private IRobustRandom _random = default!;
[Dependency] private SharedMapSystem _mapSystem = default!; [Dependency] private SharedMapSystem _mapSystem = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
{ {
_physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyPulseEvent>(OnPulse); SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyPulseEvent>(OnPulse);
SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical); SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyStabilityChangedEvent>(OnStabilityChanged); SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyStabilityChangedEvent>(OnStabilityChanged);
@@ -18,15 +18,12 @@ public sealed partial class InjectionAnomalySystem : EntitySystem
[Dependency] private EntityLookupSystem _lookup = default!; [Dependency] private EntityLookupSystem _lookup = default!;
[Dependency] private SharedSolutionContainerSystem _solutionContainer = default!; [Dependency] private SharedSolutionContainerSystem _solutionContainer = default!;
[Dependency] private TransformSystem _transform = default!; [Dependency] private TransformSystem _transform = default!;
[Dependency] private EntityQuery<InjectableSolutionComponent> _injectableQuery = default!;
private EntityQuery<InjectableSolutionComponent> _injectableQuery;
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<InjectionAnomalyComponent, AnomalyPulseEvent>(OnPulse); SubscribeLocalEvent<InjectionAnomalyComponent, AnomalyPulseEvent>(OnPulse);
SubscribeLocalEvent<InjectionAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical, before: new[] { typeof(SharedSolutionContainerSystem) }); SubscribeLocalEvent<InjectionAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical, before: new[] { typeof(SharedSolutionContainerSystem) });
_injectableQuery = GetEntityQuery<InjectableSolutionComponent>();
} }
private void OnPulse(Entity<InjectionAnomalyComponent> entity, ref AnomalyPulseEvent args) private void OnPulse(Entity<InjectionAnomalyComponent> entity, ref AnomalyPulseEvent args)
@@ -45,8 +42,7 @@ public sealed partial class InjectionAnomalySystem : EntitySystem
return; return;
//We get all the entity in the radius into which the reagent will be injected. //We get all the entity in the radius into which the reagent will be injected.
var xformQuery = GetEntityQuery<TransformComponent>(); var xform = Transform(entity);
var xform = xformQuery.GetComponent(entity);
var allEnts = _lookup.GetEntitiesInRange<InjectableSolutionComponent>(_transform.GetMapCoordinates(entity, xform: xform), injectRadius) var allEnts = _lookup.GetEntitiesInRange<InjectableSolutionComponent>(_transform.GetMapCoordinates(entity, xform: xform), injectRadius)
.Select(x => x.Owner).ToList(); .Select(x => x.Owner).ToList();
@@ -21,9 +21,7 @@ public sealed partial class ProjectileAnomalySystem : EntitySystem
[Dependency] private IMapManager _mapManager = default!; [Dependency] private IMapManager _mapManager = default!;
[Dependency] private GunSystem _gunSystem = default!; [Dependency] private GunSystem _gunSystem = default!;
[Dependency] private SharedMapSystem _map = default!; [Dependency] private SharedMapSystem _map = default!;
[Dependency] private EntityQuery<MobStateComponent> _mobStateQuery = default!;
private EntityQuery<TransformComponent> _xFormQuery;
private EntityQuery<MobStateComponent> _mobQuery;
/// <summary> Pre-allocated collection for calculating entities in range. </summary> /// <summary> Pre-allocated collection for calculating entities in range. </summary>
private readonly HashSet<EntityUid> _inRange = new(); private readonly HashSet<EntityUid> _inRange = new();
@@ -32,9 +30,6 @@ public sealed partial class ProjectileAnomalySystem : EntitySystem
{ {
SubscribeLocalEvent<ProjectileAnomalyComponent, AnomalyPulseEvent>(OnPulse); SubscribeLocalEvent<ProjectileAnomalyComponent, AnomalyPulseEvent>(OnPulse);
SubscribeLocalEvent<ProjectileAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical); SubscribeLocalEvent<ProjectileAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
_xFormQuery = GetEntityQuery<TransformComponent>();
_mobQuery = GetEntityQuery<MobStateComponent>();
} }
private void OnPulse(EntityUid uid, ProjectileAnomalyComponent component, ref AnomalyPulseEvent args) private void OnPulse(EntityUid uid, ProjectileAnomalyComponent component, ref AnomalyPulseEvent args)
@@ -51,7 +46,7 @@ public sealed partial class ProjectileAnomalySystem : EntitySystem
{ {
var projectileCount = (int)MathF.Round(MathHelper.Lerp(component.MinProjectiles, component.MaxProjectiles, severity)); var projectileCount = (int)MathF.Round(MathHelper.Lerp(component.MinProjectiles, component.MaxProjectiles, severity));
var xform = _xFormQuery.GetComponent(uid); var xform = Transform(uid);
_inRange.Clear(); _inRange.Clear();
_lookup.GetEntitiesInRange(uid, component.ProjectileRange * severity, _inRange, LookupFlags.Dynamic); _lookup.GetEntitiesInRange(uid, component.ProjectileRange * severity, _inRange, LookupFlags.Dynamic);
@@ -62,7 +57,7 @@ public sealed partial class ProjectileAnomalySystem : EntitySystem
var priority = new List<EntityUid>(); var priority = new List<EntityUid>();
foreach (var entity in _inRange) foreach (var entity in _inRange)
{ {
if (_mobQuery.HasComponent(entity)) if (_mobStateQuery.HasComponent(entity))
priority.Add(entity); priority.Add(entity);
} }
@@ -74,7 +69,7 @@ public sealed partial class ProjectileAnomalySystem : EntitySystem
? _random.PickAndTake(priority) ? _random.PickAndTake(priority)
: _random.Pick(_inRange); : _random.Pick(_inRange);
var targetXForm= _xFormQuery.GetComponent(target); var targetXForm = Transform(target);
var targetCoords = targetXForm.Coordinates.Offset(_random.NextVector2(0.5f)); var targetCoords = targetXForm.Coordinates.Offset(_random.NextVector2(0.5f));
ShootProjectile( ShootProjectile(
@@ -126,7 +126,6 @@ namespace Content.Server.Atmos.EntitySystems
public void InvalidatePosition(Entity<MapGridComponent?> grid, Vector2i pos) public void InvalidatePosition(Entity<MapGridComponent?> grid, Vector2i pos)
{ {
var query = GetEntityQuery<AirtightComponent>();
_explosionSystem.UpdateAirtightMap(grid, pos, grid); _explosionSystem.UpdateAirtightMap(grid, pos, grid);
_atmosphereSystem.InvalidateTile(grid.Owner, pos); _atmosphereSystem.InvalidateTile(grid.Owner, pos);
} }
@@ -7,7 +7,6 @@ using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Atmos.Reactions; using Content.Shared.Atmos.Reactions;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Server.Atmos.EntitySystems; namespace Content.Server.Atmos.EntitySystems;
@@ -29,7 +28,7 @@ public partial class AtmosphereSystem
[PublicAPI] [PublicAPI]
public bool HasAtmosphere(EntityUid gridUid) public bool HasAtmosphere(EntityUid gridUid)
{ {
return _atmosQuery.HasComponent(gridUid); return _gridAtmosQuery.HasComponent(gridUid);
} }
/// <summary> /// <summary>
@@ -95,7 +94,7 @@ public partial class AtmosphereSystem
[PublicAPI] [PublicAPI]
public void InvalidateTile(Entity<GridAtmosphereComponent?> entity, Vector2i tile) public void InvalidateTile(Entity<GridAtmosphereComponent?> entity, Vector2i tile)
{ {
if (_atmosQuery.Resolve(entity.Owner, ref entity.Comp, false)) if (_gridAtmosQuery.Resolve(entity.Owner, ref entity.Comp, false))
entity.Comp.InvalidatedCoords.Add(tile); entity.Comp.InvalidatedCoords.Add(tile);
} }
@@ -181,7 +180,7 @@ public partial class AtmosphereSystem
var handled = false; var handled = false;
// If we've been passed a grid, try to let it handle it. // If we've been passed a grid, try to let it handle it.
if (grid is { } gridEnt && _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp1)) if (grid is { } gridEnt && _gridAtmosQuery.Resolve(gridEnt, ref gridEnt.Comp1))
{ {
if (excite) if (excite)
Resolve(gridEnt, ref gridEnt.Comp2); Resolve(gridEnt, ref gridEnt.Comp2);
@@ -244,7 +243,7 @@ public partial class AtmosphereSystem
{ {
// If we've been passed a grid, try to let it handle it. // If we've been passed a grid, try to let it handle it.
if (grid is { } gridEnt if (grid is { } gridEnt
&& _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp1, false) && _gridAtmosQuery.Resolve(gridEnt, ref gridEnt.Comp1, false)
&& gridEnt.Comp1.Tiles.TryGetValue(gridTile, out var tile)) && gridEnt.Comp1.Tiles.TryGetValue(gridTile, out var tile))
{ {
if (excite) if (excite)
@@ -440,7 +439,7 @@ public partial class AtmosphereSystem
Vector2i tile, Vector2i tile,
AtmosDirection directions = AtmosDirection.All) AtmosDirection directions = AtmosDirection.All)
{ {
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return false; return false;
if (!grid.Comp.Tiles.TryGetValue(tile, out var atmosTile)) if (!grid.Comp.Tiles.TryGetValue(tile, out var atmosTile))
@@ -463,7 +462,7 @@ public partial class AtmosphereSystem
[PublicAPI] [PublicAPI]
public AtmosDirection GetAirflowDirections(Entity<GridAtmosphereComponent?> grid, Vector2i tile) public AtmosDirection GetAirflowDirections(Entity<GridAtmosphereComponent?> grid, Vector2i tile)
{ {
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return AtmosDirection.Invalid; return AtmosDirection.Invalid;
if (!grid.Comp.Tiles.TryGetValue(tile, out var atmosTile)) if (!grid.Comp.Tiles.TryGetValue(tile, out var atmosTile))
@@ -486,7 +485,7 @@ public partial class AtmosphereSystem
[PublicAPI] [PublicAPI]
public bool IsTileSpace(Entity<GridAtmosphereComponent?>? grid, Entity<MapAtmosphereComponent?>? map, Vector2i tile) public bool IsTileSpace(Entity<GridAtmosphereComponent?>? grid, Entity<MapAtmosphereComponent?>? map, Vector2i tile)
{ {
if (grid is { } gridEnt && _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp, false) if (grid is { } gridEnt && _gridAtmosQuery.Resolve(gridEnt, ref gridEnt.Comp, false)
&& gridEnt.Comp.Tiles.TryGetValue(tile, out var tileAtmos)) && gridEnt.Comp.Tiles.TryGetValue(tile, out var tileAtmos))
{ {
return tileAtmos.Space; return tileAtmos.Space;
@@ -541,7 +540,7 @@ public partial class AtmosphereSystem
public TileMixtureEnumerator GetAdjacentTileMixtures(Entity<GridAtmosphereComponent?> grid, Vector2i tile, bool includeBlocked = false, bool excite = false) public TileMixtureEnumerator GetAdjacentTileMixtures(Entity<GridAtmosphereComponent?> grid, Vector2i tile, bool includeBlocked = false, bool excite = false)
{ {
// TODO ATMOS includeBlocked and excite parameters are unhandled currently. // TODO ATMOS includeBlocked and excite parameters are unhandled currently.
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return TileMixtureEnumerator.Empty; return TileMixtureEnumerator.Empty;
return !grid.Comp.Tiles.TryGetValue(tile, out var atmosTile) return !grid.Comp.Tiles.TryGetValue(tile, out var atmosTile)
@@ -572,7 +571,7 @@ public partial class AtmosphereSystem
EntityUid? sparkSourceUid = null, EntityUid? sparkSourceUid = null,
bool soh = false) bool soh = false)
{ {
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return; return;
if (grid.Comp.Tiles.TryGetValue(tile, out var atmosTile)) if (grid.Comp.Tiles.TryGetValue(tile, out var atmosTile))
@@ -600,7 +599,7 @@ public partial class AtmosphereSystem
EntityUid? sparkSourceUid = null, EntityUid? sparkSourceUid = null,
bool soh = false) bool soh = false)
{ {
if (!_atmosQuery.TryGetComponent(tile.GridIndex, out var atmos)) if (!_gridAtmosQuery.TryGetComponent(tile.GridIndex, out var atmos))
return; return;
DebugTools.Assert(atmos.Tiles.TryGetValue(tile.GridIndices, out var tmp) && tmp == tile); DebugTools.Assert(atmos.Tiles.TryGetValue(tile.GridIndices, out var tmp) && tmp == tile);
@@ -644,7 +643,7 @@ public partial class AtmosphereSystem
[PublicAPI] [PublicAPI]
public bool AddPipeNet(Entity<GridAtmosphereComponent?> grid, PipeNet pipeNet) public bool AddPipeNet(Entity<GridAtmosphereComponent?> grid, PipeNet pipeNet)
{ {
return _atmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Add(pipeNet); return _gridAtmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Add(pipeNet);
} }
/// <summary> /// <summary>
@@ -664,7 +663,7 @@ public partial class AtmosphereSystem
RaiseLocalEvent(ref ev); RaiseLocalEvent(ref ev);
} }
return _atmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Remove(pipeNet); return _gridAtmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Remove(pipeNet);
} }
/// <summary> /// <summary>
@@ -679,7 +678,7 @@ public partial class AtmosphereSystem
DebugTools.Assert(device.Comp.JoinedGrid == null); DebugTools.Assert(device.Comp.JoinedGrid == null);
DebugTools.Assert(Transform(device).GridUid == grid); DebugTools.Assert(Transform(device).GridUid == grid);
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return false; return false;
if (!grid.Comp.AtmosDevices.Add(device)) if (!grid.Comp.AtmosDevices.Add(device))
@@ -699,7 +698,7 @@ public partial class AtmosphereSystem
{ {
DebugTools.Assert(device.Comp.JoinedGrid == grid); DebugTools.Assert(device.Comp.JoinedGrid == grid);
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return false; return false;
if (!grid.Comp.AtmosDevices.Remove(device)) if (!grid.Comp.AtmosDevices.Remove(device))
@@ -732,7 +731,7 @@ public partial class AtmosphereSystem
// Entity should be on the grid it's being added to. // Entity should be on the grid it's being added to.
Debug.Assert(xform.GridUid == grid.Owner); Debug.Assert(xform.GridUid == grid.Owner);
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return false; return false;
if (grid.Comp.DeltaPressureEntityLookup.ContainsKey(ent.Owner)) if (grid.Comp.DeltaPressureEntityLookup.ContainsKey(ent.Owner))
@@ -759,7 +758,7 @@ public partial class AtmosphereSystem
[PublicAPI] [PublicAPI]
public bool TryRemoveDeltaPressureEntity(Entity<GridAtmosphereComponent?> grid, Entity<DeltaPressureComponent> ent) public bool TryRemoveDeltaPressureEntity(Entity<GridAtmosphereComponent?> grid, Entity<DeltaPressureComponent> ent)
{ {
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return false; return false;
if (!grid.Comp.DeltaPressureEntityLookup.TryGetValue(ent.Owner, out var index)) if (!grid.Comp.DeltaPressureEntityLookup.TryGetValue(ent.Owner, out var index))
@@ -797,7 +796,7 @@ public partial class AtmosphereSystem
public bool IsDeltaPressureEntityInList(Entity<GridAtmosphereComponent?> grid, Entity<DeltaPressureComponent> ent) public bool IsDeltaPressureEntityInList(Entity<GridAtmosphereComponent?> grid, Entity<DeltaPressureComponent> ent)
{ {
// Dict and list must be in sync - deep-fried if we aren't. // Dict and list must be in sync - deep-fried if we aren't.
if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) if (!_gridAtmosQuery.Resolve(grid, ref grid.Comp, false))
return false; return false;
var contains = grid.Comp.DeltaPressureEntityLookup.ContainsKey(ent.Owner); var contains = grid.Comp.DeltaPressureEntityLookup.ContainsKey(ent.Owner);
@@ -13,6 +13,7 @@ namespace Content.Server.Atmos.EntitySystems;
public sealed partial class AtmosphereSystem public sealed partial class AtmosphereSystem
{ {
[Dependency] private IConsoleHost _consoleHost = default!; [Dependency] private IConsoleHost _consoleHost = default!;
[Dependency] private EntityQuery<AtmosFixMarkerComponent> _atmosFixMarkerQuery = default!;
private void InitializeCommands() private void InitializeCommands()
{ {
@@ -113,7 +114,6 @@ public sealed partial class AtmosphereSystem
RebuildGridTiles(grid); RebuildGridTiles(grid);
var query = GetEntityQuery<AtmosFixMarkerComponent>();
foreach (var (indices, tile) in ent.Comp1.Tiles.ToArray()) foreach (var (indices, tile) in ent.Comp1.Tiles.ToArray())
{ {
if (tile.Air is not {Immutable: false} air) if (tile.Air is not {Immutable: false} air)
@@ -124,7 +124,7 @@ public sealed partial class AtmosphereSystem
var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(grid, grid, indices); var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(grid, grid, indices);
while (enumerator.MoveNext(out var entUid)) while (enumerator.MoveNext(out var entUid))
{ {
if (query.TryComp(entUid, out var marker)) if (_atmosFixMarkerQuery.TryComp(entUid, out var marker))
mixtureId = marker.Mode; mixtureId = marker.Mode;
} }
@@ -14,6 +14,9 @@ namespace Content.Server.Atmos.EntitySystems
{ {
public sealed partial class AtmosphereSystem public sealed partial class AtmosphereSystem
{ {
[Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
[Dependency] private EntityQuery<MovedByPressureComponent> _movedByPressureQuery = default!;
private static readonly ProtoId<SoundCollectionPrototype> DefaultSpaceWindSounds = "SpaceWind"; private static readonly ProtoId<SoundCollectionPrototype> DefaultSpaceWindSounds = "SpaceWind";
private const int SpaceWindSoundCooldownCycles = 75; private const int SpaceWindSoundCooldownCycles = 75;
@@ -100,7 +103,7 @@ namespace Content.Server.Atmos.EntitySystems
_activePressures.Add((uid, component)); _activePressures.Add((uid, component));
} }
private void HighPressureMovements(Entity<GridAtmosphereComponent> gridAtmosphere, TileAtmosphere tile, EntityQuery<PhysicsComponent> bodies, EntityQuery<TransformComponent> xforms, EntityQuery<MovedByPressureComponent> pressureQuery, EntityQuery<MetaDataComponent> metas) private void HighPressureMovements(Entity<GridAtmosphereComponent> gridAtmosphere, TileAtmosphere tile)
{ {
// TODO ATMOS finish this // TODO ATMOS finish this
@@ -156,12 +159,12 @@ namespace Content.Server.Atmos.EntitySystems
{ {
// Ideally containers would have their own EntityQuery internally or something given recursively it may need to slam GetComp<T> anyway. // Ideally containers would have their own EntityQuery internally or something given recursively it may need to slam GetComp<T> anyway.
// Also, don't care about static bodies (but also due to collisionwakestate can't query dynamic directly atm). // Also, don't care about static bodies (but also due to collisionwakestate can't query dynamic directly atm).
if (!bodies.TryGetComponent(entity, out var body) || if (!_physicsQuery.TryGetComponent(entity, out var body) ||
!pressureQuery.TryGetComponent(entity, out var pressure) || !_movedByPressureQuery.TryGetComponent(entity, out var pressure) ||
!pressure.Enabled) !pressure.Enabled)
continue; continue;
if (_containers.IsEntityInContainer(entity, metas.GetComponent(entity))) continue; if (_containers.IsEntityInContainer(entity)) continue;
var pressureMovements = EnsureComp<MovedByPressureComponent>(entity); var pressureMovements = EnsureComp<MovedByPressureComponent>(entity);
if (pressure.LastHighPressureMovementAirCycle < gridAtmosphere.Comp.UpdateCounter) if (pressure.LastHighPressureMovementAirCycle < gridAtmosphere.Comp.UpdateCounter)
@@ -174,7 +177,7 @@ namespace Content.Server.Atmos.EntitySystems
tile.PressureDirection, 0, tile.PressureDirection, 0,
tile.PressureSpecificTarget != null ? _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.PressureSpecificTarget.GridIndices) : EntityCoordinates.Invalid, tile.PressureSpecificTarget != null ? _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.PressureSpecificTarget.GridIndices) : EntityCoordinates.Invalid,
gridWorldRotation, gridWorldRotation,
xforms.GetComponent(entity), Transform(entity),
body); body);
} }
} }
@@ -395,14 +395,9 @@ namespace Content.Server.Atmos.EntitySystems
// Note: This is still processed even if space wind is turned off since this handles playing the sounds. // Note: This is still processed even if space wind is turned off since this handles playing the sounds.
var number = 0; var number = 0;
var bodies = GetEntityQuery<PhysicsComponent>();
var xforms = GetEntityQuery<TransformComponent>();
var metas = GetEntityQuery<MetaDataComponent>();
var pressureQuery = GetEntityQuery<MovedByPressureComponent>();
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile)) while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
{ {
HighPressureMovements(ent, tile, bodies, xforms, pressureQuery, metas); HighPressureMovements(ent, tile);
tile.PressureDifference = 0f; tile.PressureDifference = 0f;
tile.LastPressureDirection = tile.PressureDirection; tile.LastPressureDirection = tile.PressureDirection;
tile.PressureDirection = AtmosDirection.Invalid; tile.PressureDirection = AtmosDirection.Invalid;
@@ -42,13 +42,14 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
[Dependency] public PuddleSystem Puddle = default!; [Dependency] public PuddleSystem Puddle = default!;
[Dependency] private DamageableSystem _damage = default!; [Dependency] private DamageableSystem _damage = default!;
[Dependency] private EntityQuery<GridAtmosphereComponent> _gridAtmosQuery = default!;
[Dependency] private EntityQuery<MapAtmosphereComponent> _mapAtmosQuery = default!;
[Dependency] private EntityQuery<AirtightComponent> _airtightQuery = default!;
[Dependency] private EntityQuery<FirelockComponent> _firelockQuery = default!;
private const float ExposedUpdateDelay = 1f; private const float ExposedUpdateDelay = 1f;
private float _exposedTimer = 0f; private float _exposedTimer = 0f;
private EntityQuery<GridAtmosphereComponent> _atmosQuery;
private EntityQuery<MapAtmosphereComponent> _mapAtmosQuery;
private EntityQuery<AirtightComponent> _airtightQuery;
private EntityQuery<FirelockComponent> _firelockQuery;
private HashSet<EntityUid> _entSet = new(); private HashSet<EntityUid> _entSet = new();
private string[] _burntDecals = []; private string[] _burntDecals = [];
@@ -65,11 +66,6 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
InitializeGridAtmosphere(); InitializeGridAtmosphere();
InitializeMap(); InitializeMap();
_atmosQuery = GetEntityQuery<GridAtmosphereComponent>();
_mapAtmosQuery = GetEntityQuery<MapAtmosphereComponent>();
_airtightQuery = GetEntityQuery<AirtightComponent>();
_firelockQuery = GetEntityQuery<FirelockComponent>();
SubscribeLocalEvent<TileChangedEvent>(OnTileChanged); SubscribeLocalEvent<TileChangedEvent>(OnTileChanged);
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded); SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypesReloaded);
@@ -51,8 +51,8 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private IRobustRandom _random = default!; [Dependency] private IRobustRandom _random = default!;
[Dependency] private IGameTiming _timing = default!; [Dependency] private IGameTiming _timing = default!;
private EntityQuery<InventoryComponent> _inventoryQuery; [Dependency] private EntityQuery<InventoryComponent> _inventoryQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery; [Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private static readonly TimeSpan UpdateTime = TimeSpan.FromSeconds(1); private static readonly TimeSpan UpdateTime = TimeSpan.FromSeconds(1);
@@ -62,9 +62,6 @@ namespace Content.Server.Atmos.EntitySystems
{ {
UpdatesAfter.Add(typeof(AtmosphereSystem)); UpdatesAfter.Add(typeof(AtmosphereSystem));
_inventoryQuery = GetEntityQuery<InventoryComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<FlammableComponent, MapInitEvent>(OnMapInit); SubscribeLocalEvent<FlammableComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<FlammableComponent, InteractUsingEvent>(OnInteractUsing); SubscribeLocalEvent<FlammableComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeLocalEvent<FlammableComponent, StartCollideEvent>(OnCollide); SubscribeLocalEvent<FlammableComponent, StartCollideEvent>(OnCollide);
@@ -1,4 +1,3 @@
using Content.Server.Atmos.Components;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.EntitySystems; using Content.Shared.Atmos.EntitySystems;
@@ -33,6 +32,9 @@ namespace Content.Server.Atmos.EntitySystems
[Robust.Shared.IoC.Dependency] private AtmosphereSystem _atmosphereSystem = default!; [Robust.Shared.IoC.Dependency] private AtmosphereSystem _atmosphereSystem = default!;
[Robust.Shared.IoC.Dependency] private ChunkingSystem _chunkingSys = default!; [Robust.Shared.IoC.Dependency] private ChunkingSystem _chunkingSys = default!;
[Robust.Shared.IoC.Dependency] private EntityQuery<MapGridComponent> _mapGridQuery = default!;
[Robust.Shared.IoC.Dependency] private EntityQuery<GasTileOverlayComponent> _gasTileOverlayQuery = default!;
/// <summary> /// <summary>
/// Per-tick cache of sessions. /// Per-tick cache of sessions.
/// </summary> /// </summary>
@@ -57,16 +59,11 @@ namespace Content.Server.Atmos.EntitySystems
private float _updateInterval; private float _updateInterval;
private int _thresholds; private int _thresholds;
private EntityQuery<MapGridComponent> _gridQuery;
private EntityQuery<GasTileOverlayComponent> _query;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_query = GetEntityQuery<GasTileOverlayComponent>();
_gridQuery = GetEntityQuery<MapGridComponent>();
_updateJob = new UpdatePlayerJob() _updateJob = new UpdatePlayerJob()
{ {
EntManager = EntityManager, EntManager = EntityManager,
@@ -77,7 +74,7 @@ namespace Content.Server.Atmos.EntitySystems
MapManager = _mapManager, MapManager = _mapManager,
ChunkViewerPool = _chunkViewerPool, ChunkViewerPool = _chunkViewerPool,
LastSentChunks = _lastSentChunks, LastSentChunks = _lastSentChunks,
GridQuery = _gridQuery, GridQuery = _mapGridQuery,
}; };
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged; _playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
@@ -136,7 +133,7 @@ namespace Content.Server.Atmos.EntitySystems
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Invalidate(Entity<GasTileOverlayComponent?> grid, Vector2i index) public void Invalidate(Entity<GasTileOverlayComponent?> grid, Vector2i index)
{ {
if (_query.Resolve(grid.Owner, ref grid.Comp)) if (_gasTileOverlayQuery.Resolve(grid.Owner, ref grid.Comp))
grid.Comp.InvalidTiles.Add(index); grid.Comp.InvalidTiles.Add(index);
} }
@@ -1,6 +1,5 @@
using System.Linq; using System.Linq;
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes; using Content.Server.NodeContainer.Nodes;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Shared.Atmos; using Content.Shared.Atmos;
@@ -21,17 +20,15 @@ public sealed partial class PipeRestrictOverlapSystem : EntitySystem
[Dependency] private MapSystem _map = default!; [Dependency] private MapSystem _map = default!;
[Dependency] private PopupSystem _popup = default!; [Dependency] private PopupSystem _popup = default!;
[Dependency] private TransformSystem _xform = default!; [Dependency] private TransformSystem _xform = default!;
[Dependency] private EntityQuery<NodeContainerComponent> _nodeContainerQuery = default!;
private readonly List<EntityUid> _anchoredEntities = new(); private readonly List<EntityUid> _anchoredEntities = new();
private EntityQuery<NodeContainerComponent> _nodeContainerQuery;
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorStateChangedEvent>(OnAnchorStateChanged); SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorStateChangedEvent>(OnAnchorStateChanged);
SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorAttemptEvent>(OnAnchorAttempt); SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorAttemptEvent>(OnAnchorAttempt);
_nodeContainerQuery = GetEntityQuery<NodeContainerComponent>();
} }
private void OnAnchorStateChanged(Entity<PipeRestrictOverlapComponent> ent, ref AnchorStateChangedEvent args) private void OnAnchorStateChanged(Entity<PipeRestrictOverlapComponent> ent, ref AnchorStateChangedEvent args)
@@ -45,6 +45,7 @@ public sealed partial class AirAlarmSystem : EntitySystem
[Dependency] private DeviceListSystem _deviceList = default!; [Dependency] private DeviceListSystem _deviceList = default!;
[Dependency] private PopupSystem _popup = default!; [Dependency] private PopupSystem _popup = default!;
[Dependency] private UserInterfaceSystem _ui = default!; [Dependency] private UserInterfaceSystem _ui = default!;
[Dependency] private EntityQuery<DeviceNetworkComponent> _deviceNetworkQuery = default!;
#region Device Network API #region Device Network API
@@ -193,10 +194,9 @@ public sealed partial class AirAlarmSystem : EntitySystem
private void OnDeviceListUpdate(EntityUid uid, AirAlarmComponent component, DeviceListUpdateEvent args) private void OnDeviceListUpdate(EntityUid uid, AirAlarmComponent component, DeviceListUpdateEvent args)
{ {
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var device in args.OldDevices) foreach (var device in args.OldDevices)
{ {
if (!query.TryGetComponent(device, out var deviceNet)) if (!_deviceNetworkQuery.TryGetComponent(device, out var deviceNet))
{ {
continue; continue;
} }
@@ -19,6 +19,7 @@ public sealed partial class FireAlarmSystem : EntitySystem
[Dependency] private SharedInteractionSystem _interactionSystem = default!; [Dependency] private SharedInteractionSystem _interactionSystem = default!;
[Dependency] private AccessReaderSystem _access = default!; [Dependency] private AccessReaderSystem _access = default!;
[Dependency] private IConfigurationManager _configManager = default!; [Dependency] private IConfigurationManager _configManager = default!;
[Dependency] private EntityQuery<DeviceNetworkComponent> _deviceNetworkQuery = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -29,10 +30,9 @@ public sealed partial class FireAlarmSystem : EntitySystem
private void OnDeviceListSync(EntityUid uid, FireAlarmComponent component, DeviceListUpdateEvent args) private void OnDeviceListSync(EntityUid uid, FireAlarmComponent component, DeviceListUpdateEvent args)
{ {
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var device in args.OldDevices) foreach (var device in args.OldDevices)
{ {
if (!query.TryGetComponent(device, out var deviceNet)) if (!_deviceNetworkQuery.TryGetComponent(device, out var deviceNet))
{ {
continue; continue;
} }
@@ -112,6 +112,12 @@ namespace Content.Server.Atmos.Piping.EntitySystems
private void OnDeviceParentChanged(Entity<AtmosDeviceComponent> ent, ref EntParentChangedMessage args) private void OnDeviceParentChanged(Entity<AtmosDeviceComponent> ent, ref EntParentChangedMessage args)
{ {
// Event is raised when a map is loaded in. Since this event mutates comp.Enabled,
// it will overwrite whatever saved value it had
// (so devices saved as enabled will just be disabled).
if (args.OldParent is null)
return;
RejoinAtmosphere(ent); RejoinAtmosphere(ent);
} }
@@ -14,14 +14,9 @@ public sealed partial class InternalsSystem : SharedInternalsSystem
[Dependency] private GasTankSystem _gasTank = default!; [Dependency] private GasTankSystem _gasTank = default!;
[Dependency] private RespiratorSystem _respirator = default!; [Dependency] private RespiratorSystem _respirator = default!;
private EntityQuery<InternalsComponent> _internalsQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_internalsQuery = GetEntityQuery<InternalsComponent>();
SubscribeLocalEvent<InternalsComponent, InhaleLocationEvent>(OnInhaleLocation); SubscribeLocalEvent<InternalsComponent, InhaleLocationEvent>(OnInhaleLocation);
SubscribeLocalEvent<InternalsComponent, StartingGearEquippedEvent>(OnStartingGear); SubscribeLocalEvent<InternalsComponent, StartingGearEquippedEvent>(OnStartingGear);
} }
@@ -17,7 +17,6 @@ using Robust.Server.Containers;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Server.Cargo.Systems; namespace Content.Server.Cargo.Systems;
@@ -28,11 +27,11 @@ public sealed partial class CargoSystem
[Dependency] private NameIdentifierSystem _nameIdentifier = default!; [Dependency] private NameIdentifierSystem _nameIdentifier = default!;
[Dependency] private EntityWhitelistSystem _whitelistSys = default!; [Dependency] private EntityWhitelistSystem _whitelistSys = default!;
private static readonly ProtoId<NameIdentifierGroupPrototype> BountyNameIdentifierGroup = "Bounty"; [Dependency] private EntityQuery<StackComponent> _stackQuery = default!;
[Dependency] private EntityQuery<ContainerManagerComponent> _containerManagerQuery = default!;
[Dependency] private EntityQuery<CargoBountyLabelComponent> _cargoBountyLabelQuery = default!;
private EntityQuery<StackComponent> _stackQuery; private static readonly ProtoId<NameIdentifierGroupPrototype> BountyNameIdentifierGroup = "Bounty";
private EntityQuery<ContainerManagerComponent> _containerQuery;
private EntityQuery<CargoBountyLabelComponent> _bountyLabelQuery;
private void InitializeBounty() private void InitializeBounty()
{ {
@@ -42,10 +41,6 @@ public sealed partial class CargoSystem
SubscribeLocalEvent<CargoBountyLabelComponent, PriceCalculationEvent>(OnGetBountyPrice); SubscribeLocalEvent<CargoBountyLabelComponent, PriceCalculationEvent>(OnGetBountyPrice);
SubscribeLocalEvent<EntitySoldEvent>(OnSold); SubscribeLocalEvent<EntitySoldEvent>(OnSold);
SubscribeLocalEvent<StationCargoBountyDatabaseComponent, MapInitEvent>(OnMapInit); SubscribeLocalEvent<StationCargoBountyDatabaseComponent, MapInitEvent>(OnMapInit);
_stackQuery = GetEntityQuery<StackComponent>();
_containerQuery = GetEntityQuery<ContainerManagerComponent>();
_bountyLabelQuery = GetEntityQuery<CargoBountyLabelComponent>();
} }
private void OnBountyConsoleOpened(EntityUid uid, CargoBountyConsoleComponent component, BoundUIOpenedEvent args) private void OnBountyConsoleOpened(EntityUid uid, CargoBountyConsoleComponent component, BoundUIOpenedEvent args)
@@ -196,7 +191,7 @@ public sealed partial class CargoSystem
{ {
labelEnt = null; labelEnt = null;
labelComp = null; labelComp = null;
if (!_containerQuery.TryGetComponent(uid, out var containerMan)) if (!_containerManagerQuery.TryGetComponent(uid, out var containerMan))
return false; return false;
// make sure this label was actually applied to a crate. // make sure this label was actually applied to a crate.
@@ -204,7 +199,7 @@ public sealed partial class CargoSystem
return false; return false;
if (container.ContainedEntities.FirstOrNull() is not { } label || if (container.ContainedEntities.FirstOrNull() is not { } label ||
!_bountyLabelQuery.TryGetComponent(label, out var component)) !_cargoBountyLabelQuery.TryGetComponent(label, out var component))
return false; return false;
labelEnt = label; labelEnt = label;
@@ -377,7 +372,7 @@ public sealed partial class CargoSystem
{ {
foreach (var ent in container.ContainedEntities) foreach (var ent in container.ContainedEntities)
{ {
if (_bountyLabelQuery.HasComponent(ent)) if (_cargoBountyLabelQuery.HasComponent(ent))
continue; continue;
var children = GetBountyEntities(ent); var children = GetBountyEntities(ent);
@@ -297,7 +297,7 @@ namespace Content.Server.Cargo.Systems
{ {
foreach (var gridUid in data.Grids) foreach (var gridUid in data.Grids)
{ {
if (!_tradeQuery.HasComponent(gridUid)) if (!_tradeStationQuery.HasComponent(gridUid))
continue; continue;
ents.Add(gridUid); ents.Add(gridUid);
@@ -6,7 +6,6 @@ using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Events; using Content.Shared.Cargo.Events;
using Content.Shared.Cargo.Prototypes; using Content.Shared.Cargo.Prototypes;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.HijackBeacon;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -169,13 +168,13 @@ public sealed partial class CargoSystem
// - anything anchored (e.g. light fixtures) // - anything anchored (e.g. light fixtures)
// - anything blacklisted (e.g. players). // - anything blacklisted (e.g. players).
if (toSell.Contains(ent) || if (toSell.Contains(ent) ||
_xformQuery.TryGetComponent(ent, out var xform) && TryComp(ent, out TransformComponent? xform) &&
(xform.Anchored || !CanSell(ent, xform))) (xform.Anchored || !CanSell(ent)))
{ {
continue; continue;
} }
if (_blacklistQuery.HasComponent(ent)) if (_cargoSellBlacklistQuery.HasComponent(ent))
continue; continue;
var price = _pricing.GetPrice(ent); var price = _pricing.GetPrice(ent);
@@ -187,9 +186,9 @@ public sealed partial class CargoSystem
} }
} }
private bool CanSell(EntityUid uid, TransformComponent xform) private bool CanSell(EntityUid uid)
{ {
if (_mobQuery.HasComponent(uid)) if (_mobStateQuery.HasComponent(uid))
{ {
return false; return false;
} }
@@ -197,13 +196,14 @@ public sealed partial class CargoSystem
var complete = IsBountyComplete(uid, out var bountyEntities); var complete = IsBountyComplete(uid, out var bountyEntities);
// Recursively check for mobs at any point. // Recursively check for mobs at any point.
var xform = Transform(uid);
var children = xform.ChildEnumerator; var children = xform.ChildEnumerator;
while (children.MoveNext(out var child)) while (children.MoveNext(out var child))
{ {
if (complete && bountyEntities.Contains(child)) if (complete && bountyEntities.Contains(child))
continue; continue;
if (!CanSell(child, _xformQuery.GetComponent(child))) if (!CanSell(child))
return false; return false;
} }
+3 -10
View File
@@ -42,10 +42,9 @@ public sealed partial class CargoSystem : SharedCargoSystem
[Dependency] private RadioSystem _radio = default!; [Dependency] private RadioSystem _radio = default!;
[Dependency] private IdentitySystem _identity = default!; [Dependency] private IdentitySystem _identity = default!;
private EntityQuery<TransformComponent> _xformQuery; [Dependency] private EntityQuery<CargoSellBlacklistComponent> _cargoSellBlacklistQuery = default!;
private EntityQuery<CargoSellBlacklistComponent> _blacklistQuery; [Dependency] private EntityQuery<MobStateComponent> _mobStateQuery = default!;
private EntityQuery<MobStateComponent> _mobQuery; [Dependency] private EntityQuery<TradeStationComponent> _tradeStationQuery = default!;
private EntityQuery<TradeStationComponent> _tradeQuery;
private HashSet<EntityUid> _setEnts = new(); private HashSet<EntityUid> _setEnts = new();
private List<EntityUid> _listEnts = new(); private List<EntityUid> _listEnts = new();
@@ -54,12 +53,6 @@ public sealed partial class CargoSystem : SharedCargoSystem
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_xformQuery = GetEntityQuery<TransformComponent>();
_blacklistQuery = GetEntityQuery<CargoSellBlacklistComponent>();
_mobQuery = GetEntityQuery<MobStateComponent>();
_tradeQuery = GetEntityQuery<TradeStationComponent>();
InitializeConsole(); InitializeConsole();
InitializeShuttle(); InitializeShuttle();
InitializeTelepad(); InitializeTelepad();
+2 -2
View File
@@ -28,6 +28,7 @@ public sealed partial class SuicideSystem : EntitySystem
[Dependency] private SharedPopupSystem _popup = default!; [Dependency] private SharedPopupSystem _popup = default!;
[Dependency] private GhostSystem _ghostSystem = default!; [Dependency] private GhostSystem _ghostSystem = default!;
[Dependency] private SharedSuicideSystem _suicide = default!; [Dependency] private SharedSuicideSystem _suicide = default!;
[Dependency] private EntityQuery<ItemComponent> _itemQuery = default!;
private static readonly ProtoId<TagPrototype> CannotSuicideTag = "CannotSuicide"; private static readonly ProtoId<TagPrototype> CannotSuicideTag = "CannotSuicide";
@@ -132,11 +133,10 @@ public sealed partial class SuicideSystem : EntitySystem
// Try to suicide by nearby entities, like Microwaves or Crematoriums, by raising an event on it // Try to suicide by nearby entities, like Microwaves or Crematoriums, by raising an event on it
// Returns upon being handled by any entity // Returns upon being handled by any entity
var itemQuery = GetEntityQuery<ItemComponent>();
foreach (var entity in _entityLookupSystem.GetEntitiesInRange(victim, 1, LookupFlags.Approximate | LookupFlags.Static)) foreach (var entity in _entityLookupSystem.GetEntitiesInRange(victim, 1, LookupFlags.Approximate | LookupFlags.Static))
{ {
// Skip any nearby items that can be picked up, we already checked the active held item above // Skip any nearby items that can be picked up, we already checked the active held item above
if (itemQuery.HasComponent(entity)) if (_itemQuery.HasComponent(entity))
continue; continue;
RaiseLocalEvent(entity, suicideByEnvironmentEvent); RaiseLocalEvent(entity, suicideByEnvironmentEvent);
+4 -6
View File
@@ -21,7 +21,6 @@ using Content.Shared.Players;
using Content.Shared.Players.RateLimiting; using Content.Shared.Players.RateLimiting;
using Content.Shared.Radio; using Content.Shared.Radio;
using Content.Shared.Station.Components; using Content.Shared.Station.Components;
using Content.Shared.Whitelist;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
@@ -58,6 +57,7 @@ public sealed partial class ChatSystem : SharedChatSystem
[Dependency] private SharedAudioSystem _audio = default!; [Dependency] private SharedAudioSystem _audio = default!;
[Dependency] private ReplacementAccentSystem _wordreplacement = default!; [Dependency] private ReplacementAccentSystem _wordreplacement = default!;
[Dependency] private ExamineSystemShared _examineSystem = default!; [Dependency] private ExamineSystemShared _examineSystem = default!;
[Dependency] private EntityQuery<GhostHearingComponent> _ghostHearingQuery = default!;
// Corvax-TTS-Start: Moved from Server to Shared // Corvax-TTS-Start: Moved from Server to Shared
// public const int VoiceRange = 10; // how far voice goes in world units // public const int VoiceRange = 10; // how far voice goes in world units
@@ -801,10 +801,8 @@ public sealed partial class ChatSystem : SharedChatSystem
// TODO proper speech occlusion // TODO proper speech occlusion
var recipients = new Dictionary<ICommonSession, ICChatRecipientData>(); var recipients = new Dictionary<ICommonSession, ICChatRecipientData>();
var ghostHearing = GetEntityQuery<GhostHearingComponent>();
var xforms = GetEntityQuery<TransformComponent>();
var transformSource = xforms.GetComponent(source); var transformSource = Transform(source);
var sourceMapId = transformSource.MapID; var sourceMapId = transformSource.MapID;
var sourceCoords = transformSource.Coordinates; var sourceCoords = transformSource.Coordinates;
@@ -813,12 +811,12 @@ public sealed partial class ChatSystem : SharedChatSystem
if (player.AttachedEntity is not { Valid: true } playerEntity) if (player.AttachedEntity is not { Valid: true } playerEntity)
continue; continue;
var transformEntity = xforms.GetComponent(playerEntity); var transformEntity = Transform(playerEntity);
if (transformEntity.MapID != sourceMapId) if (transformEntity.MapID != sourceMapId)
continue; continue;
var observer = ghostHearing.HasComponent(playerEntity); var observer = _ghostHearingQuery.HasComponent(playerEntity);
// even if they are a ghost hearer, in some situations we still need the range // even if they are a ghost hearer, in some situations we still need the range
if (sourceCoords.TryDistance(EntityManager, transformEntity.Coordinates, out var distance) && distance < voiceGetRange) if (sourceCoords.TryDistance(EntityManager, transformEntity.Coordinates, out var distance) && distance < voiceGetRange)
@@ -34,8 +34,8 @@ public sealed partial class CleanTileReaction : ITileReaction
FixedPoint2 ITileReaction.TileReact(TileRef tile, FixedPoint2 ITileReaction.TileReact(TileRef tile,
ReagentPrototype reagent, ReagentPrototype reagent,
FixedPoint2 reactVolume, FixedPoint2 reactVolume,
IEntityManager entityManager IEntityManager entityManager,
, List<ReagentData>? data) List<ReagentData>? data)
{ {
var entities = entityManager.System<EntityLookupSystem>().GetLocalEntitiesIntersecting(tile, 0f).ToArray(); var entities = entityManager.System<EntityLookupSystem>().GetLocalEntitiesIntersecting(tile, 0f).ToArray();
var puddleQuery = entityManager.GetEntityQuery<PuddleComponent>(); var puddleQuery = entityManager.GetEntityQuery<PuddleComponent>();
+1 -6
View File
@@ -1,5 +1,3 @@
using System.Linq;
using Content.Shared.Decals;
using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.ObjectPool;
using Robust.Shared; using Robust.Shared;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
@@ -22,14 +20,11 @@ public sealed partial class ChunkingSystem : EntitySystem
[Dependency] private IMapManager _mapManager = default!; [Dependency] private IMapManager _mapManager = default!;
[Dependency] private SharedTransformSystem _transform = default!; [Dependency] private SharedTransformSystem _transform = default!;
private EntityQuery<TransformComponent> _xformQuery;
private Box2 _baseViewBounds; private Box2 _baseViewBounds;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_xformQuery = GetEntityQuery<TransformComponent>();
Subs.CVar(_configurationManager, CVars.NetMaxUpdateRange, OnPvsRangeChanged, true); Subs.CVar(_configurationManager, CVars.NetMaxUpdateRange, OnPvsRangeChanged, true);
} }
@@ -67,7 +62,7 @@ public sealed partial class ChunkingSystem : EntitySystem
int chunkSize, int chunkSize,
float viewEnlargement) float viewEnlargement)
{ {
if (!_xformQuery.TryGetComponent(viewer, out var xform)) if (!TryComp(viewer, out TransformComponent? xform))
return; return;
var pos = _transform.GetWorldPosition(xform); var pos = _transform.GetWorldPosition(xform);
@@ -88,8 +88,7 @@ namespace Content.Server.Construction.Conditions
var examineName = constructionSys.GetExamineName(info); var examineName = constructionSys.GetExamineName(info);
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry", args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
("amount", info.Amount), ("amount", info.Amount),
("elementName", examineName)) ("elementName", examineName)));
+ "\n");
} }
return true; return true;
@@ -1,5 +1,4 @@
using Content.Server.DeviceLinking.Components; using Content.Server.DeviceLinking.Components;
using Content.Server.NodeContainer;
using Content.Server.Power.EntitySystems; using Content.Server.Power.EntitySystems;
using Content.Server.Power.Nodes; using Content.Server.Power.Nodes;
using Content.Server.Power.NodeGroups; using Content.Server.Power.NodeGroups;
@@ -26,16 +25,10 @@ public sealed partial class PowerSensorSystem : EntitySystem
[Dependency] private SharedToolSystem _tool = default!; [Dependency] private SharedToolSystem _tool = default!;
[Dependency] private UseDelaySystem _useDelay = default!; [Dependency] private UseDelaySystem _useDelay = default!;
private EntityQuery<NodeContainerComponent> _nodeQuery;
private EntityQuery<TransformComponent> _xformQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_nodeQuery = GetEntityQuery<NodeContainerComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
SubscribeLocalEvent<PowerSensorComponent, ComponentInit>(OnInit); SubscribeLocalEvent<PowerSensorComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<PowerSensorComponent, ExaminedEvent>(OnExamined); SubscribeLocalEvent<PowerSensorComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<PowerSensorComponent, InteractUsingEvent>(OnInteractUsing); SubscribeLocalEvent<PowerSensorComponent, InteractUsingEvent>(OnInteractUsing);
@@ -99,7 +92,7 @@ public sealed partial class PowerSensorSystem : EntitySystem
var deviceNode = (CableDeviceNode) nodeContainer.Nodes[cable.Node]; var deviceNode = (CableDeviceNode) nodeContainer.Nodes[cable.Node];
// update state based on the power stats retrieved from the selected power network // update state based on the power stats retrieved from the selected power network
var xform = _xformQuery.GetComponent(uid); var xform = Transform(uid);
if (!TryComp(xform.GridUid, out MapGridComponent? grid)) if (!TryComp(xform.GridUid, out MapGridComponent? grid))
return; return;
@@ -11,6 +11,7 @@ namespace Content.Server.DeviceNetwork.Systems;
public sealed partial class DeviceListSystem : SharedDeviceListSystem public sealed partial class DeviceListSystem : SharedDeviceListSystem
{ {
[Dependency] private NetworkConfiguratorSystem _configurator = default!; [Dependency] private NetworkConfiguratorSystem _configurator = default!;
[Dependency] private EntityQuery<DeviceNetworkComponent> _deviceNetworkQuery = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -28,10 +29,9 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem
_configurator.OnDeviceListShutdown(conf, (uid, component)); _configurator.OnDeviceListShutdown(conf, (uid, component));
} }
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var device in component.Devices) foreach (var device in component.Devices)
{ {
if (query.TryGetComponent(device, out var comp)) if (_deviceNetworkQuery.TryGetComponent(device, out var comp))
comp.DeviceLists.Remove(uid); comp.DeviceLists.Remove(uid);
} }
component.Devices.Clear(); component.Devices.Clear();
@@ -125,7 +125,6 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem
private void OnMapSave(BeforeSerializationEvent ev) private void OnMapSave(BeforeSerializationEvent ev)
{ {
List<EntityUid> toRemove = new(); List<EntityUid> toRemove = new();
var query = GetEntityQuery<TransformComponent>();
var enumerator = AllEntityQuery<DeviceListComponent, TransformComponent>(); var enumerator = AllEntityQuery<DeviceListComponent, TransformComponent>();
while (enumerator.MoveNext(out var uid, out var device, out var xform)) while (enumerator.MoveNext(out var uid, out var device, out var xform))
{ {
@@ -134,7 +133,7 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem
foreach (var ent in device.Devices) foreach (var ent in device.Devices)
{ {
if (!query.TryGetComponent(ent, out var linkedXform)) if (!TryComp(ent, out TransformComponent? linkedXform))
{ {
// Entity was deleted. // Entity was deleted.
// TODO remove these on deletion instead of on-save. // TODO remove these on deletion instead of on-save.
@@ -190,7 +189,6 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem
return DeviceListUpdateResult.TooManyDevices; return DeviceListUpdateResult.TooManyDevices;
} }
var query = GetEntityQuery<DeviceNetworkComponent>();
var oldDevices = deviceList.Devices.ToList(); var oldDevices = deviceList.Devices.ToList();
foreach (var device in oldDevices) foreach (var device in oldDevices)
{ {
@@ -198,13 +196,13 @@ public sealed partial class DeviceListSystem : SharedDeviceListSystem
continue; continue;
deviceList.Devices.Remove(device); deviceList.Devices.Remove(device);
if (query.TryGetComponent(device, out var comp)) if (_deviceNetworkQuery.TryGetComponent(device, out var comp))
comp.DeviceLists.Remove(uid); comp.DeviceLists.Remove(uid);
} }
foreach (var device in newDevices) foreach (var device in newDevices)
{ {
if (!query.TryGetComponent(device, out var comp)) if (!_deviceNetworkQuery.TryGetComponent(device, out var comp))
continue; continue;
if (!deviceList.Devices.Add(device)) if (!deviceList.Devices.Add(device))
@@ -37,6 +37,7 @@ public sealed partial class NetworkConfiguratorSystem : SharedNetworkConfigurato
[Dependency] private SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private IGameTiming _gameTiming = default!; [Dependency] private IGameTiming _gameTiming = default!;
[Dependency] private IAdminLogManager _adminLogger = default!; [Dependency] private IAdminLogManager _adminLogger = default!;
[Dependency] private EntityQuery<DeviceNetworkComponent> _deviceNetworkQuery = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -632,10 +633,9 @@ public sealed partial class NetworkConfiguratorSystem : SharedNetworkConfigurato
private void ClearDevices(EntityUid uid, NetworkConfiguratorComponent component) private void ClearDevices(EntityUid uid, NetworkConfiguratorComponent component)
{ {
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var device in component.Devices.Values) foreach (var device in component.Devices.Values)
{ {
if (query.TryGetComponent(device, out var comp)) if (_deviceNetworkQuery.TryGetComponent(device, out var comp))
comp.Configurators.Remove(uid); comp.Configurators.Remove(uid);
} }
@@ -794,10 +794,9 @@ public sealed partial class NetworkConfiguratorSystem : SharedNetworkConfigurato
ClearDevices(uid, component); ClearDevices(uid, component);
var query = GetEntityQuery<DeviceNetworkComponent>();
foreach (var (addr, device) in _deviceListSystem.GetDeviceList(component.ActiveDeviceList.Value)) foreach (var (addr, device) in _deviceListSystem.GetDeviceList(component.ActiveDeviceList.Value))
{ {
if (query.TryGetComponent(device, out var comp)) if (_deviceNetworkQuery.TryGetComponent(device, out var comp))
{ {
component.Devices.Add(addr, device); component.Devices.Add(addr, device);
comp.Configurators.Add(uid); comp.Configurators.Add(uid);
+15 -22
View File
@@ -2,7 +2,6 @@ using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Monitor.Components; using Content.Server.Atmos.Monitor.Components;
using Content.Server.Atmos.Monitor.Systems; using Content.Server.Atmos.Monitor.Systems;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems; using Content.Server.Power.EntitySystems;
using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Components;
using Content.Shared.Atmos; using Content.Shared.Atmos;
@@ -24,7 +23,10 @@ namespace Content.Server.Doors.Systems
[Dependency] private SharedMapSystem _mapping = default!; [Dependency] private SharedMapSystem _mapping = default!;
[Dependency] private PointLightSystem _pointLight = default!; [Dependency] private PointLightSystem _pointLight = default!;
private EntityQuery<AtmosAlarmableComponent> _atmosAlarmQuery; [Dependency] private EntityQuery<AtmosAlarmableComponent> _atmosAlarmQuery = default!;
[Dependency] private EntityQuery<AirtightComponent> _airtightQuery = default!;
[Dependency] private EntityQuery<AppearanceComponent> _appearanceQuery = default!;
[Dependency] private EntityQuery<PointLightComponent> _pointLightQuery = default!;
private const int UpdateInterval = 30; private const int UpdateInterval = 30;
private int _accumulatedTicks; private int _accumulatedTicks;
@@ -35,8 +37,6 @@ namespace Content.Server.Doors.Systems
SubscribeLocalEvent<FirelockComponent, AtmosAlarmEvent>(OnAtmosAlarm); SubscribeLocalEvent<FirelockComponent, AtmosAlarmEvent>(OnAtmosAlarm);
SubscribeLocalEvent<FirelockComponent, PowerChangedEvent>(PowerChanged); SubscribeLocalEvent<FirelockComponent, PowerChangedEvent>(PowerChanged);
_atmosAlarmQuery = GetEntityQuery<AtmosAlarmableComponent>();
} }
private void PowerChanged(EntityUid uid, FirelockComponent component, ref PowerChangedEvent args) private void PowerChanged(EntityUid uid, FirelockComponent component, ref PowerChangedEvent args)
@@ -53,10 +53,6 @@ namespace Content.Server.Doors.Systems
_accumulatedTicks = 0; _accumulatedTicks = 0;
var airtightQuery = GetEntityQuery<AirtightComponent>();
var appearanceQuery = GetEntityQuery<AppearanceComponent>();
var xformQuery = GetEntityQuery<TransformComponent>();
var pointLightQuery = GetEntityQuery<PointLightComponent>();
var query = EntityQueryEnumerator<FirelockComponent, DoorComponent>(); var query = EntityQueryEnumerator<FirelockComponent, DoorComponent>();
while (query.MoveNext(out var uid, out var firelock, out var door)) while (query.MoveNext(out var uid, out var firelock, out var door))
@@ -77,11 +73,10 @@ namespace Content.Server.Doors.Systems
continue; continue;
} }
if (airtightQuery.TryGetComponent(uid, out var airtight) if (_airtightQuery.TryGetComponent(uid, out var airtight)
&& xformQuery.TryGetComponent(uid, out var xform) && _appearanceQuery.TryGetComponent(uid, out var appearance))
&& appearanceQuery.TryGetComponent(uid, out var appearance))
{ {
var (pressure, fire) = CheckPressureAndFire(uid, firelock, xform, airtight, airtightQuery); var (pressure, fire) = CheckPressureAndFire(uid, firelock, airtight);
_appearance.SetData(uid, DoorVisuals.ClosedLights, fire || pressure, appearance); _appearance.SetData(uid, DoorVisuals.ClosedLights, fire || pressure, appearance);
firelock.Temperature = fire; firelock.Temperature = fire;
firelock.Pressure = pressure; firelock.Pressure = pressure;
@@ -89,7 +84,7 @@ namespace Content.Server.Doors.Systems
_appearance.SetData(uid, FirelockVisuals.TemperatureWarning, fire, appearance); _appearance.SetData(uid, FirelockVisuals.TemperatureWarning, fire, appearance);
Dirty(uid, firelock); Dirty(uid, firelock);
if (pointLightQuery.TryComp(uid, out var pointLight)) if (_pointLightQuery.TryComp(uid, out var pointLight))
{ {
_pointLight.SetEnabled(uid, fire | pressure, pointLight); _pointLight.SetEnabled(uid, fire | pressure, pointLight);
} }
@@ -118,18 +113,15 @@ namespace Content.Server.Doors.Systems
public (bool Pressure, bool Fire) CheckPressureAndFire(EntityUid uid, FirelockComponent firelock) public (bool Pressure, bool Fire) CheckPressureAndFire(EntityUid uid, FirelockComponent firelock)
{ {
var query = GetEntityQuery<AirtightComponent>(); if (_airtightQuery.TryGetComponent(uid, out AirtightComponent? airtight))
if (query.TryGetComponent(uid, out AirtightComponent? airtight)) return CheckPressureAndFire(uid, firelock, airtight);
return CheckPressureAndFire(uid, firelock, Transform(uid), airtight, query);
return (false, false); return (false, false);
} }
public (bool Pressure, bool Fire) CheckPressureAndFire( public (bool Pressure, bool Fire) CheckPressureAndFire(
EntityUid uid, EntityUid uid,
FirelockComponent firelock, FirelockComponent firelock,
TransformComponent xform, AirtightComponent airtight)
AirtightComponent airtight,
EntityQuery<AirtightComponent> airtightQuery)
{ {
if (!airtight.AirBlocked) if (!airtight.AirBlocked)
return (false, false); return (false, false);
@@ -140,6 +132,7 @@ namespace Content.Server.Doors.Systems
return (false, false); return (false, false);
} }
var xform = Transform(uid);
if (!HasComp<GridAtmosphereComponent>(xform.ParentUid)) if (!HasComp<GridAtmosphereComponent>(xform.ParentUid))
return (false, false); return (false, false);
@@ -190,7 +183,7 @@ namespace Content.Server.Doors.Systems
{ {
// Is there some airtight entity blocking this direction? If yes, don't include this direction in the // Is there some airtight entity blocking this direction? If yes, don't include this direction in the
// pressure differential // pressure differential
if (HasAirtightBlocker(_mapping.GetAnchoredEntities(xform.ParentUid, grid, adjacentPos), dir.GetOpposite(), airtightQuery)) if (HasAirtightBlocker(_mapping.GetAnchoredEntities(xform.ParentUid, grid, adjacentPos), dir.GetOpposite()))
continue; continue;
var p = gas.Pressure; var p = gas.Pressure;
@@ -233,11 +226,11 @@ namespace Content.Server.Doors.Systems
return (holdingPressure, holdingFire); return (holdingPressure, holdingFire);
} }
private bool HasAirtightBlocker(IEnumerable<EntityUid> enumerable, AtmosDirection dir, EntityQuery<AirtightComponent> airtightQuery) private bool HasAirtightBlocker(IEnumerable<EntityUid> enumerable, AtmosDirection dir)
{ {
foreach (var ent in enumerable) foreach (var ent in enumerable)
{ {
if (!airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked) if (!_airtightQuery.TryGetComponent(ent, out var airtight) || !airtight.AirBlocked)
continue; continue;
if ((airtight.AirBlockedDirection & dir) == dir) if ((airtight.AirBlockedDirection & dir) == dir)
+3 -6
View File
@@ -8,7 +8,6 @@ using Content.Shared.Dragon;
using Content.Shared.Gibbing; using Content.Shared.Gibbing;
using Content.Shared.Maps; using Content.Shared.Maps;
using Content.Shared.Mind; using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Mobs; using Content.Shared.Mobs;
using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
@@ -36,7 +35,7 @@ public sealed partial class DragonSystem : EntitySystem
[Dependency] private GibbingSystem _gibbing = default!; [Dependency] private GibbingSystem _gibbing = default!;
[Dependency] private SmokeSystem _smoke = default!; [Dependency] private SmokeSystem _smoke = default!;
private EntityQuery<CarpRiftsConditionComponent> _objQuery; [Dependency] private EntityQuery<CarpRiftsConditionComponent> _carpRiftsConditionQuery = default!;
/// <summary> /// <summary>
/// Minimum distance between 2 rifts allowed. /// Minimum distance between 2 rifts allowed.
@@ -54,8 +53,6 @@ public sealed partial class DragonSystem : EntitySystem
{ {
base.Initialize(); base.Initialize();
_objQuery = GetEntityQuery<CarpRiftsConditionComponent>();
SubscribeLocalEvent<DragonComponent, MapInitEvent>(OnInit); SubscribeLocalEvent<DragonComponent, MapInitEvent>(OnInit);
SubscribeLocalEvent<DragonComponent, ComponentShutdown>(OnShutdown); SubscribeLocalEvent<DragonComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<DragonComponent, DragonSpawnRiftActionEvent>(OnSpawnRift); SubscribeLocalEvent<DragonComponent, DragonSpawnRiftActionEvent>(OnSpawnRift);
@@ -244,7 +241,7 @@ public sealed partial class DragonSystem : EntitySystem
foreach (var objId in mind.Objectives) foreach (var objId in mind.Objectives)
{ {
if (_objQuery.TryGetComponent(objId, out var obj)) if (_carpRiftsConditionQuery.TryGetComponent(objId, out var obj))
{ {
_carpRifts.ResetRifts(objId, obj); _carpRifts.ResetRifts(objId, obj);
break; break;
@@ -265,7 +262,7 @@ public sealed partial class DragonSystem : EntitySystem
foreach (var objId in mind.Objectives) foreach (var objId in mind.Objectives)
{ {
if (_objQuery.TryGetComponent(objId, out var obj)) if (_carpRiftsConditionQuery.TryGetComponent(objId, out var obj))
{ {
_carpRifts.RiftCharged(objId, obj); _carpRifts.RiftCharged(objId, obj);
break; break;
@@ -1,8 +1,6 @@
using System.Numerics; using System.Numerics;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Explosion;
using Content.Shared.Explosion.Components; using Content.Shared.Explosion.Components;
using Content.Shared.Explosion.EntitySystems;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
@@ -102,9 +100,8 @@ public sealed partial class ExplosionSystem
continue; continue;
} }
var xforms = GetEntityQuery<TransformComponent>(); var xform = Transform(gridToTransform);
var xform = xforms.GetComponent(gridToTransform); var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = _transformSystem.GetWorldPositionRotationMatrixWithInv(xform);
var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = _transformSystem.GetWorldPositionRotationMatrixWithInv(xform, xforms);
var localEpicentre = (Vector2i) Vector2.Transform(epicentre.Position, invGridWorldMatrid); var localEpicentre = (Vector2i) Vector2.Transform(epicentre.Position, invGridWorldMatrid);
var matrix = offsetMatrix * gridWorldMatrix * targetMatrix; var matrix = offsetMatrix * gridWorldMatrix * targetMatrix;
@@ -681,13 +681,6 @@ sealed class Explosion
/// </summary> /// </summary>
private readonly Dictionary<Entity<MapGridComponent>, List<(Vector2i, Tile)>> _tileUpdateDict = new(); private readonly Dictionary<Entity<MapGridComponent>, List<(Vector2i, Tile)>> _tileUpdateDict = new();
// Entity Queries
private readonly EntityQuery<TransformComponent> _xformQuery;
private readonly EntityQuery<PhysicsComponent> _physicsQuery;
private readonly EntityQuery<DamageableComponent> _damageQuery;
private readonly EntityQuery<ProjectileComponent> _projectileQuery;
private readonly EntityQuery<TagComponent> _tagQuery;
/// <summary> /// <summary>
/// Total area that the explosion covers. /// Total area that the explosion covers.
/// </summary> /// </summary>
@@ -753,12 +746,6 @@ sealed class Explosion
_entMan = entMan; _entMan = entMan;
_damageable = damageable; _damageable = damageable;
_xformQuery = entMan.GetEntityQuery<TransformComponent>();
_physicsQuery = entMan.GetEntityQuery<PhysicsComponent>();
_damageQuery = entMan.GetEntityQuery<DamageableComponent>();
_tagQuery = entMan.GetEntityQuery<TagComponent>();
_projectileQuery = entMan.GetEntityQuery<ProjectileComponent>();
if (spaceData != null) if (spaceData != null)
{ {
var mapUid = mapSystem.GetMap(epicenter.MapId); var mapUid = mapSystem.GetMap(epicenter.MapId);
@@ -59,15 +59,14 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
[Dependency] private DestructibleSystem _destructibleSystem = default!; [Dependency] private DestructibleSystem _destructibleSystem = default!;
[Dependency] private AtmosphereSystem _atmosphere = default!; [Dependency] private AtmosphereSystem _atmosphere = default!;
private EntityQuery<FlammableComponent> _flammableQuery; [Dependency] private EntityQuery<FlammableComponent> _flammableQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery; [Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private EntityQuery<ProjectileComponent> _projectileQuery; [Dependency] private EntityQuery<ActorComponent> _actorQuery = default!;
private EntityQuery<ActorComponent> _actorQuery; [Dependency] private EntityQuery<DestructibleComponent> _destructibleQuery = default!;
private EntityQuery<DestructibleComponent> _destructibleQuery; [Dependency] private EntityQuery<DamageableComponent> _damageableQuery = default!;
private EntityQuery<DamageableComponent> _damageableQuery;
[Dependency] private EntityQuery<InjurableComponent> _injurableQuery = default!; [Dependency] private EntityQuery<InjurableComponent> _injurableQuery = default!;
private EntityQuery<AirtightComponent> _airtightQuery; [Dependency] private EntityQuery<AirtightComponent> _airtightQuery = default!;
private EntityQuery<TileHistoryComponent> _tileHistoryQuery; [Dependency] private EntityQuery<TileHistoryComponent> _tileHistoryQuery = default!;
/// <summary> /// <summary>
/// "Tile-size" for space when there are no nearby grids to use as a reference. /// "Tile-size" for space when there are no nearby grids to use as a reference.
@@ -103,15 +102,6 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
InitAirtightMap(); InitAirtightMap();
InitVisuals(); InitVisuals();
_flammableQuery = GetEntityQuery<FlammableComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_projectileQuery = GetEntityQuery<ProjectileComponent>();
_actorQuery = GetEntityQuery<ActorComponent>();
_destructibleQuery = GetEntityQuery<DestructibleComponent>();
_damageableQuery = GetEntityQuery<DamageableComponent>();
_airtightQuery = GetEntityQuery<AirtightComponent>();
_tileHistoryQuery = GetEntityQuery<TileHistoryComponent>();
_prototypeManager.PrototypesReloaded += ReloadExplosionPrototypes; _prototypeManager.PrototypesReloaded += ReloadExplosionPrototypes;
} }
@@ -37,7 +37,8 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
[Dependency] private SharedTransformSystem _transform = default!; [Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private TurfSystem _turf = default!; [Dependency] private TurfSystem _turf = default!;
private EntityQuery<PuddleComponent> _puddleQuery; [Dependency] private EntityQuery<PuddleComponent> _puddleQuery = default!;
[Dependency] private EntityQuery<EvaporationSparkleComponent> _evaporationSparklesQuery = default!;
/* /*
* TODO: Need some sort of way to do blood slash / vomit solution spill on its own * TODO: Need some sort of way to do blood slash / vomit solution spill on its own
@@ -49,8 +50,6 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
{ {
base.Initialize(); base.Initialize();
_puddleQuery = GetEntityQuery<PuddleComponent>();
SubscribeLocalEvent<PuddleComponent, SpreadNeighborsEvent>(OnPuddleSpread); SubscribeLocalEvent<PuddleComponent, SpreadNeighborsEvent>(OnPuddleSpread);
SubscribeLocalEvent<PuddleComponent, SlipEvent>(OnPuddleSlip); SubscribeLocalEvent<PuddleComponent, SlipEvent>(OnPuddleSlip);
} }
@@ -151,7 +150,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
break; break;
} }
// If there is nothing left to overflow from our tile, then we'll stop this tile being a active spreader // If there is nothing left to overflow from our tile, then we'll stop this tile being an active spreader
if (overflow.Volume == FixedPoint2.Zero) if (overflow.Volume == FixedPoint2.Zero)
{ {
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity); RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
@@ -517,19 +516,17 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
// Get normalized co-ordinate for spill location and spill it in the centre // Get normalized co-ordinate for spill location and spill it in the centre
// TODO: Does SnapGrid or something else already do this? // TODO: Does SnapGrid or something else already do this?
var anchored = _map.GetAnchoredEntitiesEnumerator(gridId, mapGrid, tileRef.GridIndices); var anchored = _map.GetAnchoredEntitiesEnumerator(gridId, mapGrid, tileRef.GridIndices);
var puddleQuery = GetEntityQuery<PuddleComponent>();
var sparklesQuery = GetEntityQuery<EvaporationSparkleComponent>();
while (anchored.MoveNext(out var ent)) while (anchored.MoveNext(out var ent))
{ {
// If there's existing sparkles then delete it // If there's existing sparkles then delete it
if (sparklesQuery.TryGetComponent(ent, out var sparkles)) if (_evaporationSparklesQuery.TryGetComponent(ent, out var sparkles))
{ {
QueueDel(ent.Value); QueueDel(ent.Value);
continue; continue;
} }
if (!puddleQuery.TryGetComponent(ent, out var puddle)) if (!_puddleQuery.TryGetComponent(ent, out var puddle))
continue; continue;
if (TryAddSolution(ent.Value, solution, sound, puddleComponent: puddle)) if (TryAddSolution(ent.Value, solution, sound, puddleComponent: puddle))
@@ -565,11 +562,9 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
return false; return false;
var anc = _map.GetAnchoredEntitiesEnumerator(tile.GridUid, grid, tile.GridIndices); var anc = _map.GetAnchoredEntitiesEnumerator(tile.GridUid, grid, tile.GridIndices);
var puddleQuery = GetEntityQuery<PuddleComponent>();
while (anc.MoveNext(out var ent)) while (anc.MoveNext(out var ent))
{ {
if (!puddleQuery.HasComponent(ent.Value)) if (!_puddleQuery.HasComponent(ent.Value))
continue; continue;
puddleUid = ent.Value; puddleUid = ent.Value;
@@ -1,6 +1,5 @@
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Body.Systems; using Content.Server.Body.Systems;
using Content.Shared.EntityEffects.Effects;
using Content.Server.Spreader; using Content.Server.Spreader;
using Content.Shared.Body.Components; using Content.Shared.Body.Components;
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
@@ -45,17 +44,14 @@ public sealed partial class SmokeSystem : EntitySystem
[Dependency] private SharedPhysicsSystem _physics = default!; [Dependency] private SharedPhysicsSystem _physics = default!;
[Dependency] private SharedSolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private SharedSolutionContainerSystem _solutionContainerSystem = default!;
private EntityQuery<SmokeComponent> _smokeQuery; [Dependency] private EntityQuery<SmokeComponent> _smokeQuery = default!;
private EntityQuery<SmokeAffectedComponent> _smokeAffectedQuery; [Dependency] private EntityQuery<SmokeAffectedComponent> _smokeAffectedQuery = default!;
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_smokeQuery = GetEntityQuery<SmokeComponent>();
_smokeAffectedQuery = GetEntityQuery<SmokeAffectedComponent>();
SubscribeLocalEvent<SmokeComponent, StartCollideEvent>(OnStartCollide); SubscribeLocalEvent<SmokeComponent, StartCollideEvent>(OnStartCollide);
SubscribeLocalEvent<SmokeComponent, EndCollideEvent>(OnEndCollide); SubscribeLocalEvent<SmokeComponent, EndCollideEvent>(OnEndCollide);
SubscribeLocalEvent<SmokeComponent, ReactionAttemptEvent>(OnReactionAttempt); SubscribeLocalEvent<SmokeComponent, ReactionAttemptEvent>(OnReactionAttempt);
@@ -165,12 +161,10 @@ public sealed partial class SmokeSystem : EntitySystem
// We have no more neighbours to spread to. So instead we will randomly distribute our volume to neighbouring smoke tiles. // We have no more neighbours to spread to. So instead we will randomly distribute our volume to neighbouring smoke tiles.
var smokeQuery = GetEntityQuery<SmokeComponent>();
_random.Shuffle(args.Neighbors); _random.Shuffle(args.Neighbors);
foreach (var neighbor in args.Neighbors) foreach (var neighbor in args.Neighbors)
{ {
if (!smokeQuery.TryGetComponent(neighbor, out var smoke)) if (!_smokeQuery.TryGetComponent(neighbor, out var smoke))
continue; continue;
smoke.SpreadAmount++; smoke.SpreadAmount++;
@@ -49,7 +49,7 @@ public sealed partial class SpraySystem : SharedSpraySystem
args.Handled = true; args.Handled = true;
var targetMapPos = _transform.GetMapCoordinates(GetEntityQuery<TransformComponent>().GetComponent(args.Target)); var targetMapPos = _transform.GetMapCoordinates(Transform(args.Target));
Spray(entity, targetMapPos, args.User); Spray(entity, targetMapPos, args.User);
} }
@@ -104,8 +104,7 @@ public sealed partial class SpraySystem : SharedSpraySystem
return; return;
} }
var xformQuery = GetEntityQuery<TransformComponent>(); var sprayerXform = Transform(entity);
var sprayerXform = xformQuery.GetComponent(entity);
var sprayerMapPos = _transform.GetMapCoordinates(sprayerXform); var sprayerMapPos = _transform.GetMapCoordinates(sprayerXform);
var clickMapPos = mapcoord; var clickMapPos = mapcoord;
@@ -149,7 +148,7 @@ public sealed partial class SpraySystem : SharedSpraySystem
// Spawn the vapor cloud onto the grid/map the user is present on. Offset the start position based on how far the target destination is. // Spawn the vapor cloud onto the grid/map the user is present on. Offset the start position based on how far the target destination is.
var vaporPos = sprayerMapPos.Offset(distance < 1 ? quarter : threeQuarters); var vaporPos = sprayerMapPos.Offset(distance < 1 ? quarter : threeQuarters);
var vapor = Spawn(entity.Comp.SprayedPrototype, vaporPos); var vapor = Spawn(entity.Comp.SprayedPrototype, vaporPos);
var vaporXform = xformQuery.GetComponent(vapor); var vaporXform = Transform(vapor);
_transform.SetWorldRotation(vaporXform, rotation); _transform.SetWorldRotation(vaporXform, rotation);
@@ -4,7 +4,6 @@ using System.Numerics;
using Content.Server.Administration.Managers; using Content.Server.Administration.Managers;
using Content.Server.Administration.Systems; using Content.Server.Administration.Systems;
using Content.Server.GameTicking.Events; using Content.Server.GameTicking.Events;
using Content.Server.Ghost;
using Content.Server.Spawners.Components; using Content.Server.Spawners.Components;
using Content.Server.Speech.Components; using Content.Server.Speech.Components;
using Content.Server.Station.Components; using Content.Server.Station.Components;
@@ -460,15 +459,13 @@ namespace Content.Server.GameTicking
_possiblePositions.Add(transform.Coordinates); _possiblePositions.Add(transform.Coordinates);
} }
var metaQuery = GetEntityQuery<MetaDataComponent>();
// Fallback to a random grid. // Fallback to a random grid.
if (_possiblePositions.Count == 0) if (_possiblePositions.Count == 0)
{ {
var query = AllEntityQuery<MapGridComponent>(); var query = AllEntityQuery<MapGridComponent>();
while (query.MoveNext(out var uid, out var grid)) while (query.MoveNext(out var uid, out var grid))
{ {
if (!metaQuery.TryGetComponent(uid, out var meta) || meta.EntityPaused || TerminatingOrDeleted(uid)) if (!TryComp(uid, out MetaDataComponent? meta) || meta.EntityPaused || TerminatingOrDeleted(uid))
{ {
continue; continue;
} }
@@ -507,7 +504,7 @@ namespace Content.Server.GameTicking
{ {
var mapUid = _map.GetMapOrInvalid(map); var mapUid = _map.GetMapOrInvalid(map);
if (!metaQuery.TryGetComponent(mapUid, out var meta) if (!TryComp(mapUid, out MetaDataComponent? meta)
|| meta.EntityPaused || meta.EntityPaused
|| TerminatingOrDeleted(mapUid)) || TerminatingOrDeleted(mapUid))
{ {
@@ -17,16 +17,15 @@ using Content.Shared.GameTicking.Components;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Mind.Components; using Content.Shared.Mind.Components;
using Content.Shared.Mindshield.Components;
using Content.Shared.Mobs; using Content.Shared.Mobs;
using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Systems;
using Content.Shared.NPC.Prototypes; using Content.Shared.NPC.Prototypes;
using Content.Shared.NPC.Systems; using Content.Shared.NPC.Systems;
using Content.Shared.Revolutionary;
using Content.Shared.Revolutionary.Components; using Content.Shared.Revolutionary.Components;
using Content.Shared.Roles.Components; using Content.Shared.Roles.Components;
using Content.Shared.Stunnable; using Content.Shared.Stunnable;
using Content.Shared.Zombies;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Content.Shared.Cuffs.Components; using Content.Shared.Cuffs.Components;
@@ -142,17 +141,20 @@ public sealed partial class RevolutionaryRuleSystem : GameRuleSystem<Revolutiona
if (!_mind.TryGetMind(ev.Target, out var mindId, out var mind) && !alwaysConvertible) if (!_mind.TryGetMind(ev.Target, out var mindId, out var mind) && !alwaysConvertible)
return; return;
if (HasComp<RevolutionaryComponent>(ev.Target) || if (!HasComp<HumanoidProfileComponent>(ev.Target) &&
HasComp<MindShieldComponent>(ev.Target) ||
!HasComp<HumanoidProfileComponent>(ev.Target) &&
!alwaysConvertible || !alwaysConvertible ||
!_mobState.IsAlive(ev.Target) || !_mobState.IsAlive(ev.Target) ||
HasComp<ZombieComponent>(ev.Target) ||
!HasComp<RevolutionaryConverterComponent>(ev.Used)) !HasComp<RevolutionaryConverterComponent>(ev.Used))
{ {
return; return;
} }
var attemptConvertEv = new AttemptConvertRevolutionaryEvent();
RaiseLocalEvent(ev.Target, ref attemptConvertEv);
if (attemptConvertEv.Cancelled)
return;
_npcFaction.AddFaction(ev.Target, RevolutionaryNpcFaction); _npcFaction.AddFaction(ev.Target, RevolutionaryNpcFaction);
var revComp = EnsureComp<RevolutionaryComponent>(ev.Target); var revComp = EnsureComp<RevolutionaryComponent>(ev.Target);
@@ -35,6 +35,7 @@ public sealed partial class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponen
[Dependency] private SharedRoleSystem _roles = default!; [Dependency] private SharedRoleSystem _roles = default!;
[Dependency] private StationSystem _station = default!; [Dependency] private StationSystem _station = default!;
[Dependency] private ZombieSystem _zombie = default!; [Dependency] private ZombieSystem _zombie = default!;
[Dependency] private EntityQuery<ZombieComponent> _zombieQuery = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -198,13 +199,12 @@ public sealed partial class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponen
} }
var players = AllEntityQuery<HumanoidProfileComponent, ActorComponent, MobStateComponent, TransformComponent>(); var players = AllEntityQuery<HumanoidProfileComponent, ActorComponent, MobStateComponent, TransformComponent>();
var zombers = GetEntityQuery<ZombieComponent>();
while (players.MoveNext(out var uid, out _, out _, out var mob, out var xform)) while (players.MoveNext(out var uid, out _, out _, out var mob, out var xform))
{ {
if (!_mobState.IsAlive(uid, mob)) if (!_mobState.IsAlive(uid, mob))
continue; continue;
if (zombers.HasComponent(uid)) if (_zombieQuery.HasComponent(uid))
continue; continue;
if (!includeOffStation && !stationGrids.Contains(xform.GridUid ?? EntityUid.Invalid)) if (!includeOffStation && !stationGrids.Contains(xform.GridUid ?? EntityUid.Invalid))
+2 -5
View File
@@ -68,8 +68,8 @@ namespace Content.Server.Ghost
[Dependency] private NameModifierSystem _nameMod = default!; [Dependency] private NameModifierSystem _nameMod = default!;
[Dependency] private GhostSpriteStateSystem _ghostState = default!; [Dependency] private GhostSpriteStateSystem _ghostState = default!;
private EntityQuery<GhostComponent> _ghostQuery; [Dependency] private EntityQuery<GhostComponent> _ghostQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery; [Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private static readonly ProtoId<TagPrototype> AllowGhostShownByEventTag = "AllowGhostShownByEvent"; private static readonly ProtoId<TagPrototype> AllowGhostShownByEventTag = "AllowGhostShownByEvent";
private static readonly ProtoId<DamageTypePrototype> AsphyxiationDamageType = "Asphyxiation"; private static readonly ProtoId<DamageTypePrototype> AsphyxiationDamageType = "Asphyxiation";
@@ -78,9 +78,6 @@ namespace Content.Server.Ghost
{ {
base.Initialize(); base.Initialize();
_ghostQuery = GetEntityQuery<GhostComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<GhostComponent, ComponentStartup>(OnGhostStartup); SubscribeLocalEvent<GhostComponent, ComponentStartup>(OnGhostStartup);
SubscribeLocalEvent<GhostComponent, MapInitEvent>(OnMapInit); SubscribeLocalEvent<GhostComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<GhostComponent, ComponentShutdown>(OnGhostShutdown); SubscribeLocalEvent<GhostComponent, ComponentShutdown>(OnGhostShutdown);
@@ -622,8 +622,7 @@ public sealed partial class GhostRoleSystem : EntitySystem
/// </summary> /// </summary>
public int GetGhostRoleCount() public int GetGhostRoleCount()
{ {
var metaQuery = GetEntityQuery<MetaDataComponent>(); return _ghostRoles.Count(pair => MetaData(pair.Value.Owner).EntityPaused == false);
return _ghostRoles.Count(pair => metaQuery.GetComponent(pair.Value.Owner).EntityPaused == false);
} }
/// <summary> /// <summary>
@@ -635,11 +634,10 @@ public sealed partial class GhostRoleSystem : EntitySystem
public GhostRoleInfo[] GetGhostRolesInfo(ICommonSession? player) public GhostRoleInfo[] GetGhostRolesInfo(ICommonSession? player)
{ {
var roles = new List<GhostRoleInfo>(); var roles = new List<GhostRoleInfo>();
var metaQuery = GetEntityQuery<MetaDataComponent>();
foreach (var (id, (uid, role)) in _ghostRoles) foreach (var (id, (uid, role)) in _ghostRoles)
{ {
if (metaQuery.GetComponent(uid).EntityPaused) if (MetaData(uid).EntityPaused)
continue; continue;
+1 -4
View File
@@ -32,8 +32,7 @@ namespace Content.Server.Hands.Systems
[Dependency] private SharedTransformSystem _transformSystem = default!; [Dependency] private SharedTransformSystem _transformSystem = default!;
[Dependency] private PullingSystem _pullingSystem = default!; [Dependency] private PullingSystem _pullingSystem = default!;
[Dependency] private ThrowingSystem _throwingSystem = default!; [Dependency] private ThrowingSystem _throwingSystem = default!;
[Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
/// <summary> /// <summary>
/// Items dropped when the holder falls down will be launched in /// Items dropped when the holder falls down will be launched in
@@ -57,8 +56,6 @@ namespace Content.Server.Hands.Systems
CommandBinds.Builder CommandBinds.Builder
.Bind(ContentKeyFunctions.ThrowItemInHand, new PointerInputCmdHandler(HandleThrowItem)) .Bind(ContentKeyFunctions.ThrowItemInHand, new PointerInputCmdHandler(HandleThrowItem))
.Register<HandsSystem>(); .Register<HandsSystem>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
} }
public override void Shutdown() public override void Shutdown()
+71 -38
View File
@@ -42,9 +42,7 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
[Dependency] private IGameTiming _timing = default!; [Dependency] private IGameTiming _timing = default!;
[Dependency] private PvsOverrideSystem _pvs = default!; [Dependency] private PvsOverrideSystem _pvs = default!;
[Dependency] private SharedPowerStateSystem _powerState = default!; [Dependency] private SharedPowerStateSystem _powerState = default!;
[Dependency] private MetaDataSystem _meta = default!;
private float _updateTimer = 1.0f;
private const float UpdateTime = 1.0f;
public override void Initialize() public override void Initialize()
{ {
@@ -79,10 +77,10 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
SubscribeLocalEvent<HolopadUserComponent, JumpToCoreEvent>(OnJumpToCore); SubscribeLocalEvent<HolopadUserComponent, JumpToCoreEvent>(OnJumpToCore);
SubscribeLocalEvent<HolopadComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleProjectorVerb); SubscribeLocalEvent<HolopadComponent, GetVerbsEvent<AlternativeVerb>>(AddToggleProjectorVerb);
SubscribeLocalEvent<HolopadComponent, EntRemovedFromContainerMessage>(OnAiRemove); SubscribeLocalEvent<HolopadComponent, EntRemovedFromContainerMessage>(OnAiRemove);
SubscribeLocalEvent<HolopadComponent, EntParentChangedMessage>(OnParentChanged); SubscribeLocalEvent<HolopadComponent, MapUidChangedEvent>(OnMapUidChanged);
SubscribeLocalEvent<HolopadComponent, PowerChangedEvent>(OnPowerChanged); SubscribeLocalEvent<HolopadComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<HolopadComponent, AnchorStateChangedEvent>(OnAnchorChanged);
SubscribeLocalEvent<HolopadUserComponent, MobStateChangedEvent>(OnMobStateChanged); SubscribeLocalEvent<HolopadUserComponent, MobStateChangedEvent>(OnMobStateChanged);
} }
#region: Holopad UI bound user interface messages #region: Holopad UI bound user interface messages
@@ -263,6 +261,8 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
SetHolopadAmbientState(holopad, this.IsPowered(holopad, EntityManager)); SetHolopadAmbientState(holopad, this.IsPowered(holopad, EntityManager));
break; break;
} }
UpdateUIState(holopad);
} }
private void OnHoloCallCommenced(Entity<HolopadComponent> source, ref TelephoneCallCommencedEvent args) private void OnHoloCallCommenced(Entity<HolopadComponent> source, ref TelephoneCallCommencedEvent args)
@@ -315,7 +315,7 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
if (receiverHolopad.Comp.Hologram == null) if (receiverHolopad.Comp.Hologram == null)
continue; continue;
_appearanceSystem.SetData(receiverHolopad.Comp.Hologram.Value.Owner, TypingIndicatorVisuals.State, ev.State); _appearanceSystem.SetData(receiverHolopad.Comp.Hologram.Value, TypingIndicatorVisuals.State, ev.State);
} }
} }
} }
@@ -328,6 +328,8 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
{ {
if (entity.Comp.User != null) if (entity.Comp.User != null)
LinkHolopadToUser(entity, entity.Comp.User.Value); LinkHolopadToUser(entity, entity.Comp.User.Value);
_meta.AddFlag(entity, MetaDataFlags.ExtraTransformEvents);
} }
private void OnHolopadUserInit(Entity<HolopadUserComponent> entity, ref ComponentInit args) private void OnHolopadUserInit(Entity<HolopadUserComponent> entity, ref ComponentInit args)
@@ -343,6 +345,7 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
ShutDownHolopad(entity); ShutDownHolopad(entity);
SetHolopadAmbientState(entity, false); SetHolopadAmbientState(entity, false);
UpdateAllUIStates();
} }
private void OnHolopadUserShutdown(Entity<HolopadUserComponent> entity, ref ComponentShutdown args) private void OnHolopadUserShutdown(Entity<HolopadUserComponent> entity, ref ComponentShutdown args)
@@ -444,15 +447,25 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
_telephoneSystem.EndTelephoneCalls((entity, entityTelephone)); _telephoneSystem.EndTelephoneCalls((entity, entityTelephone));
} }
private void OnParentChanged(Entity<HolopadComponent> entity, ref EntParentChangedMessage args) private void OnMapUidChanged(Entity<HolopadComponent> entity, ref MapUidChangedEvent args)
{ {
UpdateHolopadControlLockoutStartTime(entity); UpdateHolopadControlLockoutStartTime(entity);
UpdateAllUIStates();
} }
private void OnPowerChanged(Entity<HolopadComponent> entity, ref PowerChangedEvent args) private void OnPowerChanged(Entity<HolopadComponent> entity, ref PowerChangedEvent args)
{ {
if (args.Powered) if (args.Powered)
{
UpdateHolopadControlLockoutStartTime(entity); UpdateHolopadControlLockoutStartTime(entity);
}
UpdateAllUIStates();
}
private void OnAnchorChanged(Entity<HolopadComponent> entity, ref AnchorStateChangedEvent args)
{
UpdateAllUIStates();
} }
private void OnMobStateChanged(Entity<HolopadUserComponent> ent, ref MobStateChangedEvent args) private void OnMobStateChanged(Entity<HolopadUserComponent> ent, ref MobStateChangedEvent args)
@@ -472,27 +485,37 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
{ {
base.Update(frameTime); base.Update(frameTime);
_updateTimer += frameTime; var query = AllEntityQuery<HolopadUserComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var holopadUser, out var xform))
if (_updateTimer >= UpdateTime)
{ {
_updateTimer -= UpdateTime; if (HasComp<IgnoreUIRangeComponent>(uid))
continue;
var query = AllEntityQuery<HolopadComponent, TelephoneComponent, TransformComponent>(); foreach (var holopad in holopadUser.LinkedHolopads)
while (query.MoveNext(out var uid, out var holopad, out var telephone, out var xform))
{ {
UpdateUIState((uid, holopad), telephone); if (TryComp<TelephoneComponent>(holopad, out var telephone) &&
!_xformSystem.InRange((holopad.Owner, Transform(holopad)), (uid, xform), telephone.ListeningRange))
if (holopad.User != null &&
!HasComp<IgnoreUIRangeComponent>(holopad.User) &&
!_xformSystem.InRange((holopad.User.Value, Transform(holopad.User.Value)), (uid, xform), telephone.ListeningRange))
{ {
UnlinkHolopadFromUser((uid, holopad), holopad.User.Value); UnlinkHolopadFromUser(holopad, (uid, holopadUser));
} }
} }
} }
} }
public void UpdateAllUIStates()
{
var querySources = AllEntityQuery<HolopadComponent, TelephoneComponent, UserInterfaceComponent>();
while (querySources.MoveNext(out var uid, out var holopad, out var telephone, out var ui))
{
var uiKey = HasComp<StationAiCoreComponent>(uid) ? HolopadUiKey.AiActionWindow : HolopadUiKey.InteractionWindow;
if (!_userInterfaceSystem.IsUiOpen((uid, ui), uiKey))
continue;
UpdateUIState((uid, holopad), telephone);
}
}
public void UpdateUIState(Entity<HolopadComponent> entity, TelephoneComponent? telephone = null) public void UpdateUIState(Entity<HolopadComponent> entity, TelephoneComponent? telephone = null)
{ {
if (!Resolve(entity.Owner, ref telephone, false)) if (!Resolve(entity.Owner, ref telephone, false))
@@ -571,23 +594,26 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
return; return;
} }
if (!TryComp<HolopadUserComponent>(user, out var holopadUser)) var holopadUser = EnsureComp<HolopadUserComponent>(user.Value);
holopadUser = AddComp<HolopadUserComponent>(user.Value); var userEnt = (user.Value, holopadUser);
if (user != entity.Comp.User?.Owner) if (user != entity.Comp.User)
{ {
// Removes the old user from the holopad // Removes the old user from the holopad
UnlinkHolopadFromUser(entity, entity.Comp.User); if (TryComp<HolopadUserComponent>(entity.Comp.User, out var oldHolopadUser))
{
UnlinkHolopadFromUser(entity, (entity.Comp.User.Value, oldHolopadUser));
}
// Assigns the new user in their place // Assigns the new user in their place
holopadUser.LinkedHolopads.Add(entity); holopadUser?.LinkedHolopads.Add(entity);
entity.Comp.User = (user.Value, holopadUser); entity.Comp.User = user.Value;
} }
// Add the new user to PVS and sync their appearance with any // Add the new user to PVS and sync their appearance with any
// holopads connected to the one they are using // holopads connected to the one they are using
_pvs.AddGlobalOverride(user.Value); _pvs.AddGlobalOverride(user.Value);
SyncHolopadHologramAppearanceWithTarget(entity, entity.Comp.User); SyncHolopadHologramAppearanceWithTarget(entity, userEnt);
} }
private void UnlinkHolopadFromUser(Entity<HolopadComponent> entity, Entity<HolopadUserComponent>? user) private void UnlinkHolopadFromUser(Entity<HolopadComponent> entity, Entity<HolopadUserComponent>? user)
@@ -611,14 +637,14 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
{ {
foreach (var linkedHolopad in GetLinkedHolopads(entity)) foreach (var linkedHolopad in GetLinkedHolopads(entity))
{ {
if (linkedHolopad.Comp.Hologram == null) if (!TryComp<HolopadHologramComponent>(linkedHolopad.Comp.Hologram, out var holopadHologram))
continue; continue;
if (user == null) if (user == null)
_appearanceSystem.SetData(linkedHolopad.Comp.Hologram.Value.Owner, TypingIndicatorVisuals.State, false); _appearanceSystem.SetData(linkedHolopad.Comp.Hologram.Value, TypingIndicatorVisuals.State, false);
linkedHolopad.Comp.Hologram.Value.Comp.LinkedEntity = user; holopadHologram.LinkedEntity = user;
Dirty(linkedHolopad.Comp.Hologram.Value); Dirty(linkedHolopad.Comp.Hologram.Value, holopadHologram);
} }
} }
@@ -626,8 +652,8 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
{ {
entity.Comp.ControlLockoutOwner = null; entity.Comp.ControlLockoutOwner = null;
if (entity.Comp.Hologram != null) if (TryComp<HolopadHologramComponent>(entity.Comp.Hologram, out var holopadHologram))
DeleteHologram(entity.Comp.Hologram.Value, entity); DeleteHologram((entity.Comp.Hologram.Value, holopadHologram), entity);
// Check if the associated holopad user is an AI // Check if the associated holopad user is an AI
if (HasComp<StationAiHeldComponent>(entity.Comp.User) && if (HasComp<StationAiHeldComponent>(entity.Comp.User) &&
@@ -643,9 +669,9 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
_telephoneSystem.EndTelephoneCalls((stationAiCore.Owner, stationAiCoreTelephone)); _telephoneSystem.EndTelephoneCalls((stationAiCore.Owner, stationAiCoreTelephone));
} }
} }
else else if (TryComp<HolopadUserComponent>(entity.Comp.User, out var holopadUser))
{ {
UnlinkHolopadFromUser(entity, entity.Comp.User); UnlinkHolopadFromUser(entity, (entity.Comp.User.Value, holopadUser));
} }
Dirty(entity); Dirty(entity);
@@ -749,14 +775,16 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
// Lock out the controls of all involved holopads for a set duration // Lock out the controls of all involved holopads for a set duration
source.Comp.ControlLockoutOwner = user; source.Comp.ControlLockoutOwner = user;
source.Comp.ControlLockoutStartTime = _timing.CurTime; source.Comp.ControlLockoutEndTime = _timing.CurTime + source.Comp.ControlLockoutDuration;
source.Comp.ControlLockoutCoolDownEndTime = _timing.CurTime + source.Comp.ControlLockoutCoolDown;
Dirty(source); Dirty(source);
foreach (var receiver in GetLinkedHolopads(source)) foreach (var receiver in GetLinkedHolopads(source))
{ {
receiver.Comp.ControlLockoutOwner = user; receiver.Comp.ControlLockoutOwner = user;
receiver.Comp.ControlLockoutStartTime = _timing.CurTime; receiver.Comp.ControlLockoutEndTime = _timing.CurTime + source.Comp.ControlLockoutDuration;
receiver.Comp.ControlLockoutCoolDownEndTime = _timing.CurTime + source.Comp.ControlLockoutCoolDown;
Dirty(receiver); Dirty(receiver);
} }
@@ -796,15 +824,20 @@ public sealed partial class HolopadSystem : SharedHolopadSystem
if (!_telephoneSystem.IsSourceInRangeOfReceiver(sourceTelephoneEntity, receiverTelephoneEntity)) if (!_telephoneSystem.IsSourceInRangeOfReceiver(sourceTelephoneEntity, receiverTelephoneEntity))
continue; continue;
if (receiverHolopad.ControlLockoutStartTime > source.Comp.ControlLockoutStartTime) if (receiverHolopad.ControlLockoutEndTime > source.Comp.ControlLockoutEndTime ||
receiverHolopad.ControlLockoutCoolDownEndTime > source.Comp.ControlLockoutCoolDownEndTime)
{ {
source.Comp.ControlLockoutStartTime = receiverHolopad.ControlLockoutStartTime; source.Comp.ControlLockoutEndTime = receiverHolopad.ControlLockoutEndTime;
source.Comp.ControlLockoutCoolDownEndTime = receiverHolopad.ControlLockoutCoolDownEndTime;
isDirty = true; isDirty = true;
} }
} }
if (isDirty) if (isDirty)
{
Dirty(source); Dirty(source);
}
} }
private void SetHolopadAmbientState(Entity<HolopadComponent> entity, bool isEnabled) private void SetHolopadAmbientState(Entity<HolopadComponent> entity, bool isEnabled)
+11 -18
View File
@@ -1,7 +1,6 @@
using System.Linq; using System.Linq;
using Content.Server.Administration; using Content.Server.Administration;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Interaction;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Stunnable; using Content.Server.Stunnable;
using Content.Shared.Administration; using Content.Shared.Administration;
@@ -10,7 +9,6 @@ using Content.Shared.Database;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Instruments; using Content.Shared.Instruments;
using Content.Shared.Instruments.UI; using Content.Shared.Instruments.UI;
using Content.Shared.Physics;
using Content.Shared.Popups; using Content.Shared.Popups;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
@@ -19,9 +17,7 @@ using Robust.Shared.Collections;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Console; using Robust.Shared.Console;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Instruments; namespace Content.Server.Instruments;
@@ -36,7 +32,10 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
[Dependency] private PopupSystem _popup = default!; [Dependency] private PopupSystem _popup = default!;
[Dependency] private TransformSystem _transform = default!; [Dependency] private TransformSystem _transform = default!;
[Dependency] private ExamineSystemShared _examineSystem = default!; [Dependency] private ExamineSystemShared _examineSystem = default!;
[Dependency] private IAdminLogManager _admingLogSystem = default!; [Dependency] private IAdminLogManager _adminLogSystem = default!;
[Dependency] private EntityQuery<InstrumentComponent> _instrumentQuery = default!;
[Dependency] private EntityQuery<ActiveInstrumentComponent> _activeInstrumentQuery = default!;
private const float MaxInstrumentBandRange = 10f; private const float MaxInstrumentBandRange = 10f;
@@ -170,7 +169,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
.Where(t => t != null) .Where(t => t != null)
.Select(t => t!.ToString())); .Select(t => t!.ToString()));
_admingLogSystem.Add( _adminLogSystem.Add(
LogType.Instrument, LogType.Instrument,
LogImpact.Low, LogImpact.Low,
$"{ToPrettyString(args.SenderSession.AttachedEntity)} set the midi channels for {ToPrettyString(uid)} to {tracksString}"); $"{ToPrettyString(args.SenderSession.AttachedEntity)} set the midi channels for {ToPrettyString(uid)} to {tracksString}");
@@ -271,13 +270,10 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
public (NetEntity, string)[] GetBands(EntityUid uid) public (NetEntity, string)[] GetBands(EntityUid uid)
{ {
var metadataQuery = GetEntityQuery<MetaDataComponent>();
if (Deleted(uid)) if (Deleted(uid))
return Array.Empty<(NetEntity, string)>(); return Array.Empty<(NetEntity, string)>();
var list = new ValueList<(NetEntity, string)>(); var list = new ValueList<(NetEntity, string)>();
var instrumentQuery = GetEntityQuery<InstrumentComponent>();
if (!TryComp(uid, out InstrumentComponent? originInstrument) if (!TryComp(uid, out InstrumentComponent? originInstrument)
|| originInstrument.InstrumentPlayer is not {} originPlayer) || originInstrument.InstrumentPlayer is not {} originPlayer)
@@ -291,7 +287,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
continue; continue;
// Don't grab puppet instruments. // Don't grab puppet instruments.
if (!instrumentQuery.TryGetComponent(entity, out var instrument) || instrument.Master != null) if (!_instrumentQuery.TryGetComponent(entity, out var instrument) || instrument.Master != null)
continue; continue;
// We want to use the instrument player's name. // We want to use the instrument player's name.
@@ -303,8 +299,8 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
if (!_examineSystem.InRangeUnOccluded(uid, entity, MaxInstrumentBandRange, e => e == playerUid || e == originPlayer)) if (!_examineSystem.InRangeUnOccluded(uid, entity, MaxInstrumentBandRange, e => e == playerUid || e == originPlayer))
continue; continue;
if (!metadataQuery.TryGetComponent(playerUid, out var playerMetadata) if (!TryComp(playerUid, out MetaDataComponent? playerMetadata)
|| !metadataQuery.TryGetComponent(entity, out var metadata)) || !TryComp(entity, out MetaDataComponent? metadata))
continue; continue;
list.Add((GetNetEntity(entity), $"{playerMetadata.EntityName} - {metadata.EntityName}")); list.Add((GetNetEntity(entity), $"{playerMetadata.EntityName} - {metadata.EntityName}"));
@@ -427,9 +423,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
_bandRequestQueue.Clear(); _bandRequestQueue.Clear();
} }
var activeQuery = GetEntityQuery<ActiveInstrumentComponent>();
var transformQuery = GetEntityQuery<TransformComponent>();
var query = AllEntityQuery<ActiveInstrumentComponent, InstrumentComponent>(); var query = AllEntityQuery<ActiveInstrumentComponent, InstrumentComponent>();
while (query.MoveNext(out var uid, out _, out var instrument)) while (query.MoveNext(out var uid, out _, out var instrument))
{ {
@@ -441,15 +434,15 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
continue; continue;
} }
var masterActive = activeQuery.CompOrNull(master); _activeInstrumentQuery.TryComp(master, out var masterActive);
if (masterActive == null) if (masterActive == null)
{ {
Clean(uid, instrument); Clean(uid, instrument);
continue; continue;
} }
var trans = transformQuery.GetComponent(uid); var trans = Transform(uid);
var masterTrans = transformQuery.GetComponent(master); var masterTrans = Transform(master);
if (!_transform.InRange(masterTrans.Coordinates, trans.Coordinates, 10f)) if (!_transform.InRange(masterTrans.Coordinates, trans.Coordinates, 10f))
{ {
Clean(uid, instrument); Clean(uid, instrument);
@@ -1,5 +1,4 @@
using System.Linq; using System.Linq;
using Content.Server.Light.Components;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Light.EntitySystems; using Content.Shared.Light.EntitySystems;
@@ -7,7 +6,6 @@ using Content.Shared.Light.Components;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Storage; using Content.Shared.Storage;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -44,10 +42,9 @@ public sealed partial class LightReplacerSystem : SharedLightReplacerSystem
args.PushMarkup(Loc.GetString("comp-light-replacer-has-lights")); args.PushMarkup(Loc.GetString("comp-light-replacer-has-lights"));
var groups = new Dictionary<string, int>(); var groups = new Dictionary<string, int>();
var metaQuery = GetEntityQuery<MetaDataComponent>();
foreach (var bulb in component.InsertedBulbs.ContainedEntities) foreach (var bulb in component.InsertedBulbs.ContainedEntities)
{ {
var metaData = metaQuery.GetComponent(bulb); var metaData = MetaData(bulb);
groups[metaData.EntityName] = groups.GetValueOrDefault(metaData.EntityName) + 1; groups[metaData.EntityName] = groups.GetValueOrDefault(metaData.EntityName) + 1;
} }
@@ -8,13 +8,11 @@ namespace Content.Server.Light.EntitySystems;
public sealed partial class RoofSystem : SharedRoofSystem public sealed partial class RoofSystem : SharedRoofSystem
{ {
[Dependency] private SharedMapSystem _maps = default!; [Dependency] private SharedMapSystem _maps = default!;
[Dependency] private EntityQuery<MapGridComponent> _mapGridQuery = default!;
private EntityQuery<MapGridComponent> _gridQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_gridQuery = GetEntityQuery<MapGridComponent>();
SubscribeLocalEvent<SetRoofComponent, ComponentStartup>(OnFlagStartup); SubscribeLocalEvent<SetRoofComponent, ComponentStartup>(OnFlagStartup);
} }
@@ -22,7 +20,7 @@ public sealed partial class RoofSystem : SharedRoofSystem
{ {
var xform = Transform(ent.Owner); var xform = Transform(ent.Owner);
if (_gridQuery.TryComp(xform.GridUid, out var grid)) if (_mapGridQuery.TryComp(xform.GridUid, out var grid))
{ {
var index = _maps.LocalToTile(xform.GridUid.Value, grid, xform.Coordinates); var index = _maps.LocalToTile(xform.GridUid.Value, grid, xform.Coordinates);
SetRoof((xform.GridUid.Value, grid, null), index, ent.Comp.Value); SetRoof((xform.GridUid.Value, grid, null), index, ent.Comp.Value);
-73
View File
@@ -1,73 +0,0 @@
using Content.Shared.Hands;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.IdentityManagement;
using Content.Shared.Item;
using Content.Shared.Lube;
using Content.Shared.NameModifier.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Throwing;
using Robust.Shared.Random;
namespace Content.Server.Lube;
public sealed partial class LubedSystem : EntitySystem
{
[Dependency] private ThrowingSystem _throwing = default!;
[Dependency] private IRobustRandom _random = default!;
[Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private SharedPopupSystem _popup = default!;
[Dependency] private NameModifierSystem _nameMod = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LubedComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<LubedComponent, BeforeGettingEquippedHandEvent>(OnHandPickUp);
SubscribeLocalEvent<LubedComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
}
private void OnInit(EntityUid uid, LubedComponent component, ComponentInit args)
{
_nameMod.RefreshNameModifiers(uid);
}
/// <remarks>
/// Note to whoever makes this predicted—there is a mispredict here that
/// would be nice to keep! If this is in shared, the client will predict
/// this and not run the pickup animation in <see cref="SharedHandsSystem"/>
/// which would (probably) make this effect look less funny. You will
/// probably want to either tweak <see cref="BeforeGettingEquippedHandEvent"/>
/// to be able to cancel but still run the animation or something—we do want
/// the event to run before the animation for stuff like
/// <see cref="MultiHandedItemSystem.OnBeforeEquipped"/>.
/// </remarks>
private void OnHandPickUp(Entity<LubedComponent> ent, ref BeforeGettingEquippedHandEvent args)
{
if (args.Cancelled)
return;
if (ent.Comp.SlipsLeft <= 0)
{
RemComp<LubedComponent>(ent);
_nameMod.RefreshNameModifiers(ent.Owner);
return;
}
ent.Comp.SlipsLeft--;
args.Cancelled = true;
_transform.SetCoordinates(ent, Transform(args.User).Coordinates);
_transform.AttachToGridOrMap(ent);
_throwing.TryThrow(ent, _random.NextVector2(), ent.Comp.SlipStrength);
_popup.PopupEntity(Loc.GetString("lube-slip", ("target", Identity.Entity(ent, EntityManager))),
args.User,
args.User,
PopupType.MediumCaution);
}
private void OnRefreshNameModifiers(Entity<LubedComponent> entity, ref RefreshNameModifiersEvent args)
{
args.AddModifier("lubed-name-prefix");
}
}
@@ -5,6 +5,7 @@ using Content.Server.Roles;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Implants; using Content.Shared.Implants;
using Content.Shared.Mindshield.Components; using Content.Shared.Mindshield.Components;
using Content.Shared.Revolutionary;
using Content.Shared.Revolutionary.Components; using Content.Shared.Revolutionary.Components;
using Content.Shared.Roles.Components; using Content.Shared.Roles.Components;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -28,6 +29,7 @@ public sealed partial class MindShieldSystem : EntitySystem
SubscribeLocalEvent<MindShieldImplantComponent, ImplantImplantedEvent>(OnImplantImplanted); SubscribeLocalEvent<MindShieldImplantComponent, ImplantImplantedEvent>(OnImplantImplanted);
SubscribeLocalEvent<MindShieldImplantComponent, ImplantRemovedEvent>(OnImplantRemoved); SubscribeLocalEvent<MindShieldImplantComponent, ImplantRemovedEvent>(OnImplantRemoved);
SubscribeLocalEvent<MindShieldComponent, AttemptConvertRevolutionaryEvent>(OnAttemptConvert);
} }
private void OnImplantImplanted(Entity<MindShieldImplantComponent> ent, ref ImplantImplantedEvent ev) private void OnImplantImplanted(Entity<MindShieldImplantComponent> ent, ref ImplantImplantedEvent ev)
@@ -59,5 +61,10 @@ public sealed partial class MindShieldSystem : EntitySystem
{ {
RemComp<MindShieldComponent>(args.Implanted); RemComp<MindShieldComponent>(args.Implanted);
} }
private void OnAttemptConvert(Entity<MindShieldComponent> ent, ref AttemptConvertRevolutionaryEvent args)
{
args.Cancelled = true;
}
} }
@@ -6,14 +6,13 @@ using Robust.Shared.Player;
namespace Content.Server.Movement.Systems; namespace Content.Server.Movement.Systems;
public sealed class MobCollisionSystem : SharedMobCollisionSystem public sealed partial class MobCollisionSystem : SharedMobCollisionSystem
{ {
private EntityQuery<ActorComponent> _actorQuery; [Dependency] private EntityQuery<ActorComponent> _actorQuery = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_actorQuery = GetEntityQuery<ActorComponent>();
SubscribeLocalEvent<MobCollisionComponent, MobCollisionMessage>(OnServerMobCollision); SubscribeLocalEvent<MobCollisionComponent, MobCollisionMessage>(OnServerMobCollision);
} }
@@ -7,9 +7,7 @@ using Content.Shared.Gravity;
using Content.Shared.Input; using Content.Shared.Input;
using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Events; using Content.Shared.Movement.Pulling.Events;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Rotatable; using Content.Shared.Rotatable;
using Robust.Server.Physics;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Input.Binding; using Robust.Shared.Input.Binding;
using Robust.Shared.Map; using Robust.Shared.Map;
@@ -61,6 +59,10 @@ public sealed partial class PullController : VirtualController
[Dependency] private SharedGravitySystem _gravity = default!; [Dependency] private SharedGravitySystem _gravity = default!;
[Dependency] private SharedTransformSystem _transformSystem = default!; [Dependency] private SharedTransformSystem _transformSystem = default!;
[Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
[Dependency] private EntityQuery<PullableComponent> _pullableQuery = default!;
[Dependency] private EntityQuery<PullerComponent> _pullerQuery = default!;
/// <summary> /// <summary>
/// If distance between puller and pulled entity lower that this threshold, /// If distance between puller and pulled entity lower that this threshold,
/// pulled entity will not change its rotation. /// pulled entity will not change its rotation.
@@ -76,22 +78,12 @@ public sealed partial class PullController : VirtualController
/// </summary> /// </summary>
private const float ThresholdRotAngle = 22.5f; private const float ThresholdRotAngle = 22.5f;
private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<PullableComponent> _pullableQuery;
private EntityQuery<PullerComponent> _pullerQuery;
private EntityQuery<TransformComponent> _xformQuery;
public override void Initialize() public override void Initialize()
{ {
CommandBinds.Builder CommandBinds.Builder
.Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject)) .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject))
.Register<PullController>(); .Register<PullController>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_pullableQuery = GetEntityQuery<PullableComponent>();
_pullerQuery = GetEntityQuery<PullerComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
UpdatesAfter.Add(typeof(MoverController)); UpdatesAfter.Add(typeof(MoverController));
SubscribeLocalEvent<PullMovingComponent, PullStoppedMessage>(OnPullStop); SubscribeLocalEvent<PullMovingComponent, PullStoppedMessage>(OnPullStop);
SubscribeLocalEvent<ActivePullerComponent, MoveEvent>(OnPullerMove); SubscribeLocalEvent<ActivePullerComponent, MoveEvent>(OnPullerMove);
@@ -202,8 +194,8 @@ public sealed partial class PullController : VirtualController
if (!rotatable.RotateWhilePulling) if (!rotatable.RotateWhilePulling)
return; return;
var pulledXform = _xformQuery.GetComponent(pulled); var pulledXform = Transform(pulled);
var pullerXform = _xformQuery.GetComponent(puller); var pullerXform = Transform(puller);
var pullerData = TransformSystem.GetWorldPositionRotation(pullerXform); var pullerData = TransformSystem.GetWorldPositionRotation(pullerXform);
var pulledData = TransformSystem.GetWorldPositionRotation(pulledXform); var pulledData = TransformSystem.GetWorldPositionRotation(pulledXform);
@@ -245,7 +237,7 @@ public sealed partial class PullController : VirtualController
if (pullable.Puller is not {Valid: true} puller) if (pullable.Puller is not {Valid: true} puller)
continue; continue;
var pullerXform = _xformQuery.Get(puller); var pullerXform = Transform(puller);
var pullerPosition = TransformSystem.GetMapCoordinates(pullerXform); var pullerPosition = TransformSystem.GetMapCoordinates(pullerXform);
var movingTo = TransformSystem.ToMapCoordinates(mover.MovingTo); var movingTo = TransformSystem.ToMapCoordinates(mover.MovingTo);
@@ -305,7 +297,7 @@ public sealed partial class PullController : VirtualController
// if the puller is weightless or can't move, then we apply the inverse impulse (Newton's third law). // if the puller is weightless or can't move, then we apply the inverse impulse (Newton's third law).
// doing it under gravity produces an unsatisfying wiggling when pulling. // doing it under gravity produces an unsatisfying wiggling when pulling.
// If player can't move, assume they are on a chair and we need to prevent pull-moving. // If player can't move, assume they are on a chair and we need to prevent pull-moving.
if (_gravity.IsWeightless(puller) && pullerXform.Comp.GridUid == null || !_actionBlockerSystem.CanMove(puller)) if (_gravity.IsWeightless(puller) && pullerXform.GridUid == null || !_actionBlockerSystem.CanMove(puller))
{ {
PhysicsSystem.WakeBody(puller); PhysicsSystem.WakeBody(puller);
PhysicsSystem.ApplyLinearImpulse(puller, -impulse); PhysicsSystem.ApplyLinearImpulse(puller, -impulse);
@@ -40,6 +40,6 @@ public sealed partial class WieldedPrecondition : HTNPrecondition
return false; return false;
var wieldableSystem = _entManager.System<SharedWieldableSystem>(); var wieldableSystem = _entManager.System<SharedWieldableSystem>();
return wieldableSystem.CanWield(heldEntity.Value, wieldable, owner, quiet: true); return wieldableSystem.CanWield((heldEntity.Value, wieldable), owner, quiet: true);
} }
} }
@@ -38,7 +38,7 @@ public sealed partial class WieldOperator : HTNOperator
if (wieldable.Wielded) if (wieldable.Wielded)
return HTNOperatorStatus.Failed; return HTNOperatorStatus.Failed;
return wieldableSystem.TryWield(weaponUid.Value, wieldable, owner) return wieldableSystem.TryWield((weaponUid.Value, wieldable), owner)
? HTNOperatorStatus.Finished ? HTNOperatorStatus.Finished
: HTNOperatorStatus.Failed; : HTNOperatorStatus.Failed;
} }
@@ -46,7 +46,7 @@ public sealed partial class WieldOperator : HTNOperator
if (!wieldable.Wielded) if (!wieldable.Wielded)
return HTNOperatorStatus.Failed; return HTNOperatorStatus.Failed;
return wieldableSystem.TryUnwield(weaponUid.Value, wieldable, owner) return wieldableSystem.TryUnwield((weaponUid.Value, wieldable), owner)
? HTNOperatorStatus.Finished ? HTNOperatorStatus.Finished
: HTNOperatorStatus.Failed; : HTNOperatorStatus.Failed;
} }
@@ -96,7 +96,7 @@ public sealed partial class PathfindingSystem
// TODO: Dump all this shit and just do it live it's probably fast enough. // TODO: Dump all this shit and just do it live it's probably fast enough.
if (comp.DirtyChunks.Count == 0 || if (comp.DirtyChunks.Count == 0 ||
curTime < comp.NextUpdate || curTime < comp.NextUpdate ||
!_gridQuery.TryGetComponent(uid, out var mapGridComp)) !_mapGridQuery.TryGetComponent(uid, out var mapGridComp))
{ {
continue; continue;
} }
@@ -272,7 +272,7 @@ public sealed partial class PathfindingSystem
{ {
if (!_fixturesQuery.TryGetComponent(ev.Sender, out var fixtures) || if (!_fixturesQuery.TryGetComponent(ev.Sender, out var fixtures) ||
!IsBodyRelevant(fixtures) || !IsBodyRelevant(fixtures) ||
_gridQuery.HasComponent(ev.Sender)) _mapGridQuery.HasComponent(ev.Sender))
{ {
return; return;
} }
@@ -441,7 +441,7 @@ public sealed partial class PathfindingSystem
continue; continue;
} }
var xform = _xformQuery.GetComponent(ent); var xform = Transform(ent);
if (xform.ParentUid != grid.Owner || if (xform.ParentUid != grid.Owner ||
_maps.LocalToTile(grid.Owner, grid.Comp, xform.Coordinates) != tilePos) _maps.LocalToTile(grid.Owner, grid.Comp, xform.Coordinates) != tilePos)
@@ -494,7 +494,7 @@ public sealed partial class PathfindingSystem
} }
if (!intersects || if (!intersects ||
!_xformQuery.TryGetComponent(ent, out var xform)) !TryComp(ent, out TransformComponent? xform))
{ {
continue; continue;
} }
@@ -513,7 +513,7 @@ public sealed partial class PathfindingSystem
if (!colliding) if (!colliding)
continue; continue;
if (_accessQuery.HasComponent(ent)) if (_accessReaderQuery.HasComponent(ent))
{ {
flags |= PathfindingBreadcrumbFlag.Access; flags |= PathfindingBreadcrumbFlag.Access;
} }
@@ -53,6 +53,13 @@ namespace Content.Server.NPC.Pathfinding
[Dependency] private SharedPhysicsSystem _physics = default!; [Dependency] private SharedPhysicsSystem _physics = default!;
[Dependency] private SharedTransformSystem _transform = default!; [Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private EntityQuery<AccessReaderComponent> _accessReaderQuery = default!;
[Dependency] private EntityQuery<DestructibleComponent> _destructibleQuery = default!;
[Dependency] private EntityQuery<DoorComponent> _doorQuery = default!;
[Dependency] private EntityQuery<ClimbableComponent> _climbableQuery = default!;
[Dependency] private EntityQuery<FixturesComponent> _fixturesQuery = default!;
[Dependency] private EntityQuery<MapGridComponent> _mapGridQuery = default!;
private readonly Dictionary<ICommonSession, PathfindingDebugMode> _subscribedSessions = new(); private readonly Dictionary<ICommonSession, PathfindingDebugMode> _subscribedSessions = new();
[ViewVariables] [ViewVariables]
@@ -68,26 +75,9 @@ namespace Content.Server.NPC.Pathfinding
private int _portalIndex; private int _portalIndex;
private readonly Dictionary<int, PathPortal> _portals = new(); private readonly Dictionary<int, PathPortal> _portals = new();
private EntityQuery<AccessReaderComponent> _accessQuery;
private EntityQuery<DestructibleComponent> _destructibleQuery;
private EntityQuery<DoorComponent> _doorQuery;
private EntityQuery<ClimbableComponent> _climbableQuery;
private EntityQuery<FixturesComponent> _fixturesQuery;
private EntityQuery<MapGridComponent> _gridQuery;
private EntityQuery<TransformComponent> _xformQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_accessQuery = GetEntityQuery<AccessReaderComponent>();
_destructibleQuery = GetEntityQuery<DestructibleComponent>();
_doorQuery = GetEntityQuery<DoorComponent>();
_climbableQuery = GetEntityQuery<ClimbableComponent>();
_fixturesQuery = GetEntityQuery<FixturesComponent>();
_gridQuery = GetEntityQuery<MapGridComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
_playerManager.PlayerStatusChanged += OnPlayerChange; _playerManager.PlayerStatusChanged += OnPlayerChange;
InitializeGrid(); InitializeGrid();
SubscribeNetworkEvent<RequestPathfindingDebugMessage>(OnBreadcrumbs); SubscribeNetworkEvent<RequestPathfindingDebugMessage>(OnBreadcrumbs);
@@ -3,7 +3,6 @@ using Content.Server.NPC.Components;
using Content.Shared.CombatMode; using Content.Shared.CombatMode;
using Content.Shared.NPC; using Content.Shared.NPC;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random; using Robust.Shared.Random;
namespace Content.Server.NPC.Systems; namespace Content.Server.NPC.Systems;
@@ -38,25 +37,22 @@ public sealed partial class NPCCombatSystem
private void UpdateMelee(float frameTime) private void UpdateMelee(float frameTime)
{ {
var combatQuery = GetEntityQuery<CombatModeComponent>();
var xformQuery = GetEntityQuery<TransformComponent>();
var physicsQuery = GetEntityQuery<PhysicsComponent>();
var curTime = _timing.CurTime; var curTime = _timing.CurTime;
var query = EntityQueryEnumerator<NPCMeleeCombatComponent, ActiveNPCComponent>(); var query = EntityQueryEnumerator<NPCMeleeCombatComponent, ActiveNPCComponent>();
while (query.MoveNext(out var uid, out var comp, out _)) while (query.MoveNext(out var uid, out var comp, out _))
{ {
if (!combatQuery.TryGetComponent(uid, out var combat) || !combat.IsInCombatMode) if (!_combatQuery.TryGetComponent(uid, out var combat) || !combat.IsInCombatMode)
{ {
RemComp<NPCMeleeCombatComponent>(uid); RemComp<NPCMeleeCombatComponent>(uid);
continue; continue;
} }
Attack(uid, comp, curTime, physicsQuery, xformQuery); Attack(uid, comp, curTime);
} }
} }
private void Attack(EntityUid uid, NPCMeleeCombatComponent component, TimeSpan curTime, EntityQuery<PhysicsComponent> physicsQuery, EntityQuery<TransformComponent> xformQuery) private void Attack(EntityUid uid, NPCMeleeCombatComponent component, TimeSpan curTime)
{ {
component.Status = CombatStatus.Normal; component.Status = CombatStatus.Normal;
@@ -66,8 +62,8 @@ public sealed partial class NPCCombatSystem
return; return;
} }
if (!xformQuery.TryGetComponent(uid, out var xform) || if (!TryComp(uid, out TransformComponent? xform) ||
!xformQuery.TryGetComponent(component.Target, out var targetXform)) !TryComp(component.Target, out TransformComponent? targetXform))
{ {
component.Status = CombatStatus.TargetUnreachable; component.Status = CombatStatus.TargetUnreachable;
return; return;
@@ -105,7 +101,7 @@ public sealed partial class NPCCombatSystem
return; return;
if (_random.Prob(component.MissChance) && if (_random.Prob(component.MissChance) &&
physicsQuery.TryGetComponent(component.Target, out var targetPhysics) && _physicsQuery.TryGetComponent(component.Target, out var targetPhysics) &&
targetPhysics.LinearVelocity.LengthSquared() != 0f) targetPhysics.LinearVelocity.LengthSquared() != 0f)
{ {
_melee.AttemptLightAttackMiss(uid, weaponUid, weapon, targetXform.Coordinates.Offset(_random.NextVector2(0.5f))); _melee.AttemptLightAttackMiss(uid, weaponUid, weapon, targetXform.Coordinates.Offset(_random.NextVector2(0.5f)));
@@ -14,11 +14,11 @@ public sealed partial class NPCCombatSystem
[Dependency] private SharedCombatModeSystem _combat = default!; [Dependency] private SharedCombatModeSystem _combat = default!;
[Dependency] private RotateToFaceSystem _rotate = default!; [Dependency] private RotateToFaceSystem _rotate = default!;
private EntityQuery<CombatModeComponent> _combatQuery; [Dependency] private EntityQuery<CombatModeComponent> _combatQuery = default!;
private EntityQuery<NPCSteeringComponent> _steeringQuery; [Dependency] private EntityQuery<NPCSteeringComponent> _steeringQuery = default!;
private EntityQuery<RechargeBasicEntityAmmoComponent> _rechargeQuery; [Dependency] private EntityQuery<RechargeBasicEntityAmmoComponent> _rechargeQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery; [Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private EntityQuery<TransformComponent> _xformQuery; [Dependency] private EntityQuery<TransformComponent> _xformQuery = default!;
// TODO: Don't predict for hitscan // TODO: Don't predict for hitscan
private const float ShootSpeed = 20f; private const float ShootSpeed = 20f;
@@ -30,12 +30,6 @@ public sealed partial class NPCCombatSystem
private void InitializeRanged() private void InitializeRanged()
{ {
_combatQuery = GetEntityQuery<CombatModeComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_rechargeQuery = GetEntityQuery<RechargeBasicEntityAmmoComponent>();
_steeringQuery = GetEntityQuery<NPCSteeringComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
SubscribeLocalEvent<NPCRangedCombatComponent, ComponentStartup>(OnRangedStartup); SubscribeLocalEvent<NPCRangedCombatComponent, ComponentStartup>(OnRangedStartup);
SubscribeLocalEvent<NPCRangedCombatComponent, ComponentShutdown>(OnRangedShutdown); SubscribeLocalEvent<NPCRangedCombatComponent, ComponentShutdown>(OnRangedShutdown);
} }
+3 -11
View File
@@ -1,14 +1,10 @@
using System.Numerics; using System.Numerics;
using Content.Server.NPC.Components; using Content.Server.NPC.Components;
using Content.Server.NPC.Events; using Content.Server.NPC.Events;
using Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
using Content.Server.Weapons.Melee; using Content.Server.Weapons.Melee;
using Content.Shared.NPC; using Content.Shared.NPC;
using Content.Shared.Weapons.Melee;
using Robust.Shared.Collections;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -23,17 +19,13 @@ public sealed partial class NPCJukeSystem : EntitySystem
[Dependency] private SharedMapSystem _mapSystem = default!; [Dependency] private SharedMapSystem _mapSystem = default!;
[Dependency] private SharedTransformSystem _transform = default!; [Dependency] private SharedTransformSystem _transform = default!;
private EntityQuery<NPCMeleeCombatComponent> _npcMeleeQuery; [Dependency] private EntityQuery<NPCMeleeCombatComponent> _npcMeleeQuery = default!;
private EntityQuery<NPCRangedCombatComponent> _npcRangedQuery; [Dependency] private EntityQuery<NPCRangedCombatComponent> _npcRangedQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery; [Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_npcMeleeQuery = GetEntityQuery<NPCMeleeCombatComponent>();
_npcRangedQuery = GetEntityQuery<NPCRangedCombatComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<NPCJukeComponent, NPCSteeringEvent>(OnJukeSteering); SubscribeLocalEvent<NPCJukeComponent, NPCSteeringEvent>(OnJukeSteering);
} }
@@ -1,18 +1,15 @@
using Content.Server.Destructible; using Content.Server.Destructible;
using Content.Server.NPC.Components; using Content.Server.NPC.Components;
using Content.Server.NPC.Pathfinding; using Content.Server.NPC.Pathfinding;
using Content.Shared.Climbing;
using Content.Shared.CombatMode; using Content.Shared.CombatMode;
using Content.Shared.DoAfter; using Content.Shared.DoAfter;
using Content.Shared.Doors.Components; using Content.Shared.Doors.Components;
using Content.Shared.NPC; using Content.Shared.NPC;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics; using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using ClimbableComponent = Content.Shared.Climbing.Components.ClimbableComponent; using ClimbableComponent = Content.Shared.Climbing.Components.ClimbableComponent;
using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent; using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent;
using Robust.Shared.Random;
namespace Content.Server.NPC.Systems; namespace Content.Server.NPC.Systems;
@@ -37,6 +34,9 @@ public sealed partial class NPCSteeringSystem
* Also need to make sure it picks nearest obstacle path so it starts smashing in front of it. * Also need to make sure it picks nearest obstacle path so it starts smashing in front of it.
*/ */
[Dependency] private EntityQuery<DoorComponent> _doorQuery = default!;
[Dependency] private EntityQuery<ClimbableComponent> _climbableQuery = default!;
[Dependency] private EntityQuery<DestructibleComponent> _destructibleQuery = default!;
private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponent component, PathPoly poly) private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponent component, PathPoly poly)
{ {
@@ -84,12 +84,10 @@ public sealed partial class NPCSteeringSystem
// Just walk into it stupid // Just walk into it stupid
if (isDoor && !isAccessRequired) if (isDoor && !isAccessRequired)
{ {
var doorQuery = GetEntityQuery<DoorComponent>();
// ... At least if it's not a bump open. // ... At least if it's not a bump open.
foreach (var ent in obstacleEnts) foreach (var ent in obstacleEnts)
{ {
if (!doorQuery.TryGetComponent(ent, out var door)) if (!_doorQuery.TryGetComponent(ent, out var door))
continue; continue;
if (!door.BumpOpen && (component.Flags & PathFlags.Interact) != 0x0) if (!door.BumpOpen && (component.Flags & PathFlags.Interact) != 0x0)
@@ -107,12 +105,10 @@ public sealed partial class NPCSteeringSystem
if ((component.Flags & PathFlags.Prying) != 0x0 && isDoor) if ((component.Flags & PathFlags.Prying) != 0x0 && isDoor)
{ {
var doorQuery = GetEntityQuery<DoorComponent>();
// Get the relevant obstacle // Get the relevant obstacle
foreach (var ent in obstacleEnts) foreach (var ent in obstacleEnts)
{ {
if (doorQuery.TryGetComponent(ent, out var door) && door.State != DoorState.Open) if (_doorQuery.TryGetComponent(ent, out var door) && door.State != DoorState.Open)
{ {
// TODO: Use the verb. // TODO: Use the verb.
@@ -141,12 +137,10 @@ public sealed partial class NPCSteeringSystem
return SteeringObstacleStatus.Continuing; return SteeringObstacleStatus.Continuing;
} }
var climbableQuery = GetEntityQuery<ClimbableComponent>();
// Get the relevant obstacle // Get the relevant obstacle
foreach (var ent in obstacleEnts) foreach (var ent in obstacleEnts)
{ {
if (climbableQuery.TryGetComponent(ent, out var table) && if (_climbableQuery.TryGetComponent(ent, out var table) &&
_climb.CanVault(table, uid, uid, out _) && _climb.CanVault(table, uid, uid, out _) &&
_climb.TryClimb(uid, uid, ent, out id, table, climbing)) _climb.TryClimb(uid, uid, ent, out id, table, climbing))
{ {
@@ -165,8 +159,6 @@ public sealed partial class NPCSteeringSystem
if (_melee.TryGetWeapon(uid, out _, out var meleeWeapon) && meleeWeapon.NextAttack <= _timing.CurTime && TryComp<CombatModeComponent>(uid, out var combatMode)) if (_melee.TryGetWeapon(uid, out _, out var meleeWeapon) && meleeWeapon.NextAttack <= _timing.CurTime && TryComp<CombatModeComponent>(uid, out var combatMode))
{ {
_combat.SetInCombatMode(uid, true, combatMode); _combat.SetInCombatMode(uid, true, combatMode);
var destructibleQuery = GetEntityQuery<DestructibleComponent>();
// TODO: This is a hack around grilles and windows. // TODO: This is a hack around grilles and windows.
_random.Shuffle(obstacleEnts); _random.Shuffle(obstacleEnts);
var attackResult = false; var attackResult = false;
@@ -174,7 +166,7 @@ public sealed partial class NPCSteeringSystem
foreach (var ent in obstacleEnts) foreach (var ent in obstacleEnts)
{ {
// TODO: Validate we can damage it // TODO: Validate we can damage it
if (destructibleQuery.HasComponent(ent)) if (_destructibleQuery.HasComponent(ent))
{ {
attackResult = _melee.AttemptLightAttack(uid, uid, meleeWeapon, ent); attackResult = _melee.AttemptLightAttack(uid, uid, meleeWeapon, ent);
break; break;
@@ -68,11 +68,11 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
[Dependency] private SharedTransformSystem _transform = default!; [Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private SharedCombatModeSystem _combat = default!; [Dependency] private SharedCombatModeSystem _combat = default!;
private EntityQuery<FixturesComponent> _fixturesQuery; [Dependency] private EntityQuery<FixturesComponent> _fixturesQuery = default!;
private EntityQuery<MovementSpeedModifierComponent> _modifierQuery; [Dependency] private EntityQuery<MovementSpeedModifierComponent> _modifierQuery = default!;
private EntityQuery<NpcFactionMemberComponent> _factionQuery; [Dependency] private EntityQuery<NpcFactionMemberComponent> _factionQuery = default!;
private EntityQuery<PhysicsComponent> _physicsQuery; [Dependency] private EntityQuery<PhysicsComponent> _physicsQuery = default!;
private EntityQuery<TransformComponent> _xformQuery; [Dependency] private EntityQuery<TransformComponent> _xformQuery = default!;
private ObjectPool<HashSet<EntityUid>> _entSetPool = private ObjectPool<HashSet<EntityUid>> _entSetPool =
new DefaultObjectPool<HashSet<EntityUid>>(new SetPolicy<EntityUid>()); new DefaultObjectPool<HashSet<EntityUid>>(new SetPolicy<EntityUid>());
@@ -99,11 +99,6 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
base.Initialize(); base.Initialize();
Log.Level = LogLevel.Info; Log.Level = LogLevel.Info;
_fixturesQuery = GetEntityQuery<FixturesComponent>();
_modifierQuery = GetEntityQuery<MovementSpeedModifierComponent>();
_factionQuery = GetEntityQuery<NpcFactionMemberComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
for (var i = 0; i < InterestDirections; i++) for (var i = 0; i < InterestDirections; i++)
{ {
+3 -12
View File
@@ -60,9 +60,7 @@ public sealed partial class NPCUtilitySystem : EntitySystem
[Dependency] private TurretTargetSettingsSystem _turretTargetSettings = default!; [Dependency] private TurretTargetSettingsSystem _turretTargetSettings = default!;
[Dependency] private DamageableSystem _damageable = default!; [Dependency] private DamageableSystem _damageable = default!;
[Dependency] private SharedStealthSystem _stealth = default!; [Dependency] private SharedStealthSystem _stealth = default!;
[Dependency] private EntityQuery<PuddleComponent> _puddleQuery = default!;
private EntityQuery<PuddleComponent> _puddleQuery;
private EntityQuery<TransformComponent> _xformQuery;
private ObjectPool<HashSet<EntityUid>> _entPool = private ObjectPool<HashSet<EntityUid>> _entPool =
new DefaultObjectPool<HashSet<EntityUid>>(new SetPolicy<EntityUid>(), 256); new DefaultObjectPool<HashSet<EntityUid>>(new SetPolicy<EntityUid>(), 256);
@@ -72,13 +70,6 @@ public sealed partial class NPCUtilitySystem : EntitySystem
private HashSet<Entity<IComponent>> _entitySet = new(); private HashSet<Entity<IComponent>> _entitySet = new();
private List<EntityPrototype.ComponentRegistryEntry> _compTypes = new(); private List<EntityPrototype.ComponentRegistryEntry> _compTypes = new();
public override void Initialize()
{
base.Initialize();
_puddleQuery = GetEntityQuery<PuddleComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
}
/// <summary> /// <summary>
/// Runs the UtilityQueryPrototype and returns the best-matching entities. /// Runs the UtilityQueryPrototype and returns the best-matching entities.
/// </summary> /// </summary>
@@ -429,7 +420,7 @@ public sealed partial class NPCUtilitySystem : EntitySystem
if (compQuery.Components.Count == 0) if (compQuery.Components.Count == 0)
return; return;
var mapPos = _transform.GetMapCoordinates(owner, xform: _xformQuery.GetComponent(owner)); var mapPos = _transform.GetMapCoordinates(owner, xform: Transform(owner));
_compTypes.Clear(); _compTypes.Clear();
var i = -1; var i = -1;
EntityPrototype.ComponentRegistryEntry compZero = default!; EntityPrototype.ComponentRegistryEntry compZero = default!;
@@ -507,7 +498,7 @@ public sealed partial class NPCUtilitySystem : EntitySystem
private void RecursiveAdd(EntityUid uid, HashSet<EntityUid> entities) private void RecursiveAdd(EntityUid uid, HashSet<EntityUid> entities)
{ {
// TODO: Probably need a recursive struct enumerator on engine. // TODO: Probably need a recursive struct enumerator on engine.
var xform = _xformQuery.GetComponent(uid); var xform = Transform(uid);
var enumerator = xform.ChildEnumerator; var enumerator = xform.ChildEnumerator;
entities.Add(uid); entities.Add(uid);
@@ -33,7 +33,6 @@ public sealed partial class SpaceNinjaSystem : SharedSpaceNinjaSystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<SpaceNinjaComponent, EmaggedSomethingEvent>(OnDoorjack);
SubscribeLocalEvent<SpaceNinjaComponent, ResearchStolenEvent>(OnResearchStolen); SubscribeLocalEvent<SpaceNinjaComponent, ResearchStolenEvent>(OnResearchStolen);
SubscribeLocalEvent<SpaceNinjaComponent, ThreatCalledInEvent>(OnThreatCalledIn); SubscribeLocalEvent<SpaceNinjaComponent, ThreatCalledInEvent>(OnThreatCalledIn);
SubscribeLocalEvent<SpaceNinjaComponent, CriminalRecordsHackedEvent>(OnCriminalRecordsHacked); SubscribeLocalEvent<SpaceNinjaComponent, CriminalRecordsHackedEvent>(OnCriminalRecordsHacked);
@@ -113,23 +112,6 @@ public sealed partial class SpaceNinjaSystem : SharedSpaceNinjaSystem
return GetNinjaBattery(user, out var uid, out var battery) && _battery.TryUseCharge((uid.Value, battery), charge); return GetNinjaBattery(user, out var uid, out var battery) && _battery.TryUseCharge((uid.Value, battery), charge);
} }
/// <summary>
/// Increment greentext when emagging a door.
/// </summary>
private void OnDoorjack(EntityUid uid, SpaceNinjaComponent comp, ref EmaggedSomethingEvent args)
{
// incase someone lets ninja emag non-doors double check it here
if (!HasComp<DoorComponent>(args.Target))
return;
// this popup is serverside since door emag logic is serverside (power funnies)
Popup.PopupEntity(Loc.GetString("ninja-doorjack-success", ("target", Identity.Entity(args.Target, EntityManager))), uid, uid, PopupType.Medium);
// handle greentext
if (_mind.TryGetObjectiveComp<DoorjackConditionComponent>(uid, out var obj))
obj.DoorsJacked++;
}
/// <summary> /// <summary>
/// Add to greentext when stealing technologies. /// Add to greentext when stealing technologies.
/// </summary> /// </summary>
@@ -16,7 +16,7 @@ namespace Content.Server.NodeContainer.EntitySystems
public sealed partial class NodeContainerSystem : SharedNodeContainerSystem public sealed partial class NodeContainerSystem : SharedNodeContainerSystem
{ {
[Dependency] private NodeGroupSystem _nodeGroupSystem = default!; [Dependency] private NodeGroupSystem _nodeGroupSystem = default!;
private EntityQuery<NodeContainerComponent> _query; [Dependency] private EntityQuery<NodeContainerComponent> _nodeContainerQuery = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -29,8 +29,6 @@ namespace Content.Server.NodeContainer.EntitySystems
SubscribeLocalEvent<NodeContainerComponent, ReAnchorEvent>(OnReAnchor); SubscribeLocalEvent<NodeContainerComponent, ReAnchorEvent>(OnReAnchor);
SubscribeLocalEvent<NodeContainerComponent, MoveEvent>(OnMoveEvent); SubscribeLocalEvent<NodeContainerComponent, MoveEvent>(OnMoveEvent);
SubscribeLocalEvent<NodeContainerComponent, ExaminedEvent>(OnExamine); SubscribeLocalEvent<NodeContainerComponent, ExaminedEvent>(OnExamine);
_query = GetEntityQuery<NodeContainerComponent>();
} }
public bool TryGetNode<T>(NodeContainerComponent component, string? identifier, [NotNullWhen(true)] out T? node) where T : Node public bool TryGetNode<T>(NodeContainerComponent component, string? identifier, [NotNullWhen(true)] out T? node) where T : Node
@@ -53,7 +51,7 @@ namespace Content.Server.NodeContainer.EntitySystems
public bool TryGetNode<T>(Entity<NodeContainerComponent?> ent, string identifier, [NotNullWhen(true)] out T? node) where T : Node public bool TryGetNode<T>(Entity<NodeContainerComponent?> ent, string identifier, [NotNullWhen(true)] out T? node) where T : Node
{ {
if (_query.Resolve(ent, ref ent.Comp, false) if (_nodeContainerQuery.Resolve(ent, ref ent.Comp, false)
&& ent.Comp.Nodes.TryGetValue(identifier, out var n) && ent.Comp.Nodes.TryGetValue(identifier, out var n)
&& n is T t) && n is T t)
{ {
@@ -74,7 +72,7 @@ namespace Content.Server.NodeContainer.EntitySystems
where T1 : Node where T1 : Node
where T2 : Node where T2 : Node
{ {
if (_query.Resolve(ent, ref ent.Comp, false) if (_nodeContainerQuery.Resolve(ent, ref ent.Comp, false)
&& ent.Comp.Nodes.TryGetValue(id1, out var n1) && ent.Comp.Nodes.TryGetValue(id1, out var n1)
&& n1 is T1 t1 && n1 is T1 t1
&& ent.Comp.Nodes.TryGetValue(id2, out var n2) && ent.Comp.Nodes.TryGetValue(id2, out var n2)
@@ -102,7 +100,7 @@ namespace Content.Server.NodeContainer.EntitySystems
where T2 : Node where T2 : Node
where T3 : Node where T3 : Node
{ {
if (_query.Resolve(ent, ref ent.Comp, false) if (_nodeContainerQuery.Resolve(ent, ref ent.Comp, false)
&& ent.Comp.Nodes.TryGetValue(id1, out var n1) && ent.Comp.Nodes.TryGetValue(id1, out var n1)
&& n1 is T1 t1 && n1 is T1 t1
&& ent.Comp.Nodes.TryGetValue(id2, out var n2) && ent.Comp.Nodes.TryGetValue(id2, out var n2)
@@ -25,6 +25,8 @@ namespace Content.Server.NodeContainer.EntitySystems
[Dependency] private IAdminManager _adminManager = default!; [Dependency] private IAdminManager _adminManager = default!;
[Dependency] private INodeGroupFactory _nodeGroupFactory = default!; [Dependency] private INodeGroupFactory _nodeGroupFactory = default!;
[Dependency] private ILogManager _logManager = default!; [Dependency] private ILogManager _logManager = default!;
[Dependency] private EntityQuery<NodeContainerComponent> _nodeContainerQuery = default!;
[Dependency] private EntityQuery<TransformComponent> _xformQuery = default!;
private readonly List<int> _visDeletes = new(); private readonly List<int> _visDeletes = new();
private readonly List<BaseNodeGroup> _visSends = new(); private readonly List<BaseNodeGroup> _visSends = new();
@@ -166,9 +168,6 @@ namespace Content.Server.NodeContainer.EntitySystems
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
var xformQuery = GetEntityQuery<TransformComponent>();
var nodeQuery = GetEntityQuery<NodeContainerComponent>();
foreach (var toRemove in _toRemove) foreach (var toRemove in _toRemove)
{ {
if (toRemove.NodeGroup == null) if (toRemove.NodeGroup == null)
@@ -214,7 +213,7 @@ namespace Content.Server.NodeContainer.EntitySystems
// based on position & anchored neighbours However, here more than one node could be attached to the // based on position & anchored neighbours However, here more than one node could be attached to the
// same parent. So there is probably a better way of doing this. // same parent. So there is probably a better way of doing this.
foreach (var compatible in GetCompatibleNodes(node, xformQuery, nodeQuery)) foreach (var compatible in GetCompatibleNodes(node))
{ {
ClearReachableIfNecessary(compatible); ClearReachableIfNecessary(compatible);
@@ -346,20 +345,20 @@ namespace Content.Server.NodeContainer.EntitySystems
return allNodes; return allNodes;
} }
private IEnumerable<Node> GetCompatibleNodes(Node node, EntityQuery<TransformComponent> xformQuery, EntityQuery<NodeContainerComponent> nodeQuery) private IEnumerable<Node> GetCompatibleNodes(Node node)
{ {
var xform = xformQuery.GetComponent(node.Owner); var xform = Transform(node.Owner);
Entity<MapGridComponent>? gridEnt = TryComp<MapGridComponent>(xform.GridUid, out var grid) ? (xform.GridUid.Value, grid) : null; Entity<MapGridComponent>? gridEnt = TryComp<MapGridComponent>(xform.GridUid, out var grid) ? (xform.GridUid.Value, grid) : null;
if (!node.Connectable(EntityManager, xform)) if (!node.Connectable(EntityManager, xform))
yield break; yield break;
foreach (var reachable in node.GetReachableNodes((node.Owner, xform), nodeQuery, xformQuery, gridEnt, EntityManager)) foreach (var reachable in node.GetReachableNodes((node.Owner, xform), _nodeContainerQuery, _xformQuery, gridEnt, EntityManager))
{ {
DebugTools.Assert(reachable != node, "GetReachableNodes() should not include self."); DebugTools.Assert(reachable != node, "GetReachableNodes() should not include self.");
if (reachable.NodeGroupID == node.NodeGroupID if (reachable.NodeGroupID == node.NodeGroupID
&& reachable.Connectable(EntityManager, xformQuery.GetComponent(reachable.Owner))) && reachable.Connectable(EntityManager, Transform(reachable.Owner)))
{ {
yield return reachable; yield return reachable;
} }
@@ -5,11 +5,7 @@ namespace Content.Server.Objectives.Components;
/// <summary> /// <summary>
/// Objective condition that requires the player to be a ninja and have doorjacked at least a random number of airlocks. /// Objective condition that requires the player to be a ninja and have doorjacked at least a random number of airlocks.
/// Requires <see cref="NumberObjectiveComponent"/> to function. /// Requires <see cref="NumberObjectiveComponent"/> and <see cref="CounterConditionComponent"/> to function.
/// </summary> /// </summary>
[RegisterComponent, Access(typeof(NinjaConditionsSystem), typeof(SharedSpaceNinjaSystem))] [RegisterComponent]
public sealed partial class DoorjackConditionComponent : Component public sealed partial class DoorjackConditionComponent : Component;
{
[DataField("doorsJacked"), ViewVariables(VVAccess.ReadWrite)]
public int DoorsJacked;
}
@@ -0,0 +1,44 @@
using Content.Server.Objectives.Components;
using Content.Shared.Doors.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Mind;
using Content.Shared.Ninja.Components;
using Content.Shared.Ninja.Systems;
using Content.Shared.Popups;
namespace Content.Server.Objectives.Systems;
public sealed partial class DoorJackObjectiveConditionSystem : EntitySystem
{
[Dependency] private SharedPopupSystem _popupSystem = default!;
[Dependency] private SharedMindSystem _mind = default!;
[Dependency] private CounterConditionSystem _counterCondition = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SpaceNinjaComponent, EmaggedSomethingEvent>(OnDoorjack);
}
private void OnDoorjack(EntityUid uid, SpaceNinjaComponent comp, ref EmaggedSomethingEvent args)
{
// incase someone lets ninja emag non-doors double check it here
if (!HasComp<DoorComponent>(args.Target))
return;
if (!_mind.TryGetMind(uid, out var mindUid, out var mind))
return;
// this popup is serverside since door emag logic is serverside (power funnies)
_popupSystem.PopupEntity(
Loc.GetString("ninja-doorjack-success", ("target", Identity.Entity(args.Target, EntityManager))),
uid,
uid,
PopupType.Medium);
foreach (var obj in _mind.EnumerateObjectives<DoorjackConditionComponent>((mindUid, mind)))
{
_counterCondition.IncreaseCount(obj);
}
}
}
@@ -19,6 +19,9 @@ public sealed partial class HijackShuttleConditionSystem : EntitySystem
[Dependency] private SharedRoleSystem _role = default!; [Dependency] private SharedRoleSystem _role = default!;
[Dependency] private MobStateSystem _mobState = default!; [Dependency] private MobStateSystem _mobState = default!;
[Dependency] private EntityQuery<HumanoidProfileComponent> _humanoidsQuery = default!;
[Dependency] private EntityQuery<CuffableComponent> _cuffableQuery = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@@ -61,9 +64,6 @@ public sealed partial class HijackShuttleConditionSystem : EntitySystem
private bool IsShuttleHijacked(EntityUid shuttleGridId, EntityUid mindId) private bool IsShuttleHijacked(EntityUid shuttleGridId, EntityUid mindId)
{ {
var gridPlayers = Filter.BroadcastGrid(shuttleGridId).Recipients; var gridPlayers = Filter.BroadcastGrid(shuttleGridId).Recipients;
var humanoids = GetEntityQuery<HumanoidProfileComponent>();
var cuffable = GetEntityQuery<CuffableComponent>();
EntityQuery<MobStateComponent>();
var agentOnShuttle = false; var agentOnShuttle = false;
foreach (var player in gridPlayers) foreach (var player in gridPlayers)
@@ -78,7 +78,7 @@ public sealed partial class HijackShuttleConditionSystem : EntitySystem
continue; continue;
} }
var isHumanoid = humanoids.HasComponent(player.AttachedEntity.Value); var isHumanoid = _humanoidsQuery.HasComponent(player.AttachedEntity.Value);
if (!isHumanoid) // Only humanoids count as enemies if (!isHumanoid) // Only humanoids count as enemies
continue; continue;
@@ -91,7 +91,7 @@ public sealed partial class HijackShuttleConditionSystem : EntitySystem
continue; continue;
var isPersonCuffed = var isPersonCuffed =
cuffable.TryGetComponent(player.AttachedEntity.Value, out var cuffed) _cuffableQuery.TryGetComponent(player.AttachedEntity.Value, out var cuffed)
&& cuffed.CuffedHandCount > 0; && cuffed.CuffedHandCount > 0;
if (isPersonCuffed) // Allow handcuffed if (isPersonCuffed) // Allow handcuffed
continue; continue;
@@ -24,15 +24,12 @@ public sealed partial class MailFraudObjectiveSystem : EntitySystem
if (_fingerprintReader.IsAllowed(ent.Owner, args.User, out var _, showPopup: false, checkGloves: false)) if (_fingerprintReader.IsAllowed(ent.Owner, args.User, out var _, showPopup: false, checkGloves: false))
return; //cutting open your own letter return; //cutting open your own letter
if (!_mind.TryGetMind(args.User, out _, out var mind)) if (!_mind.TryGetMind(args.User, out var mindUid, out var mind))
return; return;
foreach (var obj in mind.Objectives) foreach (var obj in _mind.EnumerateObjectives<MailFraudConditionComponent>((mindUid, mind)))
{ {
if (HasComp<MailFraudConditionComponent>(obj)) _counterCondition.IncreaseCount(obj);
{
_counterCondition.IncreaseCount(obj);
}
} }
} }
} }
@@ -22,30 +22,12 @@ public sealed partial class NinjaConditionsSystem : EntitySystem
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<DoorjackConditionComponent, ObjectiveGetProgressEvent>(OnDoorjackGetProgress);
SubscribeLocalEvent<SpiderChargeConditionComponent, RequirementCheckEvent>(OnSpiderChargeRequirementCheck); SubscribeLocalEvent<SpiderChargeConditionComponent, RequirementCheckEvent>(OnSpiderChargeRequirementCheck);
SubscribeLocalEvent<SpiderChargeConditionComponent, ObjectiveAfterAssignEvent>(OnSpiderChargeAfterAssign); SubscribeLocalEvent<SpiderChargeConditionComponent, ObjectiveAfterAssignEvent>(OnSpiderChargeAfterAssign);
SubscribeLocalEvent<StealResearchConditionComponent, ObjectiveGetProgressEvent>(OnStealResearchGetProgress); SubscribeLocalEvent<StealResearchConditionComponent, ObjectiveGetProgressEvent>(OnStealResearchGetProgress);
} }
// doorjack
private void OnDoorjackGetProgress(EntityUid uid, DoorjackConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
args.Progress = DoorjackProgress(comp, _number.GetTarget(uid));
}
private float DoorjackProgress(DoorjackConditionComponent comp, int target)
{
// prevent divide-by-zero
if (target == 0)
return 1f;
return MathF.Min(comp.DoorsJacked / (float) target, 1f);
}
// spider charge // spider charge
private void OnSpiderChargeRequirementCheck(EntityUid uid, SpiderChargeConditionComponent comp, ref RequirementCheckEvent args) private void OnSpiderChargeRequirementCheck(EntityUid uid, SpiderChargeConditionComponent comp, ref RequirementCheckEvent args)
{ {
@@ -24,8 +24,7 @@ public sealed partial class StealConditionSystem : EntitySystem
[Dependency] private SharedInteractionSystem _interaction = default!; [Dependency] private SharedInteractionSystem _interaction = default!;
[Dependency] private SharedObjectivesSystem _objectives = default!; [Dependency] private SharedObjectivesSystem _objectives = default!;
[Dependency] private EntityLookupSystem _lookup = default!; [Dependency] private EntityLookupSystem _lookup = default!;
[Dependency] private EntityQuery<ContainerManagerComponent> _containerQuery = default!;
private EntityQuery<ContainerManagerComponent> _containerQuery;
private HashSet<Entity<TransformComponent>> _nearestEnts = new(); private HashSet<Entity<TransformComponent>> _nearestEnts = new();
private HashSet<EntityUid> _countedItems = new(); private HashSet<EntityUid> _countedItems = new();
@@ -34,8 +33,6 @@ public sealed partial class StealConditionSystem : EntitySystem
{ {
base.Initialize(); base.Initialize();
_containerQuery = GetEntityQuery<ContainerManagerComponent>();
SubscribeLocalEvent<StealConditionComponent, ObjectiveAssignedEvent>(OnAssigned); SubscribeLocalEvent<StealConditionComponent, ObjectiveAssignedEvent>(OnAssigned);
SubscribeLocalEvent<StealConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign); SubscribeLocalEvent<StealConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
SubscribeLocalEvent<StealConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress); SubscribeLocalEvent<StealConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
+5 -15
View File
@@ -1,15 +1,11 @@
using System.Linq;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.Atmos;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.EntitySystems;
using Content.Server.Decals; using Content.Server.Decals;
using Content.Server.Ghost.Roles.Components; using Content.Server.Ghost.Roles.Components;
using Content.Server.Shuttles.Events; using Content.Server.Shuttles.Events;
using Content.Server.Shuttles.Systems; using Content.Server.Shuttles.Systems;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Decals;
using Content.Shared.Ghost; using Content.Shared.Ghost;
using Content.Shared.Gravity; using Content.Shared.Gravity;
using Content.Shared.Light.Components; using Content.Shared.Light.Components;
@@ -53,10 +49,10 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
[Dependency] private ShuttleSystem _shuttles = default!; [Dependency] private ShuttleSystem _shuttles = default!;
[Dependency] private TagSystem _tags = default!; [Dependency] private TagSystem _tags = default!;
private EntityQuery<BiomeComponent> _biomeQuery; [Dependency] private EntityQuery<BiomeComponent> _biomeQuery = default!;
private EntityQuery<FixturesComponent> _fixturesQuery; [Dependency] private EntityQuery<FixturesComponent> _fixturesQuery = default!;
private EntityQuery<GhostComponent> _ghostQuery; [Dependency] private EntityQuery<GhostComponent> _ghostQuery = default!;
private EntityQuery<TransformComponent> _xformQuery; [Dependency] private EntityQuery<TransformComponent> _xformQuery = default!;
private readonly HashSet<EntityUid> _handledEntities = new(); private readonly HashSet<EntityUid> _handledEntities = new();
private const float DefaultLoadRange = 16f; private const float DefaultLoadRange = 16f;
@@ -85,10 +81,6 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
{ {
base.Initialize(); base.Initialize();
Log.Level = LogLevel.Debug; Log.Level = LogLevel.Debug;
_biomeQuery = GetEntityQuery<BiomeComponent>();
_fixturesQuery = GetEntityQuery<FixturesComponent>();
_ghostQuery = GetEntityQuery<GhostComponent>();
_xformQuery = GetEntityQuery<TransformComponent>();
SubscribeLocalEvent<BiomeComponent, MapInitEvent>(OnBiomeMapInit); SubscribeLocalEvent<BiomeComponent, MapInitEvent>(OnBiomeMapInit);
SubscribeLocalEvent<FTLStartedEvent>(OnFTLStarted); SubscribeLocalEvent<FTLStartedEvent>(OnFTLStarted);
SubscribeLocalEvent<ShuttleFlattenEvent>(OnShuttleFlatten); SubscribeLocalEvent<ShuttleFlattenEvent>(OnShuttleFlatten);
@@ -924,11 +916,9 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
// Ideally any entities that aren't modified just get deleted and re-generated later // Ideally any entities that aren't modified just get deleted and re-generated later
// This is because if we want to save the map (e.g. persistent server) it makes the file much smaller // This is because if we want to save the map (e.g. persistent server) it makes the file much smaller
// and also if the map is enormous will make stuff like physics broadphase much faster // and also if the map is enormous will make stuff like physics broadphase much faster
var xformQuery = GetEntityQuery<TransformComponent>();
foreach (var (ent, tile) in component.LoadedEntities[chunk]) foreach (var (ent, tile) in component.LoadedEntities[chunk])
{ {
if (Deleted(ent) || !xformQuery.TryGetComponent(ent, out var xform)) if (Deleted(ent) || !TryComp(ent, out TransformComponent? xform))
{ {
modified.Add(tile); modified.Add(tile);
continue; continue;
@@ -14,8 +14,7 @@ public sealed partial class ParticleAcceleratorSystem
if (!Resolve(uid, ref emitter)) if (!Resolve(uid, ref emitter))
return; return;
var xformQuery = GetEntityQuery<TransformComponent>(); if (!TryComp(uid, out TransformComponent? xform))
if (!xformQuery.TryGetComponent(uid, out var xform))
{ {
Log.Error("ParticleAccelerator attempted to emit a particle without (having) a transform from which to base its initial position and orientation."); Log.Error("ParticleAccelerator attempted to emit a particle without (having) a transform from which to base its initial position and orientation.");
return; return;
@@ -23,12 +22,12 @@ public sealed partial class ParticleAcceleratorSystem
var emitted = Spawn(emitter.EmittedPrototype, xform.Coordinates); var emitted = Spawn(emitter.EmittedPrototype, xform.Coordinates);
if (xformQuery.TryGetComponent(emitted, out var particleXform)) if (TryComp(emitted, out TransformComponent? particleXform))
_transformSystem.SetLocalRotation(emitted, xform.LocalRotation, particleXform); _transformSystem.SetLocalRotation(emitted, xform.LocalRotation, particleXform);
if (TryComp<PhysicsComponent>(emitted, out var particlePhys)) if (TryComp<PhysicsComponent>(emitted, out var particlePhys))
{ {
var angle = _transformSystem.GetWorldRotation(uid, xformQuery); var angle = _transformSystem.GetWorldRotation(uid);
_physicsSystem.SetBodyStatus(emitted, particlePhys, BodyStatus.InAir); _physicsSystem.SetBodyStatus(emitted, particlePhys, BodyStatus.InAir);
var velocity = angle.ToWorldVec() * 20f; var velocity = angle.ToWorldVec() * 20f;

Some files were not shown because too many files have changed in this diff Show More