Merge branch 'master' of https://github.com/space-wizards/space-station-14 into moss-seniorcargo
This commit is contained in:
@@ -8,6 +8,7 @@ using Robust.Shared;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Benchmarks;
|
||||
|
||||
@@ -18,9 +19,11 @@ namespace Content.Benchmarks;
|
||||
[Virtual, MemoryDiagnoser]
|
||||
public class SpawnEquipDeleteBenchmark
|
||||
{
|
||||
private static readonly EntProtoId Mob = "MobHuman";
|
||||
private static readonly ProtoId<StartingGearPrototype> CaptainStartingGear = "CaptainGear";
|
||||
|
||||
private TestPair _pair = default!;
|
||||
private StationSpawningSystem _spawnSys = default!;
|
||||
private const string Mob = "MobHuman";
|
||||
private StartingGearPrototype _gear = default!;
|
||||
private EntityUid _entity;
|
||||
private EntityCoordinates _coords;
|
||||
@@ -39,7 +42,7 @@ public class SpawnEquipDeleteBenchmark
|
||||
var mapData = await _pair.CreateTestMap();
|
||||
_coords = mapData.GridCoords;
|
||||
_spawnSys = server.System<StationSpawningSystem>();
|
||||
_gear = server.ProtoMan.Index<StartingGearPrototype>("CaptainGear");
|
||||
_gear = server.ProtoMan.Index(CaptainStartingGear);
|
||||
}
|
||||
|
||||
[GlobalCleanup]
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Content.Client.Access.UI;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||
{
|
||||
private static readonly ProtoId<AccessGroupPrototype> GeneralAccessGroup = "General";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
|
||||
private bool _isMonotone;
|
||||
@@ -63,7 +65,7 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||
|
||||
// Ensure that the 'general' access group is added to handle
|
||||
// misc. access levels that aren't associated with any group
|
||||
if (_protoManager.TryIndex<AccessGroupPrototype>("General", out var generalAccessProto))
|
||||
if (_protoManager.TryIndex(GeneralAccessGroup, out var generalAccessProto))
|
||||
_groupedAccessLevels.TryAdd(generalAccessProto, new());
|
||||
|
||||
// Assign known access levels with their associated groups
|
||||
|
||||
@@ -20,6 +20,10 @@ public sealed class AdminLogsEui : BaseEui
|
||||
[Dependency] private readonly IFileDialogManager _dialogManager = default!;
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
|
||||
private const char CsvSeparator = ',';
|
||||
private const string CsvQuote = "\"";
|
||||
private const string CsvHeader = "Date,ID,PlayerID,Severity,Type,Message";
|
||||
|
||||
private ISawmill _sawmill;
|
||||
|
||||
private bool _currentlyExportingLogs = false;
|
||||
@@ -100,7 +104,9 @@ public sealed class AdminLogsEui : BaseEui
|
||||
|
||||
try
|
||||
{
|
||||
await using var writer = new StreamWriter(file.Value.fileStream);
|
||||
// Buffer is set to 4KB for performance reasons. As the average export of 1000 logs is ~200KB
|
||||
await using var writer = new StreamWriter(file.Value.fileStream, bufferSize: 4096);
|
||||
await writer.WriteLineAsync(CsvHeader);
|
||||
foreach (var child in LogsControl.LogsContainer.Children)
|
||||
{
|
||||
if (child is not AdminLogLabel logLabel || !child.Visible)
|
||||
@@ -108,28 +114,31 @@ public sealed class AdminLogsEui : BaseEui
|
||||
|
||||
var log = logLabel.Log;
|
||||
|
||||
// Date
|
||||
// I swear to god if someone adds ,s or "s to the other fields...
|
||||
await writer.WriteAsync(log.Date.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
|
||||
await writer.WriteAsync(',');
|
||||
await writer.WriteAsync(CsvSeparator);
|
||||
// ID
|
||||
await writer.WriteAsync(log.Id.ToString());
|
||||
await writer.WriteAsync(',');
|
||||
await writer.WriteAsync(log.Impact.ToString());
|
||||
await writer.WriteAsync(',');
|
||||
// Message
|
||||
await writer.WriteAsync('"');
|
||||
await writer.WriteAsync(log.Message.Replace("\"", "\"\""));
|
||||
await writer.WriteAsync('"');
|
||||
// End of message
|
||||
await writer.WriteAsync(',');
|
||||
|
||||
await writer.WriteAsync(CsvSeparator);
|
||||
// PlayerID
|
||||
var players = log.Players;
|
||||
for (var i = 0; i < players.Length; i++)
|
||||
{
|
||||
await writer.WriteAsync(players[i] + (i == players.Length - 1 ? "" : " "));
|
||||
}
|
||||
|
||||
await writer.WriteAsync(',');
|
||||
await writer.WriteAsync(CsvSeparator);
|
||||
// Severity
|
||||
await writer.WriteAsync(log.Impact.ToString());
|
||||
await writer.WriteAsync(CsvSeparator);
|
||||
// Type
|
||||
await writer.WriteAsync(log.Type.ToString());
|
||||
await writer.WriteAsync(CsvSeparator);
|
||||
// Message
|
||||
await writer.WriteAsync(CsvQuote);
|
||||
await writer.WriteAsync(log.Message.Replace(CsvQuote, CsvQuote + CsvQuote));
|
||||
await writer.WriteAsync(CsvQuote);
|
||||
|
||||
await writer.WriteLineAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
||||
|
||||
namespace Content.Client.Atmos.EntitySystems;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the client system responsible for managing and updating the gas pressure regulator interface.
|
||||
/// Inherits from the shared system <see cref="SharedGasPressureRegulatorSystem"/>.
|
||||
/// </summary>
|
||||
public sealed partial class GasPressureRegulatorSystem : SharedGasPressureRegulatorSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasPressureRegulatorComponent, AfterAutoHandleStateEvent>(OnValveUpdate);
|
||||
}
|
||||
|
||||
private void OnValveUpdate(Entity<GasPressureRegulatorComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
UpdateUi(ent);
|
||||
}
|
||||
|
||||
protected override void UpdateUi(Entity<GasPressureRegulatorComponent> ent)
|
||||
{
|
||||
if (UserInterfaceSystem.TryGetOpenUi(ent.Owner, GasPressureRegulatorUiKey.Key, out var bui))
|
||||
{
|
||||
bui.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ namespace Content.Client.Atmos.Overlays
|
||||
{
|
||||
public sealed class GasTileOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly IMapManager _mapManager;
|
||||
private readonly SharedMapSystem _mapSystem;
|
||||
@@ -54,7 +56,7 @@ namespace Content.Client.Atmos.Overlays
|
||||
_mapManager = IoCManager.Resolve<IMapManager>();
|
||||
_mapSystem = entManager.System<SharedMapSystem>();
|
||||
_xformSys = xformSys;
|
||||
_shader = protoMan.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_shader = protoMan.Index(UnshadedShader).Instance();
|
||||
ZIndex = GasOverlayZIndex;
|
||||
|
||||
_gasCount = system.VisibleGasId.Length;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Localizations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Atmos.UI;
|
||||
|
||||
public sealed class GasPressureRegulatorBoundUserInterface(EntityUid owner, Enum uiKey)
|
||||
: BoundUserInterface(owner, uiKey)
|
||||
{
|
||||
private GasPressureRegulatorWindow? _window;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<GasPressureRegulatorWindow>();
|
||||
|
||||
_window.SetEntity(Owner);
|
||||
|
||||
_window.ThresholdPressureChanged += OnThresholdChanged;
|
||||
|
||||
if (EntMan.TryGetComponent(Owner, out GasPressureRegulatorComponent? comp))
|
||||
_window.SetThresholdPressureInput(comp.Threshold);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_window.Title = Identity.Name(Owner, EntMan);
|
||||
|
||||
if (!EntMan.TryGetComponent(Owner, out GasPressureRegulatorComponent? comp))
|
||||
return;
|
||||
|
||||
_window.SetThresholdPressureLabel(comp.Threshold);
|
||||
_window.UpdateInfo(comp.InletPressure, comp.OutletPressure, comp.FlowRate);
|
||||
}
|
||||
|
||||
private void OnThresholdChanged(string newThreshold)
|
||||
{
|
||||
var sentThreshold = 0f;
|
||||
|
||||
if (UserInputParser.TryFloat(newThreshold, out var parsedNewThreshold) && parsedNewThreshold >= 0 &&
|
||||
!float.IsInfinity(parsedNewThreshold))
|
||||
{
|
||||
sentThreshold = parsedNewThreshold;
|
||||
}
|
||||
|
||||
// Autofill to zero if the user inputs an invalid value.
|
||||
_window?.SetThresholdPressureInput(sentThreshold);
|
||||
|
||||
SendPredictedMessage(new GasPressureRegulatorChangeThresholdMessage(sentThreshold));
|
||||
}
|
||||
}
|
||||
96
Content.Client/Atmos/UI/GasPressureRegulatorWindow.xaml
Normal file
96
Content.Client/Atmos/UI/GasPressureRegulatorWindow.xaml
Normal file
@@ -0,0 +1,96 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
SetSize="345 380"
|
||||
MinSize="345 380"
|
||||
Title="{Loc gas-pressure-regulator-ui-title}"
|
||||
Resizable="False">
|
||||
|
||||
<BoxContainer Orientation="Vertical">
|
||||
|
||||
<BoxContainer Orientation="Vertical" Margin="0 10 0 10">
|
||||
|
||||
<BoxContainer Orientation="Vertical" Align="Center">
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-outlet}" Align="Center" StyleClasses="LabelKeyText" />
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Label Name="OutletPressureLabel" Text="N/A" Margin="0 0 4 0" />
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-pressure-unit}" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" Align="Center">
|
||||
<BoxContainer Orientation="Vertical" Align="Center" HorizontalExpand="True">
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-target}" Align="Right" StyleClasses="LabelKeyText" />
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Label Name="TargetPressureLabel" Margin="0 0 4 0" />
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-pressure-unit}" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<ProgressBar Name="ToTargetBar" MaxValue="1" SetSize="5 75" Margin="10" Vertical="True" />
|
||||
|
||||
<SpriteView Name="EntityView" SetSize="64 64" Scale="3 3" OverrideDirection="North" Margin="0" />
|
||||
|
||||
<ProgressBar Name="FlowRateBar" MaxValue="1" SetSize="5 75" Margin="10" Vertical="True" />
|
||||
|
||||
<BoxContainer Orientation="Vertical" Align="Center" HorizontalExpand="True">
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-flow}" StyleClasses="LabelKeyText" />
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="CurrentFlowLabel" Text="N/A" Margin="0 0 4 0" />
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-flow-rate-unit}" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Vertical" Align="Center" Margin="1">
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-inlet}" Align="Center" StyleClasses="LabelKeyText" />
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Label Name="InletPressureLabel" Text="N/A" Margin="0 0 4 0" />
|
||||
<Label Text="{Loc gas-pressure-regulator-ui-pressure-unit}" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Controls to Set Pressure -->
|
||||
<controls:StripeBack Name="SetPressureStripeBack" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="10 10 10 10">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<LineEdit Name="ThresholdInput" HorizontalExpand="True" MinSize="70 0" />
|
||||
<Button Name="SetThresholdButton" Text="{Loc gas-pressure-regulator-ui-set-threshold}"
|
||||
Disabled="True" Margin="5 0 0 0" />
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 5 0 0">
|
||||
<Button Name="Subtract1000Button" Text="{Loc gas-pressure-regulator-ui-subtract-1000}"
|
||||
HorizontalExpand="True" Margin="0 2 2 0"
|
||||
StyleClasses="OpenBoth" />
|
||||
<Button Name="Subtract100Button" Text="{Loc gas-pressure-regulator-ui-subtract-100}"
|
||||
HorizontalExpand="True" Margin="0 2 2 0"
|
||||
StyleClasses="OpenBoth" />
|
||||
<Button Name="Subtract10Button" Text="{Loc gas-pressure-regulator-ui-subtract-10}"
|
||||
HorizontalExpand="True" Margin="0 2 2 0"
|
||||
StyleClasses="OpenBoth" />
|
||||
<Button Name="Add10Button" Text="{Loc gas-pressure-regulator-ui-add-10}" HorizontalExpand="True"
|
||||
Margin="0 2 2 0"
|
||||
StyleClasses="OpenBoth" />
|
||||
<Button Name="Add100Button" Text="{Loc gas-pressure-regulator-ui-add-100}"
|
||||
HorizontalExpand="True" Margin="0 2 2 0"
|
||||
StyleClasses="OpenBoth" />
|
||||
<Button Name="Add1000Button" Text="{Loc gas-pressure-regulator-ui-add-1000}"
|
||||
HorizontalExpand="True" Margin="0 2 2 0"
|
||||
StyleClasses="OpenBoth" />
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 5 0 0">
|
||||
<Button Name="ZeroThresholdButton" Text="{Loc gas-pressure-regulator-ui-zero-threshold}"
|
||||
HorizontalExpand="True" Margin="0 0 5 0" />
|
||||
<Button Name="SetToCurrentPressureButton"
|
||||
Text="{Loc gas-pressure-regulator-ui-set-to-current-pressure}" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:StripeBack>
|
||||
|
||||
</BoxContainer>
|
||||
|
||||
</controls:FancyWindow>
|
||||
129
Content.Client/Atmos/UI/GasPressureRegulatorWindow.xaml.cs
Normal file
129
Content.Client/Atmos/UI/GasPressureRegulatorWindow.xaml.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System.Globalization;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Atmos.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Client-side UI for controlling a pressure regulator.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class GasPressureRegulatorWindow : FancyWindow
|
||||
{
|
||||
private float _flowRate;
|
||||
|
||||
public GasPressureRegulatorWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
ThresholdInput.OnTextChanged += _ => SetThresholdButton.Disabled = false;
|
||||
SetThresholdButton.OnPressed += _ =>
|
||||
{
|
||||
ThresholdPressureChanged?.Invoke(ThresholdInput.Text ??= "");
|
||||
SetThresholdButton.Disabled = true;
|
||||
};
|
||||
|
||||
SetToCurrentPressureButton.OnPressed += _ =>
|
||||
{
|
||||
if (InletPressureLabel.Text != null)
|
||||
{
|
||||
ThresholdInput.Text = InletPressureLabel.Text;
|
||||
}
|
||||
|
||||
SetThresholdButton.Disabled = false;
|
||||
};
|
||||
|
||||
ZeroThresholdButton.OnPressed += _ =>
|
||||
{
|
||||
ThresholdInput.Text = "0";
|
||||
SetThresholdButton.Disabled = false;
|
||||
};
|
||||
|
||||
Add1000Button.OnPressed += _ => AdjustThreshold(1000);
|
||||
Add100Button.OnPressed += _ => AdjustThreshold(100);
|
||||
Add10Button.OnPressed += _ => AdjustThreshold(10);
|
||||
Subtract10Button.OnPressed += _ => AdjustThreshold(-10);
|
||||
Subtract100Button.OnPressed += _ => AdjustThreshold(-100);
|
||||
Subtract1000Button.OnPressed += _ => AdjustThreshold(-1000);
|
||||
return;
|
||||
|
||||
void AdjustThreshold(float adjustment)
|
||||
{
|
||||
if (float.TryParse(ThresholdInput.Text, out var currentValue))
|
||||
{
|
||||
ThresholdInput.Text = (currentValue + adjustment).ToString(CultureInfo.CurrentCulture);
|
||||
SetThresholdButton.Disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<string>? ThresholdPressureChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current threshold pressure label. This is not setting the threshold input box.
|
||||
/// </summary>
|
||||
/// <param name="threshold"> Threshold to set.</param>
|
||||
public void SetThresholdPressureLabel(float threshold)
|
||||
{
|
||||
TargetPressureLabel.Text = threshold.ToString(CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the threshold pressure input field with the given value.
|
||||
/// When the client opens the UI the field will be autofilled with the current threshold pressure.
|
||||
/// </summary>
|
||||
/// <param name="input">The threshold pressure value to autofill into the input field.</param>
|
||||
public void SetThresholdPressureInput(float input)
|
||||
{
|
||||
ThresholdInput.Text = input.ToString(CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the entity to be visible in the UI.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
public void SetEntity(EntityUid entity)
|
||||
{
|
||||
EntityView.SetEntity(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the UI for the labels.
|
||||
/// </summary>
|
||||
/// <param name="inletPressure">The current pressure at the valve's inlet.</param>
|
||||
/// <param name="outletPressure">The current pressure at the valve's outlet.</param>
|
||||
/// <param name="flowRate">The current flow rate through the valve.</param>
|
||||
public void UpdateInfo(float inletPressure, float outletPressure, float flowRate)
|
||||
{
|
||||
if (float.TryParse(TargetPressureLabel.Text, out var parsedfloat))
|
||||
ToTargetBar.Value = inletPressure / parsedfloat;
|
||||
|
||||
InletPressureLabel.Text = float.Round(inletPressure).ToString(CultureInfo.CurrentCulture);
|
||||
OutletPressureLabel.Text = float.Round(outletPressure).ToString(CultureInfo.CurrentCulture);
|
||||
CurrentFlowLabel.Text = float.IsNaN(flowRate) ? "0" : flowRate.ToString(CultureInfo.CurrentCulture);
|
||||
_flowRate = flowRate;
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
// Defines the flow rate at which the progress bar fills in one second.
|
||||
// If the flow rate is >50 L/s, the bar will take <1 second to fill.
|
||||
// If the flow rate is <50 L/s, the bar will take >1 second to fill.
|
||||
const int barFillPerSecond = 50;
|
||||
|
||||
var maxValue = FlowRateBar.MaxValue;
|
||||
|
||||
// Increment the progress bar value based on elapsed time
|
||||
FlowRateBar.Value += (_flowRate / barFillPerSecond) * args.DeltaSeconds;
|
||||
|
||||
// Reset the progress bar when it is fully filled
|
||||
if (FlowRateBar.Value >= maxValue)
|
||||
{
|
||||
FlowRateBar.Value = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using Content.Shared.Bed;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Bed;
|
||||
|
||||
public sealed class StasisBedSystem : VisualizerSystem<StasisBedVisualsComponent>
|
||||
{
|
||||
protected override void OnAppearanceChange(EntityUid uid, StasisBedVisualsComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite != null
|
||||
&& AppearanceSystem.TryGetData<bool>(uid, StasisBedVisuals.IsOn, out var isOn, args.Component))
|
||||
{
|
||||
SpriteSystem.LayerSetVisible((uid, args.Sprite), StasisBedVisualLayers.IsOn, isOn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum StasisBedVisualLayers : byte
|
||||
{
|
||||
IsOn,
|
||||
}
|
||||
5
Content.Client/Body/Systems/BloodStreamSystem.cs
Normal file
5
Content.Client/Body/Systems/BloodStreamSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using Content.Shared.Body.Systems;
|
||||
|
||||
namespace Content.Client.Body.Systems;
|
||||
|
||||
public sealed class BloodstreamSystem : SharedBloodstreamSystem;
|
||||
6
Content.Client/Body/Systems/MetabolizerSystem.cs
Normal file
6
Content.Client/Body/Systems/MetabolizerSystem.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using Content.Shared.Body.Systems;
|
||||
|
||||
namespace Content.Client.Body.Systems;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class MetabolizerSystem : SharedMetabolizerSystem;
|
||||
@@ -18,14 +18,10 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
|
||||
{
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
||||
|
||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
||||
private const string DefaultMixingCategory = "DummyMix";
|
||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
||||
private const string DefaultGrindCategory = "DummyGrind";
|
||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
||||
private const string DefaultJuiceCategory = "DummyJuice";
|
||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
||||
private const string DefaultCondenseCategory = "DummyCondense";
|
||||
private static readonly ProtoId<MixingCategoryPrototype> DefaultMixingCategory = "DummyMix";
|
||||
private static readonly ProtoId<MixingCategoryPrototype> DefaultGrindCategory = "DummyGrind";
|
||||
private static readonly ProtoId<MixingCategoryPrototype> DefaultJuiceCategory = "DummyJuice";
|
||||
private static readonly ProtoId<MixingCategoryPrototype> DefaultCondenseCategory = "DummyCondense";
|
||||
|
||||
private readonly Dictionary<string, List<ReagentSourceData>> _reagentSources = new();
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Content.Client.CombatMode
|
||||
{
|
||||
public sealed class ColoredScreenBorderOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "ColoredScreenBorder";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
@@ -16,7 +18,7 @@ namespace Content.Client.CombatMode
|
||||
public ColoredScreenBorderOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _prototypeManager.Index<ShaderPrototype>("ColoredScreenBorder").Instance();
|
||||
_shader = _prototypeManager.Index(Shader).Instance();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -27,8 +27,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow
|
||||
|
||||
private EntityUid _owner;
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
public const string NoBoardEffectId = "FlatpackerNoBoardEffect";
|
||||
public static readonly EntProtoId NoBoardEffectId = "FlatpackerNoBoardEffect";
|
||||
|
||||
private EntityUid? _currentBoard = EntityUid.Invalid;
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace Content.Client.Cooldown
|
||||
{
|
||||
public sealed class CooldownGraphic : Control
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "CooldownAnimation";
|
||||
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||
|
||||
@@ -15,7 +17,7 @@ namespace Content.Client.Cooldown
|
||||
public CooldownGraphic()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _protoMan.Index<ShaderPrototype>("CooldownAnimation").InstanceUnique();
|
||||
_shader = _protoMan.Index(Shader).InstanceUnique();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,8 +33,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||
|
||||
public readonly EntityUid Console;
|
||||
|
||||
[ValidatePrototypeId<LocalizedDatasetPrototype>]
|
||||
private const string ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders";
|
||||
private static readonly ProtoId<LocalizedDatasetPrototype> ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders";
|
||||
|
||||
public Action<uint?>? OnKeySelected;
|
||||
public Action<StationRecordFilterType, string>? OnFiltersChanged;
|
||||
@@ -296,7 +295,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||
|
||||
var field = "reason";
|
||||
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
|
||||
var placeholders = _proto.Index<LocalizedDatasetPrototype>(ReasonPlaceholders);
|
||||
var placeholders = _proto.Index(ReasonPlaceholders);
|
||||
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders))); // just funny it doesn't actually get used
|
||||
var prompt = Loc.GetString("criminal-records-console-reason");
|
||||
var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder);
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class DeliveryVisualizerSystem : VisualizerSystem<DeliveryComponen
|
||||
|
||||
if (!_prototype.TryIndex<JobIconPrototype>(job, out var icon))
|
||||
{
|
||||
SpriteSystem.LayerSetTexture((uid, args.Sprite), DeliveryVisualLayers.JobStamp, SpriteSystem.Frame0(_prototype.Index("JobIconUnknown")));
|
||||
SpriteSystem.LayerSetTexture((uid, args.Sprite), DeliveryVisualLayers.JobStamp, SpriteSystem.Frame0(_prototype.Index(UnknownIcon).Icon));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace Content.Client.DoAfter;
|
||||
|
||||
public sealed class DoAfterOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly IGameTiming _timing;
|
||||
private readonly IPlayerManager _player;
|
||||
@@ -50,7 +52,7 @@ public sealed class DoAfterOverlay : Overlay
|
||||
var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
|
||||
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
|
||||
|
||||
_unshadedShader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_unshadedShader = protoManager.Index(UnshadedShader).Instance();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Content.Client.Drowsiness;
|
||||
|
||||
public sealed class DrowsinessOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "Drowsiness";
|
||||
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
@@ -33,7 +35,7 @@ public sealed class DrowsinessOverlay : Overlay
|
||||
|
||||
_statusEffects = _sysMan.GetEntitySystem<SharedStatusEffectsSystem>();
|
||||
|
||||
_drowsinessShader = _prototypeManager.Index<ShaderPrototype>("Drowsiness").InstanceUnique();
|
||||
_drowsinessShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Content.Client.Drugs;
|
||||
|
||||
public sealed class RainbowOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "Rainbow";
|
||||
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
@@ -41,7 +43,7 @@ public sealed class RainbowOverlay : Overlay
|
||||
|
||||
_statusEffects = _sysMan.GetEntitySystem<SharedStatusEffectsSystem>();
|
||||
|
||||
_rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique();
|
||||
_rainbowShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||
_config.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Content.Client.Drunk;
|
||||
|
||||
public sealed class DrunkOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "Drunk";
|
||||
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
@@ -30,7 +32,7 @@ public sealed class DrunkOverlay : Overlay
|
||||
public DrunkOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_drunkShader = _prototypeManager.Index<ShaderPrototype>("Drunk").InstanceUnique();
|
||||
_drunkShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Content.Client.Explosion;
|
||||
[UsedImplicitly]
|
||||
public sealed class ExplosionOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
@@ -26,7 +28,7 @@ public sealed class ExplosionOverlay : Overlay
|
||||
public ExplosionOverlay(SharedAppearanceSystem appearanceSystem)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _proto.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_shader = _proto.Index(UnshadedShader).Instance();
|
||||
_transformSystem = _entMan.System<SharedTransformSystem>();
|
||||
_appearance = appearanceSystem;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace Content.Client.Eye.Blinding
|
||||
{
|
||||
public sealed class BlindOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> GreyscaleShader = "GreyscaleFullscreen";
|
||||
private static readonly ProtoId<ShaderPrototype> CircleShader = "CircleMask";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
@@ -27,8 +30,8 @@ namespace Content.Client.Eye.Blinding
|
||||
public BlindOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_greyscaleShader = _prototypeManager.Index<ShaderPrototype>("GreyscaleFullscreen").InstanceUnique();
|
||||
_circleMaskShader = _prototypeManager.Index<ShaderPrototype>("CircleMask").InstanceUnique();
|
||||
_greyscaleShader = _prototypeManager.Index(GreyscaleShader).InstanceUnique();
|
||||
_circleMaskShader = _prototypeManager.Index(CircleShader).InstanceUnique();
|
||||
}
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,9 @@ namespace Content.Client.Eye.Blinding
|
||||
{
|
||||
public sealed class BlurryVisionOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> CataractsShader = "Cataracts";
|
||||
private static readonly ProtoId<ShaderPrototype> CircleShader = "CircleMask";
|
||||
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
@@ -33,8 +36,8 @@ namespace Content.Client.Eye.Blinding
|
||||
public BlurryVisionOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_cataractsShader = _prototypeManager.Index<ShaderPrototype>("Cataracts").InstanceUnique();
|
||||
_circleMaskShader = _prototypeManager.Index<ShaderPrototype>("CircleMask").InstanceUnique();
|
||||
_cataractsShader = _prototypeManager.Index(CataractsShader).InstanceUnique();
|
||||
_circleMaskShader = _prototypeManager.Index(CircleShader).InstanceUnique();
|
||||
|
||||
_circleMaskShader.SetParameter("CircleMinDist", 0.0f);
|
||||
_circleMaskShader.SetParameter("CirclePow", NoMotion_Pow);
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Content.Client.Flash
|
||||
{
|
||||
public sealed class FlashOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> FlashedEffectShader = "FlashedEffect";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
@@ -27,7 +29,7 @@ namespace Content.Client.Flash
|
||||
public FlashOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _prototypeManager.Index<ShaderPrototype>("FlashedEffect").InstanceUnique();
|
||||
_shader = _prototypeManager.Index(FlashedEffectShader).InstanceUnique();
|
||||
_flash = _entityManager.System<SharedFlashSystem>();
|
||||
_statusSys = _entityManager.System<StatusEffectsSystem>();
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@ namespace Content.Client.Guidebook.Controls;
|
||||
[UsedImplicitly, GenerateTypedNameReferences]
|
||||
public sealed partial class GuideReagentReaction : BoxContainer, ISearchableControl
|
||||
{
|
||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
||||
private const string DefaultMixingCategory = "DummyMix";
|
||||
private static readonly ProtoId<MixingCategoryPrototype> DefaultMixingCategory = "DummyMix";
|
||||
|
||||
private readonly IPrototypeManager _protoMan;
|
||||
|
||||
@@ -55,7 +54,7 @@ public sealed partial class GuideReagentReaction : BoxContainer, ISearchableCont
|
||||
}
|
||||
else
|
||||
{
|
||||
mixingCategories.Add(protoMan.Index<MixingCategoryPrototype>(DefaultMixingCategory));
|
||||
mixingCategories.Add(protoMan.Index(DefaultMixingCategory));
|
||||
}
|
||||
SetMixingCategory(mixingCategories, prototype, sysMan);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.Utility;
|
||||
namespace Content.Client.Guidebook.Richtext;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class KeyBindTag : IMarkupTag
|
||||
public sealed class KeyBindTag : IMarkupTagHandler
|
||||
{
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Content.Client.Guidebook.RichText;
|
||||
/// In order to be accessed by this tag, the desired field/property must
|
||||
/// be tagged with <see cref="Shared.Guidebook.GuidebookDataAttribute"/>.
|
||||
/// </summary>
|
||||
public sealed class ProtodataTag : IMarkupTag
|
||||
public sealed class ProtodataTag : IMarkupTagHandler
|
||||
{
|
||||
[Dependency] private readonly ILogManager _logMan = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
|
||||
@@ -10,16 +10,14 @@ using Content.Client.UserInterface.ControlExtensions;
|
||||
namespace Content.Client.Guidebook.RichText;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class TextLinkTag : IMarkupTag
|
||||
public sealed class TextLinkTag : IMarkupTagHandler
|
||||
{
|
||||
public static Color LinkColor => Color.CornflowerBlue;
|
||||
|
||||
public string Name => "textlink";
|
||||
|
||||
public Control? Control;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGetControl(MarkupNode node, [NotNullWhen(true)] out Control? control)
|
||||
public bool TryCreateControl(MarkupNode node, [NotNullWhen(true)] out Control? control)
|
||||
{
|
||||
if (!node.Value.TryGetString(out var text)
|
||||
|| !node.Attributes.TryGetValue("link", out var linkParameter)
|
||||
@@ -38,22 +36,21 @@ public sealed class TextLinkTag : IMarkupTag
|
||||
|
||||
label.OnMouseEntered += _ => label.FontColorOverride = Color.LightSkyBlue;
|
||||
label.OnMouseExited += _ => label.FontColorOverride = Color.CornflowerBlue;
|
||||
label.OnKeyBindDown += args => OnKeybindDown(args, link);
|
||||
label.OnKeyBindDown += args => OnKeybindDown(args, link, label);
|
||||
|
||||
control = label;
|
||||
Control = label;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnKeybindDown(GUIBoundKeyEventArgs args, string link)
|
||||
private void OnKeybindDown(GUIBoundKeyEventArgs args, string link, Control? control)
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
if (Control == null)
|
||||
if (control == null)
|
||||
return;
|
||||
|
||||
if (Control.TryGetParentHandler<ILinkClickHandler>(out var handler))
|
||||
if (control.TryGetParentHandler<ILinkClickHandler>(out var handler))
|
||||
handler.HandleClick(link);
|
||||
else
|
||||
Logger.Warning("Warning! No valid ILinkClickHandler found.");
|
||||
|
||||
@@ -27,6 +27,7 @@ public sealed class EyeColorPicker : Control
|
||||
AddChild(vBox);
|
||||
|
||||
vBox.AddChild(_colorSelectors = new ColorSelectorSliders());
|
||||
_colorSelectors.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||
|
||||
_colorSelectors.OnColorChanged += ColorValueChanged;
|
||||
}
|
||||
|
||||
@@ -416,6 +416,7 @@ public sealed partial class MarkingPicker : Control
|
||||
CMarkingColors.AddChild(colorContainer);
|
||||
|
||||
ColorSelectorSliders colorSelector = new ColorSelectorSliders();
|
||||
colorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||
colorSliders.Add(colorSelector);
|
||||
|
||||
colorContainer.AddChild(new Label { Text = $"{stateNames[i]} color:" });
|
||||
|
||||
@@ -231,6 +231,7 @@ public sealed partial class SingleMarkingPicker : BoxContainer
|
||||
HorizontalExpand = true
|
||||
};
|
||||
selector.Color = marking.MarkingColors[i];
|
||||
selector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||
|
||||
var colorIndex = i;
|
||||
selector.OnColorChanged += color =>
|
||||
|
||||
@@ -102,6 +102,8 @@ public static class MidiParser
|
||||
// 0x03 is TrackName,
|
||||
// 0x04 is InstrumentName
|
||||
|
||||
// This string can potentially contain control characters, including 0x00 which can cause problems if it ends up in database entries via admin logs
|
||||
// we sanitize TrackName and InstrumentName after they have been send to the server
|
||||
var text = Encoding.ASCII.GetString(metaData, 0, (int)metaLength);
|
||||
switch (metaType)
|
||||
{
|
||||
|
||||
@@ -7,17 +7,14 @@ namespace Content.Client.Interactable.Components
|
||||
[RegisterComponent]
|
||||
public sealed partial class InteractionOutlineComponent : Component
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> ShaderInRange = "SelectionOutlineInrange";
|
||||
private static readonly ProtoId<ShaderPrototype> ShaderOutOfRange = "SelectionOutline";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
|
||||
private const float DefaultWidth = 1;
|
||||
|
||||
[ValidatePrototypeId<ShaderPrototype>]
|
||||
private const string ShaderInRange = "SelectionOutlineInrange";
|
||||
|
||||
[ValidatePrototypeId<ShaderPrototype>]
|
||||
private const string ShaderOutOfRange = "SelectionOutline";
|
||||
|
||||
private bool _inRange;
|
||||
private ShaderInstance? _shader;
|
||||
private int _lastRenderScale;
|
||||
@@ -65,7 +62,7 @@ namespace Content.Client.Interactable.Components
|
||||
{
|
||||
var shaderName = inRange ? ShaderInRange : ShaderOutOfRange;
|
||||
|
||||
var instance = _prototypeManager.Index<ShaderPrototype>(shaderName).InstanceUnique();
|
||||
var instance = _prototypeManager.Index(shaderName).InstanceUnique();
|
||||
instance.SetParameter("outline_width", DefaultWidth * renderScale);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ namespace Content.Client.Interaction;
|
||||
/// </summary>
|
||||
public sealed class DragDropSystem : SharedDragDropSystem
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> ShaderDropTargetInRange = "SelectionOutlineInrange";
|
||||
|
||||
private static readonly ProtoId<ShaderPrototype> ShaderDropTargetOutOfRange = "SelectionOutline";
|
||||
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
@@ -54,12 +58,6 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
// mousedown event so it can be treated like a regular click
|
||||
private const float MaxMouseDownTimeForReplayingClick = 0.85f;
|
||||
|
||||
[ValidatePrototypeId<ShaderPrototype>]
|
||||
private const string ShaderDropTargetInRange = "SelectionOutlineInrange";
|
||||
|
||||
[ValidatePrototypeId<ShaderPrototype>]
|
||||
private const string ShaderDropTargetOutOfRange = "SelectionOutline";
|
||||
|
||||
/// <summary>
|
||||
/// Current entity being dragged around.
|
||||
/// </summary>
|
||||
@@ -113,8 +111,8 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||
|
||||
Subs.CVar(_cfgMan, CCVars.DragDropDeadZone, SetDeadZone, true);
|
||||
|
||||
_dropTargetInRangeShader = _prototypeManager.Index<ShaderPrototype>(ShaderDropTargetInRange).Instance();
|
||||
_dropTargetOutOfRangeShader = _prototypeManager.Index<ShaderPrototype>(ShaderDropTargetOutOfRange).Instance();
|
||||
_dropTargetInRangeShader = _prototypeManager.Index(ShaderDropTargetInRange).Instance();
|
||||
_dropTargetOutOfRangeShader = _prototypeManager.Index(ShaderDropTargetOutOfRange).Instance();
|
||||
// needs to fire on mouseup and mousedown so we can detect a drag / drop
|
||||
CommandBinds.Builder
|
||||
.BindBefore(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false, true), new[] { typeof(SharedInteractionSystem) })
|
||||
|
||||
@@ -15,6 +15,10 @@ namespace Content.Client.Light;
|
||||
/// </summary>
|
||||
public sealed class AmbientOcclusionOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
private static readonly ProtoId<ShaderPrototype> StencilMaskShader = "StencilMask";
|
||||
private static readonly ProtoId<ShaderPrototype> StencilEqualDrawShader = "StencilEqualDraw";
|
||||
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
@@ -87,7 +91,7 @@ public sealed class AmbientOcclusionOverlay : Overlay
|
||||
args.WorldHandle.RenderInRenderTarget(_aoTarget,
|
||||
() =>
|
||||
{
|
||||
worldHandle.UseShader(_proto.Index<ShaderPrototype>("unshaded").Instance());
|
||||
worldHandle.UseShader(_proto.Index(UnshadedShader).Instance());
|
||||
var invMatrix = _aoTarget.GetWorldToLocalMatrix(viewport.Eye!, scale);
|
||||
|
||||
foreach (var entry in query.QueryAabb(mapId, worldBounds))
|
||||
@@ -110,7 +114,7 @@ public sealed class AmbientOcclusionOverlay : Overlay
|
||||
() =>
|
||||
{
|
||||
// Don't want lighting affecting it.
|
||||
worldHandle.UseShader(_proto.Index<ShaderPrototype>("unshaded").Instance());
|
||||
worldHandle.UseShader(_proto.Index(UnshadedShader).Instance());
|
||||
|
||||
foreach (var grid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
|
||||
{
|
||||
@@ -131,11 +135,11 @@ public sealed class AmbientOcclusionOverlay : Overlay
|
||||
}, Color.Transparent);
|
||||
|
||||
// Draw the stencil texture to depth buffer.
|
||||
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilMask").Instance());
|
||||
worldHandle.UseShader(_proto.Index(StencilMaskShader).Instance());
|
||||
worldHandle.DrawTextureRect(_aoStencilTarget!.Texture, worldBounds);
|
||||
|
||||
// Draw the Blurred AO texture finally.
|
||||
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilEqualDraw").Instance());
|
||||
worldHandle.UseShader(_proto.Index(StencilEqualDrawShader).Instance());
|
||||
worldHandle.DrawTextureRect(_aoTarget!.Texture, worldBounds, color);
|
||||
|
||||
args.WorldHandle.SetTransform(Matrix3x2.Identity);
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Content.Client.Light;
|
||||
|
||||
public sealed class SunShadowOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> MixShader = "Mix";
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.BeforeLighting;
|
||||
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
@@ -150,7 +152,7 @@ public sealed class SunShadowOverlay : Overlay
|
||||
viewport.LightRenderTarget.GetWorldToLocalMatrix(eye, scale);
|
||||
worldHandle.SetTransform(invMatrix);
|
||||
|
||||
var maskShader = _protoManager.Index<ShaderPrototype>("Mix").Instance();
|
||||
var maskShader = _protoManager.Index(MixShader).Instance();
|
||||
worldHandle.UseShader(maskShader);
|
||||
|
||||
worldHandle.DrawTextureRect(_target.Texture, worldBounds, Color.Black.WithAlpha(alpha));
|
||||
|
||||
@@ -103,8 +103,7 @@ namespace Content.Client.Lobby.UI
|
||||
|
||||
private bool _isDirty;
|
||||
|
||||
[ValidatePrototypeId<GuideEntryPrototype>]
|
||||
private const string DefaultSpeciesGuidebook = "Species";
|
||||
private static readonly ProtoId<GuideEntryPrototype> DefaultSpeciesGuidebook = "Species";
|
||||
|
||||
public event Action<List<ProtoId<GuideEntryPrototype>>>? OnOpenGuidebook;
|
||||
|
||||
@@ -240,6 +239,7 @@ namespace Content.Client.Lobby.UI
|
||||
};
|
||||
|
||||
RgbSkinColorContainer.AddChild(_rgbSkinColorSelector = new ColorSelectorSliders());
|
||||
_rgbSkinColorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||
_rgbSkinColorSelector.OnColorChanged += _ =>
|
||||
{
|
||||
OnSkinColorOnValueChanged();
|
||||
@@ -808,9 +808,9 @@ namespace Content.Client.Lobby.UI
|
||||
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
||||
var page = DefaultSpeciesGuidebook;
|
||||
if (_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
||||
page = species;
|
||||
page = new ProtoId<GuideEntryPrototype>(species.Id); // Gross. See above todo comment.
|
||||
|
||||
if (_prototypeManager.TryIndex<GuideEntryPrototype>(DefaultSpeciesGuidebook, out var guideRoot))
|
||||
if (_prototypeManager.TryIndex(DefaultSpeciesGuidebook, out var guideRoot))
|
||||
{
|
||||
var dict = new Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>();
|
||||
dict.Add(DefaultSpeciesGuidebook, guideRoot);
|
||||
@@ -1433,17 +1433,13 @@ namespace Content.Client.Lobby.UI
|
||||
{
|
||||
return;
|
||||
}
|
||||
var hairMarking = Profile.Appearance.HairStyleId switch
|
||||
{
|
||||
HairStyles.DefaultHairStyle => new List<Marking>(),
|
||||
_ => new() { new(Profile.Appearance.HairStyleId, new List<Color>() { Profile.Appearance.HairColor }) },
|
||||
};
|
||||
var hairMarking = Profile.Appearance.HairStyleId == HairStyles.DefaultHairStyle
|
||||
? new List<Marking>()
|
||||
: new() { new(Profile.Appearance.HairStyleId, new List<Color>() { Profile.Appearance.HairColor }) };
|
||||
|
||||
var facialHairMarking = Profile.Appearance.FacialHairStyleId switch
|
||||
{
|
||||
HairStyles.DefaultFacialHairStyle => new List<Marking>(),
|
||||
_ => new() { new(Profile.Appearance.FacialHairStyleId, new List<Color>() { Profile.Appearance.FacialHairColor }) },
|
||||
};
|
||||
var facialHairMarking = Profile.Appearance.FacialHairStyleId == HairStyles.DefaultFacialHairStyle
|
||||
? new List<Marking>()
|
||||
: new() { new(Profile.Appearance.FacialHairStyleId, new List<Color>() { Profile.Appearance.FacialHairColor }) };
|
||||
|
||||
HairStylePicker.UpdateData(
|
||||
hairMarking,
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Content.Client.Mapping;
|
||||
|
||||
public sealed class MappingOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||
@@ -35,7 +37,7 @@ public sealed class MappingOverlay : Overlay
|
||||
_sprite = _entities.System<SpriteSystem>();
|
||||
|
||||
_state = state;
|
||||
_shader = _prototypes.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_shader = _prototypes.Index(UnshadedShader).Instance();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Content.Client.Movement.Systems;
|
||||
|
||||
public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> HorizontalCut = "HorizontalCut";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
private EntityQuery<SpriteComponent> _spriteQuery;
|
||||
@@ -48,7 +50,7 @@ public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem
|
||||
if (!_spriteQuery.Resolve(sprite.Owner, ref sprite.Comp, false))
|
||||
return;
|
||||
|
||||
var shader = _proto.Index<ShaderPrototype>("HorizontalCut").Instance();
|
||||
var shader = _proto.Index(HorizontalCut).Instance();
|
||||
|
||||
if (sprite.Comp.PostShader is not null && sprite.Comp.PostShader != shader)
|
||||
return;
|
||||
|
||||
@@ -23,8 +23,7 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||
[Dependency] private readonly ActionsSystem _actions = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string Action = "ActionClearNetworkLinkOverlays";
|
||||
private static readonly EntProtoId Action = "ActionClearNetworkLinkOverlays";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
Resizable="False">
|
||||
|
||||
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150">
|
||||
<changelog:ChangelogButton Access="Public" Name="ChangelogButton"/>
|
||||
<ui:VoteCallMenuButton />
|
||||
<Button Access="Public" Name="OptionsButton" Text="{Loc 'ui-escape-options'}" />
|
||||
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
|
||||
<Button Access="Public" Name="RulesButton" Text="{Loc 'ui-escape-rules'}" />
|
||||
<Button Access="Public" Name="GuidebookButton" Text="{Loc 'ui-escape-guidebook'}" />
|
||||
<Button Access="Public" Name="WikiButton" Text="{Loc 'ui-escape-wiki'}" />
|
||||
<changelog:ChangelogButton Access="Public" Name="ChangelogButton" />
|
||||
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
|
||||
<Button Access="Public" Name="OptionsButton" Text="{Loc 'ui-escape-options'}" />
|
||||
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
|
||||
<Button Access="Public" Name="DisconnectButton" Text="{Loc 'ui-escape-disconnect'}" />
|
||||
<Button Access="Public" Name="QuitButton" Text="{Loc 'ui-escape-quit'}" />
|
||||
<Button Access="Public" Name="QuitButton" Text="{Loc 'ui-escape-quit'}" StyleClasses="ButtonColorRed" />
|
||||
</BoxContainer>
|
||||
</ui1:EscapeMenu>
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace Content.Client.Outline;
|
||||
/// </summary>
|
||||
public sealed class TargetOutlineSystem : EntitySystem
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> ShaderTargetValid = "SelectionOutlineInrange";
|
||||
private static readonly ProtoId<ShaderPrototype> ShaderTargetInvalid = "SelectionOutline";
|
||||
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
@@ -70,12 +73,6 @@ public sealed class TargetOutlineSystem : EntitySystem
|
||||
|
||||
private Vector2 LookupVector => new(LookupSize, LookupSize);
|
||||
|
||||
[ValidatePrototypeId<ShaderPrototype>]
|
||||
private const string ShaderTargetValid = "SelectionOutlineInrange";
|
||||
|
||||
[ValidatePrototypeId<ShaderPrototype>]
|
||||
private const string ShaderTargetInvalid = "SelectionOutline";
|
||||
|
||||
private ShaderInstance? _shaderTargetValid;
|
||||
private ShaderInstance? _shaderTargetInvalid;
|
||||
|
||||
@@ -85,8 +82,8 @@ public sealed class TargetOutlineSystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_shaderTargetValid = _prototypeManager.Index<ShaderPrototype>(ShaderTargetValid).InstanceUnique();
|
||||
_shaderTargetInvalid = _prototypeManager.Index<ShaderPrototype>(ShaderTargetInvalid).InstanceUnique();
|
||||
_shaderTargetValid = _prototypeManager.Index(ShaderTargetValid).InstanceUnique();
|
||||
_shaderTargetInvalid = _prototypeManager.Index(ShaderTargetInvalid).InstanceUnique();
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Content.Client.Overlays;
|
||||
|
||||
public sealed partial class BlackAndWhiteOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "GreyscaleFullscreen";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
@@ -15,7 +17,7 @@ public sealed partial class BlackAndWhiteOverlay : Overlay
|
||||
public BlackAndWhiteOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_greyscaleShader = _prototypeManager.Index<ShaderPrototype>("GreyscaleFullscreen").InstanceUnique();
|
||||
_greyscaleShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||
ZIndex = 10; // draw this over the DamageOverlay, RainbowOverlay etc.
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Content.Client.Overlays;
|
||||
|
||||
public sealed partial class NoirOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "Noir";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
@@ -15,7 +17,7 @@ public sealed partial class NoirOverlay : Overlay
|
||||
public NoirOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_noirShader = _prototypeManager.Index<ShaderPrototype>("Noir").InstanceUnique();
|
||||
_noirShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||
ZIndex = 9; // draw this over the DamageOverlay, RainbowOverlay etc, but before the black and white shader
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ public sealed class ShowJobIconsSystem : EquipmentHudSystem<ShowJobIconsComponen
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
||||
|
||||
[ValidatePrototypeId<JobIconPrototype>]
|
||||
private const string JobIconForNoId = "JobIconNoId";
|
||||
private static readonly ProtoId<JobIconPrototype> JobIconForNoId = "JobIconNoId";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -52,7 +51,7 @@ public sealed class ShowJobIconsSystem : EquipmentHudSystem<ShowJobIconsComponen
|
||||
}
|
||||
}
|
||||
|
||||
if (_prototype.TryIndex<JobIconPrototype>(iconId, out var iconPrototype))
|
||||
if (_prototype.TryIndex(iconId, out var iconPrototype))
|
||||
ev.StatusIcons.Add(iconPrototype);
|
||||
else
|
||||
Log.Error($"Invalid job icon prototype: {iconPrototype}");
|
||||
|
||||
@@ -45,13 +45,13 @@ public sealed partial class StencilOverlay
|
||||
}, Color.Transparent);
|
||||
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
worldHandle.UseShader(_protoManager.Index<ShaderPrototype>("StencilMask").Instance());
|
||||
worldHandle.UseShader(_protoManager.Index(StencilMask).Instance());
|
||||
worldHandle.DrawTextureRect(_blep!.Texture, worldBounds);
|
||||
var curTime = _timing.RealTime;
|
||||
var sprite = _sprite.GetFrame(new SpriteSpecifier.Texture(new ResPath("/Textures/Parallaxes/noise.png")), curTime);
|
||||
|
||||
// Draw the rain
|
||||
worldHandle.UseShader(_protoManager.Index<ShaderPrototype>("StencilDraw").Instance());
|
||||
worldHandle.UseShader(_protoManager.Index(StencilDraw).Instance());
|
||||
_parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, new Vector2(0.5f, 0f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,13 +55,13 @@ public sealed partial class StencilOverlay
|
||||
}, Color.Transparent);
|
||||
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
worldHandle.UseShader(_protoManager.Index<ShaderPrototype>("StencilMask").Instance());
|
||||
worldHandle.UseShader(_protoManager.Index(StencilMask).Instance());
|
||||
worldHandle.DrawTextureRect(_blep!.Texture, worldBounds);
|
||||
var curTime = _timing.RealTime;
|
||||
var sprite = _sprite.GetFrame(weatherProto.Sprite, curTime);
|
||||
|
||||
// Draw the rain
|
||||
worldHandle.UseShader(_protoManager.Index<ShaderPrototype>("StencilDraw").Instance());
|
||||
worldHandle.UseShader(_protoManager.Index(StencilDraw).Instance());
|
||||
_parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, Vector2.Zero, modulate: (weatherProto.Color ?? Color.White).WithAlpha(alpha));
|
||||
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
|
||||
@@ -17,6 +17,10 @@ namespace Content.Client.Overlays;
|
||||
/// </summary>
|
||||
public sealed partial class StencilOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> CircleShader = "WorldGradientCircle";
|
||||
private static readonly ProtoId<ShaderPrototype> StencilMask = "StencilMask";
|
||||
private static readonly ProtoId<ShaderPrototype> StencilDraw = "StencilDraw";
|
||||
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
@@ -43,7 +47,7 @@ public sealed partial class StencilOverlay : Overlay
|
||||
_sprite = sprite;
|
||||
_weather = weather;
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _protoManager.Index<ShaderPrototype>("WorldGradientCircle").InstanceUnique();
|
||||
_shader = _protoManager.Index(CircleShader).InstanceUnique();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Content.Client.Paper.UI;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class StampLabel : Label
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> PaperStamp = "PaperStamp";
|
||||
|
||||
/// A scale that's applied to the text to ensure it
|
||||
/// fits in the allowed space.
|
||||
private Vector2 _textScaling = Vector2.One;
|
||||
@@ -26,7 +28,7 @@ public sealed partial class StampLabel : Label
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
var prototypes = IoCManager.Resolve<IPrototypeManager>();
|
||||
_stampShader = prototypes.Index<ShaderPrototype>("PaperStamp").InstanceUnique();
|
||||
_stampShader = prototypes.Index(PaperStamp).InstanceUnique();
|
||||
}
|
||||
|
||||
protected override Vector2 MeasureOverride(Vector2 availableSize)
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Content.Client.Paper.UI;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class StampWidget : PanelContainer
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> PaperStamp = "PaperStamp";
|
||||
|
||||
private StyleBoxTexture _borderTexture;
|
||||
private ShaderInstance? _stampShader;
|
||||
|
||||
@@ -42,7 +44,7 @@ public sealed partial class StampWidget : PanelContainer
|
||||
PanelOverride = _borderTexture;
|
||||
|
||||
var prototypes = IoCManager.Resolve<IPrototypeManager>();
|
||||
_stampShader = prototypes.Index<ShaderPrototype>("PaperStamp").InstanceUnique();
|
||||
_stampShader = prototypes.Index(PaperStamp).InstanceUnique();
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
|
||||
@@ -14,8 +14,7 @@ public sealed class ParallaxSystem : SharedParallaxSystem
|
||||
[Dependency] private readonly IParallaxManager _parallax = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
|
||||
[ValidatePrototypeId<ParallaxPrototype>]
|
||||
private const string Fallback = "Default";
|
||||
private static readonly ProtoId<ParallaxPrototype> Fallback = "Default";
|
||||
|
||||
public const int ParallaxZIndex = 0;
|
||||
|
||||
|
||||
@@ -262,6 +262,7 @@ public sealed partial class ParticleAcceleratorControlMenu : FancyWindow
|
||||
|
||||
public sealed class PASegmentControl : Control
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> GreyscaleShaderId = "Greyscale";
|
||||
private readonly ShaderInstance _greyScaleShader;
|
||||
private readonly TextureRect _base;
|
||||
private readonly TextureRect _unlit;
|
||||
@@ -272,7 +273,7 @@ public sealed class PASegmentControl : Control
|
||||
|
||||
public PASegmentControl()
|
||||
{
|
||||
_greyScaleShader = IoCManager.Resolve<IPrototypeManager>().Index<ShaderPrototype>("Greyscale").Instance();
|
||||
_greyScaleShader = IoCManager.Resolve<IPrototypeManager>().Index(GreyscaleShaderId).Instance();
|
||||
|
||||
AddChild(_base = new TextureRect());
|
||||
AddChild(_unlit = new TextureRect());
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace Content.Client.Popups;
|
||||
/// </summary>
|
||||
public sealed class PopupOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
|
||||
private readonly IConfigurationManager _configManager;
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly IPlayerManager _playerMgr;
|
||||
@@ -48,7 +50,7 @@ public sealed class PopupOverlay : Overlay
|
||||
_popup = popup;
|
||||
_controller = controller;
|
||||
|
||||
_shader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_shader = protoManager.Index(UnshadedShader).Instance();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -15,8 +15,7 @@ namespace Content.Client.Power.Generation.Teg;
|
||||
/// <seealso cref="TegCirculatorComponent"/>
|
||||
public sealed class TegSystem : EntitySystem
|
||||
{
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string ArrowPrototype = "TegCirculatorArrow";
|
||||
private static readonly EntProtoId ArrowPrototype = "TegCirculatorArrow";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
@@ -48,8 +48,9 @@ public sealed class PowerCellSystem : SharedPowerCellSystem
|
||||
if (!_sprite.LayerExists((uid, args.Sprite), PowerCellVisualLayers.Unshaded))
|
||||
return;
|
||||
|
||||
// If no appearance data is set, rely on whatever existing sprite state is set being correct.
|
||||
if (!_appearance.TryGetData<byte>(uid, PowerCellVisuals.ChargeLevel, out var level, args.Component))
|
||||
level = 0;
|
||||
return;
|
||||
|
||||
var positiveCharge = level > 0;
|
||||
_sprite.LayerSetVisible((uid, args.Sprite), PowerCellVisualLayers.Unshaded, positiveCharge);
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Content.Client.Radiation.Overlays
|
||||
{
|
||||
public sealed class RadiationPulseOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> RadiationShader = "Radiation";
|
||||
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
@@ -29,7 +31,7 @@ namespace Content.Client.Radiation.Overlays
|
||||
public RadiationPulseOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_baseShader = _prototypeManager.Index<ShaderPrototype>("Radiation").Instance().Duplicate();
|
||||
_baseShader = _prototypeManager.Index(RadiationShader).Instance().Duplicate();
|
||||
}
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace Content.Client.Shuttles;
|
||||
/// </summary>
|
||||
public sealed class FtlArrivalOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities;
|
||||
|
||||
private EntityLookupSystem _lookups;
|
||||
@@ -36,7 +38,7 @@ public sealed class FtlArrivalOverlay : Overlay
|
||||
_maps = _entManager.System<SharedMapSystem>();
|
||||
_sprites = _entManager.System<SpriteSystem>();
|
||||
|
||||
_shader = _protos.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_shader = _protos.Index(UnshadedShader).Instance();
|
||||
}
|
||||
|
||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -25,7 +25,6 @@ public sealed partial class BorgSelectTypeMenu : FancyWindow
|
||||
|
||||
public event Action<ProtoId<BorgTypePrototype>>? ConfirmedBorgType;
|
||||
|
||||
[ValidatePrototypeId<GuideEntryPrototype>]
|
||||
private static readonly List<ProtoId<GuideEntryPrototype>> GuidebookEntries = new() { "Cyborgs", "Robotics" };
|
||||
|
||||
public BorgSelectTypeMenu()
|
||||
|
||||
@@ -84,12 +84,13 @@ public sealed partial class LawDisplay : Control
|
||||
|
||||
radioChannelButton.OnPressed += _ =>
|
||||
{
|
||||
switch (radioChannel)
|
||||
if (radioChannel == SharedChatSystem.CommonChannel)
|
||||
{
|
||||
case SharedChatSystem.CommonChannel:
|
||||
_chatManager.SendMessage($"{SharedChatSystem.RadioCommonPrefix} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break;
|
||||
default:
|
||||
_chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break;
|
||||
_chatManager.SendMessage($"{SharedChatSystem.RadioCommonPrefix} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio);
|
||||
}
|
||||
else
|
||||
{
|
||||
_chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio);
|
||||
}
|
||||
_nextAllowedPress[radioChannelButton] = _timing.CurTime + PressCooldown;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,10 @@ namespace Content.Client.Silicons.StationAi;
|
||||
|
||||
public sealed class StationAiOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> CameraStaticShader = "CameraStatic";
|
||||
private static readonly ProtoId<ShaderPrototype> StencilMaskShader = "StencilMask";
|
||||
private static readonly ProtoId<ShaderPrototype> StencilDrawShader = "StencilDraw";
|
||||
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
@@ -91,7 +95,7 @@ public sealed class StationAiOverlay : Overlay
|
||||
() =>
|
||||
{
|
||||
worldHandle.SetTransform(invMatrix);
|
||||
var shader = _proto.Index<ShaderPrototype>("CameraStatic").Instance();
|
||||
var shader = _proto.Index(CameraStaticShader).Instance();
|
||||
worldHandle.UseShader(shader);
|
||||
worldHandle.DrawRect(worldBounds, Color.White);
|
||||
},
|
||||
@@ -114,11 +118,11 @@ public sealed class StationAiOverlay : Overlay
|
||||
}
|
||||
|
||||
// Use the lighting as a mask
|
||||
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilMask").Instance());
|
||||
worldHandle.UseShader(_proto.Index(StencilMaskShader).Instance());
|
||||
worldHandle.DrawTextureRect(_stencilTexture!.Texture, worldBounds);
|
||||
|
||||
// Draw the static
|
||||
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilDraw").Instance());
|
||||
worldHandle.UseShader(_proto.Index(StencilDrawShader).Instance());
|
||||
worldHandle.DrawTextureRect(_staticTexture!.Texture, worldBounds);
|
||||
|
||||
worldHandle.SetTransform(Matrix3x2.Identity);
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Content.Client.Singularity
|
||||
{
|
||||
public sealed class SingularityOverlay : Overlay, IEntityEventSubscriber
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "Singularity";
|
||||
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
private SharedTransformSystem? _xformSystem = null;
|
||||
@@ -29,7 +31,7 @@ namespace Content.Client.Singularity
|
||||
public SingularityOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_shader = _prototypeManager.Index<ShaderPrototype>("Singularity").Instance().Duplicate();
|
||||
_shader = _prototypeManager.Index(Shader).Instance().Duplicate();
|
||||
_shader.SetParameter("maxDistance", MaxDistance * EyeManager.PixelsPerMeter);
|
||||
_entMan.EventBus.SubscribeEvent<PixelToMapEvent>(EventSource.Local, this, OnProjectFromScreenToMap);
|
||||
ZIndex = 101; // Should be drawn after the placement overlay so admins placing items near the singularity can tell where they're going.
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Content.Client.StatusIcon;
|
||||
|
||||
public sealed class StatusIconOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
@@ -29,7 +31,7 @@ public sealed class StatusIconOverlay : Overlay
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
_transform = _entity.System<TransformSystem>();
|
||||
_statusIcon = _entity.System<StatusIconSystem>();
|
||||
_unshadedShader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
|
||||
_unshadedShader = _prototype.Index(UnshadedShader).Instance();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Content.Client.Stealth;
|
||||
|
||||
public sealed class StealthSystem : SharedStealthSystem
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> Shader = "Stealth";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
@@ -20,7 +22,7 @@ public sealed class StealthSystem : SharedStealthSystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_shader = _protoMan.Index<ShaderPrototype>("Stealth").InstanceUnique();
|
||||
_shader = _protoMan.Index(Shader).InstanceUnique();
|
||||
|
||||
SubscribeLocalEvent<StealthComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<StealthComponent, ComponentStartup>(OnStartup);
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<BoxContainer Margin="8,8,8,8" Orientation="Vertical">
|
||||
<BoxContainer Margin="8,0,8,8" Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Name="StoreItemName" HorizontalExpand="True" />
|
||||
<Label Name="DiscountSubText"
|
||||
HorizontalAlignment="Right"/>
|
||||
<Button
|
||||
Name="StoreItemBuyButton"
|
||||
MinWidth="64"
|
||||
HorizontalAlignment="Right"
|
||||
Access="Public" />
|
||||
</BoxContainer>
|
||||
<PanelContainer StyleClasses="HighDivider" />
|
||||
<PanelContainer StyleClasses="HighDivider" Margin="0,1,0,2"/>
|
||||
<BoxContainer HorizontalExpand="True" Orientation="Horizontal">
|
||||
<TextureRect
|
||||
Name="StoreItemTexture"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
Stretch="KeepAspectCentered" />
|
||||
<Control MinWidth="5"/>
|
||||
<RichTextLabel Name="StoreItemDescription" />
|
||||
<BoxContainer Orientation="Vertical" VerticalAlignment="Center" Margin="0,0,4,0">
|
||||
<TextureRect
|
||||
Name="StoreItemTexture"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
Stretch="KeepAspectCentered" />
|
||||
<Button
|
||||
Name="StoreItemBuyButton"
|
||||
MinWidth="48"
|
||||
MaxHeight="48"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Top"
|
||||
Margin="0,4,0,0"
|
||||
Access="Public" />
|
||||
<Label Name="DiscountSubText"
|
||||
HorizontalAlignment="Center"/>
|
||||
</BoxContainer>
|
||||
<RichTextLabel Name="StoreItemDescription" VerticalAlignment="Top"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Content.Client.SurveillanceCamera.UI;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> CameraStaticShader = "CameraStatic";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
|
||||
@@ -53,7 +55,7 @@ public sealed partial class SurveillanceCameraMonitorWindow : DefaultWindow
|
||||
|
||||
// This could be done better. I don't want to deal with stylesheets at the moment.
|
||||
var texture = _resourceCache.GetTexture("/Textures/Interface/Nano/square_black.png");
|
||||
var shader = _prototypeManager.Index<ShaderPrototype>("CameraStatic").Instance().Duplicate();
|
||||
var shader = _prototypeManager.Index(CameraStaticShader).Instance().Duplicate();
|
||||
|
||||
CameraView.ViewportSize = new Vector2i(500, 500);
|
||||
CameraView.Eye = _defaultEye; // sure
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Content.Client.UserInterface.RichText;
|
||||
/// </summary>
|
||||
public sealed class MonoTag : IMarkupTag
|
||||
{
|
||||
[ValidatePrototypeId<FontPrototype>] public const string MonoFont = "Monospace";
|
||||
public static readonly ProtoId<FontPrototype> MonoFont = "Monospace";
|
||||
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
@@ -67,8 +67,7 @@ public sealed partial class ChatUIController : UIController
|
||||
[UISystemDependency] private readonly MindSystem? _mindSystem = default!;
|
||||
[UISystemDependency] private readonly RoleCodewordSystem? _roleCodewordSystem = default!;
|
||||
|
||||
[ValidatePrototypeId<ColorPalettePrototype>]
|
||||
private const string ChatNamePalette = "ChatNames";
|
||||
private static readonly ProtoId<ColorPalettePrototype> ChatNamePalette = "ChatNames";
|
||||
private string[] _chatNameColors = default!;
|
||||
private bool _chatNameColorsEnabled;
|
||||
|
||||
@@ -232,7 +231,7 @@ public sealed partial class ChatUIController : UIController
|
||||
gameplayStateLoad.OnScreenLoad += OnScreenLoad;
|
||||
gameplayStateLoad.OnScreenUnload += OnScreenUnload;
|
||||
|
||||
var nameColors = _prototypeManager.Index<ColorPalettePrototype>(ChatNamePalette).Colors.Values.ToArray();
|
||||
var nameColors = _prototypeManager.Index(ChatNamePalette).Colors.Values.ToArray();
|
||||
_chatNameColors = new string[nameColors.Length];
|
||||
for (var i = 0; i < nameColors.Length; i++)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Content.Client.UserInterface.Systems.DamageOverlays.Overlays;
|
||||
|
||||
public sealed class DamageOverlay : Overlay
|
||||
{
|
||||
private static readonly ProtoId<ShaderPrototype> CircleMaskShader = "GradientCircleMask";
|
||||
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
@@ -49,9 +51,9 @@ public sealed class DamageOverlay : Overlay
|
||||
{
|
||||
// TODO: Replace
|
||||
IoCManager.InjectDependencies(this);
|
||||
_oxygenShader = _prototypeManager.Index<ShaderPrototype>("GradientCircleMask").InstanceUnique();
|
||||
_critShader = _prototypeManager.Index<ShaderPrototype>("GradientCircleMask").InstanceUnique();
|
||||
_bruteShader = _prototypeManager.Index<ShaderPrototype>("GradientCircleMask").InstanceUnique();
|
||||
_oxygenShader = _prototypeManager.Index(CircleMaskShader).InstanceUnique();
|
||||
_critShader = _prototypeManager.Index(CircleMaskShader).InstanceUnique();
|
||||
_bruteShader = _prototypeManager.Index(CircleMaskShader).InstanceUnique();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
|
||||
@@ -19,8 +19,7 @@ public sealed class InfoUIController : UIController, IOnStateExited<GameplayStat
|
||||
private RulesPopup? _rulesPopup;
|
||||
private RulesAndInfoWindow? _infoWindow;
|
||||
|
||||
[ValidatePrototypeId<GuideEntryPrototype>]
|
||||
private const string DefaultRuleset = "DefaultRuleset";
|
||||
private static readonly ProtoId<GuideEntryPrototype> DefaultRuleset = "DefaultRuleset";
|
||||
|
||||
public ProtoId<GuideEntryPrototype> RulesEntryId = DefaultRuleset;
|
||||
|
||||
@@ -92,7 +91,7 @@ public sealed class InfoUIController : UIController, IOnStateExited<GameplayStat
|
||||
{
|
||||
if (!_prototype.TryIndex(RulesEntryId, out var guideEntryPrototype))
|
||||
{
|
||||
guideEntryPrototype = _prototype.Index<GuideEntryPrototype>(DefaultRuleset);
|
||||
guideEntryPrototype = _prototype.Index(DefaultRuleset);
|
||||
Log.Error($"Couldn't find the following prototype: {RulesEntryId}. Falling back to {DefaultRuleset}, please check that the server has the rules set up correctly");
|
||||
return guideEntryPrototype;
|
||||
}
|
||||
|
||||
@@ -39,8 +39,7 @@ public sealed partial class GunSystem : SharedGunSystem
|
||||
[Dependency] private readonly SharedTransformSystem _xform = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
public const string HitscanProto = "HitscanEffect";
|
||||
public static readonly EntProtoId HitscanProto = "HitscanEffect";
|
||||
|
||||
public bool SpreadOverlay
|
||||
{
|
||||
|
||||
@@ -7,10 +7,12 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
[TestOf(typeof(AtmosAlarmThreshold))]
|
||||
public sealed class AlarmThresholdTest
|
||||
{
|
||||
private const string AlarmThresholdTestDummyId = "AlarmThresholdTestDummy";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = @"
|
||||
private const string Prototypes = $@"
|
||||
- type: alarmThreshold
|
||||
id: AlarmThresholdTestDummy
|
||||
id: {AlarmThresholdTestDummyId}
|
||||
upperBound: !type:AlarmThresholdSetting
|
||||
threshold: 5
|
||||
lowerBound: !type:AlarmThresholdSetting
|
||||
@@ -30,7 +32,7 @@ namespace Content.IntegrationTests.Tests.Atmos
|
||||
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
AtmosAlarmThreshold threshold = default!;
|
||||
|
||||
var proto = prototypeManager.Index<AtmosAlarmThresholdPrototype>("AlarmThresholdTestDummy");
|
||||
var proto = prototypeManager.Index<AtmosAlarmThresholdPrototype>(AlarmThresholdTestDummyId);
|
||||
threshold = new(proto);
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using Content.Shared.Cloning;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Cloning;
|
||||
|
||||
public sealed class CloningSettingsPrototypeTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks that the components named in every <see cref="CloningSettingsPrototype"/> are valid components known to the server.
|
||||
/// This is used instead of <see cref="ComponentNameSerializer"/> because we only care if the components are registered with the server,
|
||||
/// and instead of a <see cref="ComponentRegistry"/> because we only need component names.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ValidatePrototypes()
|
||||
{
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
var protoMan = server.ProtoMan;
|
||||
var compFactory = server.EntMan.ComponentFactory;
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
var protos = protoMan.EnumeratePrototypes<CloningSettingsPrototype>();
|
||||
foreach (var proto in protos)
|
||||
{
|
||||
foreach (var compName in proto.Components)
|
||||
{
|
||||
Assert.That(compFactory.TryGetRegistration(compName, out _),
|
||||
$"Failed to find a component named {compName} for {nameof(CloningSettingsPrototype)} \"{proto.ID}\""
|
||||
);
|
||||
}
|
||||
|
||||
foreach (var eventCompName in proto.EventComponents)
|
||||
{
|
||||
Assert.That(compFactory.TryGetRegistration(eventCompName, out _),
|
||||
$"Failed to find a component named {eventCompName} for {nameof(CloningSettingsPrototype)} \"{proto.ID}\""
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#nullable enable
|
||||
using System.Linq;
|
||||
using Content.Server.Objectives;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Commands;
|
||||
|
||||
public sealed class ObjectiveCommandsTest
|
||||
{
|
||||
|
||||
private const string ObjectiveProtoId = "MindCommandsTestObjective";
|
||||
private const string DummyUsername = "MindCommandsTestUser";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = $"""
|
||||
- type: entity
|
||||
id: {ObjectiveProtoId}
|
||||
components:
|
||||
- type: Objective
|
||||
difficulty: 1
|
||||
issuer: objective-issuer-syndicate
|
||||
icon:
|
||||
sprite: error.rsi
|
||||
state: error
|
||||
- type: DieCondition
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a dummy session, and assigns it a mind, then
|
||||
/// tests using <c>addobjective</c>, <c>lsobjectives</c>,
|
||||
/// and <c>rmobjective</c> on it.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AddListRemoveObjectiveTest()
|
||||
{
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
var entMan = server.EntMan;
|
||||
var playerMan = server.ResolveDependency<ISharedPlayerManager>();
|
||||
var mindSys = server.System<SharedMindSystem>();
|
||||
var objectivesSystem = server.System<ObjectivesSystem>();
|
||||
|
||||
await server.AddDummySession(DummyUsername);
|
||||
await server.WaitRunTicks(5);
|
||||
|
||||
var playerSession = playerMan.Sessions.Single();
|
||||
|
||||
Entity<MindComponent>? mindEnt = null;
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
mindEnt = mindSys.CreateMind(playerSession.UserId);
|
||||
});
|
||||
|
||||
Assert.That(mindEnt, Is.Not.Null);
|
||||
var mindComp = mindEnt.Value.Comp;
|
||||
Assert.That(mindComp.Objectives, Is.Empty, "Dummy player started with objectives.");
|
||||
|
||||
await pair.WaitCommand($"addobjective {playerSession.Name} {ObjectiveProtoId}");
|
||||
|
||||
Assert.That(mindComp.Objectives, Has.Count.EqualTo(1), "addobjective failed to increase Objectives count.");
|
||||
|
||||
await pair.WaitCommand($"lsobjectives {playerSession.Name}");
|
||||
|
||||
await pair.WaitCommand($"rmobjective {playerSession.Name} 0");
|
||||
|
||||
Assert.That(mindComp.Objectives, Is.Empty, "rmobjective failed to remove objective");
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
[TestOf(typeof(RejuvenateSystem))]
|
||||
public sealed class RejuvenateTest
|
||||
{
|
||||
private static readonly ProtoId<DamageGroupPrototype> TestDamageGroup = "Toxin";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -62,7 +64,7 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
});
|
||||
|
||||
// Kill the entity
|
||||
DamageSpecifier damage = new(prototypeManager.Index<DamageGroupPrototype>("Toxin"), FixedPoint2.New(10000000));
|
||||
DamageSpecifier damage = new(prototypeManager.Index(TestDamageGroup), FixedPoint2.New(10000000));
|
||||
|
||||
damSystem.TryChangeDamage(human, damage, true);
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ public sealed class SuicideCommandTests
|
||||
components:
|
||||
- type: MaterialReclaimer";
|
||||
private static readonly ProtoId<TagPrototype> CannotSuicideTag = "CannotSuicide";
|
||||
private static readonly ProtoId<DamageTypePrototype> DamageType = "Slash";
|
||||
|
||||
/// <summary>
|
||||
/// Run the suicide command in the console
|
||||
/// Should successfully kill the player and ghost them
|
||||
@@ -144,7 +146,7 @@ public sealed class SuicideCommandTests
|
||||
mobThresholdsComp = entManager.GetComponent<MobThresholdsComponent>(player);
|
||||
damageableComp = entManager.GetComponent<DamageableComponent>(player);
|
||||
|
||||
if (protoMan.TryIndex<DamageTypePrototype>("Slash", out var slashProto))
|
||||
if (protoMan.TryIndex(DamageType, out var slashProto))
|
||||
damageableSystem.TryChangeDamage(player, new DamageSpecifier(slashProto, FixedPoint2.New(46.5)));
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace Content.IntegrationTests.Tests.Construction.Interaction;
|
||||
|
||||
public sealed class WindowRepair : InteractionTest
|
||||
{
|
||||
private static readonly ProtoId<DamageTypePrototype> BluntDamageType = "Blunt";
|
||||
|
||||
[Test]
|
||||
public async Task RepairReinforcedWindow()
|
||||
{
|
||||
@@ -16,7 +18,7 @@ public sealed class WindowRepair : InteractionTest
|
||||
// Damage the entity.
|
||||
var sys = SEntMan.System<DamageableSystem>();
|
||||
var comp = Comp<DamageableComponent>();
|
||||
var damageType = Server.ResolveDependency<IPrototypeManager>().Index<DamageTypePrototype>("Blunt");
|
||||
var damageType = Server.ProtoMan.Index(BluntDamageType);
|
||||
var damage = new DamageSpecifier(damageType, FixedPoint2.New(10));
|
||||
Assert.That(comp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero));
|
||||
await Server.WaitPost(() => sys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true));
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -14,66 +12,79 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
[TestOf(typeof(DamageableSystem))]
|
||||
public sealed class DamageableTest
|
||||
{
|
||||
private const string TestDamageableEntityId = "TestDamageableEntityId";
|
||||
private const string TestGroup1 = "TestGroup1";
|
||||
private const string TestGroup2 = "TestGroup2";
|
||||
private const string TestGroup3 = "TestGroup3";
|
||||
private const string TestDamage1 = "TestDamage1";
|
||||
private const string TestDamage2a = "TestDamage2a";
|
||||
private const string TestDamage2b = "TestDamage2b";
|
||||
|
||||
private const string TestDamage3a = "TestDamage3a";
|
||||
|
||||
private const string TestDamage3b = "TestDamage3b";
|
||||
private const string TestDamage3c = "TestDamage3c";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = @"
|
||||
private const string Prototypes = $@"
|
||||
# Define some damage groups
|
||||
- type: damageType
|
||||
id: TestDamage1
|
||||
id: {TestDamage1}
|
||||
name: damage-type-blunt
|
||||
|
||||
- type: damageType
|
||||
id: TestDamage2a
|
||||
id: {TestDamage2a}
|
||||
name: damage-type-blunt
|
||||
|
||||
- type: damageType
|
||||
id: TestDamage2b
|
||||
id: {TestDamage2b}
|
||||
name: damage-type-blunt
|
||||
|
||||
- type: damageType
|
||||
id: TestDamage3a
|
||||
id: {TestDamage3a}
|
||||
name: damage-type-blunt
|
||||
|
||||
- type: damageType
|
||||
id: TestDamage3b
|
||||
id: {TestDamage3b}
|
||||
name: damage-type-blunt
|
||||
|
||||
- type: damageType
|
||||
id: TestDamage3c
|
||||
id: {TestDamage3c}
|
||||
name: damage-type-blunt
|
||||
|
||||
# Define damage Groups with 1,2,3 damage types
|
||||
- type: damageGroup
|
||||
id: TestGroup1
|
||||
id: {TestGroup1}
|
||||
name: damage-group-brute
|
||||
damageTypes:
|
||||
- TestDamage1
|
||||
- {TestDamage1}
|
||||
|
||||
- type: damageGroup
|
||||
id: TestGroup2
|
||||
id: {TestGroup2}
|
||||
name: damage-group-brute
|
||||
damageTypes:
|
||||
- TestDamage2a
|
||||
- TestDamage2b
|
||||
- {TestDamage2a}
|
||||
- {TestDamage2b}
|
||||
|
||||
- type: damageGroup
|
||||
id: TestGroup3
|
||||
id: {TestGroup3}
|
||||
name: damage-group-brute
|
||||
damageTypes:
|
||||
- TestDamage3a
|
||||
- TestDamage3b
|
||||
- TestDamage3c
|
||||
- {TestDamage3a}
|
||||
- {TestDamage3b}
|
||||
- {TestDamage3c}
|
||||
|
||||
# This container should not support TestDamage1 or TestDamage2b
|
||||
- type: damageContainer
|
||||
id: testDamageContainer
|
||||
supportedGroups:
|
||||
- TestGroup3
|
||||
- {TestGroup3}
|
||||
supportedTypes:
|
||||
- TestDamage2a
|
||||
- {TestDamage2a}
|
||||
|
||||
- type: entity
|
||||
id: TestDamageableEntityId
|
||||
name: TestDamageableEntityId
|
||||
id: {TestDamageableEntityId}
|
||||
name: {TestDamageableEntityId}
|
||||
components:
|
||||
- type: Damageable
|
||||
damageContainer: testDamageContainer
|
||||
@@ -113,20 +124,20 @@ namespace Content.IntegrationTests.Tests.Damageable
|
||||
{
|
||||
var coordinates = map.MapCoords;
|
||||
|
||||
sDamageableEntity = sEntityManager.SpawnEntity("TestDamageableEntityId", coordinates);
|
||||
sDamageableEntity = sEntityManager.SpawnEntity(TestDamageableEntityId, coordinates);
|
||||
sDamageableComponent = sEntityManager.GetComponent<DamageableComponent>(sDamageableEntity);
|
||||
sDamageableSystem = sEntitySystemManager.GetEntitySystem<DamageableSystem>();
|
||||
|
||||
group1 = sPrototypeManager.Index<DamageGroupPrototype>("TestGroup1");
|
||||
group2 = sPrototypeManager.Index<DamageGroupPrototype>("TestGroup2");
|
||||
group3 = sPrototypeManager.Index<DamageGroupPrototype>("TestGroup3");
|
||||
group1 = sPrototypeManager.Index<DamageGroupPrototype>(TestGroup1);
|
||||
group2 = sPrototypeManager.Index<DamageGroupPrototype>(TestGroup2);
|
||||
group3 = sPrototypeManager.Index<DamageGroupPrototype>(TestGroup3);
|
||||
|
||||
type1 = sPrototypeManager.Index<DamageTypePrototype>("TestDamage1");
|
||||
type2a = sPrototypeManager.Index<DamageTypePrototype>("TestDamage2a");
|
||||
type2b = sPrototypeManager.Index<DamageTypePrototype>("TestDamage2b");
|
||||
type3a = sPrototypeManager.Index<DamageTypePrototype>("TestDamage3a");
|
||||
type3b = sPrototypeManager.Index<DamageTypePrototype>("TestDamage3b");
|
||||
type3c = sPrototypeManager.Index<DamageTypePrototype>("TestDamage3c");
|
||||
type1 = sPrototypeManager.Index<DamageTypePrototype>(TestDamage1);
|
||||
type2a = sPrototypeManager.Index<DamageTypePrototype>(TestDamage2a);
|
||||
type2b = sPrototypeManager.Index<DamageTypePrototype>(TestDamage2b);
|
||||
type3a = sPrototypeManager.Index<DamageTypePrototype>(TestDamage3a);
|
||||
type3b = sPrototypeManager.Index<DamageTypePrototype>(TestDamage3b);
|
||||
type3c = sPrototypeManager.Index<DamageTypePrototype>(TestDamage3c);
|
||||
});
|
||||
|
||||
await server.WaitRunTicks(5);
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var bruteDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>("TestBrute");
|
||||
var burnDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>("TestBurn");
|
||||
var bruteDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>(TestBruteDamageGroupId);
|
||||
var burnDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>(TestBurnDamageGroupId);
|
||||
|
||||
DamageSpecifier bruteDamage = new(bruteDamageGroup, FixedPoint2.New(5));
|
||||
DamageSpecifier burnDamage = new(burnDamageGroup, FixedPoint2.New(5));
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var bluntDamageType = protoManager.Index<DamageTypePrototype>("TestBlunt");
|
||||
var slashDamageType = protoManager.Index<DamageTypePrototype>("TestSlash");
|
||||
var bluntDamageType = protoManager.Index<DamageTypePrototype>(TestBluntDamageTypeId);
|
||||
var slashDamageType = protoManager.Index<DamageTypePrototype>(TestSlashDamageTypeId);
|
||||
|
||||
var bluntDamage = new DamageSpecifier(bluntDamageType, 5);
|
||||
var slashDamage = new DamageSpecifier(slashDamageType, 5);
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var coordinates = sEntityManager.GetComponent<TransformComponent>(sDestructibleEntity).Coordinates;
|
||||
var bruteDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>("TestBrute");
|
||||
var bruteDamageGroup = sPrototypeManager.Index<DamageGroupPrototype>(TestBruteDamageGroupId);
|
||||
DamageSpecifier bruteDamage = new(bruteDamageGroup, 50);
|
||||
|
||||
#pragma warning disable NUnit2045 // Interdependent assertions.
|
||||
|
||||
@@ -7,48 +7,56 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
public const string DestructibleDestructionEntityId = "DestructibleTestsDestructibleDestructionEntity";
|
||||
public const string DestructibleDamageTypeEntityId = "DestructibleTestsDestructibleDamageTypeEntity";
|
||||
public const string DestructibleDamageGroupEntityId = "DestructibleTestsDestructibleDamageGroupEntity";
|
||||
public const string TestBruteDamageGroupId = "TestBrute";
|
||||
public const string TestBurnDamageGroupId = "TestBurn";
|
||||
public const string TestBluntDamageTypeId = "TestBlunt";
|
||||
public const string TestSlashDamageTypeId = "TestSlash";
|
||||
public const string TestPiercingDamageTypeId = "TestPiercing";
|
||||
public const string TestHeatDamageTypeId = "TestHeat";
|
||||
public const string TestShockDamageTypeId = "TestShock";
|
||||
public const string TestColdDamageTypeId = "TestCold";
|
||||
|
||||
[TestPrototypes]
|
||||
public const string DamagePrototypes = $@"
|
||||
- type: damageType
|
||||
id: TestBlunt
|
||||
id: {TestBluntDamageTypeId}
|
||||
name: damage-type-blunt
|
||||
|
||||
- type: damageType
|
||||
id: TestSlash
|
||||
id: {TestSlashDamageTypeId}
|
||||
name: damage-type-slash
|
||||
|
||||
- type: damageType
|
||||
id: TestPiercing
|
||||
id: {TestPiercingDamageTypeId}
|
||||
name: damage-type-piercing
|
||||
|
||||
- type: damageType
|
||||
id: TestHeat
|
||||
id: {TestHeatDamageTypeId}
|
||||
name: damage-type-heat
|
||||
|
||||
- type: damageType
|
||||
id: TestShock
|
||||
id: {TestShockDamageTypeId}
|
||||
name: damage-type-shock
|
||||
|
||||
- type: damageType
|
||||
id: TestCold
|
||||
id: {TestColdDamageTypeId}
|
||||
name: damage-type-cold
|
||||
|
||||
- type: damageGroup
|
||||
id: TestBrute
|
||||
id: {TestBruteDamageGroupId}
|
||||
name: damage-group-brute
|
||||
damageTypes:
|
||||
- TestBlunt
|
||||
- TestSlash
|
||||
- TestPiercing
|
||||
- {TestBluntDamageTypeId}
|
||||
- {TestSlashDamageTypeId}
|
||||
- {TestPiercingDamageTypeId}
|
||||
|
||||
- type: damageGroup
|
||||
id: TestBurn
|
||||
id: {TestBurnDamageGroupId}
|
||||
name: damage-group-burn
|
||||
damageTypes:
|
||||
- TestHeat
|
||||
- TestShock
|
||||
- TestCold
|
||||
- {TestHeatDamageTypeId}
|
||||
- {TestShockDamageTypeId}
|
||||
- {TestColdDamageTypeId}
|
||||
|
||||
- type: entity
|
||||
id: {SpawnedEntityId}
|
||||
@@ -114,10 +122,10 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
!type:AndTrigger
|
||||
triggers:
|
||||
- !type:DamageTypeTrigger
|
||||
damageType: TestBlunt
|
||||
damageType: {TestBluntDamageTypeId}
|
||||
damage: 10
|
||||
- !type:DamageTypeTrigger
|
||||
damageType: TestSlash
|
||||
damageType: {TestSlashDamageTypeId}
|
||||
damage: 10
|
||||
|
||||
- type: entity
|
||||
@@ -131,10 +139,10 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
!type:AndTrigger
|
||||
triggers:
|
||||
- !type:DamageGroupTrigger
|
||||
damageGroup: TestBrute
|
||||
damageGroup: {TestBruteDamageGroupId}
|
||||
damage: 10
|
||||
- !type:DamageGroupTrigger
|
||||
damageGroup: TestBurn
|
||||
damageGroup: {TestBurnDamageGroupId}
|
||||
damage: 10";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var bluntDamage = new DamageSpecifier(sPrototypeManager.Index<DamageTypePrototype>("TestBlunt"), 10);
|
||||
var bluntDamage = new DamageSpecifier(sPrototypeManager.Index<DamageTypePrototype>(TestBluntDamageTypeId), 10);
|
||||
|
||||
sDamageableSystem.TryChangeDamage(sDestructibleEntity, bluntDamage, true);
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Shared.Tag;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Linter;
|
||||
|
||||
@@ -66,25 +65,25 @@ public sealed class StaticFieldValidationTest
|
||||
[Reflect(false)]
|
||||
private sealed class StringValid
|
||||
{
|
||||
[ValidatePrototypeId<TagPrototype>] public static string Tag = "StaticFieldTestTag";
|
||||
public static readonly ProtoId<TagPrototype> Tag = "StaticFieldTestTag";
|
||||
}
|
||||
|
||||
[Reflect(false)]
|
||||
private sealed class StringInvalid
|
||||
{
|
||||
[ValidatePrototypeId<TagPrototype>] public static string Tag = string.Empty;
|
||||
public static readonly ProtoId<TagPrototype> Tag = string.Empty;
|
||||
}
|
||||
|
||||
[Reflect(false)]
|
||||
private sealed class StringArrayValid
|
||||
{
|
||||
[ValidatePrototypeId<TagPrototype>] public static string[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"];
|
||||
public static readonly ProtoId<TagPrototype>[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"];
|
||||
}
|
||||
|
||||
[Reflect(false)]
|
||||
private sealed class StringArrayInvalid
|
||||
{
|
||||
[ValidatePrototypeId<TagPrototype>] public static string[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty];
|
||||
public static readonly ProtoId<TagPrototype>[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty];
|
||||
}
|
||||
|
||||
[Reflect(false)]
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace Content.IntegrationTests.Tests.Minds;
|
||||
[TestFixture]
|
||||
public sealed partial class MindTests
|
||||
{
|
||||
private static readonly ProtoId<DamageTypePrototype> BluntDamageType = "Blunt";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -144,7 +146,7 @@ public sealed partial class MindTests
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var damageable = entMan.GetComponent<DamageableComponent>(entity);
|
||||
if (!protoMan.TryIndex<DamageTypePrototype>("Blunt", out var prototype))
|
||||
if (!protoMan.TryIndex(BluntDamageType, out var prototype))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,6 +77,8 @@ namespace Content.IntegrationTests.Tests
|
||||
"Exo",
|
||||
};
|
||||
|
||||
private static readonly ProtoId<EntityCategoryPrototype> DoNotMapCategory = "DoNotMap";
|
||||
|
||||
/// <summary>
|
||||
/// Asserts that specific files have been saved as grids and not maps.
|
||||
/// </summary>
|
||||
@@ -254,7 +256,7 @@ namespace Content.IntegrationTests.Tests
|
||||
return;
|
||||
|
||||
var yamlEntities = node["entities"];
|
||||
if (!protoManager.TryIndex<EntityCategoryPrototype>("DoNotMap", out var dnmCategory))
|
||||
if (!protoManager.TryIndex(DoNotMapCategory, out var dnmCategory))
|
||||
return;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
|
||||
@@ -17,8 +17,10 @@ namespace Content.IntegrationTests.Tests.Station;
|
||||
[TestOf(typeof(StationJobsSystem))]
|
||||
public sealed class StationJobsTest
|
||||
{
|
||||
private const string StationMapId = "FooStation";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = @"
|
||||
private const string Prototypes = $@"
|
||||
- type: playTimeTracker
|
||||
id: PlayTimeDummyAssistant
|
||||
|
||||
@@ -35,13 +37,13 @@ public sealed class StationJobsTest
|
||||
id: PlayTimeDummyChaplain
|
||||
|
||||
- type: gameMap
|
||||
id: FooStation
|
||||
id: {StationMapId}
|
||||
minPlayers: 0
|
||||
mapName: FooStation
|
||||
mapName: {StationMapId}
|
||||
mapPath: /Maps/Test/empty.yml
|
||||
stations:
|
||||
Station:
|
||||
mapNameTemplate: FooStation
|
||||
mapNameTemplate: {StationMapId}
|
||||
stationProto: StandardNanotrasenStation
|
||||
components:
|
||||
- type: StationJobs
|
||||
@@ -87,7 +89,7 @@ public sealed class StationJobsTest
|
||||
var server = pair.Server;
|
||||
|
||||
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var fooStationProto = prototypeManager.Index<GameMapPrototype>("FooStation");
|
||||
var fooStationProto = prototypeManager.Index<GameMapPrototype>(StationMapId);
|
||||
var entSysMan = server.ResolveDependency<IEntityManager>().EntitySysManager;
|
||||
var stationJobs = entSysMan.GetEntitySystem<StationJobsSystem>();
|
||||
var stationSystem = entSysMan.GetEntitySystem<StationSystem>();
|
||||
@@ -161,7 +163,7 @@ public sealed class StationJobsTest
|
||||
var server = pair.Server;
|
||||
|
||||
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var fooStationProto = prototypeManager.Index<GameMapPrototype>("FooStation");
|
||||
var fooStationProto = prototypeManager.Index<GameMapPrototype>(StationMapId);
|
||||
var entSysMan = server.ResolveDependency<IEntityManager>().EntitySysManager;
|
||||
var stationJobs = entSysMan.GetEntitySystem<StationJobsSystem>();
|
||||
var stationSystem = entSysMan.GetEntitySystem<StationSystem>();
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.VendingMachines;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Vending;
|
||||
|
||||
@@ -17,6 +18,7 @@ public sealed class VendingInteractionTest : InteractionTest
|
||||
private const string RestockBoxProtoId = "InteractionTestRestockBox";
|
||||
|
||||
private const string RestockBoxOtherProtoId = "InteractionTestRestockBoxOther";
|
||||
private static readonly ProtoId<DamageTypePrototype> TestDamageType = "Blunt";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string TestPrototypes = $@"
|
||||
@@ -196,7 +198,7 @@ public sealed class VendingInteractionTest : InteractionTest
|
||||
Assert.That(damageableComp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero), $"{VendingMachineProtoId} started with unexpected damage.");
|
||||
|
||||
// Damage the vending machine to the point that it breaks
|
||||
var damageType = ProtoMan.Index<DamageTypePrototype>("Blunt");
|
||||
var damageType = ProtoMan.Index(TestDamageType);
|
||||
var damage = new DamageSpecifier(damageType, FixedPoint2.New(100));
|
||||
await Server.WaitPost(() => damageableSys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true));
|
||||
await RunTicks(5);
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace Content.IntegrationTests.Tests
|
||||
[TestOf(typeof(VendingMachineSystem))]
|
||||
public sealed class VendingMachineRestockTest : EntitySystem
|
||||
{
|
||||
private static readonly ProtoId<DamageTypePrototype> TestDamageType = "Blunt";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = @"
|
||||
- type: entity
|
||||
@@ -293,7 +295,7 @@ namespace Content.IntegrationTests.Tests
|
||||
"Did not start with zero ramen.");
|
||||
|
||||
restock = entityManager.SpawnEntity("TestRestockExplode", coordinates);
|
||||
var damageSpec = new DamageSpecifier(prototypeManager.Index<DamageTypePrototype>("Blunt"), 100);
|
||||
var damageSpec = new DamageSpecifier(prototypeManager.Index(TestDamageType), 100);
|
||||
var damageResult = damageableSystem.TryChangeDamage(restock, damageSpec);
|
||||
|
||||
#pragma warning disable NUnit2045
|
||||
|
||||
@@ -2,39 +2,36 @@ using Content.Server.Chat.Systems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Moderator)]
|
||||
public sealed class DsayCommand : LocalizedEntityCommands
|
||||
{
|
||||
[AdminCommand(AdminFlags.Moderator)]
|
||||
sealed class DSay : IConsoleCommand
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
|
||||
public override string Command => "dsay";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _e = default!;
|
||||
|
||||
public string Command => "dsay";
|
||||
|
||||
public string Description => Loc.GetString("dsay-command-description");
|
||||
|
||||
public string Help => Loc.GetString("dsay-command-help-text", ("command", Command));
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
if (shell.Player is not { } player)
|
||||
{
|
||||
if (shell.Player is not { } player)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.AttachedEntity is not { Valid: true } entity)
|
||||
return;
|
||||
|
||||
if (args.Length < 1)
|
||||
return;
|
||||
|
||||
var message = string.Join(" ", args).Trim();
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return;
|
||||
|
||||
var chat = _e.System<ChatSystem>();
|
||||
chat.TrySendInGameOOCMessage(entity, message, InGameOOCChatType.Dead, false, shell, player);
|
||||
shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.AttachedEntity is not { Valid: true } entity)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-must-be-attached-to-entity"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 1)
|
||||
return;
|
||||
|
||||
var message = string.Join(" ", args).Trim();
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return;
|
||||
|
||||
_chatSystem.TrySendInGameOOCMessage(entity, message, InGameOOCChatType.Dead, false, shell, player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,18 @@ using Robust.Shared.Console;
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Debug)]
|
||||
public sealed class DirtyCommand : IConsoleCommand
|
||||
public sealed class DirtyCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
public override string Command => "dirty";
|
||||
|
||||
public string Command => "dirty";
|
||||
public string Description => "Marks all components on an entity as dirty, if not specified, dirties everything";
|
||||
public string Help => $"Usage: {Command} [entityUid]";
|
||||
|
||||
public async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
switch (args.Length)
|
||||
{
|
||||
case 0:
|
||||
foreach (var entity in _entManager.GetEntities())
|
||||
foreach (var entity in EntityManager.GetEntities())
|
||||
{
|
||||
DirtyAll(_entManager, entity);
|
||||
DirtyAll(entity);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -28,7 +24,7 @@ public sealed class DirtyCommand : IConsoleCommand
|
||||
shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||
return;
|
||||
}
|
||||
DirtyAll(_entManager, _entManager.GetEntity(parsedTarget));
|
||||
DirtyAll(EntityManager.GetEntity(parsedTarget));
|
||||
break;
|
||||
default:
|
||||
shell.WriteLine(Loc.GetString("shell-wrong-arguments-number"));
|
||||
@@ -36,11 +32,11 @@ public sealed class DirtyCommand : IConsoleCommand
|
||||
}
|
||||
}
|
||||
|
||||
private static void DirtyAll(IEntityManager manager, EntityUid entityUid)
|
||||
private void DirtyAll(EntityUid entityUid)
|
||||
{
|
||||
foreach (var component in manager.GetNetComponents(entityUid))
|
||||
foreach (var component in EntityManager.GetNetComponents(entityUid))
|
||||
{
|
||||
manager.Dirty(entityUid, component.component);
|
||||
EntityManager.Dirty(entityUid, component.component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,13 @@ using Robust.Shared.Enums;
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class FollowCommand : IConsoleCommand
|
||||
public sealed class FollowCommand : LocalizedEntityCommands
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly FollowerSystem _followerSystem = default!;
|
||||
|
||||
public string Command => "follow";
|
||||
public string Description => Loc.GetString("follow-command-description");
|
||||
public string Help => Loc.GetString("follow-command-help");
|
||||
public override string Command => "follow";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (shell.Player is not { } player)
|
||||
{
|
||||
@@ -34,10 +32,7 @@ public sealed class FollowCommand : IConsoleCommand
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = args[0];
|
||||
if (NetEntity.TryParse(entity, out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid))
|
||||
{
|
||||
_entManager.System<FollowerSystem>().StartFollowingEntity(playerEntity, uid.Value);
|
||||
}
|
||||
if (NetEntity.TryParse(args[0], out var uidNet) && EntityManager.TryGetEntity(uidNet, out var uid))
|
||||
_followerSystem.StartFollowingEntity(playerEntity, uid.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,6 +302,13 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
return;
|
||||
}
|
||||
|
||||
// PostgreSQL does not support storing null chars in text values.
|
||||
if (message.Contains('\0'))
|
||||
{
|
||||
_sawmill.Error($"Null character detected in admin log message '{message}'! LogType: {type}, LogImpact: {impact}");
|
||||
message = message.Replace("\0", "");
|
||||
}
|
||||
|
||||
var log = new AdminLog
|
||||
{
|
||||
Id = NextLogId,
|
||||
|
||||
@@ -22,25 +22,14 @@ public sealed partial class AdminVerbSystem
|
||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||
[Dependency] private readonly OutfitSystem _outfit = default!;
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string DefaultTraitorRule = "Traitor";
|
||||
private static readonly EntProtoId DefaultTraitorRule = "Traitor";
|
||||
private static readonly EntProtoId DefaultInitialInfectedRule = "Zombie";
|
||||
private static readonly EntProtoId DefaultNukeOpRule = "LoneOpsSpawn";
|
||||
private static readonly EntProtoId DefaultRevsRule = "Revolutionary";
|
||||
private static readonly EntProtoId DefaultThiefRule = "Thief";
|
||||
private static readonly ProtoId<StartingGearPrototype> PirateGearId = "PirateGear";
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string DefaultInitialInfectedRule = "Zombie";
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string DefaultNukeOpRule = "LoneOpsSpawn";
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string DefaultRevsRule = "Revolutionary";
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string DefaultThiefRule = "Thief";
|
||||
|
||||
[ValidatePrototypeId<StartingGearPrototype>]
|
||||
private const string PirateGearId = "PirateGear";
|
||||
|
||||
private readonly EntProtoId _paradoxCloneRuleId = "ParadoxCloneSpawn";
|
||||
private static readonly EntProtoId ParadoxCloneRuleId = "ParadoxCloneSpawn";
|
||||
|
||||
// All antag verbs have names so invokeverb works.
|
||||
private void AddAntagVerbs(GetVerbsEvent<Verb> args)
|
||||
@@ -172,7 +161,7 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/job_icons.rsi"), "ParadoxClone"),
|
||||
Act = () =>
|
||||
{
|
||||
var ruleEnt = _gameTicker.AddGameRule(_paradoxCloneRuleId);
|
||||
var ruleEnt = _gameTicker.AddGameRule(ParadoxCloneRuleId);
|
||||
|
||||
if (!TryComp<ParadoxCloneRuleComponent>(ruleEnt, out var paradoxCloneRuleComp))
|
||||
return;
|
||||
|
||||
@@ -273,7 +273,7 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/tomato_splat.rsi"), "puddle-1"),
|
||||
Act = () =>
|
||||
{
|
||||
_bloodstreamSystem.SpillAllSolutions(args.Target, bloodstream);
|
||||
_bloodstreamSystem.SpillAllSolutions((args.Target, bloodstream));
|
||||
var xform = Transform(args.Target);
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-remove-blood-self"), args.Target,
|
||||
args.Target, PopupType.LargeCaution);
|
||||
|
||||
@@ -44,8 +44,7 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
|
||||
public const float MinParticleVariation = 0.8f;
|
||||
public const float MaxParticleVariation = 1.2f;
|
||||
|
||||
[ValidatePrototypeId<WeightedRandomPrototype>]
|
||||
const string WeightListProto = "AnomalyBehaviorList";
|
||||
private static readonly ProtoId<WeightedRandomPrototype> WeightListProto = "AnomalyBehaviorList";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
@@ -189,7 +188,7 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
|
||||
#region Behavior
|
||||
private string GetRandomBehavior()
|
||||
{
|
||||
var weightList = _prototype.Index<WeightedRandomPrototype>(WeightListProto);
|
||||
var weightList = _prototype.Index(WeightListProto);
|
||||
return weightList.Pick(_random);
|
||||
}
|
||||
|
||||
|
||||
@@ -252,6 +252,128 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
Merge(destination, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the dimensionless fraction of gas required to equalize pressure between two gas mixtures.
|
||||
/// </summary>
|
||||
/// <param name="gasMixture1">The first gas mixture involved in the pressure equalization.
|
||||
/// This mixture should be the one you always expect to be the highest pressure.</param>
|
||||
/// <param name="gasMixture2">The second gas mixture involved in the pressure equalization.</param>
|
||||
/// <returns>A float (from 0 to 1) representing the dimensionless fraction of gas that needs to be transferred from the
|
||||
/// mixture of higher pressure to the mixture of lower pressure.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This properly takes into account the effect
|
||||
/// of gas merging from inlet to outlet affecting the temperature
|
||||
/// (and possibly increasing the pressure) in the outlet.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The gas is assumed to expand freely,
|
||||
/// so the temperature of the gas with the greater pressure is not changing.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// If you want to calculate the moles required to equalize pressure between an inlet and an outlet,
|
||||
/// multiply the fraction returned by the source moles.
|
||||
/// </example>
|
||||
public float FractionToEqualizePressure(GasMixture gasMixture1, GasMixture gasMixture2)
|
||||
{
|
||||
/*
|
||||
Problem: the gas being merged from the inlet to the outlet could affect the
|
||||
temp. of the gas and cause a pressure rise.
|
||||
We want the pressure to be equalized, so we have to account for this.
|
||||
|
||||
For clarity, let's assume that gasMixture1 is the inlet and gasMixture2 is the outlet.
|
||||
|
||||
We require mechanical equilibrium, so \( P_1' = P_2' \)
|
||||
|
||||
Before the transfer, we have:
|
||||
\( P_1 = \frac{n_1 R T_1}{V_1} \)
|
||||
\( P_2 = \frac{n_2 R T_2}{V_2} \)
|
||||
|
||||
After removing fraction \( x \) moles from the inlet, we have:
|
||||
\( P_1' = \frac{(1 - x) n_1 R T_1}{V_1} \)
|
||||
|
||||
The outlet will gain the same \( x n_1 \) moles of gas.
|
||||
So \( n_2' = n_2 + x n_1 \)
|
||||
|
||||
After mixing, the outlet temperature will be changed.
|
||||
Denote the new mixture temperature as \( T_2' \).
|
||||
Volume is constant.
|
||||
So we have:
|
||||
\( P_2' = \frac{(n_2 + x n_1) R T_2}{V_2} \)
|
||||
|
||||
The total energy of the incoming inlet to outlet gas at \( T_1 \) plus the existing energy of the outlet gas at \( T_2 \)
|
||||
will be equal to the energy of the new outlet gas at \( T_2' \).
|
||||
This leads to the following derivation:
|
||||
\( x n_1 C_1 T_1 + n_2 C_2 T_2 = (x n_1 C_1 + n_2 C_2) T_2' \)
|
||||
|
||||
Where \( C_1 \) and \( C_2 \) are the heat capacities of the inlet and outlet gases, respectively.
|
||||
|
||||
Solving for \( T_2' \) gives us:
|
||||
\( T_2' = \frac{x n_1 C_1 T_1 + n_2 C_2 T_2}{x n_1 C_1 + n_2 C_2} \)
|
||||
|
||||
Once again, we require mechanical equilibrium (\( P_1' = P_2' \)),
|
||||
so we can substitute \( T_2' \) into the pressure equation:
|
||||
|
||||
\( \frac{(1 - x) n_1 R T_1}{V_1} =
|
||||
\frac{(n_2 + x n_1) R}{V_2} \cdot
|
||||
\frac{x n_1 C_1 T_1 + n_2 C_2 T_2}
|
||||
{x n_1 C_1 + n_2 C_2} \)
|
||||
|
||||
Now it's a matter of solving for \( x \).
|
||||
Not going to show the full derivation here, just steps.
|
||||
1. Cancel common factor \( R \).
|
||||
2. Multiply both sides by \( x n_1 C_1 + n_2 C_2 \), so that everything
|
||||
becomes a polynomial in terms of \( x \).
|
||||
3. Expand both sides.
|
||||
4. Collect like powers of \( x \).
|
||||
5. After collecting, you should end up with a polynomial of the form:
|
||||
|
||||
\( (-n_1 C_1 T_1 (1 + \frac{V_2}{V_1})) x^2 +
|
||||
(n_1 T_1 \frac{V_2}{V_1} (C_1 - C_2) - n_2 C_1 T_1 - n_1 C_2 T_2) x +
|
||||
(n_1 T_1 \frac{V_2}{V_1} C_2 - n_2 C_2 T_2) = 0 \)
|
||||
|
||||
Divide through by \( n_1 C_1 T_1 \) and replace each ratio with a symbol for clarity:
|
||||
\( k_V = \frac{V_2}{V_1} \)
|
||||
\( k_n = \frac{n_2}{n_1} \)
|
||||
\( k_T = \frac{T_2}{T_1} \)
|
||||
\( k_C = \frac{C_2}{C_1} \)
|
||||
*/
|
||||
|
||||
// Ensure that P_1 > P_2 so the quadratic works out.
|
||||
if (gasMixture1.Pressure < gasMixture2.Pressure)
|
||||
{
|
||||
(gasMixture1, gasMixture2) = (gasMixture2, gasMixture1);
|
||||
}
|
||||
|
||||
// Establish the dimensionless ratios.
|
||||
var volumeRatio = gasMixture2.Volume / gasMixture1.Volume;
|
||||
var molesRatio = gasMixture2.TotalMoles / gasMixture1.TotalMoles;
|
||||
var temperatureRatio = gasMixture2.Temperature / gasMixture1.Temperature;
|
||||
var heatCapacityRatio = GetHeatCapacity(gasMixture2) / GetHeatCapacity(gasMixture1);
|
||||
|
||||
// The quadratic equation is solved for the transfer fraction.
|
||||
var quadraticA = 1 + volumeRatio;
|
||||
var quadraticB = molesRatio - volumeRatio + heatCapacityRatio * (temperatureRatio + volumeRatio);
|
||||
var quadraticC = heatCapacityRatio * (molesRatio * temperatureRatio - volumeRatio);
|
||||
|
||||
return (-quadraticB + MathF.Sqrt(quadraticB * quadraticB - 4 * quadraticA * quadraticC)) / (2 * quadraticA);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the number of moles that need to be removed from a <see cref="GasMixture"/> to reach a target pressure threshold.
|
||||
/// </summary>
|
||||
/// <param name="gasMixture">The gas mixture whose moles and properties will be used in the calculation.</param>
|
||||
/// <param name="targetPressure">The target pressure threshold to calculate against.</param>
|
||||
/// <returns>The difference in moles required to reach the target pressure threshold.</returns>
|
||||
/// <remarks>The temperature of the gas is assumed to be not changing due to a free expansion.</remarks>
|
||||
public static float MolesToPressureThreshold(GasMixture gasMixture, float targetPressure)
|
||||
{
|
||||
// Kid named PV = nRT.
|
||||
return gasMixture.TotalMoles -
|
||||
targetPressure * gasMixture.Volume / (Atmospherics.R * gasMixture.Temperature);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a gas mixture is probably safe.
|
||||
/// This only checks temperature and pressure, not gas composition.
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
||||
using Content.Shared.Audio;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Binary.EntitySystems;
|
||||
|
||||
/// <summary>
|
||||
/// Handles serverside logic for pressure regulators. Gas will only flow through the regulator
|
||||
/// if the pressure on the inlet side is over a certain pressure threshold.
|
||||
/// See https://en.wikipedia.org/wiki/Pressure_regulator
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed class GasPressureRegulatorSystem : SharedGasPressureRegulatorSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambientSound = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasPressureRegulatorComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<GasPressureRegulatorComponent, AtmosDeviceUpdateEvent>(OnPressureRegulatorUpdated);
|
||||
SubscribeLocalEvent<GasPressureRegulatorComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<GasPressureRegulatorComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
ent.Comp.NextUiUpdate = _timing.CurTime + ent.Comp.UpdateInterval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dirties the regulator every second or so, so that the UI can update.
|
||||
/// The UI automatically updates after an AutoHandleStateEvent.
|
||||
/// </summary>
|
||||
/// <param name="frameTime"></param>
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<GasPressureRegulatorComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (comp.NextUiUpdate > _timing.CurTime)
|
||||
continue;
|
||||
|
||||
comp.NextUiUpdate += comp.UpdateInterval;
|
||||
|
||||
DirtyFields(uid,
|
||||
comp,
|
||||
null,
|
||||
nameof(comp.InletPressure),
|
||||
nameof(comp.OutletPressure),
|
||||
nameof(comp.FlowRate));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInit(Entity<GasPressureRegulatorComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
UpdateAppearance(ent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the updating logic for the pressure regulator.
|
||||
/// </summary>
|
||||
/// <param name="ent"> the <see cref="Entity{T}" /> of the pressure regulator</param>
|
||||
/// <param name="args"> Args provided to us via <see cref="AtmosDeviceUpdateEvent" /></param>
|
||||
private void OnPressureRegulatorUpdated(Entity<GasPressureRegulatorComponent> ent,
|
||||
ref AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
if (!_nodeContainer.TryGetNodes(ent.Owner,
|
||||
ent.Comp.InletName,
|
||||
ent.Comp.OutletName,
|
||||
out PipeNode? inletPipeNode,
|
||||
out PipeNode? outletPipeNode))
|
||||
{
|
||||
ChangeStatus(false, ent, inletPipeNode, outletPipeNode, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
It's time for some math! :)
|
||||
|
||||
Gas is simply transferred from the inlet to the outlet, restricted by flow rate and pressure.
|
||||
We want to transfer enough gas to bring the inlet pressure below the threshold,
|
||||
and only as much as our max flow rate allows.
|
||||
|
||||
The equations:
|
||||
PV = nRT
|
||||
P1 = P2
|
||||
|
||||
Can be used to calculate the amount of gas we need to transfer.
|
||||
*/
|
||||
|
||||
var p1 = inletPipeNode.Air.Pressure;
|
||||
var p2 = outletPipeNode.Air.Pressure;
|
||||
|
||||
if (p1 <= ent.Comp.Threshold || p2 >= p1)
|
||||
{
|
||||
ChangeStatus(false, ent, inletPipeNode, outletPipeNode, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var t1 = inletPipeNode.Air.Temperature;
|
||||
|
||||
// First, calculate the amount of gas we need to transfer to bring us below the threshold.
|
||||
var deltaMolesToPressureThreshold =
|
||||
AtmosphereSystem.MolesToPressureThreshold(inletPipeNode.Air, ent.Comp.Threshold);
|
||||
|
||||
// Second, calculate the moles required to equalize the pressure.
|
||||
// We round here to avoid the valve staying enabled for 0.00001 pressure differences.
|
||||
var deltaMolesToEqualizePressure =
|
||||
float.Round(_atmosphere.FractionToEqualizePressure(inletPipeNode.Air, outletPipeNode.Air) *
|
||||
inletPipeNode.Air.TotalMoles,
|
||||
1,
|
||||
MidpointRounding.ToPositiveInfinity);
|
||||
|
||||
// Third, make sure we only transfer the minimum of the two.
|
||||
// We do this so that we don't accidentally transfer so much gas to the point
|
||||
// where the outlet pressure is higher than the inlet.
|
||||
var deltaMolesToTransfer = Math.Min(deltaMolesToPressureThreshold, deltaMolesToEqualizePressure);
|
||||
|
||||
// Fourth, convert to the desired volume to transfer.
|
||||
var desiredVolumeToTransfer = deltaMolesToTransfer * ((Atmospherics.R * t1) / p1);
|
||||
|
||||
// And finally, limit the transfer volume to the max flow rate of the valve.
|
||||
var actualVolumeToTransfer = Math.Min(desiredVolumeToTransfer,
|
||||
ent.Comp.MaxTransferRate * _atmosphere.PumpSpeedup() * args.dt);
|
||||
|
||||
// We remove the gas from the inlet and merge it into the outlet.
|
||||
var removed = inletPipeNode.Air.RemoveVolume(actualVolumeToTransfer);
|
||||
_atmosphere.Merge(outletPipeNode.Air, removed);
|
||||
|
||||
// Calculate the flow rate in L/s for the UI.
|
||||
var sentFlowRate = MathF.Round(actualVolumeToTransfer / args.dt, 1);
|
||||
|
||||
ChangeStatus(true, ent, inletPipeNode, outletPipeNode, sentFlowRate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the visual appearance of the pressure regulator based on its current state.
|
||||
/// </summary>
|
||||
/// <param name="ent">The <see cref="Entity{GasPressureRegulatorComponent, AppearanceComponent}"/>
|
||||
/// representing the pressure regulator with respective components.</param>
|
||||
private void UpdateAppearance(Entity<GasPressureRegulatorComponent> ent)
|
||||
{
|
||||
_appearance.SetData(ent,
|
||||
PressureRegulatorVisuals.State,
|
||||
ent.Comp.Enabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the pressure regulator's appearance and sound based on its current state, while
|
||||
/// also preventing network spamming.
|
||||
/// Also prepares data for dirtying.
|
||||
/// </summary>
|
||||
/// <param name="enabled">The new state to set</param>
|
||||
/// <param name="ent">The pressure regulator to update</param>
|
||||
/// <param name="inletNode">The inlet node of the pressure regulator</param>
|
||||
/// <param name="outletNode">The outlet node of the pressure regulator</param>
|
||||
/// <param name="flowRate">Current flow rate of the pressure regulator</param>
|
||||
private void ChangeStatus(bool enabled,
|
||||
Entity<GasPressureRegulatorComponent> ent,
|
||||
PipeNode? inletNode,
|
||||
PipeNode? outletNode,
|
||||
float flowRate)
|
||||
{
|
||||
// First, set data on the component server-side.
|
||||
ent.Comp.InletPressure = inletNode?.Air.Pressure ?? 0f;
|
||||
ent.Comp.OutletPressure = outletNode?.Air.Pressure ?? 0f;
|
||||
ent.Comp.FlowRate = flowRate;
|
||||
|
||||
// We need to prevent spamming the network with updates, so only check if we've
|
||||
// switched states.
|
||||
if (ent.Comp.Enabled == enabled)
|
||||
return;
|
||||
|
||||
ent.Comp.Enabled = enabled;
|
||||
_ambientSound.SetAmbience(ent, enabled);
|
||||
UpdateAppearance(ent);
|
||||
|
||||
// The regulator has changed state, so we need to dirty all applicable fields *right now* so the UI updates
|
||||
// at the same time as everything else.
|
||||
DirtyFields(ent.AsNullable(),
|
||||
null,
|
||||
nameof(ent.Comp.InletPressure),
|
||||
nameof(ent.Comp.OutletPressure),
|
||||
nameof(ent.Comp.FlowRate));
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Rotting;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Server.Containers;
|
||||
using Robust.Shared.Physics.Components;
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
using Content.Server.Bed.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Shared.Bed;
|
||||
using Content.Shared.Bed.Components;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Power;
|
||||
|
||||
namespace Content.Server.Bed
|
||||
{
|
||||
public sealed class BedSystem : SharedBedSystem
|
||||
{
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly EmagSystem _emag = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
||||
|
||||
private EntityQuery<SleepingComponent> _sleepingQuery;
|
||||
@@ -27,11 +19,6 @@ namespace Content.Server.Bed
|
||||
base.Initialize();
|
||||
|
||||
_sleepingQuery = GetEntityQuery<SleepingComponent>();
|
||||
|
||||
SubscribeLocalEvent<StasisBedComponent, StrappedEvent>(OnStasisStrapped);
|
||||
SubscribeLocalEvent<StasisBedComponent, UnstrappedEvent>(OnStasisUnstrapped);
|
||||
SubscribeLocalEvent<StasisBedComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
SubscribeLocalEvent<StasisBedComponent, GotEmaggedEvent>(OnEmagged);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -63,61 +50,5 @@ namespace Content.Server.Bed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAppearance(EntityUid uid, bool isOn)
|
||||
{
|
||||
_appearance.SetData(uid, StasisBedVisuals.IsOn, isOn);
|
||||
}
|
||||
|
||||
private void OnStasisStrapped(Entity<StasisBedComponent> bed, ref StrappedEvent args)
|
||||
{
|
||||
if (!HasComp<BodyComponent>(args.Buckle) || !this.IsPowered(bed, EntityManager))
|
||||
return;
|
||||
|
||||
var metabolicEvent = new ApplyMetabolicMultiplierEvent(args.Buckle, bed.Comp.Multiplier, true);
|
||||
RaiseLocalEvent(args.Buckle, ref metabolicEvent);
|
||||
}
|
||||
|
||||
private void OnStasisUnstrapped(Entity<StasisBedComponent> bed, ref UnstrappedEvent args)
|
||||
{
|
||||
if (!HasComp<BodyComponent>(args.Buckle) || !this.IsPowered(bed, EntityManager))
|
||||
return;
|
||||
|
||||
var metabolicEvent = new ApplyMetabolicMultiplierEvent(args.Buckle, bed.Comp.Multiplier, false);
|
||||
RaiseLocalEvent(args.Buckle, ref metabolicEvent);
|
||||
}
|
||||
|
||||
private void OnPowerChanged(EntityUid uid, StasisBedComponent component, ref PowerChangedEvent args)
|
||||
{
|
||||
UpdateAppearance(uid, args.Powered);
|
||||
UpdateMetabolisms(uid, component, args.Powered);
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, StasisBedComponent component, ref GotEmaggedEvent args)
|
||||
{
|
||||
if (!_emag.CompareFlag(args.Type, EmagType.Interaction))
|
||||
return;
|
||||
|
||||
if (_emag.CheckFlag(uid, EmagType.Interaction))
|
||||
return;
|
||||
|
||||
// Reset any metabolisms first so they receive the multiplier correctly
|
||||
UpdateMetabolisms(uid, component, false);
|
||||
component.Multiplier = 1 / component.Multiplier;
|
||||
UpdateMetabolisms(uid, component, true);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void UpdateMetabolisms(EntityUid uid, StasisBedComponent component, bool shouldApply)
|
||||
{
|
||||
if (!TryComp<StrapComponent>(uid, out var strap) || strap.BuckledEntities.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var buckledEntity in strap.BuckledEntities)
|
||||
{
|
||||
var metabolicEvent = new ApplyMetabolicMultiplierEvent(buckledEntity, component.Multiplier, shouldApply);
|
||||
RaiseLocalEvent(buckledEntity, ref metabolicEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user